Implement RuntimeHelpers.PrepareMethod/PrepareDelegate for CoreCLR (#16382)
[platform/upstream/coreclr.git] / src / vm / reflectioninvocation.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 #include "common.h"
8 #include "reflectioninvocation.h"
9 #include "invokeutil.h"
10 #include "object.h"
11 #include "class.h"
12 #include "method.hpp"
13 #include "typehandle.h"
14 #include "field.h"
15 #include "eeconfig.h"
16 #include "vars.hpp"
17 #include "jitinterface.h"
18 #include "contractimpl.h"
19 #include "virtualcallstub.h"
20 #include "comdelegate.h"
21 #include "generics.h"
22
23 #ifdef FEATURE_COMINTEROP
24 #include "interoputil.h"
25 #include "runtimecallablewrapper.h"
26 #endif
27
28 #include "dbginterface.h"
29 #include "argdestination.h"
30
31 // these flags are defined in XXXInfo.cs and only those that are used are replicated here
32 #define INVOCATION_FLAGS_UNKNOWN                    0x00000000
33 #define INVOCATION_FLAGS_INITIALIZED                0x00000001
34
35 // it's used for both method and field to signify that no access is allowed
36 #define INVOCATION_FLAGS_NO_INVOKE                  0x00000002
37
38 // #define unused                                   0x00000004
39
40 // because field and method are different we can reuse the same bits
41 //method
42 #define INVOCATION_FLAGS_IS_CTOR                    0x00000010
43 #define INVOCATION_FLAGS_RISKY_METHOD               0x00000020
44 // #define unused                                   0x00000040
45 #define INVOCATION_FLAGS_IS_DELEGATE_CTOR           0x00000080
46 #define INVOCATION_FLAGS_CONTAINS_STACK_POINTERS    0x00000100
47 // field
48 #define INVOCATION_FLAGS_SPECIAL_FIELD              0x00000010
49 #define INVOCATION_FLAGS_FIELD_SPECIAL_CAST         0x00000020
50
51 // temporary flag used for flagging invocation of method vs ctor
52 #define INVOCATION_FLAGS_CONSTRUCTOR_INVOKE         0x10000000
53
54 /**************************************************************************/
55 /* if the type handle 'th' is a byref to a nullable type, return the
56    type handle to the nullable type in the byref.  Otherwise return 
57    the null type handle  */
58 static TypeHandle NullableTypeOfByref(TypeHandle th) {
59     CONTRACTL
60     {
61         NOTHROW;
62         GC_NOTRIGGER;
63         SO_TOLERANT;
64         MODE_ANY;
65     }
66     CONTRACTL_END;
67
68     if (th.GetVerifierCorElementType() != ELEMENT_TYPE_BYREF)
69         return TypeHandle();
70     
71     TypeHandle subType = th.AsTypeDesc()->GetTypeParam();
72     if (!Nullable::IsNullableType(subType))
73         return TypeHandle();
74             
75     return subType;
76 }
77
78 static void TryCallMethodWorker(MethodDescCallSite* pMethodCallSite, ARG_SLOT* args, Frame* pDebuggerCatchFrame)
79 {
80     // Use static contracts b/c we have SEH.
81     STATIC_CONTRACT_THROWS;
82     STATIC_CONTRACT_GC_TRIGGERS;
83     STATIC_CONTRACT_MODE_ANY;
84
85     struct Param: public NotifyOfCHFFilterWrapperParam
86     {
87         MethodDescCallSite * pMethodCallSite;
88         ARG_SLOT* args;
89     } param;
90
91     param.pFrame = pDebuggerCatchFrame;
92     param.pMethodCallSite = pMethodCallSite;
93     param.args = args;
94
95     PAL_TRY(Param *, pParam, &param)
96     {
97         pParam->pMethodCallSite->CallWithValueTypes(pParam->args);
98     }
99     PAL_EXCEPT_FILTER(NotifyOfCHFFilterWrapper)
100     {
101         // Should never reach here b/c handler should always continue search.
102         _ASSERTE(false);
103     }
104     PAL_ENDTRY
105 }
106
107 // Warning: This method has subtle differences from CallDescrWorkerReflectionWrapper
108 // In particular that one captures watson bucket data and corrupting exception severity,
109 // then transfers that data to the newly produced TargetInvocationException. This one
110 // doesn't take those same steps. 
111 //
112 static void TryCallMethod(MethodDescCallSite* pMethodCallSite, ARG_SLOT* args, bool wrapExceptions) {
113     CONTRACTL {
114         THROWS;
115         GC_TRIGGERS;
116         MODE_COOPERATIVE;
117     }
118     CONTRACTL_END;
119
120     if (wrapExceptions)
121     {
122         OBJECTREF ppException = NULL;
123         GCPROTECT_BEGIN(ppException);
124
125         // The sole purpose of having this frame is to tell the debugger that we have a catch handler here
126         // which may swallow managed exceptions.  The debugger needs this in order to send a
127         // CatchHandlerFound (CHF) notification.
128         FrameWithCookie<DebuggerU2MCatchHandlerFrame> catchFrame;
129         EX_TRY{
130             TryCallMethodWorker(pMethodCallSite, args, &catchFrame);
131         }
132             EX_CATCH{
133                 ppException = GET_THROWABLE();
134                 _ASSERTE(ppException);
135         }
136             EX_END_CATCH(RethrowTransientExceptions)
137             catchFrame.Pop();
138
139         // It is important to re-throw outside the catch block because re-throwing will invoke
140         // the jitter and managed code and will cause us to use more than the backout stack limit.
141         if (ppException != NULL)
142         {
143             // If we get here we need to throw an TargetInvocationException
144             OBJECTREF except = InvokeUtil::CreateTargetExcept(&ppException);
145             COMPlusThrow(except);
146         }
147         GCPROTECT_END();
148     }
149     else
150     {
151         pMethodCallSite->CallWithValueTypes(args);
152     }
153 }
154
155
156
157
158 FCIMPL5(Object*, RuntimeFieldHandle::GetValue, ReflectFieldObject *pFieldUNSAFE, Object *instanceUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, ReflectClassBaseObject *pDeclaringTypeUNSAFE, CLR_BOOL *pDomainInitialized) {
159     CONTRACTL {
160         FCALL_CHECK;
161     }
162     CONTRACTL_END;
163
164     struct _gc
165     {
166         OBJECTREF target;
167         REFLECTCLASSBASEREF pFieldType;
168         REFLECTCLASSBASEREF pDeclaringType;
169         REFLECTFIELDREF refField;
170     }gc;
171
172     gc.target = ObjectToOBJECTREF(instanceUNSAFE);
173     gc.pFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
174     gc.pDeclaringType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDeclaringTypeUNSAFE);
175     gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
176
177     if ((gc.pFieldType == NULL) || (gc.refField == NULL))
178         FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
179
180     TypeHandle fieldType = gc.pFieldType->GetType();
181     TypeHandle declaringType = (gc.pDeclaringType != NULL) ? gc.pDeclaringType->GetType() : TypeHandle();
182     
183     Assembly *pAssem;
184     if (declaringType.IsNull())
185     {
186         // global field
187         pAssem = gc.refField->GetField()->GetModule()->GetAssembly();
188     }
189     else
190     {
191         pAssem = declaringType.GetAssembly();
192     }
193
194     if (pAssem->IsIntrospectionOnly())
195         FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
196
197     // We should throw NotSupportedException here. 
198     // But for backward compatibility we are throwing FieldAccessException instead.
199     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
200         FCThrow(kFieldAccessException);
201
202     OBJECTREF rv = NULL; // not protected
203
204     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
205     // There can be no GC after this until the Object is returned.
206     rv = InvokeUtil::GetFieldValue(gc.refField->GetField(), fieldType, &gc.target, declaringType, pDomainInitialized);
207     HELPER_METHOD_FRAME_END();
208
209     return OBJECTREFToObject(rv);
210 }
211 FCIMPLEND
212
213 FCIMPL2(FC_BOOL_RET, ReflectionInvocation::CanValueSpecialCast, ReflectClassBaseObject *pValueTypeUNSAFE, ReflectClassBaseObject *pTargetTypeUNSAFE) {
214     CONTRACTL {
215         FCALL_CHECK;
216         PRECONDITION(CheckPointer(pValueTypeUNSAFE));
217         PRECONDITION(CheckPointer(pTargetTypeUNSAFE));
218     }
219     CONTRACTL_END;
220     
221     REFLECTCLASSBASEREF refValueType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pValueTypeUNSAFE);
222     REFLECTCLASSBASEREF refTargetType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTargetTypeUNSAFE);
223
224     TypeHandle valueType = refValueType->GetType();
225     TypeHandle targetType = refTargetType->GetType();
226
227     // we are here only if the target type is a primitive, an enum or a pointer
228
229     CorElementType targetCorElement = targetType.GetVerifierCorElementType();
230
231     BOOL ret = TRUE;
232     HELPER_METHOD_FRAME_BEGIN_RET_2(refValueType, refTargetType);
233     // the field type is a pointer
234     if (targetCorElement == ELEMENT_TYPE_PTR || targetCorElement == ELEMENT_TYPE_FNPTR) {
235         // the object must be an IntPtr or a System.Reflection.Pointer
236         if (valueType == TypeHandle(MscorlibBinder::GetClass(CLASS__INTPTR))) {
237             //
238             // it's an IntPtr, it's good.
239         }
240         //
241         // it's a System.Reflection.Pointer object
242
243         // void* assigns to any pointer. Otherwise the type of the pointer must match
244         else if (!InvokeUtil::IsVoidPtr(targetType)) {
245             if (!valueType.CanCastTo(targetType))
246                 ret = FALSE;
247         }
248     } else {
249         // the field type is an enum or a primitive. To have any chance of assignement the object type must
250         // be an enum or primitive as well.
251         // So get the internal cor element and that must be the same or widen
252         CorElementType valueCorElement = valueType.GetVerifierCorElementType();
253         if (InvokeUtil::IsPrimitiveType(valueCorElement))
254             ret = (InvokeUtil::CanPrimitiveWiden(targetCorElement, valueCorElement)) ? TRUE : FALSE;
255         else
256             ret = FALSE;
257     }
258     HELPER_METHOD_FRAME_END();
259     FC_RETURN_BOOL(ret);
260 }
261 FCIMPLEND
262
263 FCIMPL3(Object*, ReflectionInvocation::AllocateValueType, ReflectClassBaseObject *pTargetTypeUNSAFE, Object *valueUNSAFE, CLR_BOOL fForceTypeChange) {
264     CONTRACTL {
265         FCALL_CHECK;
266         PRECONDITION(CheckPointer(pTargetTypeUNSAFE));
267         PRECONDITION(CheckPointer(valueUNSAFE, NULL_OK));
268     }
269     CONTRACTL_END;
270
271     struct _gc
272     {
273         REFLECTCLASSBASEREF refTargetType;
274         OBJECTREF value;
275         OBJECTREF obj;
276     }gc;
277
278     gc.value = ObjectToOBJECTREF(valueUNSAFE);
279     gc.obj = gc.value;
280     gc.refTargetType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTargetTypeUNSAFE);
281
282     TypeHandle targetType = gc.refTargetType->GetType();
283
284     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
285     CorElementType targetElementType = targetType.GetSignatureCorElementType();
286     if (InvokeUtil::IsPrimitiveType(targetElementType) || targetElementType == ELEMENT_TYPE_VALUETYPE)
287     {
288         MethodTable* allocMT = targetType.AsMethodTable();
289         if (gc.value != NULL)
290         {
291             // ignore the type of the incoming box if fForceTypeChange is set
292             // and the target type is not nullable
293             if (!fForceTypeChange || Nullable::IsNullableType(targetType))
294                 allocMT = gc.value->GetMethodTable();
295         }
296
297         // for null Nullable<T> we don't want a default value being created.  
298         // just allow the null value to be passed, as it will be converted to 
299         // a true nullable 
300         if (!(gc.value == NULL && Nullable::IsNullableType(targetType)))
301         {
302             // boxed value type are 'read-only' in the sence that you can't
303             // only the implementor of the value type can expose mutators.
304             // To insure byrefs don't mutate value classes in place, we make
305             // a copy (and if we were not given one, we create a null value type
306             // instance.
307             gc.obj = allocMT->Allocate();
308
309             if (gc.value != NULL)
310                     CopyValueClassUnchecked(gc.obj->UnBox(), gc.value->UnBox(), allocMT);
311         }
312     }
313
314     HELPER_METHOD_FRAME_END();
315
316     return OBJECTREFToObject(gc.obj);
317 }
318 FCIMPLEND
319
320 FCIMPL7(void, RuntimeFieldHandle::SetValue, ReflectFieldObject *pFieldUNSAFE, Object *targetUNSAFE, Object *valueUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, DWORD attr, ReflectClassBaseObject *pDeclaringTypeUNSAFE, CLR_BOOL *pDomainInitialized) {
321     CONTRACTL {
322         FCALL_CHECK;
323     }
324     CONTRACTL_END;
325
326     struct _gc {
327         OBJECTREF       target;
328         OBJECTREF       value;
329         REFLECTCLASSBASEREF fieldType;
330         REFLECTCLASSBASEREF declaringType;
331         REFLECTFIELDREF refField;
332     } gc;
333
334     gc.target   = ObjectToOBJECTREF(targetUNSAFE);
335     gc.value    = ObjectToOBJECTREF(valueUNSAFE);
336     gc.fieldType= (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
337     gc.declaringType= (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDeclaringTypeUNSAFE);
338     gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
339
340     if ((gc.fieldType == NULL) || (gc.refField == NULL))
341         FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
342     
343     TypeHandle fieldType = gc.fieldType->GetType();
344     TypeHandle declaringType = gc.declaringType != NULL ? gc.declaringType->GetType() : TypeHandle();
345
346     Assembly *pAssem;
347     if (declaringType.IsNull())
348     {
349         // global field
350         pAssem = gc.refField->GetField()->GetModule()->GetAssembly();
351     }
352     else
353     {
354         pAssem = declaringType.GetAssembly();
355     }
356
357     if (pAssem->IsIntrospectionOnly())
358         FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
359
360     // We should throw NotSupportedException here. 
361     // But for backward compatibility we are throwing FieldAccessException instead.
362     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
363         FCThrowVoid(kFieldAccessException);
364
365     FC_GC_POLL_NOT_NEEDED();
366
367     FieldDesc* pFieldDesc = gc.refField->GetField();
368
369     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
370
371     //TODO: cleanup this function
372     InvokeUtil::SetValidField(fieldType.GetSignatureCorElementType(), fieldType, pFieldDesc, &gc.target, &gc.value, declaringType, pDomainInitialized);
373
374     HELPER_METHOD_FRAME_END();
375 }
376 FCIMPLEND
377
378 //A.CI work
379 FCIMPL1(Object*, RuntimeTypeHandle::Allocate, ReflectClassBaseObject* pTypeUNSAFE)  
380 {
381     CONTRACTL {
382         FCALL_CHECK;
383         PRECONDITION(CheckPointer(pTypeUNSAFE));
384     }
385     CONTRACTL_END
386
387     REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
388     TypeHandle type = refType->GetType();
389
390         // Handle the nullable<T> special case
391     if (Nullable::IsNullableType(type)) {
392         return OBJECTREFToObject(Nullable::BoxedNullableNull(type));
393     }
394
395     OBJECTREF rv = NULL;
396     HELPER_METHOD_FRAME_BEGIN_RET_1(refType);
397     rv = AllocateObject(type.GetMethodTable());
398     HELPER_METHOD_FRAME_END();
399     return OBJECTREFToObject(rv);
400
401 }//Allocate
402 FCIMPLEND
403
404 FCIMPL5(Object*, RuntimeTypeHandle::CreateInstance, ReflectClassBaseObject* refThisUNSAFE,
405                                                     CLR_BOOL publicOnly,
406                                                     CLR_BOOL wrapExceptions,
407                                                     CLR_BOOL* pbCanBeCached,
408                                                     MethodDesc** pConstructor) {
409     CONTRACTL {
410         FCALL_CHECK;
411         PRECONDITION(CheckPointer(refThisUNSAFE));
412         PRECONDITION(CheckPointer(pbCanBeCached));
413         PRECONDITION(CheckPointer(pConstructor));
414         PRECONDITION(*pbCanBeCached == false);
415         PRECONDITION(*pConstructor == NULL);
416     }
417     CONTRACTL_END;
418
419     if (refThisUNSAFE == NULL) 
420         FCThrow(kNullReferenceException);
421
422     MethodDesc* pMeth;
423
424     OBJECTREF           rv      = NULL;
425     REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(refThisUNSAFE);
426     TypeHandle thisTH = refThis->GetType();
427
428     Assembly *pAssem = thisTH.GetAssembly();
429
430     if (pAssem->IsIntrospectionOnly())
431         FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
432
433     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
434         FCThrowRes(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
435
436     HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refThis);
437
438     MethodTable* pVMT;
439
440     // Get the type information associated with refThis
441     if (thisTH.IsNull() || thisTH.IsTypeDesc())
442         COMPlusThrow(kMissingMethodException,W("Arg_NoDefCTor"));
443         
444     pVMT = thisTH.AsMethodTable();
445
446     pVMT->EnsureInstanceActive();
447
448 #ifdef FEATURE_COMINTEROP
449     // If this is __ComObject then create the underlying COM object.
450     if (IsComObjectClass(refThis->GetType())) {
451 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
452         SyncBlock* pSyncBlock = refThis->GetSyncBlock();
453
454         void* pClassFactory = (void*)pSyncBlock->GetInteropInfo()->GetComClassFactory();
455         if (!pClassFactory)
456             COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY);
457
458         // create an instance of the Com Object
459         rv = ((ComClassFactory*)pClassFactory)->CreateInstance(NULL);
460
461 #else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
462
463         COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY);
464
465 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
466     }
467     else
468 #endif // FEATURE_COMINTEROP
469     {
470         // if this is an abstract class then we will fail this
471         if (pVMT->IsAbstract())  {
472             if (pVMT->IsInterface())
473                 COMPlusThrow(kMissingMethodException,W("Acc_CreateInterface"));
474             else
475                 COMPlusThrow(kMissingMethodException,W("Acc_CreateAbst"));
476         }
477         else if (pVMT->ContainsGenericVariables()) {
478             COMPlusThrow(kArgumentException,W("Acc_CreateGeneric"));
479         }
480         
481         if (pVMT->IsByRefLike())
482             COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike"));
483         
484         if (pVMT->IsSharedByGenericInstantiations())
485             COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
486
487         if (!pVMT->HasDefaultConstructor())
488         {
489             // We didn't find the parameterless constructor,
490             //  if this is a Value class we can simply allocate one and return it
491
492             if (!pVMT->IsValueType()) {
493                 COMPlusThrow(kMissingMethodException,W("Arg_NoDefCTor"));
494             }
495
496             // Handle the nullable<T> special case
497             if (Nullable::IsNullableType(thisTH)) {
498                 rv = Nullable::BoxedNullableNull(thisTH);
499             }
500             else 
501                 rv = pVMT->Allocate();
502
503             if (!pVMT->Collectible())
504             {
505                 *pbCanBeCached = true;
506             }
507         }
508         else // !pVMT->HasDefaultConstructor()
509         {
510             pMeth = pVMT->GetDefaultConstructor();
511
512             // Validate the method can be called by this caller
513             DWORD attr = pMeth->GetAttrs();
514
515             if (!IsMdPublic(attr) && publicOnly)
516                 COMPlusThrow(kMissingMethodException, W("Arg_NoDefCTor"));
517
518             // We've got the class, lets allocate it and call the constructor
519             OBJECTREF o;
520             bool remoting = false;
521
522             o = AllocateObject(pVMT);
523             GCPROTECT_BEGIN(o);
524
525             MethodDescCallSite ctor(pMeth, &o);
526
527             // Copy "this" pointer
528             ARG_SLOT arg;
529             if (pVMT->IsValueType())
530                 arg = PtrToArgSlot(o->UnBox());
531             else
532                 arg = ObjToArgSlot(o);
533
534             // Call the method
535             TryCallMethod(&ctor, &arg, wrapExceptions);
536
537             rv = o;
538             GCPROTECT_END();
539
540             // No need to set these if they cannot be cached. In particular, if the type is a value type with a custom
541             // parameterless constructor, don't allow caching and have subsequent calls come back here to allocate an object and
542             // call the constructor.
543             if (!remoting && !pVMT->Collectible() && !pVMT->IsValueType())
544             {
545                 *pbCanBeCached = true;
546                 *pConstructor = pMeth;
547             }
548         }
549     }
550
551     HELPER_METHOD_FRAME_END();
552     return OBJECTREFToObject(rv);
553 }
554 FCIMPLEND
555
556 FCIMPL2(Object*, RuntimeTypeHandle::CreateInstanceForGenericType, ReflectClassBaseObject* pTypeUNSAFE, ReflectClassBaseObject* pParameterTypeUNSAFE) {
557     FCALL_CONTRACT;
558
559     struct _gc
560     {
561         OBJECTREF rv;
562         REFLECTCLASSBASEREF refType;
563         REFLECTCLASSBASEREF refParameterType;
564     } gc;
565
566     gc.rv = NULL;
567     gc.refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
568     gc.refParameterType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pParameterTypeUNSAFE);
569
570     MethodDesc* pMeth;
571     TypeHandle genericType = gc.refType->GetType();
572
573     TypeHandle parameterHandle = gc.refParameterType->GetType();
574
575     _ASSERTE (genericType.HasInstantiation());
576
577     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
578
579     TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(&parameterHandle, 1));
580
581     // Get the type information associated with refThis
582     MethodTable* pVMT = instantiatedType.GetMethodTable();
583     _ASSERTE (pVMT != 0 &&  !instantiatedType.IsTypeDesc());
584     _ASSERTE(!(pVMT->GetAssembly()->IsDynamic() && !pVMT->GetAssembly()->HasRunAccess()));
585     _ASSERTE( !pVMT->IsAbstract() ||! instantiatedType.ContainsGenericVariables());
586     _ASSERTE(!pVMT->IsByRefLike() && pVMT->HasDefaultConstructor());
587
588     pMeth = pVMT->GetDefaultConstructor();            
589     MethodDescCallSite ctor(pMeth);
590
591     // We've got the class, lets allocate it and call the constructor
592    
593     // Nullables don't take this path, if they do we need special logic to make an instance
594     _ASSERTE(!Nullable::IsNullableType(instantiatedType));
595     gc.rv = instantiatedType.GetMethodTable()->Allocate();
596
597     ARG_SLOT arg = ObjToArgSlot(gc.rv); 
598
599     // Call the method
600     TryCallMethod(&ctor, &arg, true);
601
602     HELPER_METHOD_FRAME_END();
603     return OBJECTREFToObject(gc.rv);
604 }
605 FCIMPLEND
606
607 NOINLINE FC_BOOL_RET IsInstanceOfTypeHelper(OBJECTREF obj, REFLECTCLASSBASEREF refType)
608 {
609     FCALL_CONTRACT;
610
611     BOOL canCast = false;
612
613     FC_INNER_PROLOG(RuntimeTypeHandle::IsInstanceOfType);
614
615     HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, obj, refType);
616     canCast = ObjIsInstanceOf(OBJECTREFToObject(obj), refType->GetType());
617     HELPER_METHOD_FRAME_END();
618
619     FC_RETURN_BOOL(canCast);
620 }
621
622 FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsInstanceOfType, ReflectClassBaseObject* pTypeUNSAFE, Object *objectUNSAFE) {
623     FCALL_CONTRACT;
624
625     OBJECTREF obj = ObjectToOBJECTREF(objectUNSAFE);
626     REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
627
628     // Null is not instance of anything in reflection world
629     if (obj == NULL)
630         FC_RETURN_BOOL(false);
631
632     if (refType == NULL)
633         FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));    
634
635     switch (ObjIsInstanceOfNoGC(objectUNSAFE, refType->GetType())) {
636     case TypeHandle::CanCast:
637         FC_RETURN_BOOL(true);
638     case TypeHandle::CannotCast:
639         FC_RETURN_BOOL(false);
640     default:
641         // fall through to the slow helper
642         break;
643     }
644
645     FC_INNER_RETURN(FC_BOOL_RET, IsInstanceOfTypeHelper(obj, refType));
646 }
647 FCIMPLEND
648
649 FCIMPL1(DWORD, ReflectionInvocation::GetSpecialSecurityFlags, ReflectMethodObject *pMethodUNSAFE) {
650     CONTRACTL {
651         FCALL_CHECK;
652     }
653     CONTRACTL_END;
654     
655     DWORD dwFlags = 0;
656
657     struct
658     {
659         REFLECTMETHODREF refMethod;
660     }
661     gc;
662
663     gc.refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
664
665     if (!gc.refMethod)
666         FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
667
668     MethodDesc* pMethod = gc.refMethod->GetMethod();
669
670     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
671
672     // this is an information that is critical for ctors, otherwise is not important
673     // we get it here anyway to simplify code
674     MethodTable *pMT = pMethod->GetMethodTable();
675     _ASSERTE(pMT);
676
677     // We should also check the return type here. 
678     // Is there an easier way to get the return type of a method?
679     MetaSig metaSig(pMethod);
680     TypeHandle retTH = metaSig.GetRetTypeHandleThrowing();
681     MethodTable *pRetMT = retTH.GetMethodTable();
682
683     // If either the declaring type or the return type contains stack pointers (ByRef or typedbyref), 
684     // the type cannot be boxed and thus cannot be invoked through reflection invocation.
685     if ( pMT->IsByRefLike() || (pRetMT != NULL && pRetMT->IsByRefLike()) )
686         dwFlags |= INVOCATION_FLAGS_CONTAINS_STACK_POINTERS;
687
688     // Is this a call to a potentially dangerous method? (If so, we're going
689     // to demand additional permission).
690     if (InvokeUtil::IsDangerousMethod(pMethod))
691         dwFlags |= INVOCATION_FLAGS_RISKY_METHOD;
692
693     HELPER_METHOD_FRAME_END();
694     return dwFlags;
695 }
696 FCIMPLEND
697
698
699 /****************************************************************************/
700 /* boxed Nullable<T> are represented as a boxed T, so there is no unboxed
701    Nullable<T> inside to point at by reference.  Because of this a byref
702    parameters  of type Nullable<T> are copied out of the boxed instance
703    (to a place on the stack), before the call is made (and this copy is
704    pointed at).  After the call returns, this copy must be copied back to
705    the original argument array.  ByRefToNullable, is a simple linked list
706    that remembers what copy-backs are needed */
707
708 struct ByRefToNullable  {
709     unsigned argNum;            // The argument number for this byrefNullable argument
710     void* data;                 // The data to copy back to the ByRefNullable.  This points to the stack 
711     TypeHandle type;            // The type of Nullable for this argument
712     ByRefToNullable* next;      // list of these
713
714     ByRefToNullable(unsigned aArgNum, void* aData, TypeHandle aType, ByRefToNullable* aNext) {
715         argNum = aArgNum;
716         data = aData;
717         type = aType;
718         next = aNext;
719     }
720 };
721
722 void CallDescrWorkerReflectionWrapper(CallDescrData * pCallDescrData, Frame * pFrame)
723 {
724     // Use static contracts b/c we have SEH.
725     STATIC_CONTRACT_THROWS;
726     STATIC_CONTRACT_GC_TRIGGERS;
727     STATIC_CONTRACT_MODE_ANY;
728
729     struct Param: public NotifyOfCHFFilterWrapperParam
730     {
731         CallDescrData * pCallDescrData;
732     } param;
733
734     param.pFrame = pFrame;
735     param.pCallDescrData = pCallDescrData;
736
737     PAL_TRY(Param *, pParam, &param)
738     {
739         CallDescrWorkerWithHandler(pParam->pCallDescrData);
740     }
741     PAL_EXCEPT_FILTER(ReflectionInvocationExceptionFilter)
742     {
743         // Should never reach here b/c handler should always continue search.
744         _ASSERTE(false);
745     }
746     PAL_ENDTRY
747 } // CallDescrWorkerReflectionWrapper
748
749 OBJECTREF InvokeArrayConstructor(ArrayTypeDesc* arrayDesc, MethodDesc* pMeth, PTRARRAYREF* objs, int argCnt)
750 {
751     CONTRACTL {
752         THROWS;
753         GC_TRIGGERS;
754         MODE_COOPERATIVE;
755     }
756     CONTRACTL_END;
757
758     DWORD i;
759
760     // If we're trying to create an array of pointers or function pointers,
761     // check that the caller has skip verification permission.
762     CorElementType et = arrayDesc->GetArrayElementTypeHandle().GetVerifierCorElementType();
763
764     // Validate the argCnt an the Rank. Also allow nested SZARRAY's.
765     _ASSERTE(argCnt == (int) arrayDesc->GetRank() || argCnt == (int) arrayDesc->GetRank() * 2 ||
766              arrayDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
767
768     // Validate all of the parameters.  These all typed as integers
769     int allocSize = 0;
770     if (!ClrSafeInt<int>::multiply(sizeof(INT32), argCnt, allocSize))
771         COMPlusThrow(kArgumentException, IDS_EE_SIGTOOCOMPLEX);
772         
773     INT32* indexes = (INT32*) _alloca((size_t)allocSize);
774     ZeroMemory(indexes, allocSize);
775
776     for (i=0; i<(DWORD)argCnt; i++)
777     {
778         if (!(*objs)->m_Array[i])
779             COMPlusThrowArgumentException(W("parameters"), W("Arg_NullIndex"));
780         
781         MethodTable* pMT = ((*objs)->m_Array[i])->GetMethodTable();
782         CorElementType oType = TypeHandle(pMT).GetVerifierCorElementType();
783         
784         if (!InvokeUtil::IsPrimitiveType(oType) || !InvokeUtil::CanPrimitiveWiden(ELEMENT_TYPE_I4,oType))
785             COMPlusThrow(kArgumentException,W("Arg_PrimWiden"));
786         
787         memcpy(&indexes[i],(*objs)->m_Array[i]->UnBox(),pMT->GetNumInstanceFieldBytes());
788     }
789
790     return AllocateArrayEx(TypeHandle(arrayDesc), indexes, argCnt);
791 }
792
793 static BOOL IsActivationNeededForMethodInvoke(MethodDesc * pMD)
794 {
795     CONTRACTL {
796         THROWS;
797         GC_TRIGGERS;
798         MODE_COOPERATIVE;
799     }
800     CONTRACTL_END;
801
802     // The activation for non-generic instance methods is covered by non-null "this pointer"
803     if (!pMD->IsStatic() && !pMD->HasMethodInstantiation() && !pMD->IsInterface())
804         return FALSE;
805
806     // We need to activate each time for domain neutral types
807     if (pMD->IsDomainNeutral())
808         return TRUE;
809
810     // We need to activate the instance at least once
811     pMD->EnsureActive();
812     return FALSE;
813 }
814
815 class ArgIteratorBaseForMethodInvoke
816 {
817 protected:
818     SIGNATURENATIVEREF * m_ppNativeSig;
819
820     FORCEINLINE CorElementType GetReturnType(TypeHandle * pthValueType)
821     {
822         WRAPPER_NO_CONTRACT;
823         return (*pthValueType = (*m_ppNativeSig)->GetReturnTypeHandle()).GetInternalCorElementType();
824     }
825
826     FORCEINLINE CorElementType GetNextArgumentType(DWORD iArg, TypeHandle * pthValueType)
827     {
828         WRAPPER_NO_CONTRACT;
829         return (*pthValueType = (*m_ppNativeSig)->GetArgumentAt(iArg)).GetInternalCorElementType();
830     }
831
832     FORCEINLINE void Reset()
833     {
834         LIMITED_METHOD_CONTRACT;
835     }
836
837 public:
838     BOOL HasThis()
839     {
840         LIMITED_METHOD_CONTRACT;
841         return (*m_ppNativeSig)->HasThis();
842     }
843
844     BOOL HasParamType()
845     {
846         LIMITED_METHOD_CONTRACT;
847         // param type methods are not supported for reflection invoke, so HasParamType is always false for them
848         return FALSE;
849     }
850
851     BOOL IsVarArg()
852     {
853         LIMITED_METHOD_CONTRACT;
854         // vararg methods are not supported for reflection invoke, so IsVarArg is always false for them
855         return FALSE;
856     }
857
858     DWORD NumFixedArgs()
859     {
860         LIMITED_METHOD_CONTRACT;
861         return (*m_ppNativeSig)->NumFixedArgs();
862     }
863
864 #ifdef FEATURE_INTERPRETER
865     BYTE CallConv()
866     {
867         LIMITED_METHOD_CONTRACT;
868         return IMAGE_CEE_CS_CALLCONV_DEFAULT;
869     }
870 #endif // FEATURE_INTERPRETER
871 };
872
873 class ArgIteratorForMethodInvoke : public ArgIteratorTemplate<ArgIteratorBaseForMethodInvoke>
874 {
875 public:
876     ArgIteratorForMethodInvoke(SIGNATURENATIVEREF * ppNativeSig)
877     {
878         m_ppNativeSig = ppNativeSig;
879
880         DWORD dwFlags = (*m_ppNativeSig)->GetArgIteratorFlags();
881
882         // Use the cached values if they are available
883         if (dwFlags & SIZE_OF_ARG_STACK_COMPUTED)
884         {
885             m_dwFlags = dwFlags;
886             m_nSizeOfArgStack = (*m_ppNativeSig)->GetSizeOfArgStack();
887             return;
888         }
889
890         //
891         // Compute flags and stack argument size, and cache them for next invocation
892         //
893
894         ForceSigWalk();
895
896         if (IsActivationNeededForMethodInvoke((*m_ppNativeSig)->GetMethod()))
897         {
898             m_dwFlags |= METHOD_INVOKE_NEEDS_ACTIVATION;
899         }
900
901         (*m_ppNativeSig)->SetSizeOfArgStack(m_nSizeOfArgStack);
902         _ASSERTE((*m_ppNativeSig)->GetSizeOfArgStack() == m_nSizeOfArgStack);
903
904         // This has to be last
905         (*m_ppNativeSig)->SetArgIteratorFlags(m_dwFlags);
906         _ASSERTE((*m_ppNativeSig)->GetArgIteratorFlags() == m_dwFlags);
907     }
908
909     BOOL IsActivationNeeded()
910     {
911         LIMITED_METHOD_CONTRACT;
912         return (m_dwFlags & METHOD_INVOKE_NEEDS_ACTIVATION) != 0;
913     }
914 };
915
916
917 void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTREF targetException)
918 {
919     CONTRACTL {
920         THROWS;
921         GC_TRIGGERS;
922         MODE_COOPERATIVE;
923     }
924     CONTRACTL_END;
925
926     GCPROTECT_BEGIN(targetException);
927
928 #if defined(_DEBUG) && !defined(FEATURE_PAL)
929     if (IsWatsonEnabled())
930     {
931         if (!CLRException::IsPreallocatedExceptionObject(targetException))
932         {
933             // If the exception is not preallocated, we should be having the
934             // watson buckets in the throwable already.
935             if(!((EXCEPTIONREF)targetException)->AreWatsonBucketsPresent())
936             {
937                 // If an exception is raised by the VM (e.g. type load exception by the JIT) and it comes
938                 // across the reflection invocation boundary before CLR's personality routine for managed
939                 // code has been invoked, then no buckets would be available for us at this point.
940                 //
941                 // Since we cannot assert this, better log it for diagnosis if required.
942                 LOG((LF_EH, LL_INFO100, "InvokeImpl - No watson buckets available - regular exception likely raised within VM and not seen by managed code.\n"));
943             }
944         }
945         else
946         {
947             // Exception is preallocated.
948             PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = GetThread()->GetExceptionState()->GetUEWatsonBucketTracker();
949             if ((IsThrowableThreadAbortException(targetException) && pUEWatsonBucketTracker->CapturedForThreadAbort())||
950                 (pUEWatsonBucketTracker->CapturedAtReflectionInvocation()))
951             {
952                 // ReflectionInvocationExceptionFilter would have captured
953                 // the watson bucket details for preallocated exceptions
954                 // in the UE watson bucket tracker.
955
956                 if(pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
957                 {
958                     // See comment above
959                     LOG((LF_EH, LL_INFO100, "InvokeImpl - No watson buckets available - preallocated exception likely raised within VM and not seen by managed code.\n"));
960                 }
961             }
962         }
963     }
964 #endif // _DEBUG && !FEATURE_PAL
965
966 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
967     // Get the corruption severity of the exception that came in through reflection invocation.
968     CorruptionSeverity severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity();
969
970     // Since we are dealing with an exception, set the flag indicating if the target of Reflection can handle exception or not.
971     // This flag is used in CEHelper::CanIDispatchTargetHandleException.
972     GetThread()->GetExceptionState()->SetCanReflectionTargetHandleException(CEHelper::CanMethodHandleException(severity, pMethod));
973 #endif // FEATURE_CORRUPTING_EXCEPTIONS
974
975     OBJECTREF except = InvokeUtil::CreateTargetExcept(&targetException);
976
977 #ifndef FEATURE_PAL
978     if (IsWatsonEnabled())
979     {
980         struct 
981         {
982             OBJECTREF oExcept;
983         } gcTIE;
984         ZeroMemory(&gcTIE, sizeof(gcTIE));
985         GCPROTECT_BEGIN(gcTIE);
986         
987         gcTIE.oExcept = except;
988
989         _ASSERTE(!CLRException::IsPreallocatedExceptionObject(gcTIE.oExcept));
990             
991         // If the original exception was preallocated, then copy over the captured
992         // watson buckets to the TargetInvocationException object, if available.
993         //
994         // We dont need to do this if the original exception was not preallocated
995         // since it already contains the watson buckets inside the object.
996         if (CLRException::IsPreallocatedExceptionObject(targetException))
997         {
998             PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = GetThread()->GetExceptionState()->GetUEWatsonBucketTracker();
999             BOOL fCopyWatsonBuckets = TRUE;
1000             PTR_VOID pBuckets = pUEWatsonBucketTracker->RetrieveWatsonBuckets();
1001             if (pBuckets != NULL)
1002             {
1003                 // Copy the buckets to the exception object
1004                 CopyWatsonBucketsToThrowable(pBuckets, gcTIE.oExcept);
1005
1006                 // Confirm that they are present.
1007                 _ASSERTE(((EXCEPTIONREF)gcTIE.oExcept)->AreWatsonBucketsPresent());
1008             }
1009                 
1010             // Clear the UE watson bucket tracker since the bucketing
1011             // details are now in the TargetInvocationException object.
1012             pUEWatsonBucketTracker->ClearWatsonBucketDetails();
1013         }
1014
1015         // update "except" incase the reference to the object
1016         // was updated by the GC
1017         except = gcTIE.oExcept;
1018         GCPROTECT_END();
1019     }
1020 #endif // !FEATURE_PAL
1021
1022     // Since the original exception is inner of target invocation exception,
1023     // when TIE is seen to be raised for the first time, we will end up
1024     // using the inner exception buckets automatically.
1025
1026     // Since VM is throwing the exception, we set it to use the same corruption severity
1027     // that the original exception came in with from reflection invocation.
1028     COMPlusThrow(except 
1029 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
1030         , severity
1031 #endif // FEATURE_CORRUPTING_EXCEPTIONS
1032         );
1033
1034     GCPROTECT_END();
1035 }
1036
1037 FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
1038     Object *target, PTRArray *objs, SignatureNative* pSigUNSAFE,
1039     CLR_BOOL fConstructor, CLR_BOOL fWrapExceptions)
1040 {
1041     FCALL_CONTRACT;
1042
1043     struct {
1044         OBJECTREF target;
1045         PTRARRAYREF args;
1046         SIGNATURENATIVEREF pSig;
1047         OBJECTREF retVal;
1048     } gc;
1049
1050     gc.target = ObjectToOBJECTREF(target);
1051     gc.args = (PTRARRAYREF)objs;
1052     gc.pSig = (SIGNATURENATIVEREF)pSigUNSAFE;
1053     gc.retVal = NULL;
1054
1055     MethodDesc* pMeth = gc.pSig->GetMethod();
1056     TypeHandle ownerType = gc.pSig->GetDeclaringType();
1057    
1058     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1059
1060     Assembly *pAssem = pMeth->GetAssembly();
1061
1062     if (pAssem->IsIntrospectionOnly())
1063         COMPlusThrow(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY);
1064
1065     // We should throw NotSupportedException here. 
1066     // But for backward compatibility we are throwing TargetException instead.
1067     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1068         COMPlusThrow(kTargetException);
1069
1070     if (ownerType.IsSharedByGenericInstantiations())
1071         COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
1072  
1073 #ifdef _DEBUG 
1074     if (g_pConfig->ShouldInvokeHalt(pMeth))
1075     {
1076         _ASSERTE(!"InvokeHalt");
1077     }
1078 #endif
1079
1080     // Skip the activation optimization for remoting because of remoting proxy is not always activated.
1081     // It would be nice to clean this up and get remoting to always activate methodtable behind the proxy.
1082     BOOL fForceActivationForRemoting = FALSE;
1083
1084     if (fConstructor)
1085     {
1086         // If we are invoking a constructor on an array then we must
1087         // handle this specially.  String objects allocate themselves
1088         // so they are a special case.
1089         if (ownerType.IsArray()) {
1090             gc.retVal = InvokeArrayConstructor(ownerType.AsArray(),
1091                                                pMeth,
1092                                                &gc.args,
1093                                                gc.pSig->NumFixedArgs());
1094             goto Done;
1095         }
1096
1097         MethodTable * pMT = ownerType.AsMethodTable();
1098
1099         {
1100             if (pMT != g_pStringClass)
1101                 gc.retVal = pMT->Allocate();
1102         }
1103     }
1104     else
1105     {
1106     }
1107
1108     {
1109     ArgIteratorForMethodInvoke argit(&gc.pSig);
1110
1111     if (argit.IsActivationNeeded() || fForceActivationForRemoting)
1112         pMeth->EnsureActive();
1113     CONSISTENCY_CHECK(pMeth->CheckActivated());
1114
1115     UINT nStackBytes = argit.SizeOfFrameArgumentArray();
1116
1117     // Note that SizeOfFrameArgumentArray does overflow checks with sufficient margin to prevent overflows here
1118     SIZE_T nAllocaSize = TransitionBlock::GetNegSpaceSize() + sizeof(TransitionBlock) + nStackBytes;
1119
1120     Thread * pThread = GET_THREAD();
1121
1122     // Make sure we have enough room on the stack for this. Note that we will need the stack amount twice - once to build the stack
1123     // and second time to actually make the call.
1124     INTERIOR_STACK_PROBE_FOR(pThread, 1 + static_cast<UINT>((2 * nAllocaSize) / GetOsPageSize()) + static_cast<UINT>(HOLDER_CODE_NORMAL_STACK_LIMIT));
1125
1126     LPBYTE pAlloc = (LPBYTE)_alloca(nAllocaSize);
1127
1128     LPBYTE pTransitionBlock = pAlloc + TransitionBlock::GetNegSpaceSize();
1129
1130     CallDescrData callDescrData;
1131
1132     callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
1133     callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
1134 #ifdef CALLDESCR_ARGREGS
1135     callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters());
1136 #endif
1137 #ifdef CALLDESCR_FPARGREGS
1138     callDescrData.pFloatArgumentRegisters = NULL;
1139 #endif
1140 #ifdef CALLDESCR_REGTYPEMAP
1141     callDescrData.dwRegTypeMap = 0;
1142 #endif
1143     callDescrData.fpReturnSize = argit.GetFPReturnSize();
1144
1145     // This is duplicated logic from MethodDesc::GetCallTarget
1146     PCODE pTarget;
1147     if (pMeth->IsVtableMethod())
1148     {
1149         pTarget = pMeth->GetSingleCallableAddrOfVirtualizedCode(&gc.target, ownerType);
1150     }
1151     else
1152     {
1153         pTarget = pMeth->GetSingleCallableAddrOfCode();
1154     }
1155     callDescrData.pTarget = pTarget;
1156
1157     // Build the arguments on the stack
1158
1159     GCStress<cfg_any>::MaybeTrigger();
1160
1161     FrameWithCookie<ProtectValueClassFrame> *pProtectValueClassFrame = NULL;
1162     ValueClassInfo *pValueClasses = NULL;
1163     ByRefToNullable* byRefToNullables = NULL;
1164
1165     // if we have the magic Value Class return, we need to allocate that class
1166     // and place a pointer to it on the stack.
1167
1168     TypeHandle retTH = gc.pSig->GetReturnTypeHandle();
1169     BOOL fHasRetBuffArg = argit.HasRetBuffArg();
1170     CorElementType retType = retTH.GetInternalCorElementType();
1171     if (retType == ELEMENT_TYPE_VALUETYPE || fHasRetBuffArg) {
1172         gc.retVal = retTH.GetMethodTable()->Allocate();
1173     }
1174
1175     // Copy "this" pointer
1176     if (!pMeth->IsStatic()) {
1177         PVOID pThisPtr;
1178
1179         if (fConstructor)
1180         {
1181             // Copy "this" pointer: only unbox if type is value type and method is not unboxing stub
1182             if (ownerType.IsValueType() && !pMeth->IsUnboxingStub()) {
1183                 // Note that we create a true boxed nullabe<T> and then convert it to a T below
1184                 pThisPtr = gc.retVal->GetData();
1185             }
1186             else
1187                 pThisPtr = OBJECTREFToObject(gc.retVal);
1188         }
1189         else
1190         if (!pMeth->GetMethodTable()->IsValueType())
1191             pThisPtr = OBJECTREFToObject(gc.target);
1192         else {
1193             if (pMeth->IsUnboxingStub())
1194                 pThisPtr = OBJECTREFToObject(gc.target);
1195             else {
1196                     // Create a true boxed Nullable<T> and use that as the 'this' pointer.
1197                     // since what is passed in is just a boxed T
1198                 MethodTable* pMT = pMeth->GetMethodTable();
1199                 if (Nullable::IsNullableType(pMT)) {
1200                     OBJECTREF bufferObj = pMT->Allocate();
1201                     void* buffer = bufferObj->GetData();
1202                     Nullable::UnBox(buffer, gc.target, pMT);
1203                     pThisPtr = buffer;
1204                 }
1205                 else
1206                     pThisPtr = gc.target->UnBox();
1207             }
1208         }
1209
1210         *((LPVOID*) (pTransitionBlock + argit.GetThisOffset())) = pThisPtr;
1211     }
1212
1213     // NO GC AFTER THIS POINT. The object references in the method frame are not protected.
1214     //
1215     // We have already copied "this" pointer so we do not want GC to happen even sooner. Unfortunately, 
1216     // we may allocate in the process of copying this pointer that makes it hard to express using contracts.
1217     //
1218     // If an exception occurs a gc may happen but we are going to dump the stack anyway and we do 
1219     // not need to protect anything.
1220
1221     PVOID pRetBufStackCopy = NULL;
1222
1223     {
1224     BEGINFORBIDGC();
1225 #ifdef _DEBUG
1226     GCForbidLoaderUseHolder forbidLoaderUse;
1227 #endif
1228
1229     // Take care of any return arguments
1230     if (fHasRetBuffArg)
1231     {
1232         // We stack-allocate this ret buff, to preserve the invariant that ret-buffs are always in the
1233         // caller's stack frame.  We'll copy into gc.retVal later.
1234         TypeHandle retTH = gc.pSig->GetReturnTypeHandle();
1235         MethodTable* pMT = retTH.GetMethodTable();
1236         if (pMT->IsStructRequiringStackAllocRetBuf())
1237         {
1238             SIZE_T sz = pMT->GetNumInstanceFieldBytes();
1239             pRetBufStackCopy = _alloca(sz);
1240             memset(pRetBufStackCopy, 0, sz);
1241
1242             pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pRetBufStackCopy, pMT, pValueClasses);
1243             *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBufStackCopy;
1244         }
1245         else
1246         {
1247             PVOID pRetBuff = gc.retVal->GetData();
1248             *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBuff;
1249         }
1250     }
1251
1252     // copy args
1253     UINT nNumArgs = gc.pSig->NumFixedArgs();
1254     for (UINT i = 0 ; i < nNumArgs; i++) {
1255
1256         TypeHandle th = gc.pSig->GetArgumentAt(i);
1257
1258         int ofs = argit.GetNextOffset();
1259         _ASSERTE(ofs != TransitionBlock::InvalidOffset);
1260
1261 #ifdef CALLDESCR_REGTYPEMAP
1262         FillInRegTypeMap(ofs, argit.GetArgType(), (BYTE *)&callDescrData.dwRegTypeMap);
1263 #endif
1264
1265 #ifdef CALLDESCR_FPARGREGS
1266         // Under CALLDESCR_FPARGREGS -ve offsets indicate arguments in floating point registers. If we have at
1267         // least one such argument we point the call worker at the floating point area of the frame (we leave
1268         // it null otherwise since the worker can perform a useful optimization if it knows no floating point
1269         // registers need to be set up).
1270
1271         if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs()) && 
1272             (callDescrData.pFloatArgumentRegisters == NULL))
1273         {
1274             callDescrData.pFloatArgumentRegisters = (FloatArgumentRegisters*) (pTransitionBlock +
1275                                                                                TransitionBlock::GetOffsetOfFloatArgumentRegisters());
1276         }
1277 #endif
1278
1279         UINT structSize = argit.GetArgSize();
1280
1281         bool needsStackCopy = false;
1282
1283         // A boxed Nullable<T> is represented as boxed T. So to pass a Nullable<T> by reference, 
1284         // we have to create a Nullable<T> on stack, copy the T into it, then pass it to the callee and
1285         // after returning from the call, copy the T out of the Nullable<T> back to the boxed T.
1286         TypeHandle nullableType = NullableTypeOfByref(th);
1287         if (!nullableType.IsNull()) {
1288             th = nullableType;
1289             structSize = th.GetSize();
1290             needsStackCopy = true;
1291         }
1292 #ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
1293         else if (argit.IsArgPassedByRef()) 
1294         {
1295             needsStackCopy = true;
1296         }
1297 #endif
1298
1299         ArgDestination argDest(pTransitionBlock, ofs, argit.GetArgLocDescForStructInRegs());
1300
1301         if(needsStackCopy)
1302         {
1303             MethodTable * pMT = th.GetMethodTable();
1304             _ASSERTE(pMT && pMT->IsValueType());
1305
1306             PVOID pArgDst = argDest.GetDestinationAddress();
1307
1308             PVOID pStackCopy = _alloca(structSize);
1309             *(PVOID *)pArgDst = pStackCopy;
1310             pArgDst = pStackCopy;
1311
1312             if (!nullableType.IsNull())
1313             {
1314                 byRefToNullables = new(_alloca(sizeof(ByRefToNullable))) ByRefToNullable(i, pStackCopy, nullableType, byRefToNullables);
1315             }
1316
1317             // save the info into ValueClassInfo
1318             if (pMT->ContainsPointers()) 
1319             {
1320                 pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pStackCopy, pMT, pValueClasses);
1321             }
1322
1323             // We need a new ArgDestination that points to the stack copy
1324             argDest = ArgDestination(pStackCopy, 0, NULL);
1325         }
1326
1327         InvokeUtil::CopyArg(th, &(gc.args->m_Array[i]), &argDest);
1328     }
1329
1330     ENDFORBIDGC();
1331     }
1332
1333 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
1334     // By default, set the flag in TES indicating the reflection target can handle CSE.
1335     // This flag is used in CEHelper::CanIDispatchTargetHandleException.
1336     pThread->GetExceptionState()->SetCanReflectionTargetHandleException(TRUE);
1337 #endif // FEATURE_CORRUPTING_EXCEPTIONS
1338
1339     if (pValueClasses != NULL)
1340     {
1341         pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie<ProtectValueClassFrame>))) 
1342             FrameWithCookie<ProtectValueClassFrame>(pThread, pValueClasses);
1343     }
1344
1345     // Call the method
1346     bool fExceptionThrown = false;
1347     if (fWrapExceptions)
1348     {
1349         // The sole purpose of having this frame is to tell the debugger that we have a catch handler here
1350         // which may swallow managed exceptions.  The debugger needs this in order to send a
1351         // CatchHandlerFound (CHF) notification.
1352         FrameWithCookie<DebuggerU2MCatchHandlerFrame> catchFrame(pThread);
1353
1354         EX_TRY_THREAD(pThread) {
1355             CallDescrWorkerReflectionWrapper(&callDescrData, &catchFrame);
1356         } EX_CATCH{
1357             // Rethrow transient exceptions for constructors for backward compatibility
1358             if (fConstructor && GET_EXCEPTION()->IsTransient())
1359             {
1360                 EX_RETHROW;
1361             }
1362
1363         // Abuse retval to store the exception object
1364         gc.retVal = GET_THROWABLE();
1365         _ASSERTE(gc.retVal);
1366
1367         fExceptionThrown = true;
1368         } EX_END_CATCH(SwallowAllExceptions);
1369
1370         catchFrame.Pop(pThread);
1371     }
1372     else
1373     {
1374         CallDescrWorkerWithHandler(&callDescrData);
1375     }
1376
1377
1378     // Now that we are safely out of the catch block, we can create and raise the
1379     // TargetInvocationException.
1380     if (fExceptionThrown)
1381     {
1382         ThrowInvokeMethodException(pMeth, gc.retVal);
1383     }
1384
1385     // It is still illegal to do a GC here.  The return type might have/contain GC pointers.
1386     if (fConstructor)
1387     {
1388         // We have a special case for Strings...The object is returned...
1389         if (ownerType == TypeHandle(g_pStringClass)) {
1390             PVOID pReturnValue = &callDescrData.returnValue;
1391             gc.retVal = *(OBJECTREF *)pReturnValue;
1392         }
1393
1394         // If it is a Nullable<T>, box it using Nullable<T> conventions.
1395         // TODO: this double allocates on constructions which is wasteful
1396         gc.retVal = Nullable::NormalizeBox(gc.retVal);
1397     }
1398     else
1399     if (retType == ELEMENT_TYPE_VALUETYPE)
1400     {
1401         _ASSERTE(gc.retVal != NULL);
1402
1403         // if the structure is returned by value, then we need to copy in the boxed object
1404         // we have allocated for this purpose.
1405         if (!fHasRetBuffArg) 
1406         {
1407             CopyValueClass(gc.retVal->GetData(), &callDescrData.returnValue, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
1408         }
1409         else if (pRetBufStackCopy)
1410         {
1411             CopyValueClass(gc.retVal->GetData(), pRetBufStackCopy, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
1412         }
1413         // From here on out, it is OK to have GCs since the return object (which may have had
1414         // GC pointers has been put into a GC object and thus protected. 
1415
1416             // TODO this creates two objects which is inefficient
1417             // If the return type is a Nullable<T> box it into the correct form
1418         gc.retVal = Nullable::NormalizeBox(gc.retVal);
1419     }
1420     else 
1421     {
1422         gc.retVal = InvokeUtil::CreateObject(retTH, &callDescrData.returnValue);
1423     }
1424
1425     while (byRefToNullables != NULL) {
1426         OBJECTREF obj = Nullable::Box(byRefToNullables->data, byRefToNullables->type.GetMethodTable());
1427         SetObjectReference(&gc.args->m_Array[byRefToNullables->argNum], obj, gc.args->GetAppDomain());
1428         byRefToNullables = byRefToNullables->next;
1429     }
1430
1431     if (pProtectValueClassFrame != NULL)
1432         pProtectValueClassFrame->Pop(pThread);
1433
1434     END_INTERIOR_STACK_PROBE;
1435     }
1436
1437 Done:
1438     HELPER_METHOD_FRAME_END();
1439
1440     return OBJECTREFToObject(gc.retVal);
1441 }
1442 FCIMPLEND
1443
1444 struct SkipStruct {
1445     StackCrawlMark* pStackMark;
1446     MethodDesc*     pMeth;
1447 };
1448
1449 // This method is called by the GetMethod function and will crawl backward
1450 //  up the stack for integer methods.
1451 static StackWalkAction SkipMethods(CrawlFrame* frame, VOID* data) {
1452     CONTRACTL {
1453         NOTHROW;
1454         GC_NOTRIGGER;
1455         MODE_ANY;
1456     }
1457     CONTRACTL_END;
1458     
1459     SkipStruct* pSkip = (SkipStruct*) data;
1460
1461     MethodDesc *pFunc = frame->GetFunction();
1462
1463     /* We asked to be called back only for functions */
1464     _ASSERTE(pFunc);
1465
1466     // The check here is between the address of a local variable
1467     // (the stack mark) and a pointer to the EIP for a frame
1468     // (which is actually the pointer to the return address to the
1469     // function from the previous frame). So we'll actually notice
1470     // which frame the stack mark was in one frame later. This is
1471     // fine since we only implement LookForMyCaller.
1472     _ASSERTE(*pSkip->pStackMark == LookForMyCaller);
1473     if (!frame->IsInCalleesFrames(pSkip->pStackMark))
1474         return SWA_CONTINUE;
1475
1476     if (pFunc->RequiresInstMethodDescArg())
1477     {
1478         pSkip->pMeth = (MethodDesc *) frame->GetParamTypeArg();
1479         if (pSkip->pMeth == NULL)
1480             pSkip->pMeth = pFunc;
1481     }
1482     else
1483         pSkip->pMeth = pFunc;
1484     return SWA_ABORT;
1485 }
1486
1487 // Return the MethodInfo that represents the current method (two above this one)
1488 FCIMPL1(ReflectMethodObject*, RuntimeMethodHandle::GetCurrentMethod, StackCrawlMark* stackMark) {
1489     FCALL_CONTRACT;
1490     REFLECTMETHODREF pRet = NULL;
1491     
1492     HELPER_METHOD_FRAME_BEGIN_RET_0();
1493     SkipStruct skip;
1494     skip.pStackMark = stackMark;
1495     skip.pMeth = 0;
1496     StackWalkFunctions(GetThread(), SkipMethods, &skip);
1497
1498     // If C<Foo>.m<Bar> was called, the stack walker returns C<object>.m<object>. We cannot
1499     // get know that the instantiation used Foo or Bar at that point. So the next best thing
1500     // is to return C<T>.m<P> and that's what LoadTypicalMethodDefinition will do for us. 
1501
1502     if (skip.pMeth != NULL)
1503         pRet = skip.pMeth->LoadTypicalMethodDefinition()->GetStubMethodInfo();
1504     else
1505         pRet = NULL;
1506
1507     HELPER_METHOD_FRAME_END();
1508    
1509     return (ReflectMethodObject*)OBJECTREFToObject(pRet);
1510 }
1511 FCIMPLEND
1512
1513 static OBJECTREF DirectObjectFieldGet(FieldDesc *pField, TypeHandle fieldType, TypeHandle enclosingType, TypedByRef *pTarget, CLR_BOOL *pDomainInitialized) {
1514     CONTRACTL {
1515         THROWS;
1516         GC_TRIGGERS;
1517         MODE_COOPERATIVE;
1518
1519         PRECONDITION(CheckPointer(pField));
1520     }
1521     CONTRACTL_END;
1522     
1523     OBJECTREF refRet;
1524     OBJECTREF objref = NULL;
1525     GCPROTECT_BEGIN(objref);
1526     if (!pField->IsStatic()) {
1527         objref = ObjectToOBJECTREF(*((Object**)pTarget->data));
1528     }
1529
1530     InvokeUtil::ValidateObjectTarget(pField, enclosingType, &objref);
1531     refRet = InvokeUtil::GetFieldValue(pField, fieldType, &objref, enclosingType, pDomainInitialized);
1532     GCPROTECT_END();
1533     return refRet;
1534 }
1535
1536 FCIMPL4(Object*, RuntimeFieldHandle::GetValueDirect, ReflectFieldObject *pFieldUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, TypedByRef *pTarget, ReflectClassBaseObject *pDeclaringTypeUNSAFE) {
1537     CONTRACTL {
1538         FCALL_CHECK;
1539     }
1540     CONTRACTL_END;
1541
1542     struct 
1543     {
1544         REFLECTCLASSBASEREF refFieldType;
1545         REFLECTCLASSBASEREF refDeclaringType;
1546         REFLECTFIELDREF refField;
1547     }gc;
1548     gc.refFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
1549     gc.refDeclaringType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDeclaringTypeUNSAFE);
1550     gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
1551
1552     if ((gc.refFieldType == NULL) || (gc.refField == NULL))
1553         FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1554
1555     TypeHandle fieldType = gc.refFieldType->GetType();
1556
1557     FieldDesc *pField = gc.refField->GetField();
1558
1559     Assembly *pAssem = pField->GetModule()->GetAssembly();
1560
1561     if (pAssem->IsIntrospectionOnly())
1562         FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1563
1564     // We should throw NotSupportedException here. 
1565     // But for backward compatibility we are throwing FieldAccessException instead.
1566     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1567         FCThrow(kFieldAccessException);
1568
1569     OBJECTREF refRet  = NULL;
1570     CorElementType fieldElType;
1571
1572     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1573
1574     // Find the Object and its type
1575     TypeHandle targetType = pTarget->type;
1576     _ASSERTE(gc.refDeclaringType == NULL || !gc.refDeclaringType->GetType().IsTypeDesc());
1577     MethodTable *pEnclosingMT = (gc.refDeclaringType != NULL ? gc.refDeclaringType->GetType() : TypeHandle()).AsMethodTable();
1578
1579     // Verify the callee/caller access
1580     if (!pField->IsPublic() || (pEnclosingMT != NULL && !pEnclosingMT->IsExternallyVisible()))
1581     {
1582
1583         bool targetRemoted = false;
1584
1585
1586         RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType(targetRemoted));
1587
1588         MethodTable* pInstanceMT = NULL;
1589         if (!pField->IsStatic())
1590         {
1591             if (!targetType.IsTypeDesc())
1592                 pInstanceMT = targetType.AsMethodTable();
1593         }
1594
1595         //TODO: missing check that the field is consistent
1596
1597         // Perform the normal access check (caller vs field).
1598         InvokeUtil::CanAccessField(&sCtx,
1599                                    pEnclosingMT,
1600                                    pInstanceMT,
1601                                    pField);
1602     }
1603
1604     CLR_BOOL domainInitialized = FALSE;
1605     if (pField->IsStatic() || !targetType.IsValueType()) {
1606         refRet = DirectObjectFieldGet(pField, fieldType, TypeHandle(pEnclosingMT), pTarget, &domainInitialized);
1607         goto lExit;
1608     }
1609
1610     // Validate that the target type can be cast to the type that owns this field info.
1611     if (!targetType.CanCastTo(TypeHandle(pEnclosingMT)))
1612         COMPlusThrowArgumentException(W("obj"), NULL);
1613
1614     // This is a workaround because from the previous case we may end up with an
1615     //  Enum.  We want to process it here.
1616     // Get the value from the field
1617     void* p;
1618     fieldElType = fieldType.GetSignatureCorElementType();
1619     switch (fieldElType) {
1620     case ELEMENT_TYPE_VOID:
1621         _ASSERTE(!"Void used as Field Type!");
1622         COMPlusThrow(kInvalidProgramException);
1623
1624     case ELEMENT_TYPE_BOOLEAN:  // boolean
1625     case ELEMENT_TYPE_I1:       // byte
1626     case ELEMENT_TYPE_U1:       // unsigned byte
1627     case ELEMENT_TYPE_I2:       // short
1628     case ELEMENT_TYPE_U2:       // unsigned short
1629     case ELEMENT_TYPE_CHAR:     // char
1630     case ELEMENT_TYPE_I4:       // int
1631     case ELEMENT_TYPE_U4:       // unsigned int
1632     case ELEMENT_TYPE_I:
1633     case ELEMENT_TYPE_U:
1634     case ELEMENT_TYPE_R4:       // float
1635     case ELEMENT_TYPE_I8:       // long
1636     case ELEMENT_TYPE_U8:       // unsigned long
1637     case ELEMENT_TYPE_R8:       // double
1638     case ELEMENT_TYPE_VALUETYPE:
1639         _ASSERTE(!fieldType.IsTypeDesc());
1640         p = ((BYTE*) pTarget->data) + pField->GetOffset();
1641         refRet = fieldType.AsMethodTable()->Box(p);
1642         break;
1643
1644     case ELEMENT_TYPE_OBJECT:
1645     case ELEMENT_TYPE_CLASS:
1646     case ELEMENT_TYPE_SZARRAY:          // Single Dim, Zero
1647     case ELEMENT_TYPE_ARRAY:            // general array
1648         p = ((BYTE*) pTarget->data) + pField->GetOffset();
1649         refRet = ObjectToOBJECTREF(*(Object**) p);
1650         break;
1651
1652     case ELEMENT_TYPE_PTR:
1653         {
1654             p = ((BYTE*) pTarget->data) + pField->GetOffset();
1655
1656             refRet = InvokeUtil::CreatePointer(fieldType, *(void **)p);
1657
1658             break;
1659         }
1660
1661     default:
1662         _ASSERTE(!"Unknown Type");
1663         // this is really an impossible condition
1664         COMPlusThrow(kNotSupportedException);
1665     }
1666
1667 lExit: ;
1668     HELPER_METHOD_FRAME_END();
1669     return OBJECTREFToObject(refRet);
1670 }
1671 FCIMPLEND
1672
1673 static void DirectObjectFieldSet(FieldDesc *pField, TypeHandle fieldType, TypeHandle enclosingType, TypedByRef *pTarget, OBJECTREF *pValue, CLR_BOOL *pDomainInitialized) {
1674     CONTRACTL {
1675         THROWS;
1676         GC_TRIGGERS;
1677         MODE_COOPERATIVE;
1678     
1679         PRECONDITION(CheckPointer(pField));
1680         PRECONDITION(!fieldType.IsNull());
1681     }
1682     CONTRACTL_END;
1683
1684     OBJECTREF objref = NULL;
1685     GCPROTECT_BEGIN(objref);
1686     if (!pField->IsStatic()) {
1687         objref = ObjectToOBJECTREF(*((Object**)pTarget->data));
1688     }
1689     // Validate the target/fld type relationship
1690     InvokeUtil::ValidateObjectTarget(pField, enclosingType, &objref);
1691
1692     InvokeUtil::ValidField(fieldType, pValue);
1693     InvokeUtil::SetValidField(pField->GetFieldType(), fieldType, pField, &objref, pValue, enclosingType, pDomainInitialized);
1694     GCPROTECT_END();
1695 }
1696
1697 FCIMPL5(void, RuntimeFieldHandle::SetValueDirect, ReflectFieldObject *pFieldUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, TypedByRef *pTarget, Object *valueUNSAFE, ReflectClassBaseObject *pContextTypeUNSAFE) {
1698     CONTRACTL {
1699         FCALL_CHECK;
1700     }
1701     CONTRACTL_END;
1702
1703     struct _gc
1704     {
1705         OBJECTREF       oValue;
1706         REFLECTCLASSBASEREF pFieldType;
1707         REFLECTCLASSBASEREF pContextType;
1708         REFLECTFIELDREF refField;
1709     }gc;
1710
1711     gc.oValue   = ObjectToOBJECTREF(valueUNSAFE);
1712     gc.pFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
1713     gc.pContextType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pContextTypeUNSAFE);
1714     gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
1715
1716     if ((gc.pFieldType == NULL) || (gc.refField == NULL))
1717         FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
1718
1719     TypeHandle fieldType = gc.pFieldType->GetType();
1720     TypeHandle contextType = (gc.pContextType != NULL) ? gc.pContextType->GetType() : NULL;
1721
1722     FieldDesc *pField = gc.refField->GetField();
1723
1724     Assembly *pAssem = pField->GetModule()->GetAssembly();
1725
1726     if (pAssem->IsIntrospectionOnly())
1727         FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1728
1729     // We should throw NotSupportedException here. 
1730     // But for backward compatibility we are throwing FieldAccessException instead.
1731     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1732         FCThrowVoid(kFieldAccessException);
1733
1734     BYTE           *pDst = NULL;
1735     ARG_SLOT        value = NULL;
1736     CorElementType  fieldElType;
1737
1738     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
1739
1740     // Find the Object and its type
1741     TypeHandle targetType = pTarget->type;
1742     MethodTable *pEnclosingMT = contextType.GetMethodTable();
1743
1744     {
1745         // Verify that the value passed can be widened into the target
1746         InvokeUtil::ValidField(fieldType, &gc.oValue);
1747
1748         // Verify that this is not a Final Field
1749         DWORD attr = pField->GetAttributes(); // should we cache?
1750         if (IsFdLiteral(attr))
1751             COMPlusThrow(kFieldAccessException,W("Acc_ReadOnly"));
1752
1753         // Verify the callee/caller access
1754         if (!pField->IsPublic() || (pEnclosingMT != NULL && !pEnclosingMT->IsExternallyVisible())) 
1755         {
1756             // security and consistency checks
1757
1758             bool targetRemoted = false;
1759
1760             RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType(targetRemoted));
1761
1762             MethodTable* pInstanceMT = NULL;
1763             if (!pField->IsStatic()) {
1764                 if (!targetType.IsTypeDesc())
1765                     pInstanceMT = targetType.AsMethodTable();
1766             }
1767
1768             //TODO: missing check that the field is consistent
1769
1770             // Perform the normal access check (caller vs field).
1771             InvokeUtil::CanAccessField(&sCtx,
1772                                        pEnclosingMT,
1773                                        pInstanceMT,
1774                                        pField);
1775         }
1776
1777     }
1778
1779     CLR_BOOL domainInitialized = FALSE;
1780     if (pField->IsStatic() || !targetType.IsValueType()) {
1781         DirectObjectFieldSet(pField, fieldType, TypeHandle(pEnclosingMT), pTarget, &gc.oValue, &domainInitialized);
1782         goto lExit;
1783     }
1784
1785     if (gc.oValue == NULL && fieldType.IsValueType() && !Nullable::IsNullableType(fieldType))
1786         COMPlusThrowArgumentNull(W("value"));
1787
1788     // Validate that the target type can be cast to the type that owns this field info.
1789     if (!targetType.CanCastTo(TypeHandle(pEnclosingMT)))
1790         COMPlusThrowArgumentException(W("obj"), NULL);
1791
1792     // Set the field
1793     fieldElType = fieldType.GetInternalCorElementType();
1794     if (ELEMENT_TYPE_BOOLEAN <= fieldElType && fieldElType <= ELEMENT_TYPE_R8) {
1795         CorElementType objType = gc.oValue->GetTypeHandle().GetInternalCorElementType();
1796         if (objType != fieldElType)
1797             InvokeUtil::CreatePrimitiveValue(fieldElType, objType, gc.oValue, &value);
1798         else
1799             value = *(ARG_SLOT*)gc.oValue->UnBox();
1800     }
1801     pDst = ((BYTE*) pTarget->data) + pField->GetOffset();
1802
1803     switch (fieldElType) {
1804     case ELEMENT_TYPE_VOID:
1805         _ASSERTE(!"Void used as Field Type!");
1806         COMPlusThrow(kInvalidProgramException);
1807
1808     case ELEMENT_TYPE_BOOLEAN:  // boolean
1809     case ELEMENT_TYPE_I1:       // byte
1810     case ELEMENT_TYPE_U1:       // unsigned byte
1811         VolatileStore((UINT8*)pDst, *(UINT8*)&value);
1812     break;
1813
1814     case ELEMENT_TYPE_I2:       // short
1815     case ELEMENT_TYPE_U2:       // unsigned short
1816     case ELEMENT_TYPE_CHAR:     // char
1817         VolatileStore((UINT16*)pDst, *(UINT16*)&value);
1818     break;
1819
1820     case ELEMENT_TYPE_I4:       // int
1821     case ELEMENT_TYPE_U4:       // unsigned int
1822     case ELEMENT_TYPE_R4:       // float
1823         VolatileStore((UINT32*)pDst, *(UINT32*)&value);
1824     break;
1825
1826     case ELEMENT_TYPE_I8:       // long
1827     case ELEMENT_TYPE_U8:       // unsigned long
1828     case ELEMENT_TYPE_R8:       // double
1829         VolatileStore((UINT64*)pDst, *(UINT64*)&value);
1830     break;
1831
1832     case ELEMENT_TYPE_I:
1833     {
1834         INT_PTR valuePtr = (INT_PTR) InvokeUtil::GetIntPtrValue(gc.oValue);
1835         VolatileStore((INT_PTR*) pDst, valuePtr);
1836     }    
1837     break;
1838     case ELEMENT_TYPE_U:
1839     {
1840         UINT_PTR valuePtr = (UINT_PTR) InvokeUtil::GetIntPtrValue(gc.oValue);
1841         VolatileStore((UINT_PTR*) pDst, valuePtr);
1842     }
1843     break;
1844
1845     case ELEMENT_TYPE_PTR:      // pointers
1846         if (gc.oValue != 0) {
1847             value = 0;
1848             if (MscorlibBinder::IsClass(gc.oValue->GetMethodTable(), CLASS__POINTER)) {
1849                 value = (size_t) InvokeUtil::GetPointerValue(gc.oValue);
1850 #ifdef _MSC_VER
1851 #pragma warning(disable: 4267) //work-around for compiler
1852 #endif
1853                 VolatileStore((size_t*) pDst, (size_t) value);
1854 #ifdef _MSC_VER
1855 #pragma warning(default: 4267)
1856 #endif
1857                 break;
1858             }
1859         }
1860     // drop through
1861     case ELEMENT_TYPE_FNPTR:
1862     {
1863         value = 0;
1864         if (gc.oValue != 0) {
1865             CorElementType objType = gc.oValue->GetTypeHandle().GetInternalCorElementType();
1866             InvokeUtil::CreatePrimitiveValue(objType, objType, gc.oValue, &value);
1867         }
1868 #ifdef _MSC_VER
1869 #pragma warning(disable: 4267) //work-around for compiler
1870 #endif
1871         VolatileStore((size_t*) pDst, (size_t) value);
1872 #ifdef _MSC_VER
1873 #pragma warning(default: 4267)
1874 #endif
1875     }
1876     break;
1877
1878     case ELEMENT_TYPE_SZARRAY:          // Single Dim, Zero
1879     case ELEMENT_TYPE_ARRAY:            // General Array
1880     case ELEMENT_TYPE_CLASS:
1881     case ELEMENT_TYPE_OBJECT:
1882         SetObjectReferenceUnchecked((OBJECTREF*)pDst, gc.oValue);
1883     break;
1884
1885     case ELEMENT_TYPE_VALUETYPE:
1886     {
1887         _ASSERTE(!fieldType.IsTypeDesc());
1888         MethodTable* pMT = fieldType.AsMethodTable();
1889
1890         // If we have a null value then we must create an empty field
1891         if (gc.oValue == 0)
1892             InitValueClass(pDst, pMT);
1893         else {
1894             pMT->UnBoxIntoUnchecked(pDst, gc.oValue);
1895         }
1896     }
1897     break;
1898
1899     default:
1900         _ASSERTE(!"Unknown Type");
1901         // this is really an impossible condition
1902         COMPlusThrow(kNotSupportedException);
1903     }
1904
1905 lExit: ;
1906     HELPER_METHOD_FRAME_END();
1907 }
1908 FCIMPLEND
1909
1910 void QCALLTYPE ReflectionInvocation::CompileMethod(MethodDesc * pMD)
1911 {
1912     QCALL_CONTRACT;
1913
1914     // Argument is checked on the managed side
1915     PRECONDITION(pMD != NULL);
1916
1917     if (!pMD->IsPointingToPrestub())
1918         return;
1919
1920     BEGIN_QCALL;
1921     pMD->DoPrestub(NULL);
1922     END_QCALL;
1923 }
1924
1925 // This method triggers the class constructor for a give type
1926 FCIMPL1(void, ReflectionInvocation::RunClassConstructor, ReflectClassBaseObject *pTypeUNSAFE)
1927 {
1928     FCALL_CONTRACT;
1929     
1930     REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
1931
1932     if (refType == NULL)
1933         FCThrowArgumentVoidEx(kArgumentException, NULL, W("InvalidOperation_HandleIsNotInitialized"));
1934
1935     TypeHandle typeHnd = refType->GetType();
1936     if (typeHnd.IsTypeDesc())
1937         return;
1938
1939     MethodTable *pMT = typeHnd.AsMethodTable();
1940
1941     Assembly *pAssem = pMT->GetAssembly();
1942
1943     if (pAssem->IsIntrospectionOnly())
1944         FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1945
1946     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1947     {
1948         FCThrowResVoid(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
1949     }
1950
1951     if (!pMT->IsClassInited()) 
1952     {
1953         HELPER_METHOD_FRAME_BEGIN_1(refType);
1954
1955         // We perform the access check only on CoreCLR for backward compatibility.
1956         RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType());
1957         InvokeUtil::CanAccessClass(&sCtx, pMT);
1958
1959         pMT->CheckRestore();
1960         pMT->EnsureInstanceActive();
1961         pMT->CheckRunClassInitThrowing();
1962
1963         HELPER_METHOD_FRAME_END();
1964     }
1965 }
1966 FCIMPLEND
1967
1968 // This method triggers the module constructor for a give module
1969 FCIMPL1(void, ReflectionInvocation::RunModuleConstructor, ReflectModuleBaseObject *pModuleUNSAFE) {
1970     FCALL_CONTRACT;
1971     
1972     REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
1973
1974     if(refModule == NULL)
1975         FCThrowArgumentVoidEx(kArgumentException, NULL, W("InvalidOperation_HandleIsNotInitialized"));
1976
1977     Module *pModule = refModule->GetModule();
1978
1979     Assembly *pAssem = pModule->GetAssembly();
1980
1981     if (pAssem->IsIntrospectionOnly())
1982         FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1983
1984     if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1985         FCThrowResVoid(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
1986
1987     DomainFile *pDomainFile = pModule->FindDomainFile(GetAppDomain());
1988     if (pDomainFile==NULL || !pDomainFile->IsActive())
1989     {
1990         HELPER_METHOD_FRAME_BEGIN_1(refModule);
1991         if(pDomainFile==NULL)
1992             pDomainFile=pModule->GetDomainFile();
1993         pDomainFile->EnsureActive();
1994         HELPER_METHOD_FRAME_END();
1995     }
1996 }
1997 FCIMPLEND
1998
1999 static void PrepareMethodHelper(MethodDesc * pMD)
2000 {
2001     CONTRACTL
2002     {
2003         THROWS;
2004         GC_TRIGGERS;
2005         MODE_ANY;
2006     }
2007     CONTRACTL_END;
2008
2009     GCX_PREEMP();
2010
2011     if (pMD->IsPointingToPrestub())
2012         pMD->DoPrestub(NULL);
2013
2014     if (pMD->IsWrapperStub())
2015     {
2016         pMD = pMD->GetWrappedMethodDesc();
2017         if (pMD->IsPointingToPrestub())
2018             pMD->DoPrestub(NULL);
2019     }
2020 }
2021
2022 // This method triggers a given method to be jitted. CoreCLR implementation of this method triggers jiting of the given method only.
2023 // It does not walk a subset of callgraph to provide CER guarantees.
2024 FCIMPL3(void, ReflectionInvocation::PrepareMethod, ReflectMethodObject* pMethodUNSAFE, TypeHandle *pInstantiation, UINT32 cInstantiation)
2025 {
2026     CONTRACTL {
2027         FCALL_CHECK;
2028         PRECONDITION(CheckPointer(pMethodUNSAFE, NULL_OK));
2029         PRECONDITION(CheckPointer(pInstantiation, NULL_OK));
2030     }
2031     CONTRACTL_END;
2032     
2033     REFLECTMETHODREF refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
2034     
2035     HELPER_METHOD_FRAME_BEGIN_1(refMethod);
2036
2037     if (refMethod == NULL)
2038         COMPlusThrow(kArgumentException, W("InvalidOperation_HandleIsNotInitialized"));
2039
2040     MethodDesc *pMD = refMethod->GetMethod();
2041
2042     if (pMD->IsAbstract())
2043         COMPlusThrow(kArgumentException, W("Argument_CannotPrepareAbstract"));
2044
2045     MethodTable * pExactMT = pMD->GetMethodTable();
2046     if (pInstantiation != NULL)
2047     {
2048         // We were handed an instantiation, check that the method expects it and the right number of types has been provided (the
2049         // caller supplies one array containing the class instantiation immediately followed by the method instantiation).
2050         if (cInstantiation != (pMD->GetNumGenericMethodArgs() + pMD->GetNumGenericClassArgs()))
2051             COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
2052
2053         // Check we've got a reasonable looking instantiation.
2054         if (!Generics::CheckInstantiation(Instantiation(pInstantiation, cInstantiation)))
2055             COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
2056         for (ULONG i = 0; i < cInstantiation; i++)
2057             if (pInstantiation[i].ContainsGenericVariables())
2058                 COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
2059
2060         TypeHandle thExactType = ClassLoader::LoadGenericInstantiationThrowing(pMD->GetModule(),
2061                                                                                pMD->GetMethodTable()->GetCl(),
2062                                                                                Instantiation(pInstantiation, pMD->GetNumGenericClassArgs()));
2063         pExactMT = thExactType.AsMethodTable();
2064
2065         pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
2066                                                            pExactMT,
2067                                                            FALSE,
2068                                                            Instantiation(&pInstantiation[pMD->GetNumGenericClassArgs()], pMD->GetNumGenericMethodArgs()),
2069                                                            FALSE);
2070     }
2071
2072     if (pMD->ContainsGenericVariables())
2073         COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
2074
2075     PrepareMethodHelper(pMD);
2076
2077     HELPER_METHOD_FRAME_END();
2078 }
2079 FCIMPLEND
2080
2081 // This method triggers target of a given method to be jitted. CoreCLR implementation of this method triggers jiting
2082 // of the given method only. It does not walk a subset of callgraph to provide CER guarantees.
2083 // In the case of a multi-cast delegate, we rely on the fact that each individual component
2084 // was prepared prior to the Combine.
2085 FCIMPL1(void, ReflectionInvocation::PrepareDelegate, Object* delegateUNSAFE)
2086 {
2087     CONTRACTL {
2088         FCALL_CHECK;
2089         PRECONDITION(CheckPointer(delegateUNSAFE, NULL_OK));
2090     }
2091     CONTRACTL_END;
2092     
2093     if (delegateUNSAFE == NULL)
2094         return;
2095
2096     OBJECTREF delegate = ObjectToOBJECTREF(delegateUNSAFE);
2097     HELPER_METHOD_FRAME_BEGIN_1(delegate);
2098
2099     MethodDesc *pMD = COMDelegate::GetMethodDesc(delegate);
2100
2101     PrepareMethodHelper(pMD);
2102
2103     HELPER_METHOD_FRAME_END();
2104 }
2105 FCIMPLEND
2106
2107 // This method checks to see if there is sufficient stack to execute the average Framework method.
2108 // If there is not, then it throws System.InsufficientExecutionStackException. The limit for each
2109 // thread is precomputed when the thread is created.
2110 FCIMPL0(void, ReflectionInvocation::EnsureSufficientExecutionStack)
2111 {
2112     FCALL_CONTRACT;
2113
2114     Thread *pThread = GetThread();
2115
2116     // We use the address of a local variable as our "current stack pointer", which is 
2117     // plenty close enough for the purposes of this method.
2118     UINT_PTR current = reinterpret_cast<UINT_PTR>(&pThread);
2119     UINT_PTR limit = pThread->GetCachedStackSufficientExecutionLimit();
2120
2121     if (current < limit)
2122     {
2123         FCThrowVoid(kInsufficientExecutionStackException);
2124     }
2125 }
2126 FCIMPLEND
2127
2128 // As with EnsureSufficientExecutionStack, this method checks and returns whether there is 
2129 // sufficient stack to execute the average Framework method, but rather than throwing,
2130 // it simply returns a Boolean: true for sufficient stack space, otherwise false.
2131 FCIMPL0(FC_BOOL_RET, ReflectionInvocation::TryEnsureSufficientExecutionStack)
2132 {
2133         FCALL_CONTRACT;
2134
2135         Thread *pThread = GetThread();
2136
2137         // Same logic as EnsureSufficientExecutionStack
2138         UINT_PTR current = reinterpret_cast<UINT_PTR>(&pThread);
2139         UINT_PTR limit = pThread->GetCachedStackSufficientExecutionLimit();
2140
2141         FC_RETURN_BOOL(current >= limit);
2142 }
2143 FCIMPLEND
2144
2145 struct ECWGCFContext
2146 {
2147     BOOL fHandled;
2148     Frame *pStartFrame;
2149 };
2150
2151 // Crawl the stack looking for Thread Abort related information (whether we're executing inside a CER or an error handling clauses
2152 // of some sort).
2153 StackWalkAction ECWGCFCrawlCallBack(CrawlFrame* pCf, void* data)
2154 {
2155     CONTRACTL {
2156         NOTHROW;
2157         GC_NOTRIGGER;
2158     }
2159     CONTRACTL_END;
2160
2161     ECWGCFContext *pData = (ECWGCFContext *)data;
2162
2163     Frame *pFrame = pCf->GetFrame();
2164     if (pFrame && pFrame->GetFunction() != NULL && pFrame != pData->pStartFrame)
2165     {
2166         // We walk through a transition frame, but it is not our start frame.
2167         // This means ExecuteCodeWithGuarantee is not at the bottom of stack.
2168         pData->fHandled = TRUE;
2169         return SWA_ABORT;
2170     }
2171
2172     MethodDesc *pMD = pCf->GetFunction();
2173
2174     // Non-method frames don't interest us.
2175     if (pMD == NULL)
2176         return SWA_CONTINUE;
2177
2178     if (!pMD->GetModule()->IsSystem())
2179     {
2180         // We walk through some user code.  This means that ExecuteCodeWithGuarantee is not at the bottom of stack.
2181         pData->fHandled = TRUE;
2182         return SWA_ABORT;
2183     }
2184
2185     return SWA_CONTINUE;
2186 }
2187
2188 struct ECWGC_Param
2189 {
2190     BOOL fExceptionThrownInTryCode;
2191     BOOL fStackOverflow;
2192     struct ECWGC_GC *gc;
2193     ECWGC_Param()
2194     {
2195         fExceptionThrownInTryCode = FALSE;
2196         fStackOverflow = FALSE;
2197     }
2198 };
2199
2200 LONG SODetectionFilter(EXCEPTION_POINTERS *ep, void* pv)
2201 {
2202     WRAPPER_NO_CONTRACT;
2203     DefaultCatchFilterParam param(COMPLUS_EXCEPTION_EXECUTE_HANDLER);
2204     if (DefaultCatchFilter(ep, &param) == EXCEPTION_CONTINUE_EXECUTION)
2205     {
2206         return EXCEPTION_CONTINUE_EXECUTION;
2207     }
2208
2209     // Record the fact that an exception occurred while running the try code.
2210     ECWGC_Param *pParam= (ECWGC_Param *)pv;
2211     pParam->fExceptionThrownInTryCode = TRUE;
2212
2213     // We unwind the stack only in the case of a stack overflow.
2214     if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
2215     {
2216         pParam->fStackOverflow = TRUE;
2217         return EXCEPTION_EXECUTE_HANDLER;
2218     }
2219
2220     return EXCEPTION_CONTINUE_SEARCH;
2221 }
2222
2223 struct ECWGC_GC
2224 {
2225     DELEGATEREF     codeDelegate;
2226     DELEGATEREF     backoutDelegate;
2227     OBJECTREF       userData;
2228 };
2229
2230 void ExecuteCodeWithGuaranteedCleanupBackout(ECWGC_GC *gc, BOOL fExceptionThrownInTryCode)
2231 {
2232     // We need to prevent thread aborts from occuring for the duration of the call to the backout code. 
2233     // Once we enter managed code, the CER will take care of it as well; however without this holder, 
2234     // MethodDesc::Call would raise a thread abort exception if the thread is currently requesting one.
2235     ThreadPreventAbortHolder preventAbort;
2236
2237 #ifdef _DEBUG
2238     // We have prevented abort on this thread.  Normally we don't allow 
2239     // a thread to enter managed code if abort is prevented.  But here the code
2240     // requires the thread not be aborted.
2241     Thread::DisableAbortCheckHolder dach;
2242 #endif
2243
2244     GCX_COOP();
2245
2246     PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(g_pExecuteBackoutCodeHelperMethod);
2247
2248     DECLARE_ARGHOLDER_ARRAY(args, 3);
2249
2250     args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc->backoutDelegate);
2251     args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc->userData);
2252     args[ARGNUM_2] = DWORD_TO_ARGHOLDER(fExceptionThrownInTryCode);
2253
2254     CRITICAL_CALLSITE;
2255     CALL_MANAGED_METHOD_NORET(args);
2256 }
2257
2258 void ExecuteCodeWithGuaranteedCleanupHelper (ECWGC_GC *gc)
2259 {
2260     STATIC_CONTRACT_THROWS;
2261     STATIC_CONTRACT_MODE_COOPERATIVE;
2262
2263     ECWGC_Param param;
2264     param.gc = gc;
2265
2266     PAL_TRY(ECWGC_Param *, pParamOuter, &param)
2267     {
2268         PAL_TRY(ECWGC_Param *, pParam, pParamOuter)
2269         {
2270             PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pParam->gc->codeDelegate->GetMethodPtr());
2271
2272             DECLARE_ARGHOLDER_ARRAY(args, 2);
2273
2274             args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(pParam->gc->codeDelegate->GetTarget());
2275             args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(pParam->gc->userData);
2276
2277             CALL_MANAGED_METHOD_NORET(args);
2278         }
2279         PAL_EXCEPT_FILTER(SODetectionFilter)
2280         {
2281         }
2282         PAL_ENDTRY;
2283
2284         if (pParamOuter->fStackOverflow)
2285         {
2286             GCX_COOP_NO_DTOR();
2287         }
2288     }
2289     PAL_FINALLY
2290     {
2291         ExecuteCodeWithGuaranteedCleanupBackout(gc, param.fExceptionThrownInTryCode);
2292     }
2293     PAL_ENDTRY;
2294
2295 #ifdef FEATURE_STACK_PROBE
2296     if (param.fStackOverflow)   
2297         COMPlusThrowSO();
2298 #else
2299     //This will not be set as clr to managed transition code will terminate the
2300     //process if there is an SO before SODetectionFilter() is called.
2301     _ASSERTE(!param.fStackOverflow);
2302 #endif
2303 }
2304
2305 //
2306 // ExecuteCodeWithGuaranteedCleanup ensures that we will call the backout code delegate even if an SO occurs. We do this by calling the 
2307 // try delegate from within an EX_TRY/EX_CATCH block that will catch any thrown exceptions and thus cause the stack to be unwound. This 
2308 // guarantees that the backout delegate is called with at least DEFAULT_ENTRY_PROBE_SIZE pages of stack. After the backout delegate is called, 
2309 // we re-raise any exceptions that occurred inside the try delegate. Note that any CER that uses large or arbitraty amounts of stack in 
2310 // it's try block must use ExecuteCodeWithGuaranteedCleanup. 
2311 //
2312 // ExecuteCodeWithGuaranteedCleanup also guarantees that the backount code will be run before any filters higher up on the stack. This
2313 // is important to prevent security exploits.
2314 //
2315 FCIMPL3(void, ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup, Object* codeDelegateUNSAFE, Object* backoutDelegateUNSAFE, Object* userDataUNSAFE)
2316 {
2317     CONTRACTL {
2318         FCALL_CHECK;
2319         PRECONDITION(CheckPointer(codeDelegateUNSAFE, NULL_OK));
2320         PRECONDITION(CheckPointer(backoutDelegateUNSAFE, NULL_OK));
2321         PRECONDITION(CheckPointer(userDataUNSAFE, NULL_OK));
2322     }
2323     CONTRACTL_END;
2324
2325     ECWGC_GC gc;
2326
2327     gc.codeDelegate = (DELEGATEREF)ObjectToOBJECTREF(codeDelegateUNSAFE);
2328     gc.backoutDelegate = (DELEGATEREF)ObjectToOBJECTREF(backoutDelegateUNSAFE);
2329     gc.userData = ObjectToOBJECTREF(userDataUNSAFE);
2330
2331     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
2332
2333     if (gc.codeDelegate == NULL)
2334         COMPlusThrowArgumentNull(W("code"));
2335     if (gc.backoutDelegate == NULL)
2336         COMPlusThrowArgumentNull(W("backoutCode"));
2337
2338
2339     ExecuteCodeWithGuaranteedCleanupHelper(&gc);
2340
2341     HELPER_METHOD_FRAME_END();
2342 }
2343 FCIMPLEND
2344
2345
2346 FCIMPL4(void, ReflectionInvocation::MakeTypedReference, TypedByRef * value, Object* targetUNSAFE, ArrayBase* fldsUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE)
2347 {
2348     CONTRACTL {
2349         FCALL_CHECK;
2350         PRECONDITION(CheckPointer(targetUNSAFE));
2351         PRECONDITION(CheckPointer(fldsUNSAFE));
2352     }
2353     CONTRACTL_END;
2354     
2355     DWORD offset = 0;
2356
2357     struct _gc
2358     {
2359         OBJECTREF   target;
2360         BASEARRAYREF flds;
2361         REFLECTCLASSBASEREF refFieldType;
2362     } gc;
2363     gc.target  = (OBJECTREF)   targetUNSAFE;
2364     gc.flds   = (BASEARRAYREF) fldsUNSAFE;
2365     gc.refFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
2366
2367     TypeHandle fieldType = gc.refFieldType->GetType();
2368
2369     HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
2370     GCPROTECT_BEGININTERIOR (value)
2371
2372     DWORD cnt = gc.flds->GetNumComponents();
2373     FieldDesc** fields = (FieldDesc**)gc.flds->GetDataPtr();
2374     for (DWORD i = 0; i < cnt; i++) {
2375         FieldDesc* pField = fields[i];
2376         offset += pField->GetOffset();
2377     }
2378
2379         // Fields already are prohibted from having ArgIterator and RuntimeArgumentHandles
2380     _ASSERTE(!gc.target->GetTypeHandle().GetMethodTable()->IsByRefLike());
2381
2382     // Create the ByRef
2383     value->data = ((BYTE *)(gc.target->GetAddress() + offset)) + sizeof(Object);
2384     value->type = fieldType;
2385
2386     GCPROTECT_END();
2387     HELPER_METHOD_FRAME_END();
2388 }
2389 FCIMPLEND
2390
2391 FCIMPL2(void, ReflectionInvocation::SetTypedReference, TypedByRef * target, Object* objUNSAFE) {
2392     FCALL_CONTRACT;
2393     
2394     // <TODO>@TODO: We fixed serious bugs in this method very late in the endgame
2395     // for V1 RTM. So it was decided to disable this API (nobody would seem to
2396     // be using it anyway). If this API is enabled again, the implementation should 
2397     // be similar to COMArrayInfo::SetValue.
2398     // </TODO>
2399     HELPER_METHOD_FRAME_BEGIN_0();
2400     COMPlusThrow(kNotSupportedException);
2401     HELPER_METHOD_FRAME_END();
2402 }
2403 FCIMPLEND
2404
2405
2406 // This is an internal helper function to TypedReference class.
2407 // It extracts the object from the typed reference.
2408 FCIMPL1(Object*, ReflectionInvocation::TypedReferenceToObject, TypedByRef * value) {
2409     FCALL_CONTRACT;
2410     
2411     OBJECTREF       Obj = NULL;
2412
2413     TypeHandle th(value->type);
2414
2415     if (th.IsNull())
2416         FCThrowRes(kArgumentNullException, W("ArgumentNull_TypedRefType"));
2417
2418     MethodTable* pMT = th.GetMethodTable();
2419     PREFIX_ASSUME(NULL != pMT);
2420
2421     if (pMT->IsValueType())
2422     {
2423         // value->data is protected by the caller
2424     HELPER_METHOD_FRAME_BEGIN_RET_1(Obj);
2425
2426         Obj = pMT->Box(value->data);
2427
2428         HELPER_METHOD_FRAME_END();
2429     }
2430     else {
2431         Obj = ObjectToOBJECTREF(*((Object**)value->data));
2432     }
2433
2434     return OBJECTREFToObject(Obj);
2435 }
2436 FCIMPLEND
2437
2438 #ifdef _DEBUG
2439 FCIMPL1(FC_BOOL_RET, ReflectionInvocation::IsAddressInStack, void * ptr)
2440 {
2441     FCALL_CONTRACT;
2442     FC_RETURN_BOOL(Thread::IsAddressInCurrentStack(ptr));
2443 }
2444 FCIMPLEND
2445 #endif
2446
2447 FCIMPL2_IV(Object*, ReflectionInvocation::CreateEnum, ReflectClassBaseObject *pTypeUNSAFE, INT64 value) {
2448     FCALL_CONTRACT;
2449     
2450     REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
2451
2452     TypeHandle typeHandle = refType->GetType();
2453     _ASSERTE(typeHandle.IsEnum());
2454     OBJECTREF obj = NULL;
2455     HELPER_METHOD_FRAME_BEGIN_RET_1(refType);
2456     MethodTable *pEnumMT = typeHandle.AsMethodTable();
2457     obj = pEnumMT->Box(ArgSlotEndianessFixup ((ARG_SLOT*)&value,
2458                                              pEnumMT->GetNumInstanceFieldBytes()));
2459
2460     HELPER_METHOD_FRAME_END();
2461     return OBJECTREFToObject(obj);
2462 }
2463 FCIMPLEND
2464
2465 #ifdef FEATURE_COMINTEROP
2466
2467 static void TryGetClassFromProgID(STRINGREF className, STRINGREF server, OBJECTREF* pRefClass, DWORD bThrowOnError) {
2468     CONTRACTL {
2469         THROWS;
2470         GC_TRIGGERS;
2471         MODE_COOPERATIVE;
2472     }
2473     CONTRACTL_END;
2474
2475     EX_TRY
2476     {
2477         // NOTE: this call enables GC
2478         GetComClassFromProgID(className, server, pRefClass);
2479     }
2480     EX_CATCH
2481     {
2482         if (bThrowOnError)
2483         {
2484             EX_RETHROW;
2485         }
2486     }
2487     EX_END_CATCH(SwallowAllExceptions)
2488 }
2489
2490 // GetClassFromProgID
2491 // This method will return a Class object for a COM Classic object based
2492 //  upon its ProgID.  The COM Classic object is found and a wrapper object created
2493 FCIMPL3(Object*, ReflectionInvocation::GetClassFromProgID, StringObject* classNameUNSAFE, 
2494                                                            StringObject* serverUNSAFE, 
2495                                                            CLR_BOOL bThrowOnError) {
2496     FCALL_CONTRACT;
2497     
2498     REFLECTCLASSBASEREF refClass    = NULL;
2499     STRINGREF           className   = (STRINGREF) classNameUNSAFE;
2500     STRINGREF           server      = (STRINGREF) serverUNSAFE;
2501
2502     HELPER_METHOD_FRAME_BEGIN_RET_2(className, server);
2503
2504     GCPROTECT_BEGIN(refClass)
2505
2506     // Since we will be returning a type that represents a COM component, we need
2507     // to make sure COM is started before we return it.
2508     EnsureComStarted();
2509     
2510     // Make sure a prog id was provided
2511     if (className == NULL)
2512         COMPlusThrowArgumentNull(W("progID"),W("ArgumentNull_String"));
2513
2514     TryGetClassFromProgID(className, server, (OBJECTREF*) &refClass, bThrowOnError);
2515     GCPROTECT_END();
2516
2517     HELPER_METHOD_FRAME_END();
2518     return OBJECTREFToObject(refClass);
2519 }
2520 FCIMPLEND
2521
2522 static void TryGetClassFromCLSID(GUID clsid, STRINGREF server, OBJECTREF* pRefClass, DWORD bThrowOnError) {
2523     CONTRACTL {
2524         THROWS;
2525         GC_TRIGGERS;
2526         MODE_COOPERATIVE;
2527     }
2528     CONTRACTL_END;
2529     
2530     EX_TRY
2531     {
2532         // NOTE: this call enables GC
2533         GetComClassFromCLSID(clsid, server, pRefClass);
2534     }
2535     EX_CATCH
2536     {
2537         if (bThrowOnError)
2538         {
2539             EX_RETHROW;
2540         }
2541     }
2542     EX_END_CATCH(SwallowAllExceptions)
2543 }
2544
2545 // GetClassFromCLSID
2546 // This method will return a Class object for a COM Classic object based
2547 //  upon its ProgID.  The COM Classic object is found and a wrapper object created
2548 FCIMPL3(Object*, ReflectionInvocation::GetClassFromCLSID, GUID clsid, StringObject* serverUNSAFE, CLR_BOOL bThrowOnError) {
2549     FCALL_CONTRACT;
2550     
2551     struct _gc {
2552         REFLECTCLASSBASEREF refClass;
2553         STRINGREF           server;
2554     } gc;
2555
2556     gc.refClass = NULL;
2557     gc.server   = (STRINGREF) serverUNSAFE;
2558
2559     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc.server);
2560
2561     // Since we will be returning a type that represents a COM component, we need
2562     // to make sure COM is started before we return it.
2563     EnsureComStarted();
2564     
2565     TryGetClassFromCLSID(clsid, gc.server, (OBJECTREF*) &gc.refClass, bThrowOnError);
2566
2567     HELPER_METHOD_FRAME_END();
2568     return OBJECTREFToObject(gc.refClass);
2569 }
2570 FCIMPLEND
2571
2572
2573 FCIMPL8(Object*, ReflectionInvocation::InvokeDispMethod, ReflectClassBaseObject* refThisUNSAFE, 
2574                                                          StringObject* nameUNSAFE, 
2575                                                          INT32 invokeAttr, 
2576                                                          Object* targetUNSAFE, 
2577                                                          PTRArray* argsUNSAFE, 
2578                                                          PTRArray* byrefModifiersUNSAFE, 
2579                                                          LCID lcid, 
2580                                                          PTRArray* namedParametersUNSAFE) {
2581     FCALL_CONTRACT;
2582     
2583     struct _gc
2584     {
2585         REFLECTCLASSBASEREF refThis;
2586         STRINGREF           name;
2587         OBJECTREF           target;
2588         PTRARRAYREF         args;
2589         PTRARRAYREF         byrefModifiers;
2590         PTRARRAYREF         namedParameters;
2591         OBJECTREF           RetObj;
2592     } gc;
2593
2594     gc.refThis          = (REFLECTCLASSBASEREF) refThisUNSAFE;
2595     gc.name             = (STRINGREF)           nameUNSAFE;
2596     gc.target           = (OBJECTREF)           targetUNSAFE;
2597     gc.args             = (PTRARRAYREF)         argsUNSAFE;
2598     gc.byrefModifiers   = (PTRARRAYREF)         byrefModifiersUNSAFE;
2599     gc.namedParameters  = (PTRARRAYREF)         namedParametersUNSAFE;
2600     gc.RetObj           = NULL;
2601
2602     HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
2603
2604     _ASSERTE(gc.target != NULL);
2605     _ASSERTE(gc.target->GetMethodTable()->IsComObjectType());
2606
2607     WORD flags = 0;
2608     if (invokeAttr & BINDER_InvokeMethod)
2609         flags |= DISPATCH_METHOD;
2610     if (invokeAttr & BINDER_GetProperty)
2611         flags |= DISPATCH_PROPERTYGET;
2612     if (invokeAttr & BINDER_SetProperty)
2613         flags = DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF;
2614     if (invokeAttr & BINDER_PutDispProperty)
2615         flags = DISPATCH_PROPERTYPUT;
2616     if (invokeAttr & BINDER_PutRefDispProperty)
2617         flags = DISPATCH_PROPERTYPUTREF;
2618     if (invokeAttr & BINDER_CreateInstance)
2619         flags = DISPATCH_CONSTRUCT;
2620
2621     IUInvokeDispMethod(&gc.refThis,
2622                         &gc.target,
2623                         (OBJECTREF*)&gc.name,
2624                         NULL,
2625                         (OBJECTREF*)&gc.args,
2626                         (OBJECTREF*)&gc.byrefModifiers,
2627                         (OBJECTREF*)&gc.namedParameters,
2628                         &gc.RetObj,
2629                         lcid,
2630                         flags,
2631                         invokeAttr & BINDER_IgnoreReturn,
2632                         invokeAttr & BINDER_IgnoreCase);
2633
2634     HELPER_METHOD_FRAME_END();
2635     return OBJECTREFToObject(gc.RetObj);
2636 }
2637 FCIMPLEND
2638 #endif  // FEATURE_COMINTEROP
2639
2640 FCIMPL2(void, ReflectionInvocation::GetGUID, ReflectClassBaseObject* refThisUNSAFE, GUID * result) {
2641     FCALL_CONTRACT;
2642     
2643     REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF) refThisUNSAFE;
2644
2645     HELPER_METHOD_FRAME_BEGIN_1(refThis);
2646     GCPROTECT_BEGININTERIOR (result);
2647
2648     if (result == NULL || refThis == NULL)
2649         COMPlusThrow(kNullReferenceException);
2650
2651     TypeHandle type = refThis->GetType();
2652     if (type.IsTypeDesc()) {
2653         memset(result,0,sizeof(GUID));
2654         goto lExit;
2655     }
2656
2657 #ifdef FEATURE_COMINTEROP
2658     if (IsComObjectClass(type))
2659     {
2660         SyncBlock* pSyncBlock = refThis->GetSyncBlock();
2661
2662 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2663         ComClassFactory* pComClsFac = pSyncBlock->GetInteropInfo()->GetComClassFactory();
2664         if (pComClsFac)
2665         {
2666             memcpyNoGCRefs(result, &pComClsFac->m_rclsid, sizeof(GUID));
2667         }
2668         else
2669 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2670         {
2671             memset(result, 0, sizeof(GUID));
2672         }
2673     
2674         goto lExit;
2675     }
2676 #endif // FEATURE_COMINTEROP
2677
2678     GUID guid;
2679     type.AsMethodTable()->GetGuid(&guid, TRUE);
2680     memcpyNoGCRefs(result, &guid, sizeof(GUID));
2681
2682 lExit: ;
2683     GCPROTECT_END();
2684     HELPER_METHOD_FRAME_END();
2685 }
2686 FCIMPLEND
2687
2688 //*************************************************************************************************
2689 //*************************************************************************************************
2690 //*************************************************************************************************
2691 //      ReflectionSerialization
2692 //*************************************************************************************************
2693 //*************************************************************************************************
2694 //*************************************************************************************************
2695 FCIMPL1(Object*, ReflectionSerialization::GetUninitializedObject, ReflectClassBaseObject* objTypeUNSAFE) {
2696     FCALL_CONTRACT;
2697     
2698     OBJECTREF           retVal  = NULL;
2699     REFLECTCLASSBASEREF objType = (REFLECTCLASSBASEREF) objTypeUNSAFE;
2700
2701     HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL();
2702
2703     if (objType == NULL) {
2704         COMPlusThrowArgumentNull(W("type"), W("ArgumentNull_Type"));
2705     }
2706
2707     TypeHandle type = objType->GetType();
2708
2709     // Don't allow arrays, pointers, byrefs or function pointers.
2710     if (type.IsTypeDesc())
2711         COMPlusThrow(kArgumentException, W("Argument_InvalidValue"));
2712
2713     MethodTable *pMT = type.GetMethodTable();
2714     PREFIX_ASSUME(pMT != NULL);
2715
2716     //We don't allow unitialized strings.
2717     if (pMT == g_pStringClass) {
2718         COMPlusThrow(kArgumentException, W("Argument_NoUninitializedStrings"));
2719     }
2720
2721     // if this is an abstract class or an interface type then we will
2722     //  fail this
2723     if (pMT->IsAbstract()) {
2724         COMPlusThrow(kMemberAccessException,W("Acc_CreateAbst"));
2725     }
2726
2727     if (pMT->ContainsGenericVariables()) {
2728         COMPlusThrow(kMemberAccessException,W("Acc_CreateGeneric"));
2729     }
2730
2731     if (pMT->IsByRefLike()) {
2732         COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike"));
2733     }
2734
2735     // Never allow allocation of generics actually instantiated over __Canon
2736     if (pMT->IsSharedByGenericInstantiations()) {
2737         COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
2738     }
2739
2740     // Never allow the allocation of an unitialized ContextBoundObject derived type, these must always be created with a paired
2741     // transparent proxy or the jit will get confused.
2742
2743 #ifdef FEATURE_COMINTEROP
2744     // Also do not allow allocation of uninitialized RCWs (COM objects).
2745     if (pMT->IsComObjectType())
2746         COMPlusThrow(kNotSupportedException, W("NotSupported_ManagedActivation"));
2747 #endif // FEATURE_COMINTEROP
2748
2749     // If it is a nullable, return the underlying type instead.  
2750     if (Nullable::IsNullableType(pMT)) 
2751         pMT = pMT->GetInstantiation()[0].GetMethodTable();
2752  
2753     retVal = pMT->Allocate();
2754
2755     HELPER_METHOD_FRAME_END();
2756     return OBJECTREFToObject(retVal);
2757 }
2758 FCIMPLEND
2759
2760 //*************************************************************************************************
2761 //*************************************************************************************************
2762 //*************************************************************************************************
2763 //      ReflectionEnum
2764 //*************************************************************************************************
2765 //*************************************************************************************************
2766 //*************************************************************************************************
2767
2768 FCIMPL1(Object *, ReflectionEnum::InternalGetEnumUnderlyingType, ReflectClassBaseObject *target) {
2769     FCALL_CONTRACT;
2770     
2771     VALIDATEOBJECT(target);
2772     TypeHandle th = target->GetType();
2773     if (!th.IsEnum())
2774         FCThrowArgument(NULL, NULL);
2775
2776     OBJECTREF result = NULL;
2777
2778     HELPER_METHOD_FRAME_BEGIN_RET_0();
2779     MethodTable *pMT = MscorlibBinder::GetElementType(th.AsMethodTable()->GetInternalCorElementType());
2780     result = pMT->GetManagedClassObject();
2781     HELPER_METHOD_FRAME_END();
2782
2783     return OBJECTREFToObject(result);
2784 }
2785 FCIMPLEND
2786
2787 FCIMPL1(INT32, ReflectionEnum::InternalGetCorElementType, Object *pRefThis) {
2788     FCALL_CONTRACT;
2789     
2790     VALIDATEOBJECT(pRefThis);
2791     if (pRefThis == NULL)
2792         FCThrowArgumentNull(NULL);
2793
2794     return pRefThis->GetMethodTable()->GetInternalCorElementType();
2795 }
2796 FCIMPLEND
2797
2798 //*******************************************************************************
2799 struct TempEnumValue
2800 {
2801     LPCUTF8 name;
2802     UINT64 value;
2803 };
2804
2805 //*******************************************************************************
2806 class TempEnumValueSorter : public CQuickSort<TempEnumValue>
2807 {
2808 public:
2809     TempEnumValueSorter(TempEnumValue *pArray, SSIZE_T iCount)
2810         : CQuickSort<TempEnumValue>(pArray, iCount) { LIMITED_METHOD_CONTRACT; }
2811
2812     int Compare(TempEnumValue *pFirst, TempEnumValue *pSecond)
2813     {
2814         LIMITED_METHOD_CONTRACT;
2815
2816         if (pFirst->value == pSecond->value)
2817             return 0;
2818         if (pFirst->value > pSecond->value)
2819             return 1;
2820         else
2821             return -1;
2822     }
2823 };
2824
2825 void QCALLTYPE ReflectionEnum::GetEnumValuesAndNames(EnregisteredTypeHandle pEnumType, QCall::ObjectHandleOnStack pReturnValues, QCall::ObjectHandleOnStack pReturnNames, BOOL fGetNames)
2826 {
2827     QCALL_CONTRACT;
2828
2829     BEGIN_QCALL;
2830
2831     TypeHandle th = TypeHandle::FromPtr(pEnumType);
2832
2833     if (!th.IsEnum())
2834         COMPlusThrow(kArgumentException, W("Arg_MustBeEnum"));
2835
2836     MethodTable *pMT = th.AsMethodTable();
2837
2838     IMDInternalImport *pImport = pMT->GetMDImport();
2839
2840     StackSArray<TempEnumValue> temps;
2841     UINT64 previousValue = 0;
2842
2843     HENUMInternalHolder fieldEnum(pImport);
2844     fieldEnum.EnumInit(mdtFieldDef, pMT->GetCl());
2845
2846     //
2847     // Note that we're fine treating signed types as unsigned, because all we really
2848     // want to do is sort them based on a convenient strong ordering.
2849     //
2850
2851     BOOL sorted = TRUE;
2852
2853     CorElementType type = pMT->GetInternalCorElementType();
2854
2855     mdFieldDef field;
2856     while (pImport->EnumNext(&fieldEnum, &field))
2857     {
2858         DWORD dwFlags;
2859         IfFailThrow(pImport->GetFieldDefProps(field, &dwFlags));
2860         if (IsFdStatic(dwFlags))
2861         {
2862             TempEnumValue temp;
2863
2864             if (fGetNames)
2865                 IfFailThrow(pImport->GetNameOfFieldDef(field, &temp.name));
2866
2867             UINT64 value = 0;
2868
2869             MDDefaultValue defaultValue;
2870             IfFailThrow(pImport->GetDefaultValue(field, &defaultValue));
2871
2872             // The following code assumes that the address of all union members is the same.
2873             static_assert_no_msg(offsetof(MDDefaultValue, m_byteValue) == offsetof(MDDefaultValue, m_usValue));
2874             static_assert_no_msg(offsetof(MDDefaultValue, m_ulValue) == offsetof(MDDefaultValue, m_ullValue));
2875             PVOID pValue = &defaultValue.m_byteValue;
2876
2877             switch (type) {
2878             case ELEMENT_TYPE_I1:
2879                 value = *((INT8 *)pValue);
2880                 break;
2881
2882             case ELEMENT_TYPE_U1:
2883             case ELEMENT_TYPE_BOOLEAN:
2884                 value = *((UINT8 *)pValue);
2885                 break;
2886
2887             case ELEMENT_TYPE_I2:
2888                 value = *((INT16 *)pValue);
2889                 break;
2890
2891             case ELEMENT_TYPE_U2:
2892             case ELEMENT_TYPE_CHAR:
2893                 value = *((UINT16 *)pValue);
2894                 break;
2895
2896             case ELEMENT_TYPE_I4:
2897             IN_WIN32(case ELEMENT_TYPE_I:)
2898                 value = *((INT32 *)pValue);
2899                 break;
2900
2901             case ELEMENT_TYPE_U4:
2902             IN_WIN32(case ELEMENT_TYPE_U:)
2903                 value = *((UINT32 *)pValue);
2904                 break;
2905
2906             case ELEMENT_TYPE_I8:
2907             case ELEMENT_TYPE_U8:
2908             IN_WIN64(case ELEMENT_TYPE_I:)
2909             IN_WIN64(case ELEMENT_TYPE_U:)
2910                 value = *((INT64 *)pValue);
2911                 break;
2912
2913             default:
2914                 break;
2915             }
2916
2917             temp.value = value;
2918
2919             //
2920             // Check to see if we are already sorted.  This may seem extraneous, but is
2921             // actually probably the normal case.
2922             //
2923
2924             if (previousValue > value)
2925                 sorted = FALSE;
2926             previousValue = value;
2927
2928             temps.Append(temp);
2929         }
2930     }
2931
2932     TempEnumValue * pTemps = &(temps[0]);
2933     DWORD cFields = temps.GetCount();
2934
2935     if (!sorted)
2936     {
2937         TempEnumValueSorter sorter(pTemps, cFields);
2938         sorter.Sort();
2939     }
2940
2941     {
2942         GCX_COOP();
2943
2944         struct gc {
2945             I8ARRAYREF values;
2946             PTRARRAYREF names;
2947         } gc;
2948         gc.values = NULL;
2949         gc.names = NULL;
2950
2951         GCPROTECT_BEGIN(gc);
2952
2953         {
2954             gc.values = (I8ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_U8, cFields);
2955
2956             INT64 *pToValues = gc.values->GetDirectPointerToNonObjectElements();
2957
2958             for (DWORD i = 0; i < cFields; i++) {
2959                 pToValues[i] = pTemps[i].value;
2960             }
2961
2962             pReturnValues.Set(gc.values);
2963         }
2964  
2965         if (fGetNames)
2966         {
2967             gc.names = (PTRARRAYREF) AllocateObjectArray(cFields, g_pStringClass);
2968
2969             for (DWORD i = 0; i < cFields; i++) {
2970                 STRINGREF str = StringObject::NewString(pTemps[i].name);
2971                 gc.names->SetAt(i, str);
2972             }
2973
2974             pReturnNames.Set(gc.names);
2975         }
2976
2977         GCPROTECT_END();
2978     }
2979
2980     END_QCALL;
2981 }
2982
2983 FCIMPL2_IV(Object*, ReflectionEnum::InternalBoxEnum, ReflectClassBaseObject* target, INT64 value) {
2984     FCALL_CONTRACT;
2985     
2986     VALIDATEOBJECT(target);
2987     OBJECTREF ret = NULL;
2988
2989     MethodTable* pMT = target->GetType().AsMethodTable();
2990     HELPER_METHOD_FRAME_BEGIN_RET_0();
2991
2992     ret = pMT->Box(ArgSlotEndianessFixup((ARG_SLOT*)&value, pMT->GetNumInstanceFieldBytes()));
2993
2994     HELPER_METHOD_FRAME_END();
2995     return OBJECTREFToObject(ret);
2996 }
2997 FCIMPLEND
2998
2999 //*************************************************************************************************
3000 //*************************************************************************************************
3001 //*************************************************************************************************
3002 //      ReflectionBinder
3003 //*************************************************************************************************
3004 //*************************************************************************************************
3005 //*************************************************************************************************
3006
3007 FCIMPL2(FC_BOOL_RET, ReflectionBinder::DBCanConvertPrimitive, ReflectClassBaseObject* source, ReflectClassBaseObject* target) {
3008     FCALL_CONTRACT;
3009     
3010     VALIDATEOBJECT(source);
3011     VALIDATEOBJECT(target);
3012
3013     CorElementType tSRC = source->GetType().GetSignatureCorElementType();
3014     CorElementType tTRG = target->GetType().GetSignatureCorElementType();
3015
3016     FC_RETURN_BOOL(InvokeUtil::IsPrimitiveType(tTRG) && InvokeUtil::CanPrimitiveWiden(tTRG, tSRC));
3017 }
3018 FCIMPLEND
3019
3020 FCIMPL2(FC_BOOL_RET, ReflectionBinder::DBCanConvertObjectPrimitive, Object* sourceObj, ReflectClassBaseObject* target) {
3021     FCALL_CONTRACT;
3022     
3023     VALIDATEOBJECT(sourceObj);
3024     VALIDATEOBJECT(target);
3025
3026     if (sourceObj == 0)
3027         FC_RETURN_BOOL(true);
3028
3029     TypeHandle th(sourceObj->GetMethodTable());
3030     CorElementType tSRC = th.GetVerifierCorElementType();
3031
3032     CorElementType tTRG = target->GetType().GetSignatureCorElementType();
3033     FC_RETURN_BOOL(InvokeUtil::IsPrimitiveType(tTRG) && InvokeUtil::CanPrimitiveWiden(tTRG, tSRC));
3034 }
3035 FCIMPLEND
3036
3037 FCIMPL2(FC_BOOL_RET, ReflectionEnum::InternalEquals, Object *pRefThis, Object* pRefTarget)
3038 {
3039     FCALL_CONTRACT;
3040
3041     VALIDATEOBJECT(pRefThis);
3042     BOOL ret = false;
3043     if (pRefTarget == NULL) {
3044         FC_RETURN_BOOL(ret);
3045     }
3046
3047     if( pRefThis == pRefTarget)
3048         FC_RETURN_BOOL(true);
3049
3050     //Make sure we are comparing same type.
3051     MethodTable* pMTThis = pRefThis->GetMethodTable();
3052     _ASSERTE(!pMTThis->IsArray());  // bunch of assumptions about arrays wrong.
3053     if ( pMTThis != pRefTarget->GetMethodTable()) {
3054         FC_RETURN_BOOL(ret);
3055     }
3056
3057     void * pThis = pRefThis->UnBox();
3058     void * pTarget = pRefTarget->UnBox();
3059     switch (pMTThis->GetNumInstanceFieldBytes()) {
3060     case 1:
3061         ret = (*(UINT8*)pThis == *(UINT8*)pTarget);
3062         break;
3063     case 2:
3064         ret = (*(UINT16*)pThis == *(UINT16*)pTarget);
3065         break;
3066     case 4:
3067         ret = (*(UINT32*)pThis == *(UINT32*)pTarget);
3068         break;
3069     case 8:
3070         ret = (*(UINT64*)pThis == *(UINT64*)pTarget);
3071         break;
3072     default:
3073         // should not reach here.
3074         UNREACHABLE_MSG("Incorrect Enum Type size!");
3075         break;
3076     }
3077
3078     FC_RETURN_BOOL(ret);
3079 }
3080 FCIMPLEND
3081
3082 // preform (this & flags) != flags
3083 FCIMPL2(FC_BOOL_RET, ReflectionEnum::InternalHasFlag, Object *pRefThis, Object* pRefFlags)
3084 {
3085     FCALL_CONTRACT;
3086
3087     VALIDATEOBJECT(pRefThis);
3088
3089     BOOL cmp = false;
3090
3091     _ASSERTE(pRefFlags != NULL); // Enum.cs would have thrown ArgumentNullException before calling into InternalHasFlag
3092
3093     VALIDATEOBJECT(pRefFlags);
3094
3095     void * pThis = pRefThis->UnBox();
3096     void * pFlags = pRefFlags->UnBox();
3097
3098     MethodTable* pMTThis = pRefThis->GetMethodTable();
3099
3100     _ASSERTE(!pMTThis->IsArray());  // bunch of assumptions about arrays wrong.
3101     _ASSERTE(pMTThis->GetNumInstanceFieldBytes() == pRefFlags->GetMethodTable()->GetNumInstanceFieldBytes()); // Enum.cs verifies that the types are Equivalent
3102
3103     switch (pMTThis->GetNumInstanceFieldBytes()) {
3104     case 1:
3105         cmp = ((*(UINT8*)pThis & *(UINT8*)pFlags) == *(UINT8*)pFlags);
3106         break;
3107     case 2:
3108         cmp = ((*(UINT16*)pThis & *(UINT16*)pFlags) == *(UINT16*)pFlags);
3109         break;
3110     case 4:
3111         cmp = ((*(UINT32*)pThis & *(UINT32*)pFlags) == *(UINT32*)pFlags);
3112         break;
3113     case 8:
3114         cmp = ((*(UINT64*)pThis & *(UINT64*)pFlags) == *(UINT64*)pFlags);
3115         break;
3116     default:
3117         // should not reach here.
3118         UNREACHABLE_MSG("Incorrect Enum Type size!");
3119         break;
3120     }
3121
3122     FC_RETURN_BOOL(cmp);
3123 }
3124 FCIMPLEND
3125
3126 // compare two boxed enums using their underlying enum type
3127 FCIMPL2(int, ReflectionEnum::InternalCompareTo, Object *pRefThis, Object* pRefTarget)
3128 {
3129     FCALL_CONTRACT;
3130
3131     const int retIncompatibleMethodTables = 2;  // indicates that the method tables did not match
3132     const int retInvalidEnumType = 3; // indicates that the enum was of an unknown/unsupported unerlying type
3133
3134     VALIDATEOBJECT(pRefThis);
3135     
3136     if (pRefTarget == NULL) {
3137         return 1; // all values are greater than null
3138     }
3139
3140     if( pRefThis == pRefTarget)
3141         return 0;
3142
3143     VALIDATEOBJECT(pRefTarget);
3144
3145     //Make sure we are comparing same type.
3146     MethodTable* pMTThis = pRefThis->GetMethodTable();
3147
3148     _ASSERTE(pMTThis->IsEnum());  
3149
3150     if ( pMTThis != pRefTarget->GetMethodTable()) {
3151         return retIncompatibleMethodTables;   // error case, types incompatible
3152     }
3153
3154     void * pThis = pRefThis->UnBox();
3155     void * pTarget = pRefTarget->UnBox();
3156
3157     #define CMPEXPR(x1,x2) ((x1) == (x2)) ? 0 : ((x1) < (x2)) ? -1 : 1
3158
3159     switch (pMTThis->GetInternalCorElementType()) {
3160
3161     case ELEMENT_TYPE_I1:
3162         {
3163             INT8 i1 = *(INT8*)pThis;
3164             INT8 i2 = *(INT8*)pTarget;
3165
3166             return CMPEXPR(i1,i2);
3167         }
3168         break;
3169
3170     case ELEMENT_TYPE_I2:
3171         {
3172             INT16 i1 = *(INT16*)pThis;
3173             INT16 i2 = *(INT16*)pTarget;
3174
3175             return CMPEXPR(i1,i2);
3176         }
3177         break;
3178
3179         
3180     case ELEMENT_TYPE_I4:
3181     IN_WIN32(case ELEMENT_TYPE_I:)
3182         {
3183             INT32 i1 = *(INT32*)pThis;
3184             INT32 i2 = *(INT32*)pTarget;
3185
3186             return CMPEXPR(i1,i2);
3187         }
3188         break;
3189      
3190
3191     case ELEMENT_TYPE_I8:
3192     IN_WIN64(case ELEMENT_TYPE_I:)
3193         {
3194             INT64 i1 = *(INT64*)pThis;
3195             INT64 i2 = *(INT64*)pTarget;
3196
3197             return CMPEXPR(i1,i2);
3198         }
3199         break;
3200     
3201     case ELEMENT_TYPE_BOOLEAN:
3202         {
3203             bool b1 = !!*(UINT8 *)pThis;
3204             bool b2 = !!*(UINT8 *)pTarget;
3205
3206             return CMPEXPR(b1,b2);
3207         }
3208         break;
3209
3210     case ELEMENT_TYPE_U1:
3211         {
3212             UINT8 u1 = *(UINT8 *)pThis;
3213             UINT8 u2 = *(UINT8 *)pTarget;
3214
3215             return CMPEXPR(u1,u2);
3216         }
3217         break;
3218         
3219     case ELEMENT_TYPE_U2:
3220     case ELEMENT_TYPE_CHAR:
3221         {
3222             UINT16 u1 = *(UINT16 *)pThis;
3223             UINT16 u2 = *(UINT16 *)pTarget;
3224
3225             return CMPEXPR(u1,u2);
3226         }
3227         break;
3228
3229     case ELEMENT_TYPE_U4:
3230     IN_WIN32(case ELEMENT_TYPE_U:)
3231         {
3232             UINT32 u1 = *(UINT32 *)pThis;
3233             UINT32 u2 = *(UINT32 *)pTarget;
3234
3235             return CMPEXPR(u1,u2);
3236         }
3237         break;
3238
3239     case ELEMENT_TYPE_U8:
3240     IN_WIN64(case ELEMENT_TYPE_U:)
3241         {
3242             UINT64 u1 = *(UINT64*)pThis;
3243             UINT64 u2 = *(UINT64*)pTarget;
3244
3245             return CMPEXPR(u1,u2);
3246         }
3247         break;
3248
3249     case ELEMENT_TYPE_R4:
3250         {
3251             static_assert_no_msg(sizeof(float) == 4);
3252
3253             float f1 = *(float*)pThis;
3254             float f2 = *(float*)pTarget;
3255
3256             return CMPEXPR(f1,f2);
3257         }
3258         break;
3259         
3260     case ELEMENT_TYPE_R8:
3261         {
3262             static_assert_no_msg(sizeof(double) == 8);
3263
3264             double d1 = *(double*)pThis;
3265             double d2 = *(double*)pTarget;
3266
3267             return CMPEXPR(d1,d2);
3268         }
3269         break;
3270
3271     default:
3272         break;
3273     }
3274    
3275     return retInvalidEnumType; // second error case -- unsupported enum type
3276 }
3277 FCIMPLEND
3278