Remove always defined FEATURE_CORECLR
[platform/upstream/coreclr.git] / src / vm / comutilnative.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5
6 //
7
8 /*============================================================
9 **
10 ** File:  COMUtilNative
11 **
12 **  
13 **
14 ** Purpose: A dumping ground for classes which aren't large
15 ** enough to get their own file in the EE.
16 **
17 **
18 **
19 ===========================================================*/
20 #include "common.h"
21 #include "object.h"
22 #include "excep.h"
23 #include "vars.hpp"
24 #include "comutilnative.h"
25
26 #include "utilcode.h"
27 #include "frames.h"
28 #include "field.h"
29 #include "winwrap.h"
30 #include "gcheaputilities.h"
31 #include "fcall.h"
32 #include "invokeutil.h"
33 #include "eeconfig.h"
34 #include "typestring.h"
35 #include "sha1.h"
36 #include "finalizerthread.h"
37
38 #ifdef FEATURE_COMINTEROP
39     #include "comcallablewrapper.h"
40     #include "comcache.h"
41 #endif // FEATURE_COMINTEROP
42
43 #define STACK_OVERFLOW_MESSAGE   W("StackOverflowException")
44
45 //These are defined in System.ParseNumbers and should be kept in sync.
46 #define PARSE_TREATASUNSIGNED 0x200
47 #define PARSE_TREATASI1 0x400
48 #define PARSE_TREATASI2 0x800
49 #define PARSE_ISTIGHT 0x1000
50 #define PARSE_NOSPACE 0x2000
51
52
53 //
54 //
55 // PARSENUMBERS (and helper functions)
56 //
57 //
58
59 /*===================================IsDigit====================================
60 **Returns a bool indicating whether the character passed in represents a   **
61 **digit.
62 ==============================================================================*/
63 bool IsDigit(WCHAR c, int radix, int *result)
64 {
65     CONTRACTL
66     {
67         NOTHROW;
68         GC_NOTRIGGER;
69         MODE_ANY;
70         PRECONDITION(CheckPointer(result));
71     }
72     CONTRACTL_END;
73
74     if (IS_DIGIT(c)) {
75         *result = DIGIT_TO_INT(c);
76     }
77     else if (c>='A' && c<='Z') {
78         //+10 is necessary because A is actually 10, etc.
79         *result = c-'A'+10;
80     }
81     else if (c>='a' && c<='z') {
82         //+10 is necessary because a is actually 10, etc.
83         *result = c-'a'+10;
84     }
85     else {
86         *result = -1;
87     }
88
89     if ((*result >=0) && (*result < radix))
90         return true;
91
92     return false;
93 }
94
95 INT32 wtoi(__in_ecount(length) WCHAR* wstr, DWORD length)
96 {  
97     CONTRACTL
98     {
99         NOTHROW;
100         GC_NOTRIGGER;
101         MODE_ANY;
102         PRECONDITION(CheckPointer(wstr));
103         PRECONDITION(length >= 0);
104     }
105     CONTRACTL_END;
106
107     DWORD i = 0;
108     int value;
109     INT32 result = 0;
110
111     while ( (i < length) && (IsDigit(wstr[i], 10 ,&value)) ) {
112         //Read all of the digits and convert to a number
113         result = result*10 + value;
114         i++;
115     }
116
117     return result;
118 }
119
120 INT32 ParseNumbers::GrabInts(const INT32 radix, __in_ecount(length) WCHAR *buffer, const int length, int *i, BOOL isUnsigned)
121 {
122     CONTRACTL
123     {
124         THROWS;
125         GC_NOTRIGGER;
126         MODE_COOPERATIVE;
127         PRECONDITION(CheckPointer(buffer));
128         PRECONDITION(CheckPointer(i));
129         PRECONDITION(*i >= 0);
130         PRECONDITION(length >= 0);
131         PRECONDITION( radix==2 || radix==8 || radix==10 || radix==16 );
132     }
133     CONTRACTL_END;
134
135     UINT32 result=0;
136     int value;
137     UINT32 maxVal;
138
139     // Allow all non-decimal numbers to set the sign bit.
140     if (radix==10 && !isUnsigned) {
141         maxVal = (0x7FFFFFFF / 10);
142
143         //Read all of the digits and convert to a number
144         while (*i<length&&(IsDigit(buffer[*i],radix,&value))) {
145             // Check for overflows - this is sufficient & correct.
146             if (result > maxVal || ((INT32)result)<0)
147                 COMPlusThrow(kOverflowException, W("Overflow_Int32"));
148             result = result*radix + value;
149             (*i)++;
150         }
151         if ((INT32)result<0 && result!=0x80000000)
152             COMPlusThrow(kOverflowException, W("Overflow_Int32"));
153
154     }
155     else {
156         maxVal = ((UINT32) -1) / radix;
157
158         //Read all of the digits and convert to a number
159         while (*i<length&&(IsDigit(buffer[*i],radix,&value))) {
160             // Check for overflows - this is sufficient & correct.
161             if (result > maxVal)
162                 COMPlusThrow(kOverflowException, W("Overflow_UInt32"));
163             // the above check won't cover 4294967296 to 4294967299
164             UINT32 temp = result*radix + value;
165             if( temp < result) { // this means overflow as well
166                 COMPlusThrow(kOverflowException, W("Overflow_UInt32"));
167             }
168
169             result = temp;
170             (*i)++;
171         }
172     }
173     return(INT32) result;
174 }
175
176 INT64 ParseNumbers::GrabLongs(const INT32 radix, __in_ecount(length) WCHAR *buffer, const int length, int *i, BOOL isUnsigned)
177 {
178     CONTRACTL
179     {
180         THROWS;
181         GC_NOTRIGGER;
182         MODE_COOPERATIVE;
183         PRECONDITION(CheckPointer(buffer));
184         PRECONDITION(CheckPointer(i));
185         PRECONDITION(*i >= 0);
186         PRECONDITION(length >= 0);
187     }
188     CONTRACTL_END;
189
190     UINT64 result=0;
191     int value;
192     UINT64 maxVal;
193
194     // Allow all non-decimal numbers to set the sign bit.
195     if (radix==10 && !isUnsigned) {
196         maxVal = (UI64(0x7FFFFFFFFFFFFFFF) / 10);
197
198         //Read all of the digits and convert to a number
199         while (*i<length&&(IsDigit(buffer[*i],radix,&value))) {
200             // Check for overflows - this is sufficient & correct.
201             if (result > maxVal || ((INT64)result)<0)
202                 COMPlusThrow(kOverflowException, W("Overflow_Int64"));
203             result = result*radix + value;
204             (*i)++;
205         }
206         if ((INT64)result<0 && result!=UI64(0x8000000000000000))
207             COMPlusThrow(kOverflowException, W("Overflow_Int64"));
208
209     }
210     else {
211         maxVal = ((UINT64) -1L) / radix;
212
213         //Read all of the digits and convert to a number
214         while (*i<length&&(IsDigit(buffer[*i],radix,&value))) {
215             // Check for overflows - this is sufficient & correct.
216             if (result > maxVal)
217                 COMPlusThrow(kOverflowException, W("Overflow_UInt64"));
218
219             UINT64 temp = result*radix + value;
220             if( temp < result) { // this means overflow as well
221                 COMPlusThrow(kOverflowException, W("Overflow_UInt64"));
222             }
223             result = temp;
224
225             (*i)++;
226         }
227     }
228     return(INT64) result;
229 }
230
231 void EatWhiteSpace(__in_ecount(length) WCHAR *buffer, int length, int *i)
232 {
233     CONTRACTL
234     {
235         NOTHROW;
236         GC_NOTRIGGER;
237         MODE_ANY;
238         PRECONDITION(CheckPointer(buffer));
239         PRECONDITION(CheckPointer(i));
240         PRECONDITION(length >= 0);
241     }
242     CONTRACTL_END;
243
244     for (; *i<length && COMCharacter::nativeIsWhiteSpace(buffer[*i]); (*i)++);
245 }
246
247 FCIMPL5_VII(LPVOID, ParseNumbers::LongToString, INT64 n, INT32 radix, INT32 width, CLR_CHAR paddingChar, INT32 flags)
248 {
249     FCALL_CONTRACT;
250
251     LPVOID rv = NULL;
252
253     HELPER_METHOD_FRAME_BEGIN_RET_0();
254
255     bool isNegative = false;
256     int index=0;
257     int charVal;
258     UINT64 l;
259     INT32 i;
260     INT32 buffLength=0;
261     WCHAR buffer[67];//Longest possible string length for an integer in binary notation with prefix
262
263     if (radix<MinRadix || radix>MaxRadix)
264         COMPlusThrowArgumentException(W("radix"), W("Arg_InvalidBase"));
265
266     //If the number is negative, make it positive and remember the sign.
267     if (n<0) {
268         isNegative=true;
269
270         // For base 10, write out -num, but other bases write out the
271         // 2's complement bit pattern
272         if (10==radix)
273             l = (UINT64)(-n);
274         else
275             l = (UINT64)n;
276     }
277     else {
278         l=(UINT64)n;
279     }
280
281     if (flags&PrintAsI1)
282         l = l&0xFF;
283     else if (flags&PrintAsI2)
284         l = l&0xFFFF;
285     else if (flags&PrintAsI4)
286         l=l&0xFFFFFFFF;
287
288     //Special case the 0.
289     if (0==l) {
290         buffer[0]='0';
291         index=1;
292     }
293     else {
294         //Pull apart the number and put the digits (in reverse order) into the buffer.
295         for (index=0; l>0; l=l/radix, index++) {
296             if ((charVal=(int)(l%radix))<10)
297                 buffer[index] = (WCHAR)(charVal + '0');
298             else
299                 buffer[index] = (WCHAR)(charVal + 'a' - 10);
300         }
301     }
302
303     //If they want the base, append that to the string (in reverse order)
304     if (radix!=10 && ((flags&PrintBase)!=0)) {
305         if (16==radix) {
306             buffer[index++]='x';
307             buffer[index++]='0';
308         }
309         else if (8==radix) {
310             buffer[index++]='0';
311         }
312         else if ((flags&PrintRadixBase)!=0) {
313             buffer[index++]='#';
314             buffer[index++]=((radix%10)+'0');
315             buffer[index++]=((static_cast<char>(radix)/10)+'0');
316         }
317     }
318
319     if (10==radix) {
320         //If it was negative, append the sign.
321         if (isNegative) {
322             buffer[index++]='-';
323         }
324
325         //else if they requested, add the '+';
326         else if ((flags&PrintSign)!=0) {
327             buffer[index++]='+';
328         }
329
330         //If they requested a leading space, put it on.
331         else if ((flags&PrefixSpace)!=0) {
332             buffer[index++]=' ';
333         }
334     }
335
336     //Figure out the size of our string.
337     if (width<=index)
338         buffLength=index;
339     else
340         buffLength=width;
341
342     STRINGREF Local = StringObject::NewString(buffLength);
343     WCHAR *LocalBuffer = Local->GetBuffer();
344
345     //Put the characters into the String in reverse order
346     //Fill the remaining space -- if there is any --
347     //with the correct padding character.
348     if ((flags&LeftAlign)!=0) {
349         for (i=0; i<index; i++) {
350             LocalBuffer[i]=buffer[index-i-1];
351         }
352         for (;i<buffLength; i++) {
353             LocalBuffer[i]=paddingChar;
354         }
355     }
356     else {
357         for (i=0; i<index; i++) {
358             LocalBuffer[buffLength-i-1]=buffer[i];
359         }
360         for (int j=buffLength-i-1; j>=0; j--) {
361             LocalBuffer[j]=paddingChar;
362         }
363     }
364
365     *((STRINGREF *)&rv)=Local;
366
367     HELPER_METHOD_FRAME_END();
368
369     return rv;
370 }
371 FCIMPLEND
372
373
374 FCIMPL5(LPVOID, ParseNumbers::IntToString, INT32 n, INT32 radix, INT32 width, CLR_CHAR paddingChar, INT32 flags)
375 {
376     FCALL_CONTRACT;
377
378     LPVOID rv = NULL;
379
380     HELPER_METHOD_FRAME_BEGIN_RET_0();
381
382     bool isNegative = false;
383     int index=0;
384     int charVal;
385     int buffLength;
386     int i;
387     UINT32 l;
388     WCHAR buffer[66];  //Longest possible string length for an integer in binary notation with prefix
389
390     if (radix<MinRadix || radix>MaxRadix)
391         COMPlusThrowArgumentException(W("radix"), W("Arg_InvalidBase"));
392
393     //If the number is negative, make it positive and remember the sign.
394     //If the number is MIN_VALUE, this will still be negative, so we'll have to
395     //special case this later.
396     if (n<0) {
397         isNegative=true;
398         // For base 10, write out -num, but other bases write out the
399         // 2's complement bit pattern
400         if (10==radix)
401             l = (UINT32)(-n);
402         else
403             l = (UINT32)n;
404     }
405     else {
406         l=(UINT32)n;
407     }
408
409     //The conversion to a UINT will sign extend the number.  In order to ensure
410     //that we only get as many bits as we expect, we chop the number.
411     if (flags&PrintAsI1) {
412         l = l&0xFF;
413     }
414     else if (flags&PrintAsI2) {
415         l = l&0xFFFF;
416     }
417     else if (flags&PrintAsI4) {
418         l=l&0xFFFFFFFF;
419     }
420
421     //Special case the 0.
422     if (0==l) {
423         buffer[0]='0';
424         index=1;
425     }
426     else {
427         do {
428             charVal = l%radix;
429             l=l/radix;
430             if (charVal<10) {
431                 buffer[index++] = (WCHAR)(charVal + '0');
432             }
433             else {
434                 buffer[index++] = (WCHAR)(charVal + 'a' - 10);
435             }
436         }
437         while (l!=0);
438     }
439
440     //If they want the base, append that to the string (in reverse order)
441     if (radix!=10 && ((flags&PrintBase)!=0)) {
442         if (16==radix) {
443             buffer[index++]='x';
444             buffer[index++]='0';
445         }
446         else if (8==radix) {
447             buffer[index++]='0';
448         }
449     }
450
451     if (10==radix) {
452         //If it was negative, append the sign.
453         if (isNegative) {
454             buffer[index++]='-';
455         }
456
457         //else if they requested, add the '+';
458         else if ((flags&PrintSign)!=0) {
459             buffer[index++]='+';
460         }
461
462         //If they requested a leading space, put it on.
463         else if ((flags&PrefixSpace)!=0) {
464             buffer[index++]=' ';
465         }
466     }
467
468     //Figure out the size of our string.
469     if (width<=index) {
470         buffLength=index;
471     }
472     else {
473         buffLength=width;
474     }
475
476     STRINGREF Local = StringObject::NewString(buffLength);
477     WCHAR *LocalBuffer = Local->GetBuffer();
478
479     //Put the characters into the String in reverse order
480     //Fill the remaining space -- if there is any --
481     //with the correct padding character.
482     if ((flags&LeftAlign)!=0) {
483         for (i=0; i<index; i++) {
484             LocalBuffer[i]=buffer[index-i-1];
485         }
486         for (;i<buffLength; i++) {
487             LocalBuffer[i]=paddingChar;
488         }
489     }
490     else {
491         for (i=0; i<index; i++) {
492             LocalBuffer[buffLength-i-1]=buffer[i];
493         }
494         for (int j=buffLength-i-1; j>=0; j--) {
495             LocalBuffer[j]=paddingChar;
496         }
497     }
498
499     *((STRINGREF *)&rv)=Local;
500
501     HELPER_METHOD_FRAME_END();
502
503     return rv;
504 }
505 FCIMPLEND
506
507
508 /*===================================FixRadix===================================
509 **It's possible that we parsed the radix in a base other than 10 by accident.
510 **This method will take that number, verify that it only contained valid base 10
511 **digits, and then do the conversion to base 10.  If it contained invalid digits,
512 **they tried to pass us a radix such as 1A, so we throw a FormatException.
513 **
514 **Args: oldVal: The value that we had actually parsed in some arbitrary base.
515 **      oldBase: The base in which we actually did the parsing.
516 **
517 **Returns:  oldVal as if it had been parsed as a base-10 number.
518 **Exceptions: FormatException if either of the digits in the radix aren't
519 **            valid base-10 numbers.
520 ==============================================================================*/
521 int FixRadix(int oldVal, int oldBase)
522 {
523     CONTRACTL
524     {
525         THROWS;
526         GC_NOTRIGGER;
527         MODE_COOPERATIVE;
528     }
529     CONTRACTL_END;
530
531     int firstDigit = (oldVal/oldBase);
532     int secondDigit = (oldVal%oldBase);
533
534     if ((firstDigit>=10) || (secondDigit>=10))
535         COMPlusThrow(kFormatException, W("Format_BadBase"));
536
537     return(firstDigit*10)+secondDigit;
538 }
539
540 /*=================================StringToLong=================================
541 **Action:
542 **Returns:
543 **Exceptions:
544 ==============================================================================*/
545 FCIMPL4(INT64, ParseNumbers::StringToLong, StringObject * s, INT32 radix, INT32 flags, INT32 *currPos)
546 {
547     FCALL_CONTRACT;
548
549     INT64 result = 0;
550
551     HELPER_METHOD_FRAME_BEGIN_RET_1(s);
552
553     int sign = 1;
554     WCHAR *input;
555     int length;
556     int i;
557     int grabNumbersStart=0;
558     INT32 r;
559
560     _ASSERTE((flags & PARSE_TREATASI1) == 0 && (flags & PARSE_TREATASI2) == 0);
561
562     if (s) {
563         i = currPos ? *currPos : 0;
564
565         //Do some radix checking.
566         //A radix of -1 says to use whatever base is spec'd on the number.
567         //Parse in Base10 until we figure out what the base actually is.
568         r = (-1==radix)?10:radix;
569
570         if (r!=2 && r!=10 && r!=8 && r!=16)
571             COMPlusThrow(kArgumentException, W("Arg_InvalidBase"));
572
573         s->RefInterpretGetStringValuesDangerousForGC(&input, &length);
574
575         if (i<0 || i>=length)
576             COMPlusThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Index"));
577
578         //Get rid of the whitespace and then check that we've still got some digits to parse.
579         if (!(flags & PARSE_ISTIGHT) && !(flags & PARSE_NOSPACE)) {
580             EatWhiteSpace(input,length,&i);
581             if (i==length)
582                 COMPlusThrow(kFormatException, W("Format_EmptyInputString"));
583         }
584
585         //Check for a sign
586         if (input[i]=='-') {
587             if (r != 10)
588                 COMPlusThrow(kArgumentException, W("Arg_CannotHaveNegativeValue"));
589
590             if (flags & PARSE_TREATASUNSIGNED)
591                 COMPlusThrow(kOverflowException, W("Overflow_NegativeUnsigned"));
592
593             sign = -1;
594             i++;
595         }
596         else if (input[i]=='+') {
597             i++;
598         }
599
600         if ((radix==-1 || radix==16) && (i+1<length) && input[i]=='0') {
601             if (input[i+1]=='x' || input [i+1]=='X') {
602                 r=16;
603                 i+=2;
604             }
605         }
606
607         grabNumbersStart=i;
608         result = GrabLongs(r,input,length,&i, (flags & PARSE_TREATASUNSIGNED));
609
610         //Check if they passed us a string with no parsable digits.
611         if (i==grabNumbersStart)
612             COMPlusThrow(kFormatException, W("Format_NoParsibleDigits"));
613
614         if (flags & PARSE_ISTIGHT) {
615             //If we've got effluvia left at the end of the string, complain.
616             if (i<length)
617                 COMPlusThrow(kFormatException, W("Format_ExtraJunkAtEnd"));
618         }
619
620         //Put the current index back into the correct place.
621         if (currPos != NULL) *currPos = i;
622
623         //Return the value properly signed.
624         if ((UINT64) result==UI64(0x8000000000000000) && sign==1 && r==10 && !(flags & PARSE_TREATASUNSIGNED))
625             COMPlusThrow(kOverflowException, W("Overflow_Int64"));
626
627         if (r == 10)
628             result *= sign;
629     }
630     else {
631         result = 0;
632     }
633
634     HELPER_METHOD_FRAME_END();
635
636     return result;
637 }
638 FCIMPLEND
639
640 FCIMPL4(INT32, ParseNumbers::StringToInt, StringObject * s, INT32 radix, INT32 flags, INT32* currPos)
641 {
642     FCALL_CONTRACT;
643
644     INT32 result = 0;
645
646     HELPER_METHOD_FRAME_BEGIN_RET_1(s);
647
648     int sign = 1;
649     WCHAR *input;
650     int length;
651     int i;
652     int grabNumbersStart=0;
653     INT32 r;
654
655     // TreatAsI1 and TreatAsI2 are mutually exclusive.
656     _ASSERTE(!((flags & PARSE_TREATASI1) != 0 && (flags & PARSE_TREATASI2) != 0));
657
658     if (s) {
659         //They're requied to tell me where to start parsing.
660         i = currPos ? (*currPos) : 0;
661
662         //Do some radix checking.
663         //A radix of -1 says to use whatever base is spec'd on the number.
664         //Parse in Base10 until we figure out what the base actually is.
665         r = (-1==radix)?10:radix;
666
667         if (r!=2 && r!=10 && r!=8 && r!=16)
668             COMPlusThrow(kArgumentException, W("Arg_InvalidBase"));
669
670         s->RefInterpretGetStringValuesDangerousForGC(&input, &length);
671
672         if (i<0 || i>=length)
673             COMPlusThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Index"));
674
675         //Get rid of the whitespace and then check that we've still got some digits to parse.
676         if (!(flags & PARSE_ISTIGHT) && !(flags & PARSE_NOSPACE)) {
677             EatWhiteSpace(input,length,&i);
678             if (i==length)
679                 COMPlusThrow(kFormatException, W("Format_EmptyInputString"));
680         }
681
682         //Check for a sign
683         if (input[i]=='-') {
684             if (r != 10)
685                 COMPlusThrow(kArgumentException, W("Arg_CannotHaveNegativeValue"));
686
687             if (flags & PARSE_TREATASUNSIGNED)
688                 COMPlusThrow(kOverflowException, W("Overflow_NegativeUnsigned"));
689
690             sign = -1;
691             i++;
692         }
693         else if (input[i]=='+') {
694             i++;
695         }
696
697         //Consume the 0x if we're in an unknown base or in base-16.
698         if ((radix==-1||radix==16) && (i+1<length) && input[i]=='0') {
699             if (input[i+1]=='x' || input [i+1]=='X') {
700                 r=16;
701                 i+=2;
702             }
703         }
704
705         grabNumbersStart=i;
706         result = GrabInts(r,input,length,&i, (flags & PARSE_TREATASUNSIGNED));
707
708         //Check if they passed us a string with no parsable digits.
709         if (i==grabNumbersStart)
710             COMPlusThrow(kFormatException, W("Format_NoParsibleDigits"));
711
712         if (flags & PARSE_ISTIGHT) {
713             //If we've got effluvia left at the end of the string, complain.
714             if (i<(length))
715                 COMPlusThrow(kFormatException, W("Format_ExtraJunkAtEnd"));
716         }
717
718         //Put the current index back into the correct place.
719         if (currPos != NULL) *currPos = i;
720
721         //Return the value properly signed.
722         if (flags & PARSE_TREATASI1) {
723             if ((UINT32)result > 0xFF)
724                 COMPlusThrow(kOverflowException, W("Overflow_SByte"));
725
726             // result looks positive when parsed as an I4
727             _ASSERTE(sign==1 || r==10);
728         }
729         else if (flags & PARSE_TREATASI2) {
730             if ((UINT32)result > 0xFFFF)
731                 COMPlusThrow(kOverflowException, W("Overflow_Int16"));
732
733             // result looks positive when parsed as an I4
734             _ASSERTE(sign==1 || r==10);
735         }
736         else if ((UINT32) result==0x80000000U && sign==1 && r==10 && !(flags & PARSE_TREATASUNSIGNED)) {
737             COMPlusThrow(kOverflowException, W("Overflow_Int32"));
738         }
739
740         if (r == 10)
741             result *= sign;
742     }
743     else {
744         result = 0;
745     }
746
747     HELPER_METHOD_FRAME_END();
748
749     return result;
750 }
751 FCIMPLEND
752
753 //
754 //
755 // EXCEPTION NATIVE
756 //
757 //
758 FCIMPL1(FC_BOOL_RET, ExceptionNative::IsImmutableAgileException, Object* pExceptionUNSAFE)
759 {
760     FCALL_CONTRACT;
761
762     ASSERT(pExceptionUNSAFE != NULL);
763
764     OBJECTREF pException = (OBJECTREF) pExceptionUNSAFE;
765
766     // The preallocated exception objects may be used from multiple AppDomains
767     // and therefore must remain immutable from the application's perspective.
768     FC_RETURN_BOOL(CLRException::IsPreallocatedExceptionObject(pException));
769 }
770 FCIMPLEND
771
772 FCIMPL1(FC_BOOL_RET, ExceptionNative::IsTransient, INT32 hresult)
773 {
774     FCALL_CONTRACT;
775
776     FC_RETURN_BOOL(Exception::IsTransient(hresult));
777 }
778 FCIMPLEND
779
780
781 #if defined(FEATURE_EXCEPTIONDISPATCHINFO)
782 // This FCall sets a flag against the thread exception state to indicate to
783 // IL_Throw and the StackTraceInfo implementation to account for the fact
784 // that we have restored a foreign exception dispatch details.
785 //
786 // Refer to the respective methods for details on how they use this flag.
787 FCIMPL0(VOID, ExceptionNative::PrepareForForeignExceptionRaise)
788 {
789     FCALL_CONTRACT;
790
791     PTR_ThreadExceptionState pCurTES = GetThread()->GetExceptionState();
792
793         // Set a flag against the TES to indicate this is a foreign exception raise.
794         pCurTES->SetRaisingForeignException();
795 }
796 FCIMPLEND
797
798 // Given an exception object, this method will extract the stacktrace and dynamic method array and set them up for return to the caller.
799 FCIMPL3(VOID, ExceptionNative::GetStackTracesDeepCopy, Object* pExceptionObjectUnsafe, Object **pStackTraceUnsafe, Object **pDynamicMethodsUnsafe);
800 {
801     CONTRACTL
802     {
803         FCALL_CHECK;
804     }
805     CONTRACTL_END;
806
807     ASSERT(pExceptionObjectUnsafe != NULL);
808     ASSERT(pStackTraceUnsafe != NULL);
809     ASSERT(pDynamicMethodsUnsafe != NULL);
810
811     struct _gc
812     {
813         StackTraceArray stackTrace;
814         StackTraceArray stackTraceCopy;
815         EXCEPTIONREF refException;
816         PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
817         PTRARRAYREF dynamicMethodsArrayCopy; // Copy of the object array of Managed Resolvers
818     };
819     _gc gc;
820     ZeroMemory(&gc, sizeof(gc));
821
822     // GC protect the array reference
823     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
824     
825     // Get the exception object reference
826     gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe));
827
828     // Fetch the stacktrace details from the exception under a lock
829     gc.refException->GetStackTrace(gc.stackTrace, &gc.dynamicMethodsArray);
830     
831     bool fHaveStackTrace = false;
832     bool fHaveDynamicMethodArray = false;
833
834     if ((unsigned)gc.stackTrace.Size() > 0)
835     {
836         // Deepcopy the array
837         gc.stackTraceCopy.CopyFrom(gc.stackTrace);
838         fHaveStackTrace = true;
839     }
840     
841     if (gc.dynamicMethodsArray != NULL)
842     {
843         // Get the number of elements in the dynamic methods array
844         unsigned   cOrigDynamic = gc.dynamicMethodsArray->GetNumComponents();
845     
846         // ..and allocate a new array. This can trigger GC or throw under OOM.
847         gc.dynamicMethodsArrayCopy = (PTRARRAYREF)AllocateObjectArray(cOrigDynamic, g_pObjectClass);
848     
849         // Deepcopy references to the new array we just allocated
850         memmoveGCRefs(gc.dynamicMethodsArrayCopy->GetDataPtr(), gc.dynamicMethodsArray->GetDataPtr(),
851                                                   cOrigDynamic * sizeof(Object *));
852
853         fHaveDynamicMethodArray = true;
854     }
855
856     // Prep to return
857     *pStackTraceUnsafe = fHaveStackTrace?OBJECTREFToObject(gc.stackTraceCopy.Get()):NULL;
858     *pDynamicMethodsUnsafe = fHaveDynamicMethodArray?OBJECTREFToObject(gc.dynamicMethodsArrayCopy):NULL;
859
860     HELPER_METHOD_FRAME_END();
861 }
862 FCIMPLEND
863
864 // Given an exception object and deep copied instances of a stacktrace and/or dynamic method array, this method will set the latter in the exception object instance.
865 FCIMPL3(VOID, ExceptionNative::SaveStackTracesFromDeepCopy, Object* pExceptionObjectUnsafe, Object *pStackTraceUnsafe, Object *pDynamicMethodsUnsafe);
866 {
867     CONTRACTL
868     {
869         FCALL_CHECK;
870     }
871     CONTRACTL_END;
872
873     ASSERT(pExceptionObjectUnsafe != NULL);
874
875     struct _gc
876     {
877         StackTraceArray stackTrace;
878         EXCEPTIONREF refException;
879         PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
880     };
881     _gc gc;
882     ZeroMemory(&gc, sizeof(gc));
883
884     // GC protect the array reference
885     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
886     
887     // Get the exception object reference
888     gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe));
889
890     if (pStackTraceUnsafe != NULL)
891     {
892         // Copy the stacktrace
893         StackTraceArray stackTraceArray((I1ARRAYREF)ObjectToOBJECTREF(pStackTraceUnsafe));
894         gc.stackTrace.Swap(stackTraceArray);
895     }
896
897     gc.dynamicMethodsArray = NULL;
898     if (pDynamicMethodsUnsafe != NULL)
899     {
900         gc.dynamicMethodsArray = (PTRARRAYREF)ObjectToOBJECTREF(pDynamicMethodsUnsafe);
901     }
902
903     // If there is no stacktrace, then there cannot be any dynamic method array. Thus,
904     // save stacktrace only when we have it.
905     if (gc.stackTrace.Size() > 0)
906     {
907         // Save the stacktrace details in the exception under a lock
908         gc.refException->SetStackTrace(gc.stackTrace, gc.dynamicMethodsArray);
909     }
910     else
911     {
912         gc.refException->SetNullStackTrace();
913     }
914
915     HELPER_METHOD_FRAME_END();
916 }
917 FCIMPLEND
918
919 // This method performs a deep copy of the stack trace array.
920 FCIMPL1(Object*, ExceptionNative::CopyStackTrace, Object* pStackTraceUNSAFE)
921 {
922     FCALL_CONTRACT;
923
924     ASSERT(pStackTraceUNSAFE != NULL);
925
926     struct _gc
927     {
928         StackTraceArray stackTrace;
929         StackTraceArray stackTraceCopy;
930         _gc(I1ARRAYREF refStackTrace)
931             : stackTrace(refStackTrace)
932         {}
933     };
934     _gc gc((I1ARRAYREF)(ObjectToOBJECTREF(pStackTraceUNSAFE)));
935
936     // GC protect the array reference
937     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
938         
939     // Deepcopy the array
940     gc.stackTraceCopy.CopyFrom(gc.stackTrace);
941     
942     HELPER_METHOD_FRAME_END();
943
944     return OBJECTREFToObject(gc.stackTraceCopy.Get());
945 }
946 FCIMPLEND
947
948 // This method performs a deep copy of the dynamic method array.
949 FCIMPL1(Object*, ExceptionNative::CopyDynamicMethods, Object* pDynamicMethodsUNSAFE)
950 {
951     FCALL_CONTRACT;
952
953     ASSERT(pDynamicMethodsUNSAFE != NULL);
954
955     struct _gc
956     {
957         PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
958         PTRARRAYREF dynamicMethodsArrayCopy; // Copy of the object array of Managed Resolvers
959         _gc()
960         {}
961     };
962     _gc gc;
963     ZeroMemory(&gc, sizeof(gc));
964     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
965     
966     gc.dynamicMethodsArray = (PTRARRAYREF)(ObjectToOBJECTREF(pDynamicMethodsUNSAFE));
967
968     // Get the number of elements in the array
969     unsigned   cOrigDynamic = gc.dynamicMethodsArray->GetNumComponents();
970     // ..and allocate a new array. This can trigger GC or throw under OOM.
971     gc.dynamicMethodsArrayCopy = (PTRARRAYREF)AllocateObjectArray(cOrigDynamic, g_pObjectClass);
972     
973     // Copy references to the new array we just allocated
974     memmoveGCRefs(gc.dynamicMethodsArrayCopy->GetDataPtr(), gc.dynamicMethodsArray->GetDataPtr(),
975                                               cOrigDynamic * sizeof(Object *));
976     HELPER_METHOD_FRAME_END();
977
978     return OBJECTREFToObject(gc.dynamicMethodsArrayCopy);
979 }
980 FCIMPLEND
981
982 #endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
983
984 BSTR BStrFromString(STRINGREF s)
985 {
986     CONTRACTL
987     {
988         THROWS;
989     }
990     CONTRACTL_END;
991
992     WCHAR *wz;
993     int cch;
994     BSTR bstr;
995
996     if (s == NULL)
997         return NULL;
998
999     s->RefInterpretGetStringValuesDangerousForGC(&wz, &cch);
1000
1001     bstr = SysAllocString(wz);
1002     if (bstr == NULL)
1003         COMPlusThrowOM();
1004
1005     return bstr;
1006 }
1007
1008 static BSTR GetExceptionDescription(OBJECTREF objException)
1009 {
1010     CONTRACTL
1011     {
1012         THROWS;
1013         GC_TRIGGERS;
1014         MODE_COOPERATIVE;
1015         PRECONDITION( IsException(objException->GetMethodTable()) );
1016     }
1017     CONTRACTL_END;
1018
1019     BSTR bstrDescription;
1020
1021     STRINGREF MessageString = NULL;
1022     GCPROTECT_BEGIN(MessageString)
1023     GCPROTECT_BEGIN(objException)
1024     {
1025 #ifdef FEATURE_APPX
1026         if (AppX::IsAppXProcess())
1027         {
1028             // In AppX, call Exception.ToString(false, false) which returns a string containing the exception class
1029             // name and callstack without file paths/names. This is used for unhandled exception bucketing/analysis.
1030             MethodDescCallSite getMessage(METHOD__EXCEPTION__TO_STRING, &objException);
1031
1032             ARG_SLOT GetMessageArgs[] =
1033             {
1034                 ObjToArgSlot(objException),
1035                 BoolToArgSlot(false),  // needFileLineInfo
1036                 BoolToArgSlot(false)   // needMessage
1037             };
1038             MessageString = getMessage.Call_RetSTRINGREF(GetMessageArgs);
1039         }
1040         else
1041 #endif // FEATURE_APPX
1042         {
1043             // read Exception.Message property
1044             MethodDescCallSite getMessage(METHOD__EXCEPTION__GET_MESSAGE, &objException);
1045
1046             ARG_SLOT GetMessageArgs[] = { ObjToArgSlot(objException)};
1047             MessageString = getMessage.Call_RetSTRINGREF(GetMessageArgs);
1048
1049             // if the message string is empty then use the exception classname.
1050             if (MessageString == NULL || MessageString->GetStringLength() == 0) {
1051                 // call GetClassName
1052                 MethodDescCallSite getClassName(METHOD__EXCEPTION__GET_CLASS_NAME, &objException);
1053                 ARG_SLOT GetClassNameArgs[] = { ObjToArgSlot(objException)};
1054                 MessageString = getClassName.Call_RetSTRINGREF(GetClassNameArgs);
1055                 _ASSERTE(MessageString != NULL && MessageString->GetStringLength() != 0);
1056             }
1057         }
1058
1059         // Allocate the description BSTR.
1060         int DescriptionLen = MessageString->GetStringLength();
1061         bstrDescription = SysAllocStringLen(MessageString->GetBuffer(), DescriptionLen);
1062     }
1063     GCPROTECT_END();
1064     GCPROTECT_END();
1065
1066     return bstrDescription;
1067 }
1068
1069 static BSTR GetExceptionSource(OBJECTREF objException)
1070 {
1071     CONTRACTL
1072     {
1073         THROWS;
1074         GC_TRIGGERS;
1075         MODE_COOPERATIVE;
1076         PRECONDITION( IsException(objException->GetMethodTable()) );
1077     }
1078     CONTRACTL_END;
1079
1080     STRINGREF refRetVal;
1081     GCPROTECT_BEGIN(objException)
1082
1083     // read Exception.Source property
1084     MethodDescCallSite getSource(METHOD__EXCEPTION__GET_SOURCE, &objException);
1085
1086     ARG_SLOT GetSourceArgs[] = { ObjToArgSlot(objException)};
1087
1088     refRetVal = getSource.Call_RetSTRINGREF(GetSourceArgs);
1089
1090     GCPROTECT_END();
1091     return BStrFromString(refRetVal);
1092 }
1093
1094 static void GetExceptionHelp(OBJECTREF objException, BSTR *pbstrHelpFile, DWORD *pdwHelpContext)
1095 {
1096     CONTRACTL
1097     {
1098         THROWS;
1099         GC_TRIGGERS;
1100         MODE_COOPERATIVE;
1101         INJECT_FAULT(COMPlusThrowOM());
1102         PRECONDITION(IsException(objException->GetMethodTable()));
1103         PRECONDITION(CheckPointer(pbstrHelpFile));
1104         PRECONDITION(CheckPointer(pdwHelpContext));
1105     }
1106     CONTRACTL_END;
1107
1108     *pdwHelpContext = 0;
1109
1110     GCPROTECT_BEGIN(objException);
1111
1112     // read Exception.HelpLink property
1113     MethodDescCallSite getHelpLink(METHOD__EXCEPTION__GET_HELP_LINK, &objException);
1114
1115     ARG_SLOT GetHelpLinkArgs[] = { ObjToArgSlot(objException)};
1116     *pbstrHelpFile = BStrFromString(getHelpLink.Call_RetSTRINGREF(GetHelpLinkArgs));
1117
1118     GCPROTECT_END();
1119
1120     // parse the help file to check for the presence of helpcontext
1121     int len = SysStringLen(*pbstrHelpFile);
1122     int pos = len;
1123     WCHAR *pwstr = *pbstrHelpFile;
1124     if (pwstr) {
1125         BOOL fFoundPound = FALSE;
1126
1127         for (pos = len - 1; pos >= 0; pos--) {
1128             if (pwstr[pos] == W('#')) {
1129                 fFoundPound = TRUE;
1130                 break;
1131             }
1132         }
1133
1134         if (fFoundPound) {
1135             int PoundPos = pos;
1136             int NumberStartPos = -1;
1137             BOOL bNumberStarted = FALSE;
1138             BOOL bNumberFinished = FALSE;
1139             BOOL bInvalidDigitsFound = FALSE;
1140
1141             _ASSERTE(pwstr[pos] == W('#'));
1142
1143             // Check to see if the string to the right of the pound a valid number.
1144             for (pos++; pos < len; pos++) {
1145                 if (bNumberFinished) {
1146                     if (!COMCharacter::nativeIsWhiteSpace(pwstr[pos])) {
1147                         bInvalidDigitsFound = TRUE;
1148                         break;
1149                     }
1150                 }
1151                 else if (bNumberStarted) {
1152                     if (COMCharacter::nativeIsWhiteSpace(pwstr[pos])) {
1153                         bNumberFinished = TRUE;
1154                     }
1155                     else if (!COMCharacter::nativeIsDigit(pwstr[pos])) {
1156                         bInvalidDigitsFound = TRUE;
1157                         break;
1158                     }
1159                 }
1160                 else {
1161                     if (COMCharacter::nativeIsDigit(pwstr[pos])) {
1162                         NumberStartPos = pos;
1163                         bNumberStarted = TRUE;
1164                     }
1165                     else if (!COMCharacter::nativeIsWhiteSpace(pwstr[pos])) {
1166                         bInvalidDigitsFound = TRUE;
1167                         break;
1168                     }
1169                 }
1170             }
1171
1172             if (bNumberStarted && !bInvalidDigitsFound) {
1173                 // Grab the help context and remove it from the help file.
1174                 *pdwHelpContext = (DWORD)wtoi(&pwstr[NumberStartPos], len - NumberStartPos);
1175
1176                 // Allocate a new help file string of the right length.
1177                 BSTR strOld = *pbstrHelpFile;
1178                 *pbstrHelpFile = SysAllocStringLen(strOld, PoundPos);
1179                 SysFreeString(strOld);
1180                 if (!*pbstrHelpFile)
1181                     COMPlusThrowOM();
1182             }
1183         }
1184     }
1185 }
1186
1187 // NOTE: caller cleans up any partially initialized BSTRs in pED
1188 void ExceptionNative::GetExceptionData(OBJECTREF objException, ExceptionData *pED)
1189 {
1190     CONTRACTL
1191     {
1192         THROWS;
1193         GC_TRIGGERS;
1194         MODE_COOPERATIVE;
1195         PRECONDITION(IsException(objException->GetMethodTable()));
1196         PRECONDITION(CheckPointer(pED));
1197     }
1198     CONTRACTL_END;
1199
1200     ZeroMemory(pED, sizeof(ExceptionData));
1201
1202     if (objException->GetMethodTable() == g_pStackOverflowExceptionClass) {
1203         // In a low stack situation, most everything else in here will fail.
1204         // <TODO>@TODO: We're not turning the guard page back on here, yet.</TODO>
1205         pED->hr = COR_E_STACKOVERFLOW;
1206         pED->bstrDescription = SysAllocString(STACK_OVERFLOW_MESSAGE);
1207         return;
1208     }
1209
1210     GCPROTECT_BEGIN(objException);
1211     pED->hr = GetExceptionHResult(objException);
1212     pED->bstrDescription = GetExceptionDescription(objException);
1213     pED->bstrSource = GetExceptionSource(objException);
1214     GetExceptionHelp(objException, &pED->bstrHelpFile, &pED->dwHelpContext);
1215     GCPROTECT_END();
1216     return;
1217 }
1218
1219 #ifdef FEATURE_COMINTEROP
1220
1221 HRESULT SimpleComCallWrapper::IErrorInfo_hr()
1222 {
1223     WRAPPER_NO_CONTRACT;
1224     return GetExceptionHResult(this->GetObjectRef());
1225 }
1226
1227 BSTR SimpleComCallWrapper::IErrorInfo_bstrDescription()
1228 {
1229     WRAPPER_NO_CONTRACT;
1230     return GetExceptionDescription(this->GetObjectRef());
1231 }
1232
1233 BSTR SimpleComCallWrapper::IErrorInfo_bstrSource()
1234 {
1235     WRAPPER_NO_CONTRACT;
1236     return GetExceptionSource(this->GetObjectRef());
1237 }
1238
1239 BSTR SimpleComCallWrapper::IErrorInfo_bstrHelpFile()
1240 {
1241     WRAPPER_NO_CONTRACT;
1242     BSTR  bstrHelpFile;
1243     DWORD dwHelpContext;
1244     GetExceptionHelp(this->GetObjectRef(), &bstrHelpFile, &dwHelpContext);
1245     return bstrHelpFile;
1246 }
1247
1248 DWORD SimpleComCallWrapper::IErrorInfo_dwHelpContext()
1249 {
1250     WRAPPER_NO_CONTRACT;
1251     BSTR  bstrHelpFile;
1252     DWORD dwHelpContext;
1253     GetExceptionHelp(this->GetObjectRef(), &bstrHelpFile, &dwHelpContext);
1254     SysFreeString(bstrHelpFile);
1255     return dwHelpContext;
1256 }
1257
1258 GUID SimpleComCallWrapper::IErrorInfo_guid()
1259 {
1260     LIMITED_METHOD_CONTRACT;
1261     return GUID_NULL;
1262 }
1263
1264 #endif // FEATURE_COMINTEROP
1265
1266 FCIMPL0(EXCEPTION_POINTERS*, ExceptionNative::GetExceptionPointers)
1267 {
1268     FCALL_CONTRACT;
1269
1270     EXCEPTION_POINTERS* retVal = NULL;
1271
1272     Thread *pThread = GetThread();
1273     _ASSERTE(pThread);
1274
1275     if (pThread->IsExceptionInProgress())
1276     {
1277         retVal = pThread->GetExceptionState()->GetExceptionPointers();
1278     }
1279
1280     return retVal;
1281 }
1282 FCIMPLEND
1283
1284 FCIMPL0(INT32, ExceptionNative::GetExceptionCode)
1285 {
1286     FCALL_CONTRACT;
1287
1288     INT32 retVal = 0;
1289
1290     Thread *pThread = GetThread();
1291     _ASSERTE(pThread);
1292
1293     if (pThread->IsExceptionInProgress())
1294     {
1295         retVal = pThread->GetExceptionState()->GetExceptionCode();
1296     }
1297
1298     return retVal;
1299 }
1300 FCIMPLEND
1301
1302
1303 //
1304 // This must be implemented as an FCALL because managed code cannot
1305 // swallow a thread abort exception without resetting the abort,
1306 // which we don't want to do.  Additionally, we can run into deadlocks
1307 // if we use the ResourceManager to do resource lookups - it requires
1308 // taking managed locks when initializing Globalization & Security,
1309 // but a thread abort on a separate thread initializing those same
1310 // systems would also do a resource lookup via the ResourceManager.
1311 // We've deadlocked in CompareInfo.GetCompareInfo &
1312 // Environment.GetResourceString.  It's not practical to take all of
1313 // our locks within CER's to avoid this problem - just use the CLR's
1314 // unmanaged resources.
1315 //
1316 void QCALLTYPE ExceptionNative::GetMessageFromNativeResources(ExceptionMessageKind kind, QCall::StringHandleOnStack retMesg)
1317 {
1318     QCALL_CONTRACT;
1319
1320     BEGIN_QCALL;
1321
1322     SString buffer;
1323     HRESULT hr = S_OK;
1324     const WCHAR * wszFallbackString = NULL;
1325
1326     switch(kind) {
1327     case ThreadAbort:
1328         hr = buffer.LoadResourceAndReturnHR(CCompRC::Error, IDS_EE_THREAD_ABORT);
1329         if (FAILED(hr)) {
1330             wszFallbackString = W("Thread was being aborted.");
1331         }
1332         break;
1333
1334     case ThreadInterrupted:
1335         hr = buffer.LoadResourceAndReturnHR(CCompRC::Error, IDS_EE_THREAD_INTERRUPTED);
1336         if (FAILED(hr)) {
1337             wszFallbackString = W("Thread was interrupted from a waiting state.");
1338         }
1339         break;
1340
1341     case OutOfMemory:
1342         hr = buffer.LoadResourceAndReturnHR(CCompRC::Error, IDS_EE_OUT_OF_MEMORY);
1343         if (FAILED(hr)) {
1344             wszFallbackString = W("Insufficient memory to continue the execution of the program.");
1345         }
1346         break;
1347
1348     default:
1349         _ASSERTE(!"Unknown ExceptionMessageKind value!");
1350     }
1351     if (FAILED(hr)) {       
1352         STRESS_LOG1(LF_BCL, LL_ALWAYS, "LoadResource error: %x", hr);
1353         _ASSERTE(wszFallbackString != NULL);
1354         retMesg.Set(wszFallbackString);
1355     }
1356     else {
1357         retMesg.Set(buffer);
1358     }
1359
1360     END_QCALL;
1361 }
1362
1363 // BlockCopy
1364 // This method from one primitive array to another based
1365 //  upon an offset into each an a byte count.
1366 FCIMPL5(VOID, Buffer::BlockCopy, ArrayBase *src, int srcOffset, ArrayBase *dst, int dstOffset, int count)
1367 {
1368     FCALL_CONTRACT;
1369
1370     // Verify that both the src and dst are Arrays of primitive
1371     //  types.
1372     // <TODO>@TODO: We need to check for booleans</TODO>
1373     if (src==NULL || dst==NULL)
1374         FCThrowArgumentNullVoid((src==NULL) ? W("src") : W("dst"));
1375
1376     SIZE_T srcLen, dstLen;
1377
1378     //
1379     // Use specialized fast path for byte arrays because of it is what Buffer::BlockCopy is 
1380     // typically used for.
1381     //
1382
1383     MethodTable * pByteArrayMT = g_pByteArrayMT;
1384     _ASSERTE(pByteArrayMT != NULL);
1385     
1386     // Optimization: If src is a byte array, we can
1387     // simply set srcLen to GetNumComponents, without having
1388     // to call GetComponentSize or verifying GetArrayElementType
1389     if (src->GetMethodTable() == pByteArrayMT)
1390     {
1391         srcLen = src->GetNumComponents();
1392     }
1393     else
1394     {
1395         srcLen = src->GetNumComponents() * src->GetComponentSize();
1396
1397         // We only want to allow arrays of primitives, no Objects.
1398         const CorElementType srcET = src->GetArrayElementType();
1399         if (!CorTypeInfo::IsPrimitiveType_NoThrow(srcET))
1400             FCThrowArgumentVoid(W("src"), W("Arg_MustBePrimArray"));
1401     }
1402     
1403     // Optimization: If copying to/from the same array, then
1404     // we know that dstLen and srcLen must be the same.
1405     if (src == dst)
1406     {
1407         dstLen = srcLen;
1408     }
1409     else if (dst->GetMethodTable() == pByteArrayMT)
1410     {
1411         dstLen = dst->GetNumComponents();
1412     }
1413     else
1414     {
1415         dstLen = dst->GetNumComponents() * dst->GetComponentSize();
1416         if (dst->GetMethodTable() != src->GetMethodTable())
1417         {
1418             const CorElementType dstET = dst->GetArrayElementType();
1419             if (!CorTypeInfo::IsPrimitiveType_NoThrow(dstET))
1420                 FCThrowArgumentVoid(W("dest"), W("Arg_MustBePrimArray"));
1421         }
1422     }
1423
1424     if (srcOffset < 0 || dstOffset < 0 || count < 0) {
1425         const wchar_t* str = W("srcOffset");
1426         if (dstOffset < 0) str = W("dstOffset");
1427         if (count < 0) str = W("count");
1428         FCThrowArgumentOutOfRangeVoid(str, W("ArgumentOutOfRange_NeedNonNegNum"));
1429     }
1430
1431     if (srcLen < (SIZE_T)srcOffset + (SIZE_T)count || dstLen < (SIZE_T)dstOffset + (SIZE_T)count) {
1432         FCThrowArgumentVoid(NULL, W("Argument_InvalidOffLen"));
1433     }
1434     
1435     PTR_BYTE srcPtr = src->GetDataPtr() + srcOffset;
1436     PTR_BYTE dstPtr = dst->GetDataPtr() + dstOffset;
1437
1438     if ((srcPtr != dstPtr) && (count > 0)) {
1439 #if defined(_AMD64_) && !defined(PLATFORM_UNIX)
1440         JIT_MemCpy(dstPtr, srcPtr, count);
1441 #else
1442         memmove(dstPtr, srcPtr, count);
1443 #endif
1444     }
1445
1446     FC_GC_POLL();
1447 }
1448 FCIMPLEND
1449
1450
1451 // InternalBlockCopy
1452 // This method from one primitive array to another based
1453 //  upon an offset into each an a byte count.
1454 FCIMPL5(VOID, Buffer::InternalBlockCopy, ArrayBase *src, int srcOffset, ArrayBase *dst, int dstOffset, int count)
1455 {
1456     FCALL_CONTRACT;
1457
1458     // @TODO: We should consider writing this in managed code.  We probably
1459     // cannot easily do this though - how do we get at the array's data?
1460
1461     // Unfortunately, we must do a check to make sure we're writing within
1462     // the bounds of the array.  This will ensure that we don't overwrite
1463     // memory elsewhere in the system nor do we write out junk.  This can
1464     // happen if multiple threads interact with our IO classes simultaneously
1465     // without being threadsafe.  Throw here.  
1466     // Unfortunately this even applies to setting our internal buffers to
1467     // null.  We don't want to debug races between Close and Read or Write.
1468     if (src == NULL || dst == NULL)
1469         FCThrowResVoid(kIndexOutOfRangeException, W("IndexOutOfRange_IORaceCondition"));
1470
1471     SIZE_T srcLen = src->GetNumComponents() * src->GetComponentSize();
1472     SIZE_T dstLen = srcLen;
1473     if (src != dst)
1474         dstLen = dst->GetNumComponents() * dst->GetComponentSize();
1475
1476     if (srcOffset < 0 || dstOffset < 0 || count < 0)
1477         FCThrowResVoid(kIndexOutOfRangeException, W("IndexOutOfRange_IORaceCondition"));
1478
1479     if (srcLen < (SIZE_T)srcOffset + (SIZE_T)count || dstLen < (SIZE_T)dstOffset + (SIZE_T)count)
1480         FCThrowResVoid(kIndexOutOfRangeException, W("IndexOutOfRange_IORaceCondition"));
1481
1482     _ASSERTE(srcOffset >= 0);
1483     _ASSERTE((src->GetNumComponents() * src->GetComponentSize()) - (unsigned) srcOffset >= (unsigned) count);
1484     _ASSERTE((dst->GetNumComponents() * dst->GetComponentSize()) - (unsigned) dstOffset >= (unsigned) count);
1485     _ASSERTE(dstOffset >= 0);
1486     _ASSERTE(count >= 0);
1487
1488     // Copy the data.
1489 #if defined(_AMD64_) && !defined(PLATFORM_UNIX)
1490     JIT_MemCpy(dst->GetDataPtr() + dstOffset, src->GetDataPtr() + srcOffset, count);
1491 #else
1492     memmove(dst->GetDataPtr() + dstOffset, src->GetDataPtr() + srcOffset, count);
1493 #endif
1494
1495     FC_GC_POLL();
1496 }
1497 FCIMPLEND
1498
1499 void QCALLTYPE Buffer::MemMove(void *dst, void *src, size_t length)
1500 {
1501     QCALL_CONTRACT;
1502
1503
1504     memmove(dst, src, length);
1505 }
1506
1507 // Returns a bool to indicate if the array is of primitive types or not.
1508 FCIMPL1(FC_BOOL_RET, Buffer::IsPrimitiveTypeArray, ArrayBase *arrayUNSAFE)
1509 {
1510     FCALL_CONTRACT;
1511
1512     _ASSERTE(arrayUNSAFE != NULL);
1513
1514     // Check the type from the contained element's handle
1515     TypeHandle elementTH = arrayUNSAFE->GetArrayElementTypeHandle();
1516     BOOL fIsPrimitiveTypeArray = CorTypeInfo::IsPrimitiveType_NoThrow(elementTH.GetVerifierCorElementType());
1517
1518     FC_RETURN_BOOL(fIsPrimitiveTypeArray);
1519
1520 }
1521 FCIMPLEND
1522
1523 // Gets a particular byte out of the array.  The array can't be an array of Objects - it
1524 // must be a primitive array.
1525 FCIMPL2(FC_UINT8_RET, Buffer::GetByte, ArrayBase *arrayUNSAFE, INT32 index)
1526 {
1527     FCALL_CONTRACT;
1528
1529     _ASSERTE(arrayUNSAFE != NULL);
1530     _ASSERTE(index >=0 && index < ((INT32)(arrayUNSAFE->GetComponentSize() * arrayUNSAFE->GetNumComponents())));
1531
1532     UINT8 bData = *((BYTE*)arrayUNSAFE->GetDataPtr() + index);
1533     return bData;
1534 }
1535 FCIMPLEND
1536
1537 // Sets a particular byte in an array.  The array can't be an array of Objects - it
1538 // must be a primitive array.
1539 //
1540 // Semantically the bData argment is of type BYTE but FCallCheckSignature expects the 
1541 // type to be UINT8 and raises an error if this isn't this case when 
1542 // COMPlus_ConsistencyCheck is set.
1543 FCIMPL3(VOID, Buffer::SetByte, ArrayBase *arrayUNSAFE, INT32 index, UINT8 bData)
1544 {
1545     FCALL_CONTRACT;
1546
1547     _ASSERTE(arrayUNSAFE != NULL);
1548     _ASSERTE(index >=0 && index < ((INT32)(arrayUNSAFE->GetComponentSize() * arrayUNSAFE->GetNumComponents())));
1549     
1550     *((BYTE*)arrayUNSAFE->GetDataPtr() + index) = (BYTE) bData;
1551 }
1552 FCIMPLEND
1553
1554 // Returns the length in bytes of an array containing
1555 // primitive type elements
1556 FCIMPL1(INT32, Buffer::ByteLength, ArrayBase* arrayUNSAFE)
1557 {
1558     FCALL_CONTRACT;
1559
1560     _ASSERTE(arrayUNSAFE != NULL);
1561
1562     SIZE_T iRetVal = arrayUNSAFE->GetNumComponents() * arrayUNSAFE->GetComponentSize();
1563
1564     // This API is explosed both as Buffer.ByteLength and also used indirectly in argument
1565     // checks for Buffer.GetByte/SetByte.
1566     //
1567     // If somebody called Get/SetByte on 2GB+ arrays, there is a decent chance that 
1568     // the computation of the index has overflowed. Thus we intentionally always 
1569     // throw on 2GB+ arrays in Get/SetByte argument checks (even for indicies <2GB)
1570     // to prevent people from running into a trap silently.
1571     if (iRetVal > INT32_MAX)
1572         FCThrow(kOverflowException);
1573
1574     return (INT32)iRetVal;
1575 }
1576 FCIMPLEND
1577
1578 //
1579 // GCInterface
1580 //
1581 MethodDesc *GCInterface::m_pCacheMethod=NULL;
1582
1583 UINT64   GCInterface::m_ulMemPressure = 0;
1584 UINT64   GCInterface::m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
1585 INT32    GCInterface::m_gc_counts[3] = {0,0,0};
1586 CrstStatic GCInterface::m_MemoryPressureLock;
1587
1588 UINT64   GCInterface::m_addPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0};   // history of memory pressure additions
1589 UINT64   GCInterface::m_remPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0};   // history of memory pressure removals
1590
1591 // incremented after a gen2 GC has been detected,
1592 // (m_iteration % NEW_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure
1593 UINT     GCInterface::m_iteration = 0;
1594
1595 FCIMPL0(int, GCInterface::GetGcLatencyMode)
1596 {
1597     FCALL_CONTRACT;
1598
1599     FC_GC_POLL_NOT_NEEDED();
1600
1601     int result = (INT32)GCHeapUtilities::GetGCHeap()->GetGcLatencyMode();
1602     return result;
1603 }
1604 FCIMPLEND
1605
1606 FCIMPL1(int, GCInterface::SetGcLatencyMode, int newLatencyMode)
1607 {
1608     FCALL_CONTRACT;
1609
1610     FC_GC_POLL_NOT_NEEDED();
1611     
1612     return GCHeapUtilities::GetGCHeap()->SetGcLatencyMode(newLatencyMode);
1613 }
1614 FCIMPLEND
1615
1616 FCIMPL0(int, GCInterface::GetLOHCompactionMode)
1617 {
1618     FCALL_CONTRACT;
1619
1620     FC_GC_POLL_NOT_NEEDED();
1621
1622     int result = (INT32)GCHeapUtilities::GetGCHeap()->GetLOHCompactionMode();
1623     return result;
1624 }
1625 FCIMPLEND
1626
1627 FCIMPL1(void, GCInterface::SetLOHCompactionMode, int newLOHCompactionyMode)
1628 {
1629     FCALL_CONTRACT;
1630
1631     FC_GC_POLL_NOT_NEEDED();
1632     
1633     GCHeapUtilities::GetGCHeap()->SetLOHCompactionMode(newLOHCompactionyMode);
1634 }
1635 FCIMPLEND
1636
1637
1638 FCIMPL2(FC_BOOL_RET, GCInterface::RegisterForFullGCNotification, UINT32 gen2Percentage, UINT32 lohPercentage)
1639 {
1640     FCALL_CONTRACT;
1641
1642     FC_GC_POLL_NOT_NEEDED();
1643
1644     FC_RETURN_BOOL(GCHeapUtilities::GetGCHeap()->RegisterForFullGCNotification(gen2Percentage, lohPercentage));
1645 }
1646 FCIMPLEND
1647
1648 FCIMPL0(FC_BOOL_RET, GCInterface::CancelFullGCNotification)
1649 {
1650     FCALL_CONTRACT;
1651
1652     FC_GC_POLL_NOT_NEEDED();
1653     FC_RETURN_BOOL(GCHeapUtilities::GetGCHeap()->CancelFullGCNotification());
1654 }
1655 FCIMPLEND
1656
1657 FCIMPL1(int, GCInterface::WaitForFullGCApproach, int millisecondsTimeout)
1658 {
1659     CONTRACTL
1660     {
1661         THROWS;
1662         MODE_COOPERATIVE;
1663         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
1664         SO_TOLERANT;
1665     }
1666     CONTRACTL_END;
1667
1668     int result = 0; 
1669
1670     //We don't need to check the top end because the GC will take care of that.
1671     HELPER_METHOD_FRAME_BEGIN_RET_0();
1672
1673     DWORD dwMilliseconds = ((millisecondsTimeout == -1) ? INFINITE : millisecondsTimeout);
1674     result = GCHeapUtilities::GetGCHeap()->WaitForFullGCApproach(dwMilliseconds);
1675
1676     HELPER_METHOD_FRAME_END();
1677
1678     return result;
1679 }
1680 FCIMPLEND
1681
1682 FCIMPL1(int, GCInterface::WaitForFullGCComplete, int millisecondsTimeout)
1683 {
1684     CONTRACTL
1685     {
1686         THROWS;
1687         MODE_COOPERATIVE;
1688         DISABLED(GC_TRIGGERS);  // can't use this in an FCALL because we're in forbid gc mode until we setup a H_M_F.
1689         SO_TOLERANT;
1690     }
1691     CONTRACTL_END;
1692
1693     int result = 0; 
1694
1695     //We don't need to check the top end because the GC will take care of that.
1696     HELPER_METHOD_FRAME_BEGIN_RET_0();
1697
1698     DWORD dwMilliseconds = ((millisecondsTimeout == -1) ? INFINITE : millisecondsTimeout);
1699     result = GCHeapUtilities::GetGCHeap()->WaitForFullGCComplete(dwMilliseconds);
1700
1701     HELPER_METHOD_FRAME_END();
1702
1703     return result;
1704 }
1705 FCIMPLEND
1706
1707 /*================================GetGeneration=================================
1708 **Action: Returns the generation in which args->obj is found.
1709 **Returns: The generation in which args->obj is found.
1710 **Arguments: args->obj -- The object to locate.
1711 **Exceptions: ArgumentException if args->obj is null.
1712 ==============================================================================*/
1713 FCIMPL1(int, GCInterface::GetGeneration, Object* objUNSAFE)
1714 {
1715     FCALL_CONTRACT;
1716
1717     if (objUNSAFE == NULL)
1718         FCThrowArgumentNull(W("obj"));
1719
1720     int result = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(objUNSAFE);
1721     FC_GC_POLL_RET();
1722     return result;
1723 }
1724 FCIMPLEND
1725
1726 /*================================CollectionCount=================================
1727 **Action: Returns the number of collections for this generation since the begining of the life of the process
1728 **Returns: The collection count.
1729 **Arguments: args->generation -- The generation
1730 **Exceptions: Argument exception if args->generation is < 0 or > GetMaxGeneration();
1731 ==============================================================================*/
1732 FCIMPL2(int, GCInterface::CollectionCount, INT32 generation, INT32 getSpecialGCCount)
1733 {
1734     FCALL_CONTRACT;
1735
1736     //We've already checked this in GC.cs, so we'll just assert it here.
1737     _ASSERTE(generation >= 0);
1738
1739     //We don't need to check the top end because the GC will take care of that.
1740     int result = (INT32)GCHeapUtilities::GetGCHeap()->CollectionCount(generation, getSpecialGCCount);
1741     FC_GC_POLL_RET();
1742     return result;
1743 }
1744 FCIMPLEND
1745
1746 int QCALLTYPE GCInterface::StartNoGCRegion(INT64 totalSize, BOOL lohSizeKnown, INT64 lohSize, BOOL disallowFullBlockingGC)
1747 {
1748     QCALL_CONTRACT;
1749
1750     int retVal = 0;
1751
1752     BEGIN_QCALL;
1753
1754     GCX_COOP();
1755
1756     retVal = GCHeapUtilities::GetGCHeap()->StartNoGCRegion((ULONGLONG)totalSize, 
1757                                                   lohSizeKnown,
1758                                                   (ULONGLONG)lohSize,
1759                                                   disallowFullBlockingGC);
1760
1761     END_QCALL;
1762
1763     return retVal;
1764 }
1765
1766 int QCALLTYPE GCInterface::EndNoGCRegion()
1767 {
1768     QCALL_CONTRACT;
1769
1770     int retVal = FALSE;
1771
1772     BEGIN_QCALL;
1773
1774     retVal = GCHeapUtilities::GetGCHeap()->EndNoGCRegion();
1775
1776     END_QCALL;
1777
1778     return retVal;
1779 }
1780
1781 /*===============================GetGenerationWR================================
1782 **Action: Returns the generation in which the object pointed to by a WeakReference is found.
1783 **Returns:
1784 **Arguments: args->handle -- the OBJECTHANDLE to the object which we're locating.
1785 **Exceptions: ArgumentException if handle points to an object which is not accessible.
1786 ==============================================================================*/
1787 FCIMPL1(int, GCInterface::GetGenerationWR, LPVOID handle)
1788 {
1789     FCALL_CONTRACT;
1790
1791     int iRetVal = 0;
1792
1793     HELPER_METHOD_FRAME_BEGIN_RET_0();
1794
1795     OBJECTREF temp;
1796     temp = ObjectFromHandle((OBJECTHANDLE) handle);
1797     if (temp == NULL)
1798         COMPlusThrowArgumentNull(W("weak handle"));
1799
1800     iRetVal = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(OBJECTREFToObject(temp));
1801
1802     HELPER_METHOD_FRAME_END();
1803
1804     return iRetVal;
1805 }
1806 FCIMPLEND
1807
1808 /*================================GetTotalMemory================================
1809 **Action: Returns the total number of bytes in use
1810 **Returns: The total number of bytes in use
1811 **Arguments: None
1812 **Exceptions: None
1813 ==============================================================================*/
1814 INT64 QCALLTYPE GCInterface::GetTotalMemory()
1815 {
1816     QCALL_CONTRACT;
1817
1818     INT64 iRetVal = 0;
1819
1820     BEGIN_QCALL;
1821
1822     GCX_COOP();
1823     iRetVal = (INT64) GCHeapUtilities::GetGCHeap()->GetTotalBytesInUse();
1824
1825     END_QCALL;
1826
1827     return iRetVal;
1828 }
1829
1830 /*==============================Collect=========================================
1831 **Action: Collects all generations <= args->generation
1832 **Returns: void
1833 **Arguments: args->generation:  The maximum generation to collect
1834 **Exceptions: Argument exception if args->generation is < 0 or > GetMaxGeneration();
1835 ==============================================================================*/
1836 void QCALLTYPE GCInterface::Collect(INT32 generation, INT32 mode)
1837 {
1838     QCALL_CONTRACT;
1839
1840     BEGIN_QCALL;
1841
1842     //We've already checked this in GC.cs, so we'll just assert it here.
1843     _ASSERTE(generation >= -1);
1844
1845     //We don't need to check the top end because the GC will take care of that.
1846
1847     GCX_COOP();
1848     GCHeapUtilities::GetGCHeap()->GarbageCollect(generation, FALSE, mode);
1849
1850     END_QCALL;
1851 }
1852
1853
1854 /*==========================WaitForPendingFinalizers============================
1855 **Action: Run all Finalizers that haven't been run.
1856 **Arguments: None
1857 **Exceptions: None
1858 ==============================================================================*/
1859 void QCALLTYPE GCInterface::WaitForPendingFinalizers()
1860 {
1861     QCALL_CONTRACT;
1862
1863     BEGIN_QCALL;
1864
1865     FinalizerThread::FinalizerThreadWait();
1866
1867     END_QCALL;
1868 }
1869
1870
1871 /*===============================GetMaxGeneration===============================
1872 **Action: Returns the largest GC generation
1873 **Returns: The largest GC Generation
1874 **Arguments: None
1875 **Exceptions: None
1876 ==============================================================================*/
1877 FCIMPL0(int, GCInterface::GetMaxGeneration)
1878 {
1879     FCALL_CONTRACT;
1880
1881     return(INT32)GCHeapUtilities::GetGCHeap()->GetMaxGeneration();
1882 }
1883 FCIMPLEND
1884
1885 /*===============================GetAllocatedBytesForCurrentThread===============================
1886 **Action: Computes the allocated bytes so far on the current thread
1887 **Returns: The allocated bytes so far on the current thread
1888 **Arguments: None
1889 **Exceptions: None
1890 ==============================================================================*/
1891 FCIMPL0(INT64, GCInterface::GetAllocatedBytesForCurrentThread)
1892 {
1893     FCALL_CONTRACT;
1894
1895     INT64 currentAllocated = 0;
1896     Thread *pThread = GetThread();
1897     gc_alloc_context* ac = pThread->GetAllocContext();
1898     currentAllocated = ac->alloc_bytes + ac->alloc_bytes_loh - (ac->alloc_limit - ac->alloc_ptr);
1899
1900     return currentAllocated;
1901 }
1902 FCIMPLEND
1903
1904 /*==============================SuppressFinalize================================
1905 **Action: Indicate that an object's finalizer should not be run by the system
1906 **Arguments: Object of interest
1907 **Exceptions: None
1908 ==============================================================================*/
1909 FCIMPL1(void, GCInterface::SuppressFinalize, Object *obj)
1910 {
1911     FCALL_CONTRACT;
1912
1913     // Checked by the caller
1914     _ASSERTE(obj != NULL);
1915
1916     if (!obj->GetMethodTable ()->HasFinalizer())
1917         return;
1918
1919     GCHeapUtilities::GetGCHeap()->SetFinalizationRun(obj);
1920     FC_GC_POLL();
1921 }
1922 FCIMPLEND
1923
1924
1925 /*============================ReRegisterForFinalize==============================
1926 **Action: Indicate that an object's finalizer should be run by the system.
1927 **Arguments: Object of interest
1928 **Exceptions: None
1929 ==============================================================================*/
1930 FCIMPL1(void, GCInterface::ReRegisterForFinalize, Object *obj)
1931 {
1932     FCALL_CONTRACT;
1933
1934     // Checked by the caller
1935     _ASSERTE(obj != NULL);
1936
1937     if (obj->GetMethodTable()->HasFinalizer())
1938     {
1939         HELPER_METHOD_FRAME_BEGIN_1(obj);
1940         GCHeapUtilities::GetGCHeap()->RegisterForFinalization(-1, obj);
1941         HELPER_METHOD_FRAME_END();
1942     }
1943 }
1944 FCIMPLEND
1945
1946 FORCEINLINE UINT64 GCInterface::InterlockedAdd (UINT64 *pAugend, UINT64 addend) {
1947     WRAPPER_NO_CONTRACT;
1948     STATIC_CONTRACT_SO_TOLERANT;
1949
1950     UINT64 oldMemValue;
1951     UINT64 newMemValue;
1952
1953     do {
1954         oldMemValue = *pAugend;
1955         newMemValue = oldMemValue + addend;
1956
1957         // check for overflow
1958         if (newMemValue < oldMemValue)
1959         {
1960             newMemValue = UINT64_MAX;
1961         }
1962     } while (InterlockedCompareExchange64((LONGLONG*) pAugend, (LONGLONG) newMemValue, (LONGLONG) oldMemValue) != (LONGLONG) oldMemValue);
1963
1964     return newMemValue;
1965 }
1966
1967 FORCEINLINE UINT64 GCInterface::InterlockedSub(UINT64 *pMinuend, UINT64 subtrahend) {
1968     WRAPPER_NO_CONTRACT;
1969     STATIC_CONTRACT_SO_TOLERANT;
1970
1971     UINT64 oldMemValue;
1972     UINT64 newMemValue;
1973
1974     do {
1975         oldMemValue = *pMinuend;
1976         newMemValue = oldMemValue - subtrahend;
1977
1978         // check for underflow
1979         if (newMemValue > oldMemValue)
1980             newMemValue = 0;
1981         
1982     } while (InterlockedCompareExchange64((LONGLONG*) pMinuend, (LONGLONG) newMemValue, (LONGLONG) oldMemValue) != (LONGLONG) oldMemValue);
1983
1984     return newMemValue;
1985 }
1986
1987 void QCALLTYPE GCInterface::_AddMemoryPressure(UINT64 bytesAllocated) 
1988 {
1989     QCALL_CONTRACT;
1990
1991     // AddMemoryPressure could cause a GC, so we need a frame 
1992     BEGIN_QCALL;
1993     AddMemoryPressure(bytesAllocated);
1994     END_QCALL;
1995 }
1996
1997 void GCInterface::AddMemoryPressure(UINT64 bytesAllocated)
1998 {
1999     CONTRACTL
2000     {
2001         THROWS;
2002         GC_TRIGGERS;
2003         MODE_ANY;
2004     }
2005     CONTRACTL_END;
2006
2007     SendEtwAddMemoryPressureEvent(bytesAllocated);
2008
2009     UINT64 newMemValue = InterlockedAdd(&m_ulMemPressure, bytesAllocated);
2010
2011     if (newMemValue > m_ulThreshold)
2012     {
2013         INT32 gen_collect = 0;
2014         {
2015             GCX_PREEMP();
2016             CrstHolder holder(&m_MemoryPressureLock);
2017
2018             // to avoid collecting too often, take the max threshold of the linear and geometric growth 
2019             // heuristics.          
2020             UINT64 addMethod;
2021             UINT64 multMethod;
2022             UINT64 bytesAllocatedMax = (UINT64_MAX - m_ulThreshold) / 8;
2023
2024             if (bytesAllocated >= bytesAllocatedMax) // overflow check
2025             {
2026                 addMethod = UINT64_MAX;
2027             }
2028             else
2029             {
2030                 addMethod = m_ulThreshold + bytesAllocated * 8;
2031             }
2032
2033             multMethod = newMemValue + newMemValue / 10;
2034             if (multMethod < newMemValue) // overflow check
2035             {
2036                 multMethod = UINT64_MAX;
2037             }
2038
2039             m_ulThreshold = (addMethod > multMethod) ? addMethod : multMethod;
2040             for (int i = 0; i <= 1; i++)
2041             {
2042                 if ((GCHeapUtilities::GetGCHeap()->CollectionCount(i) / RELATIVE_GC_RATIO) > GCHeapUtilities::GetGCHeap()->CollectionCount(i + 1))
2043                 {
2044                     gen_collect = i + 1;
2045                     break;
2046                 }
2047             }
2048         }
2049
2050         PREFIX_ASSUME(gen_collect <= 2);
2051
2052         if ((gen_collect == 0) || (m_gc_counts[gen_collect] == GCHeapUtilities::GetGCHeap()->CollectionCount(gen_collect)))
2053         {
2054             GarbageCollectModeAny(gen_collect);
2055         }
2056
2057         for (int i = 0; i < 3; i++) 
2058         {
2059             m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i);
2060         }
2061     }
2062 }
2063
2064 #ifdef _WIN64
2065 const unsigned MIN_MEMORYPRESSURE_BUDGET = 4 * 1024 * 1024;        // 4 MB
2066 #else // _WIN64
2067 const unsigned MIN_MEMORYPRESSURE_BUDGET = 3 * 1024 * 1024;        // 3 MB
2068 #endif // _WIN64
2069
2070 const unsigned MAX_MEMORYPRESSURE_RATIO = 10;                      // 40 MB or 30 MB
2071
2072
2073 // Resets pressure accounting after a gen2 GC has occurred.
2074 void GCInterface::CheckCollectionCount()
2075 {
2076     LIMITED_METHOD_CONTRACT;
2077
2078     IGCHeap * pHeap = GCHeapUtilities::GetGCHeap();
2079     
2080     if (m_gc_counts[2] != pHeap->CollectionCount(2))
2081     {
2082         for (int i = 0; i < 3; i++) 
2083         {
2084             m_gc_counts[i] = pHeap->CollectionCount(i);
2085         }
2086
2087         m_iteration++;
2088
2089         UINT p = m_iteration % NEW_PRESSURE_COUNT;
2090
2091         m_addPressure[p] = 0;   // new pressure will be accumulated here
2092         m_remPressure[p] = 0; 
2093     }
2094 }
2095
2096
2097 // New AddMemoryPressure implementation (used by RCW and the CLRServicesImpl class)
2098 //
2099 //   1. Less sensitive than the original implementation (start budget 3 MB)
2100 //   2. Focuses more on newly added memory pressure
2101 //   3. Budget adjusted by effectiveness of last 3 triggered GC (add / remove ratio, max 10x)
2102 //   4. Budget maxed with 30% of current managed GC size
2103 //   5. If Gen2 GC is happening naturally, ignore past pressure
2104 //
2105 // Here's a brief description of the ideal algorithm for Add/Remove memory pressure:
2106 // Do a GC when (HeapStart < X * MemPressureGrowth) where
2107 // - HeapStart is GC Heap size after doing the last GC
2108 // - MemPressureGrowth is the net of Add and Remove since the last GC
2109 // - X is proportional to our guess of the ummanaged memory death rate per GC interval,
2110 //   and would be calculated based on historic data using standard exponential approximation:
2111 //   Xnew = UMDeath/UMTotal * 0.5 + Xprev
2112 //
2113 void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated)
2114 {
2115     CONTRACTL
2116     {
2117         THROWS;
2118         GC_TRIGGERS;
2119         MODE_ANY;
2120     }
2121     CONTRACTL_END;
2122
2123     CheckCollectionCount();
2124
2125     UINT p = m_iteration % NEW_PRESSURE_COUNT;
2126
2127     UINT64 newMemValue = InterlockedAdd(&m_addPressure[p], bytesAllocated);
2128
2129     static_assert(NEW_PRESSURE_COUNT == 4, "NewAddMemoryPressure contains unrolled loops which depend on NEW_PRESSURE_COUNT");
2130
2131     UINT64 add = m_addPressure[0] + m_addPressure[1] + m_addPressure[2] + m_addPressure[3] - m_addPressure[p];
2132     UINT64 rem = m_remPressure[0] + m_remPressure[1] + m_remPressure[2] + m_remPressure[3] - m_remPressure[p];
2133
2134     STRESS_LOG4(LF_GCINFO, LL_INFO10000, "AMP Add: %I64u => added=%I64u total_added=%I64u total_removed=%I64u",
2135         bytesAllocated, newMemValue, add, rem);
2136
2137     SendEtwAddMemoryPressureEvent(bytesAllocated); 
2138
2139     if (newMemValue >= MIN_MEMORYPRESSURE_BUDGET)
2140     {
2141         UINT64 budget = MIN_MEMORYPRESSURE_BUDGET;
2142
2143         if (m_iteration >= NEW_PRESSURE_COUNT) // wait until we have enough data points
2144         {
2145             // Adjust according to effectiveness of GC
2146             // Scale budget according to past m_addPressure / m_remPressure ratio
2147             if (add >= rem * MAX_MEMORYPRESSURE_RATIO)
2148             {
2149                 budget = MIN_MEMORYPRESSURE_BUDGET * MAX_MEMORYPRESSURE_RATIO;
2150             }
2151             else if (add > rem)
2152             {
2153                 CONSISTENCY_CHECK(rem != 0);
2154
2155                 // Avoid overflow by calculating addPressure / remPressure as fixed point (1 = 1024)
2156                 budget = (add * 1024 / rem) * budget / 1024;
2157             }
2158         }
2159
2160         // If still over budget, check current managed heap size
2161         if (newMemValue >= budget)
2162         {
2163             IGCHeap *pGCHeap = GCHeapUtilities::GetGCHeap();
2164             UINT64 heapOver3 = pGCHeap->GetCurrentObjSize() / 3;
2165
2166             if (budget < heapOver3) // Max
2167             {
2168                 budget = heapOver3;
2169             }
2170
2171             if (newMemValue >= budget)
2172             {
2173                 // last check - if we would exceed 20% of GC "duty cycle", do not trigger GC at this time
2174                 if ((pGCHeap->GetNow() - pGCHeap->GetLastGCStartTime(2)) > (pGCHeap->GetLastGCDuration(2) * 5))
2175                 {
2176                     STRESS_LOG6(LF_GCINFO, LL_INFO10000, "AMP Budget: pressure=%I64u ? budget=%I64u (total_added=%I64u, total_removed=%I64u, mng_heap=%I64u) pos=%d",
2177                         newMemValue, budget, add, rem, heapOver3 * 3, m_iteration);
2178
2179                     GarbageCollectModeAny(2);
2180
2181                     CheckCollectionCount();
2182                 }
2183             }
2184         }
2185     }
2186 }
2187
2188 void QCALLTYPE GCInterface::_RemoveMemoryPressure(UINT64 bytesAllocated)
2189 {
2190     QCALL_CONTRACT;
2191
2192     BEGIN_QCALL;
2193     RemoveMemoryPressure(bytesAllocated);
2194     END_QCALL;
2195 }
2196
2197 void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated)
2198 {
2199     CONTRACTL
2200     {
2201         NOTHROW;
2202         GC_TRIGGERS;
2203         MODE_ANY;
2204     }
2205     CONTRACTL_END;
2206
2207     SendEtwRemoveMemoryPressureEvent(bytesAllocated);
2208
2209     UINT64 newMemValue = InterlockedSub(&m_ulMemPressure, bytesAllocated);
2210     UINT64 new_th;  
2211     UINT64 bytesAllocatedMax = (m_ulThreshold / 4);
2212     UINT64 addMethod;
2213     UINT64 multMethod = (m_ulThreshold - m_ulThreshold / 20); // can never underflow
2214     if (bytesAllocated >= bytesAllocatedMax) // protect against underflow
2215     {
2216         m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
2217         return;
2218     }
2219     else
2220     {
2221         addMethod = m_ulThreshold - bytesAllocated * 4;
2222     }
2223
2224     new_th = (addMethod < multMethod) ? addMethod : multMethod;
2225
2226     if (newMemValue <= new_th)
2227     {
2228         GCX_PREEMP();
2229         CrstHolder holder(&m_MemoryPressureLock);
2230         if (new_th > MIN_GC_MEMORYPRESSURE_THRESHOLD)
2231             m_ulThreshold = new_th;
2232         else
2233             m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
2234
2235         for (int i = 0; i < 3; i++) 
2236         {
2237             m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i);
2238         }
2239     }
2240 }
2241
2242 void GCInterface::NewRemoveMemoryPressure(UINT64 bytesAllocated)
2243 {
2244     CONTRACTL
2245     {
2246         NOTHROW;
2247         GC_TRIGGERS;
2248         MODE_ANY;
2249     }
2250     CONTRACTL_END;
2251
2252     CheckCollectionCount();
2253     
2254     UINT p = m_iteration % NEW_PRESSURE_COUNT;
2255
2256     SendEtwRemoveMemoryPressureEvent(bytesAllocated);
2257
2258     InterlockedAdd(&m_remPressure[p], bytesAllocated);
2259
2260     STRESS_LOG2(LF_GCINFO, LL_INFO10000, "AMP Remove: %I64u => removed=%I64u",
2261         bytesAllocated, m_remPressure[p]);
2262 }
2263
2264 inline void GCInterface::SendEtwAddMemoryPressureEvent(UINT64 bytesAllocated)
2265 {
2266     CONTRACTL
2267     {
2268         THROWS;
2269         GC_TRIGGERS;
2270         MODE_ANY;
2271     }
2272     CONTRACTL_END;
2273
2274     FireEtwIncreaseMemoryPressure(bytesAllocated, GetClrInstanceId());
2275 }
2276
2277 // Out-of-line helper to avoid EH prolog/epilog in functions that otherwise don't throw.
2278 NOINLINE void GCInterface::SendEtwRemoveMemoryPressureEvent(UINT64 bytesAllocated)
2279 {
2280     CONTRACTL
2281     {
2282         NOTHROW;
2283         GC_TRIGGERS;
2284         MODE_ANY;
2285     }
2286     CONTRACTL_END;
2287
2288     EX_TRY
2289     {
2290         FireEtwDecreaseMemoryPressure(bytesAllocated, GetClrInstanceId());
2291     }
2292     EX_CATCH
2293     {
2294         // Ignore failures
2295     }
2296     EX_END_CATCH(SwallowAllExceptions)
2297 }
2298
2299 // Out-of-line helper to avoid EH prolog/epilog in functions that otherwise don't throw.
2300 NOINLINE void GCInterface::GarbageCollectModeAny(int generation)
2301 {
2302     CONTRACTL
2303     {
2304         THROWS;
2305         GC_TRIGGERS;
2306         MODE_ANY;
2307     }
2308     CONTRACTL_END;
2309
2310     GCX_COOP();
2311     GCHeapUtilities::GetGCHeap()->GarbageCollect(generation, FALSE, collection_non_blocking);
2312 }
2313
2314 //
2315 // COMInterlocked
2316 //
2317
2318 #include <optsmallperfcritical.h>
2319
2320 FCIMPL2(INT32,COMInterlocked::Exchange, INT32 *location, INT32 value)
2321 {
2322     FCALL_CONTRACT;
2323
2324     if( NULL == location) {
2325         FCThrow(kNullReferenceException);
2326     }
2327
2328     return FastInterlockExchange((LONG *) location, value);
2329 }
2330 FCIMPLEND
2331
2332 FCIMPL2_IV(INT64,COMInterlocked::Exchange64, INT64 *location, INT64 value)
2333 {
2334     FCALL_CONTRACT;
2335
2336     if( NULL == location) {
2337         FCThrow(kNullReferenceException);
2338     }
2339
2340     return FastInterlockExchangeLong((INT64 *) location, value);
2341 }
2342 FCIMPLEND
2343
2344 FCIMPL2(LPVOID,COMInterlocked::ExchangePointer, LPVOID *location, LPVOID value)
2345 {
2346     FCALL_CONTRACT;
2347
2348     if( NULL == location) {
2349         FCThrow(kNullReferenceException);
2350     }
2351
2352     FCUnique(0x15);
2353     return FastInterlockExchangePointer(location, value);
2354 }
2355 FCIMPLEND
2356
2357 FCIMPL3(INT32, COMInterlocked::CompareExchange, INT32* location, INT32 value, INT32 comparand)
2358 {
2359     FCALL_CONTRACT;
2360
2361     if( NULL == location) {
2362         FCThrow(kNullReferenceException);
2363     }
2364
2365     return FastInterlockCompareExchange((LONG*)location, value, comparand);
2366 }
2367 FCIMPLEND
2368
2369 FCIMPL4(INT32, COMInterlocked::CompareExchangeReliableResult, INT32* location, INT32 value, INT32 comparand, CLR_BOOL* succeeded)
2370 {
2371     FCALL_CONTRACT;
2372
2373     if( NULL == location) {
2374         FCThrow(kNullReferenceException);
2375     }
2376
2377     INT32 result = FastInterlockCompareExchange((LONG*)location, value, comparand);
2378     if (result == comparand)
2379         *succeeded = true;
2380
2381     return result;
2382 }
2383 FCIMPLEND
2384
2385 FCIMPL3_IVV(INT64, COMInterlocked::CompareExchange64, INT64* location, INT64 value, INT64 comparand)
2386 {
2387     FCALL_CONTRACT;
2388
2389     if( NULL == location) {
2390         FCThrow(kNullReferenceException);
2391     }
2392
2393     return FastInterlockCompareExchangeLong((INT64*)location, value, comparand);
2394 }
2395 FCIMPLEND
2396
2397 FCIMPL3(LPVOID,COMInterlocked::CompareExchangePointer, LPVOID *location, LPVOID value, LPVOID comparand)
2398 {
2399     FCALL_CONTRACT;
2400
2401     if( NULL == location) {
2402         FCThrow(kNullReferenceException);
2403     }
2404
2405     FCUnique(0x59);
2406     return FastInterlockCompareExchangePointer(location, value, comparand);
2407 }
2408 FCIMPLEND
2409
2410 FCIMPL2_IV(float,COMInterlocked::ExchangeFloat, float *location, float value)
2411 {
2412     FCALL_CONTRACT;
2413
2414     if( NULL == location) {
2415         FCThrow(kNullReferenceException);
2416     }
2417
2418     LONG ret = FastInterlockExchange((LONG *) location, *(LONG*)&value);
2419     return *(float*)&ret;
2420 }
2421 FCIMPLEND
2422
2423 FCIMPL2_IV(double,COMInterlocked::ExchangeDouble, double *location, double value)
2424 {
2425     FCALL_CONTRACT;
2426
2427     if( NULL == location) {
2428         FCThrow(kNullReferenceException);
2429     }
2430
2431
2432     INT64 ret = FastInterlockExchangeLong((INT64 *) location, *(INT64*)&value);
2433     return *(double*)&ret;
2434 }
2435 FCIMPLEND
2436
2437 FCIMPL3_IVV(float,COMInterlocked::CompareExchangeFloat, float *location, float value, float comparand)
2438 {
2439     FCALL_CONTRACT;
2440
2441     if( NULL == location) {
2442         FCThrow(kNullReferenceException);
2443     }
2444
2445     LONG ret = (LONG)FastInterlockCompareExchange((LONG*) location, *(LONG*)&value, *(LONG*)&comparand);
2446     return *(float*)&ret;
2447 }
2448 FCIMPLEND
2449
2450 FCIMPL3_IVV(double,COMInterlocked::CompareExchangeDouble, double *location, double value, double comparand)
2451 {
2452     FCALL_CONTRACT;
2453
2454     if( NULL == location) {
2455         FCThrow(kNullReferenceException);
2456     }
2457
2458     INT64 ret = (INT64)FastInterlockCompareExchangeLong((INT64*) location, *(INT64*)&value, *(INT64*)&comparand);
2459     return *(double*)&ret;
2460 }
2461 FCIMPLEND
2462
2463 FCIMPL2(LPVOID,COMInterlocked::ExchangeObject, LPVOID*location, LPVOID value)
2464 {
2465     FCALL_CONTRACT;
2466
2467     if( NULL == location) {
2468         FCThrow(kNullReferenceException);
2469     }
2470
2471     LPVOID ret = FastInterlockExchangePointer(location, value);
2472 #ifdef _DEBUG
2473     Thread::ObjectRefAssign((OBJECTREF *)location);
2474 #endif
2475     ErectWriteBarrier((OBJECTREF*) location, ObjectToOBJECTREF((Object*) value));
2476     return ret;
2477 }
2478 FCIMPLEND
2479
2480 FCIMPL2_VV(void,COMInterlocked::ExchangeGeneric, FC_TypedByRef location, FC_TypedByRef value)
2481 {
2482     FCALL_CONTRACT;
2483
2484     LPVOID* loc = (LPVOID*)location.data;
2485     if( NULL == loc) {
2486         FCThrowVoid(kNullReferenceException);
2487     }
2488
2489     LPVOID val = *(LPVOID*)value.data;
2490     *(LPVOID*)value.data = FastInterlockExchangePointer(loc, val);
2491 #ifdef _DEBUG
2492     Thread::ObjectRefAssign((OBJECTREF *)loc);
2493 #endif
2494     ErectWriteBarrier((OBJECTREF*) loc, ObjectToOBJECTREF((Object*) val));
2495 }
2496 FCIMPLEND
2497
2498 FCIMPL3_VVI(void,COMInterlocked::CompareExchangeGeneric, FC_TypedByRef location, FC_TypedByRef value, LPVOID comparand)
2499 {
2500     FCALL_CONTRACT;
2501
2502     LPVOID* loc = (LPVOID*)location.data;
2503     LPVOID val = *(LPVOID*)value.data;
2504     if( NULL == loc) {
2505         FCThrowVoid(kNullReferenceException);
2506     }
2507
2508     LPVOID ret = FastInterlockCompareExchangePointer(loc, val, comparand);
2509     *(LPVOID*)value.data = ret;
2510     if(ret == comparand)
2511     {
2512 #ifdef _DEBUG
2513         Thread::ObjectRefAssign((OBJECTREF *)loc);
2514 #endif
2515         ErectWriteBarrier((OBJECTREF*) loc, ObjectToOBJECTREF((Object*) val));
2516     }
2517 }
2518 FCIMPLEND
2519
2520 FCIMPL3(LPVOID,COMInterlocked::CompareExchangeObject, LPVOID *location, LPVOID value, LPVOID comparand)
2521 {
2522     FCALL_CONTRACT;
2523
2524     if( NULL == location) {
2525         FCThrow(kNullReferenceException);
2526     }
2527
2528     // <TODO>@todo: only set ref if is updated</TODO>
2529     LPVOID ret = FastInterlockCompareExchangePointer(location, value, comparand);
2530     if (ret == comparand) {
2531 #ifdef _DEBUG
2532         Thread::ObjectRefAssign((OBJECTREF *)location);
2533 #endif
2534         ErectWriteBarrier((OBJECTREF*) location, ObjectToOBJECTREF((Object*) value));
2535     }
2536     return ret;
2537 }
2538 FCIMPLEND
2539
2540 FCIMPL2(INT32,COMInterlocked::ExchangeAdd32, INT32 *location, INT32 value)
2541 {
2542     FCALL_CONTRACT;
2543
2544     if( NULL == location) {
2545         FCThrow(kNullReferenceException);
2546     }
2547
2548     return FastInterlockExchangeAdd((LONG *) location, value);
2549 }
2550 FCIMPLEND
2551
2552 FCIMPL2_IV(INT64,COMInterlocked::ExchangeAdd64, INT64 *location, INT64 value)
2553 {
2554     FCALL_CONTRACT;
2555
2556     if( NULL == location) {
2557         FCThrow(kNullReferenceException);
2558     }
2559
2560     return FastInterlockExchangeAddLong((INT64 *) location, value);
2561 }
2562 FCIMPLEND
2563
2564 #include <optdefault.h>
2565
2566
2567
2568 FCIMPL6(INT32, ManagedLoggingHelper::GetRegistryLoggingValues, CLR_BOOL* bLoggingEnabled, CLR_BOOL* bLogToConsole, INT32 *iLogLevel, CLR_BOOL* bPerfWarnings, CLR_BOOL* bCorrectnessWarnings, CLR_BOOL* bSafeHandleStackTraces)
2569 {
2570     FCALL_CONTRACT;
2571
2572     INT32 logFacility = 0;
2573
2574     HELPER_METHOD_FRAME_BEGIN_RET_0();
2575
2576     *bLoggingEnabled         = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogEnable, 0)!=0);
2577     *bLogToConsole           = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogToConsole, 0)!=0);
2578     *iLogLevel               = (INT32)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, 0));
2579     logFacility              = (INT32)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ManagedLogFacility, 0));
2580     *bPerfWarnings           = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_BCLPerfWarnings, 0)!=0);
2581     *bCorrectnessWarnings    = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_BCLCorrectnessWarnings, 0)!=0);
2582     *bSafeHandleStackTraces  = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SafeHandleStackTraces, 0)!=0);
2583
2584     HELPER_METHOD_FRAME_END();                              \
2585
2586     return logFacility;
2587 }
2588 FCIMPLEND
2589
2590 // Return true if the valuetype does not contain pointer and is tightly packed
2591 FCIMPL1(FC_BOOL_RET, ValueTypeHelper::CanCompareBits, Object* obj)
2592 {
2593     FCALL_CONTRACT;
2594
2595     _ASSERTE(obj != NULL);
2596     MethodTable* mt = obj->GetMethodTable();
2597     FC_RETURN_BOOL(!mt->ContainsPointers() && !mt->IsNotTightlyPacked());
2598 }
2599 FCIMPLEND
2600
2601 FCIMPL2(FC_BOOL_RET, ValueTypeHelper::FastEqualsCheck, Object* obj1, Object* obj2)
2602 {
2603     FCALL_CONTRACT;
2604
2605     _ASSERTE(obj1 != NULL);
2606     _ASSERTE(obj2 != NULL);
2607     _ASSERTE(!obj1->GetMethodTable()->ContainsPointers());
2608     _ASSERTE(obj1->GetSize() == obj2->GetSize());
2609
2610     TypeHandle pTh = obj1->GetTypeHandle();
2611
2612     FC_RETURN_BOOL(memcmp(obj1->GetData(),obj2->GetData(),pTh.GetSize()) == 0);
2613 }
2614 FCIMPLEND
2615
2616 static BOOL CanUseFastGetHashCodeHelper(MethodTable *mt)
2617 {
2618     LIMITED_METHOD_CONTRACT;
2619     return !mt->ContainsPointers() && !mt->IsNotTightlyPacked();
2620 }
2621
2622 static INT32 FastGetValueTypeHashCodeHelper(MethodTable *mt, void *pObjRef)
2623 {
2624     CONTRACTL
2625     {
2626         NOTHROW;
2627         GC_NOTRIGGER;
2628         MODE_COOPERATIVE;
2629         SO_TOLERANT;
2630         PRECONDITION(CanUseFastGetHashCodeHelper(mt));
2631     } CONTRACTL_END;
2632
2633     INT32 hashCode = 0;
2634     INT32 *pObj = (INT32*)pObjRef;
2635             
2636     // this is a struct with no refs and no "strange" offsets, just go through the obj and xor the bits
2637     INT32 size = mt->GetNumInstanceFieldBytes();
2638     for (INT32 i = 0; i < (INT32)(size / sizeof(INT32)); i++)
2639         hashCode ^= *pObj++;
2640
2641     return hashCode;
2642 }
2643
2644 static INT32 RegularGetValueTypeHashCode(MethodTable *mt, void *pObjRef)
2645 {
2646     CONTRACTL
2647     {
2648         THROWS;
2649         GC_TRIGGERS;
2650         MODE_COOPERATIVE;
2651     } CONTRACTL_END;
2652
2653     INT32 hashCode = 0;
2654     INT32 *pObj = (INT32*)pObjRef;
2655
2656     // While we shouln't get here directly from ValueTypeHelper::GetHashCode, if we recurse we need to 
2657     // be able to handle getting the hashcode for an embedded structure whose hashcode is computed by the fast path.
2658     if (CanUseFastGetHashCodeHelper(mt))
2659     {
2660         return FastGetValueTypeHashCodeHelper(mt, pObjRef);
2661     }
2662     else
2663     {
2664         // it's looking ugly so we'll use the old behavior in managed code. Grab the first non-null
2665         // field and return its hash code or 'it' as hash code
2666         // <TODO> Note that the old behavior has already been broken for value types
2667         //              that is qualified for CanUseFastGetHashCodeHelper. So maybe we should
2668         //              change the implementation here to use all fields instead of just the 1st one.
2669         // </TODO>
2670         //
2671         // <TODO> check this approximation - we may be losing exact type information </TODO>
2672         ApproxFieldDescIterator fdIterator(mt, ApproxFieldDescIterator::INSTANCE_FIELDS);
2673         INT32 count = (INT32)fdIterator.Count();
2674
2675         if (count != 0)
2676         {
2677             for (INT32 i = 0; i < count; i++)
2678             {
2679                 FieldDesc *field = fdIterator.Next();
2680                 _ASSERTE(!field->IsRVA());
2681                 void *pFieldValue = (BYTE *)pObj + field->GetOffsetUnsafe();
2682                 if (field->IsObjRef())
2683                 {
2684                     // if we get an object reference we get the hash code out of that
2685                     if (*(Object**)pFieldValue != NULL)
2686                     {
2687
2688                         OBJECTREF fieldObjRef = ObjectToOBJECTREF(*(Object **) pFieldValue);
2689                         GCPROTECT_BEGIN(fieldObjRef);
2690
2691                         MethodDescCallSite getHashCode(METHOD__OBJECT__GET_HASH_CODE, &fieldObjRef);
2692
2693                         // Make the call.
2694                         ARG_SLOT arg[1] = {ObjToArgSlot(fieldObjRef)};
2695                         hashCode = getHashCode.Call_RetI4(arg);
2696
2697                         GCPROTECT_END();
2698                     }
2699                     else
2700                     {
2701                         // null object reference, try next
2702                         continue;
2703                     }
2704                 }
2705                 else
2706                 {
2707                     UINT fieldSize = field->LoadSize();
2708                     INT32 *pValue = (INT32*)pFieldValue;
2709                     CorElementType fieldType = field->GetFieldType();
2710                     if (fieldType != ELEMENT_TYPE_VALUETYPE)
2711                     {
2712                         for (INT32 j = 0; j < (INT32)(fieldSize / sizeof(INT32)); j++)
2713                             hashCode ^= *pValue++;
2714                     }
2715                     else
2716                     {
2717                         // got another value type. Get the type
2718                         TypeHandle fieldTH = field->LookupFieldTypeHandle(); // the type was loaded already
2719                         _ASSERTE(!fieldTH.IsNull());
2720                         hashCode = RegularGetValueTypeHashCode(fieldTH.GetMethodTable(), pValue);
2721                     }
2722                 }
2723                 break;
2724             }
2725         }
2726     }
2727     return hashCode;
2728 }
2729
2730 // The default implementation of GetHashCode() for all value types.
2731 // Note that this implementation reveals the value of the fields.
2732 // So if the value type contains any sensitive information it should
2733 // implement its own GetHashCode().
2734 FCIMPL1(INT32, ValueTypeHelper::GetHashCode, Object* objUNSAFE)
2735 {
2736     FCALL_CONTRACT;
2737
2738     if (objUNSAFE == NULL)
2739         FCThrow(kNullReferenceException);
2740
2741     OBJECTREF obj = ObjectToOBJECTREF(objUNSAFE);
2742     VALIDATEOBJECTREF(obj);
2743
2744     INT32 hashCode = 0;
2745     MethodTable *pMT = objUNSAFE->GetMethodTable();
2746
2747     // We don't want to expose the method table pointer in the hash code
2748     // Let's use the typeID instead.
2749     UINT32 typeID = pMT->LookupTypeID();
2750     if (typeID == TypeIDProvider::INVALID_TYPE_ID)
2751     {
2752         // If the typeID has yet to be generated, fall back to GetTypeID
2753         // This only needs to be done once per MethodTable
2754         HELPER_METHOD_FRAME_BEGIN_RET_1(obj);        
2755         typeID = pMT->GetTypeID();
2756         HELPER_METHOD_FRAME_END();
2757     }
2758
2759     // To get less colliding and more evenly distributed hash codes,
2760     // we munge the class index with two big prime numbers
2761     hashCode = typeID * 711650207 + 2506965631U;
2762
2763     if (CanUseFastGetHashCodeHelper(pMT))
2764     {
2765         hashCode ^= FastGetValueTypeHashCodeHelper(pMT, obj->UnBox());
2766     }
2767     else
2768     {
2769         HELPER_METHOD_FRAME_BEGIN_RET_1(obj);        
2770         hashCode ^= RegularGetValueTypeHashCode(pMT, obj->UnBox());
2771         HELPER_METHOD_FRAME_END();
2772     }
2773     
2774     return hashCode;
2775 }
2776 FCIMPLEND
2777
2778 static LONG s_dwSeed;
2779
2780 FCIMPL1(INT32, ValueTypeHelper::GetHashCodeOfPtr, LPVOID ptr)
2781 {
2782     FCALL_CONTRACT;
2783
2784     INT32 hashCode = (INT32)((INT64)(ptr));
2785
2786     if (hashCode == 0)
2787     {
2788         return 0;
2789     }
2790
2791     DWORD dwSeed = s_dwSeed;
2792
2793     // Initialize s_dwSeed lazily
2794     if (dwSeed == 0)
2795     {
2796         // We use the first non-0 pointer as the seed, all hashcodes will be based off that.
2797         // This is to make sure that we only reveal relative memory addresses and never absolute ones.
2798         dwSeed = hashCode;
2799         InterlockedCompareExchange(&s_dwSeed, dwSeed, 0);
2800         dwSeed = s_dwSeed;
2801     }
2802     _ASSERTE(dwSeed != 0);
2803
2804     return hashCode - dwSeed;
2805 }
2806 FCIMPLEND
2807
2808
2809 COMNlsHashProvider COMNlsHashProvider::s_NlsHashProvider;
2810
2811
2812 COMNlsHashProvider::COMNlsHashProvider()
2813 {
2814     LIMITED_METHOD_CONTRACT;
2815
2816 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2817     bUseRandomHashing = FALSE;
2818     pEntropy = NULL;
2819     pDefaultSeed = NULL;
2820 #endif // FEATURE_RANDOMIZED_STRING_HASHING
2821 }
2822
2823 INT32 COMNlsHashProvider::HashString(LPCWSTR szStr, SIZE_T strLen, BOOL forceRandomHashing, INT64 additionalEntropy)
2824 {
2825     CONTRACTL {
2826         THROWS;
2827         GC_NOTRIGGER;
2828         MODE_ANY;
2829     }
2830     CONTRACTL_END;
2831
2832 #ifndef FEATURE_RANDOMIZED_STRING_HASHING
2833    _ASSERTE(forceRandomHashing == false);
2834    _ASSERTE(additionalEntropy == 0);
2835 #endif
2836
2837 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2838     if(bUseRandomHashing || forceRandomHashing)
2839     {
2840         int marvinResult[SYMCRYPT_MARVIN32_RESULT_SIZE / sizeof(int)];
2841         
2842         if(additionalEntropy == 0)
2843         {
2844             SymCryptMarvin32(GetDefaultSeed(), (PCBYTE) szStr, strLen * sizeof(WCHAR), (PBYTE) &marvinResult);
2845         }
2846         else
2847         {
2848             SYMCRYPT_MARVIN32_EXPANDED_SEED seed;
2849             CreateMarvin32Seed(additionalEntropy, &seed);
2850             SymCryptMarvin32(&seed, (PCBYTE) szStr, strLen * sizeof(WCHAR), (PBYTE) &marvinResult);
2851         }
2852
2853         return marvinResult[0] ^ marvinResult[1];
2854     }
2855     else
2856     {
2857 #endif // FEATURE_RANDOMIZED_STRING_HASHING
2858         return ::HashString(szStr);
2859 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2860     }
2861 #endif // FEATURE_RANDOMIZED_STRING_HASHING
2862 }
2863
2864
2865 INT32 COMNlsHashProvider::HashSortKey(PCBYTE pSrc, SIZE_T cbSrc, BOOL forceRandomHashing, INT64 additionalEntropy)
2866 {
2867     CONTRACTL {
2868         THROWS;
2869         GC_NOTRIGGER;
2870         MODE_ANY;
2871     }
2872     CONTRACTL_END;
2873
2874 #ifndef FEATURE_RANDOMIZED_STRING_HASHING
2875    _ASSERTE(forceRandomHashing == false);
2876    _ASSERTE(additionalEntropy == 0);
2877 #endif
2878
2879 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2880     if(bUseRandomHashing || forceRandomHashing)
2881     {
2882         int marvinResult[SYMCRYPT_MARVIN32_RESULT_SIZE / sizeof(int)];
2883         
2884         // Sort Keys are terminated with a null byte which we didn't hash using the old algorithm, 
2885         // so we don't have it with Marvin32 either.
2886         if(additionalEntropy == 0)
2887         {
2888             SymCryptMarvin32(GetDefaultSeed(), pSrc, cbSrc - 1, (PBYTE) &marvinResult);
2889         }
2890         else
2891         {
2892             SYMCRYPT_MARVIN32_EXPANDED_SEED seed;       
2893             CreateMarvin32Seed(additionalEntropy, &seed);
2894             SymCryptMarvin32(&seed, pSrc, cbSrc - 1, (PBYTE) &marvinResult);
2895         }
2896  
2897         return marvinResult[0] ^ marvinResult[1];
2898     }
2899     else
2900     {
2901 #endif // FEATURE_RANDOMIZED_STRING_HASHING 
2902         // Ok, lets build the hashcode -- mostly lifted from GetHashCode() in String.cs, for strings.
2903         int hash1 = 5381;
2904         int hash2 = hash1;
2905         const BYTE *pB = pSrc;
2906         BYTE    c;
2907
2908         while (pB != 0 && *pB != 0) {
2909             hash1 = ((hash1 << 5) + hash1) ^ *pB;
2910             c = pB[1];
2911
2912             //
2913             // FUTURE: Update NewAPis::LCMapStringEx to perhaps use a different, bug free, Win32 API on Win2k3 to workaround the issue discussed below.
2914             //
2915             // On Win2k3 Server, LCMapStringEx(LCMAP_SORTKEY) output does not correspond to CompareString in all cases, breaking the .NET GetHashCode<->Equality Contract
2916             // Due to a fluke in our GetHashCode method, we avoided this issue due to the break out of the loop on the binary-zero byte.
2917             //
2918             if (c == 0)
2919                 break;
2920
2921             hash2 = ((hash2 << 5) + hash2) ^ c;
2922             pB += 2;
2923         }
2924
2925         return hash1 + (hash2 * 1566083941);
2926
2927 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2928     }
2929 #endif // FEATURE_RANDOMIZED_STRING_HASHING
2930
2931 }
2932
2933 INT32 COMNlsHashProvider::HashiStringKnownLower80(LPCWSTR szStr, INT32 strLen, BOOL forceRandomHashing, INT64 additionalEntropy)
2934 {
2935     CONTRACTL {
2936         THROWS;
2937         GC_NOTRIGGER;
2938         MODE_ANY;
2939     }
2940     CONTRACTL_END;
2941
2942 #ifndef FEATURE_RANDOMIZED_STRING_HASHING
2943    _ASSERTE(forceRandomHashing == false);
2944    _ASSERTE(additionalEntropy == 0);
2945 #endif
2946
2947 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
2948     if(bUseRandomHashing || forceRandomHashing)
2949     {
2950         WCHAR buf[SYMCRYPT_MARVIN32_INPUT_BLOCK_SIZE * 8];
2951         SYMCRYPT_MARVIN32_STATE marvinState;
2952         SYMCRYPT_MARVIN32_EXPANDED_SEED seed;
2953
2954         if(additionalEntropy == 0)
2955         {
2956             SymCryptMarvin32Init(&marvinState, GetDefaultSeed());
2957         }
2958         else
2959         {
2960             CreateMarvin32Seed(additionalEntropy, &seed);
2961             SymCryptMarvin32Init(&marvinState, &seed);
2962         }
2963
2964         LPCWSTR szEnd = szStr + strLen;
2965
2966         const UINT A_TO_Z_RANGE = (UINT)('z' - 'a');
2967
2968         while (szStr != szEnd)
2969         {
2970             size_t count = (sizeof(buf) / sizeof(buf[0]));
2971
2972             if ((size_t)(szEnd - szStr) < count)
2973                 count = (size_t)(szEnd - szStr);
2974
2975             for (size_t i = 0; i<count; i++)
2976             {
2977                 WCHAR c = szStr[i];
2978
2979                 if ((UINT)(c - 'a') <= A_TO_Z_RANGE)  // if (c >='a' && c <= 'z') 
2980                 {
2981                    //If we have a lowercase character, ANDing off 0x20
2982                    // will make it an uppercase character.
2983                    c &= ~0x20;
2984                 }
2985
2986                 buf[i] = c;
2987             }
2988
2989             szStr += count;
2990
2991             SymCryptMarvin32Append(&marvinState, (PCBYTE) &buf, sizeof(WCHAR) * count);
2992         }
2993
2994         int marvinResult[SYMCRYPT_MARVIN32_RESULT_SIZE / sizeof(int)];
2995         SymCryptMarvin32Result(&marvinState, (PBYTE) &marvinResult);
2996         return marvinResult[0] ^ marvinResult[1];
2997     }
2998     else
2999     {
3000 #endif // FEATURE_RANDOMIZED_STRING_HASHING
3001         return ::HashiStringKnownLower80(szStr);
3002 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
3003     }
3004 #endif // FEATURE_RANDOMIZED_STRING_HASHING
3005 }
3006
3007
3008 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
3009 void COMNlsHashProvider::InitializeDefaultSeed()
3010 {
3011     CONTRACTL {
3012         THROWS;
3013         GC_NOTRIGGER;
3014         MODE_ANY;
3015     }
3016     CONTRACTL_END;
3017
3018     PCBYTE pEntropy = GetEntropy();
3019     AllocMemHolder<SYMCRYPT_MARVIN32_EXPANDED_SEED> pSeed(GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_EXPANDED_SEED))));
3020     SymCryptMarvin32ExpandSeed(pSeed, pEntropy, SYMCRYPT_MARVIN32_SEED_SIZE);
3021
3022     if(InterlockedCompareExchangeT(&pDefaultSeed, (PCSYMCRYPT_MARVIN32_EXPANDED_SEED) pSeed, NULL) == NULL)
3023     {
3024         pSeed.SuppressRelease();
3025     }
3026 }
3027
3028 PCSYMCRYPT_MARVIN32_EXPANDED_SEED COMNlsHashProvider::GetDefaultSeed()
3029 {
3030     CONTRACTL {
3031         THROWS;
3032         GC_NOTRIGGER;
3033         MODE_ANY;
3034     }
3035     CONTRACTL_END;
3036
3037     if(pDefaultSeed == NULL)
3038     {
3039         InitializeDefaultSeed();
3040     }
3041
3042     return pDefaultSeed;
3043 }
3044
3045 PCBYTE COMNlsHashProvider::GetEntropy()
3046 {
3047     CONTRACTL {
3048         THROWS;
3049         GC_NOTRIGGER;
3050         MODE_ANY;
3051     }
3052     CONTRACTL_END;
3053
3054     if(pEntropy == NULL)
3055     {
3056         AllocMemHolder<BYTE> pNewEntropy(GetAppDomain()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SYMCRYPT_MARVIN32_SEED_SIZE))));
3057
3058 #ifdef FEATURE_PAL
3059         PAL_Random(TRUE, pNewEntropy, SYMCRYPT_MARVIN32_SEED_SIZE);
3060 #else
3061         HCRYPTPROV hCryptProv;
3062         WszCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
3063         CryptGenRandom(hCryptProv, SYMCRYPT_MARVIN32_SEED_SIZE, pNewEntropy);
3064         CryptReleaseContext(hCryptProv, 0);
3065 #endif
3066
3067         if(InterlockedCompareExchangeT(&pEntropy, (PBYTE) pNewEntropy, NULL) == NULL)
3068         {
3069             pNewEntropy.SuppressRelease();
3070         }
3071     }
3072  
3073     return (PCBYTE) pEntropy;
3074 }
3075
3076
3077 void COMNlsHashProvider::CreateMarvin32Seed(INT64 additionalEntropy, PSYMCRYPT_MARVIN32_EXPANDED_SEED pExpandedMarvinSeed)
3078 {
3079     CONTRACTL {
3080         THROWS;
3081         GC_NOTRIGGER;
3082         MODE_ANY;
3083     }
3084     CONTRACTL_END;
3085
3086     INT64 *pEntropy = (INT64*) GetEntropy();
3087     INT64 entropy;
3088
3089     entropy = *pEntropy ^ additionalEntropy;
3090
3091     SymCryptMarvin32ExpandSeed(pExpandedMarvinSeed, (PCBYTE) &entropy, SYMCRYPT_MARVIN32_SEED_SIZE);
3092 }
3093 #endif // FEATURE_RANDOMIZED_STRING_HASHING
3094
3095 #ifdef FEATURE_COREFX_GLOBALIZATION
3096 INT32 QCALLTYPE CoreFxGlobalization::HashSortKey(PCBYTE pSortKey, INT32 cbSortKey, BOOL forceRandomizedHashing, INT64 additionalEntropy)
3097 {
3098     QCALL_CONTRACT;
3099
3100     INT32 retVal = 0;
3101
3102     BEGIN_QCALL;
3103
3104     retVal = COMNlsHashProvider::s_NlsHashProvider.HashSortKey(pSortKey, cbSortKey, forceRandomizedHashing, additionalEntropy);
3105
3106     END_QCALL;
3107
3108     return retVal;
3109 }
3110 #endif //FEATURE_COREFX_GLOBALIZATION
3111
3112 static MethodTable * g_pStreamMT;
3113 static WORD g_slotBeginRead, g_slotEndRead;
3114 static WORD g_slotBeginWrite, g_slotEndWrite;
3115
3116 static bool HasOverriddenStreamMethod(MethodTable * pMT, WORD slot)
3117 {
3118     CONTRACTL{
3119         NOTHROW;
3120         GC_NOTRIGGER;
3121         MODE_ANY;
3122         SO_TOLERANT;
3123     } CONTRACTL_END;
3124
3125     PCODE actual = pMT->GetRestoredSlot(slot);
3126     PCODE base = g_pStreamMT->GetRestoredSlot(slot);
3127     if (actual == base)
3128         return false;
3129
3130     if (!g_pStreamMT->IsZapped())
3131     {
3132         // If mscorlib is JITed, the slots can be patched and thus we need to compare the actual MethodDescs 
3133         // to detect match reliably
3134         if (MethodTable::GetMethodDescForSlotAddress(actual) == MethodTable::GetMethodDescForSlotAddress(base))
3135             return false;
3136     }
3137
3138     return true;
3139 }
3140
3141 FCIMPL1(FC_BOOL_RET, StreamNative::HasOverriddenBeginEndRead, Object *stream)
3142 {
3143     FCALL_CONTRACT;
3144
3145     if (stream == NULL)
3146         FC_RETURN_BOOL(TRUE);
3147
3148     if (g_pStreamMT == NULL || g_slotBeginRead == 0 || g_slotEndRead == 0)
3149     {
3150         HELPER_METHOD_FRAME_BEGIN_RET_1(stream);
3151         g_pStreamMT = MscorlibBinder::GetClass(CLASS__STREAM);
3152         g_slotBeginRead = MscorlibBinder::GetMethod(METHOD__STREAM__BEGIN_READ)->GetSlot();
3153         g_slotEndRead = MscorlibBinder::GetMethod(METHOD__STREAM__END_READ)->GetSlot();
3154         HELPER_METHOD_FRAME_END();
3155     }
3156
3157     MethodTable * pMT = stream->GetMethodTable();
3158
3159     FC_RETURN_BOOL(HasOverriddenStreamMethod(pMT, g_slotBeginRead) || HasOverriddenStreamMethod(pMT, g_slotEndRead));
3160 }
3161 FCIMPLEND
3162
3163 FCIMPL1(FC_BOOL_RET, StreamNative::HasOverriddenBeginEndWrite, Object *stream)
3164 {
3165     FCALL_CONTRACT;
3166
3167     if (stream == NULL) 
3168         FC_RETURN_BOOL(TRUE);
3169
3170     if (g_pStreamMT == NULL || g_slotBeginWrite == 0 || g_slotEndWrite == 0)
3171     {
3172         HELPER_METHOD_FRAME_BEGIN_RET_1(stream);
3173         g_pStreamMT = MscorlibBinder::GetClass(CLASS__STREAM);
3174         g_slotBeginWrite = MscorlibBinder::GetMethod(METHOD__STREAM__BEGIN_WRITE)->GetSlot();
3175         g_slotEndWrite = MscorlibBinder::GetMethod(METHOD__STREAM__END_WRITE)->GetSlot();
3176         HELPER_METHOD_FRAME_END();
3177     }
3178
3179     MethodTable * pMT = stream->GetMethodTable();
3180
3181     FC_RETURN_BOOL(HasOverriddenStreamMethod(pMT, g_slotBeginWrite) || HasOverriddenStreamMethod(pMT, g_slotEndWrite));
3182 }
3183 FCIMPLEND