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.
8 #include "reflectioninvocation.h"
9 #include "invokeutil.h"
13 #include "typehandle.h"
17 #include "jitinterface.h"
18 #include "contractimpl.h"
19 #include "virtualcallstub.h"
20 #include "comdelegate.h"
23 #ifdef FEATURE_COMINTEROP
24 #include "interoputil.h"
25 #include "runtimecallablewrapper.h"
28 #include "dbginterface.h"
29 #include "argdestination.h"
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
35 // it's used for both method and field to signify that no access is allowed
36 #define INVOCATION_FLAGS_NO_INVOKE 0x00000002
38 // #define unused 0x00000004
40 // because field and method are different we can reuse the same bits
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
48 #define INVOCATION_FLAGS_SPECIAL_FIELD 0x00000010
49 #define INVOCATION_FLAGS_FIELD_SPECIAL_CAST 0x00000020
51 // temporary flag used for flagging invocation of method vs ctor
52 #define INVOCATION_FLAGS_CONSTRUCTOR_INVOKE 0x10000000
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) {
68 if (th.GetVerifierCorElementType() != ELEMENT_TYPE_BYREF)
71 TypeHandle subType = th.AsTypeDesc()->GetTypeParam();
72 if (!Nullable::IsNullableType(subType))
78 static void TryCallMethodWorker(MethodDescCallSite* pMethodCallSite, ARG_SLOT* args, Frame* pDebuggerCatchFrame)
80 // Use static contracts b/c we have SEH.
81 STATIC_CONTRACT_THROWS;
82 STATIC_CONTRACT_GC_TRIGGERS;
83 STATIC_CONTRACT_MODE_ANY;
85 struct Param: public NotifyOfCHFFilterWrapperParam
87 MethodDescCallSite * pMethodCallSite;
91 param.pFrame = pDebuggerCatchFrame;
92 param.pMethodCallSite = pMethodCallSite;
95 PAL_TRY(Param *, pParam, ¶m)
97 pParam->pMethodCallSite->CallWithValueTypes(pParam->args);
99 PAL_EXCEPT_FILTER(NotifyOfCHFFilterWrapper)
101 // Should never reach here b/c handler should always continue search.
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.
112 static void TryCallMethod(MethodDescCallSite* pMethodCallSite, ARG_SLOT* args, bool wrapExceptions) {
122 OBJECTREF ppException = NULL;
123 GCPROTECT_BEGIN(ppException);
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;
130 TryCallMethodWorker(pMethodCallSite, args, &catchFrame);
133 ppException = GET_THROWABLE();
134 _ASSERTE(ppException);
136 EX_END_CATCH(RethrowTransientExceptions)
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)
143 // If we get here we need to throw an TargetInvocationException
144 OBJECTREF except = InvokeUtil::CreateTargetExcept(&ppException);
145 COMPlusThrow(except);
151 pMethodCallSite->CallWithValueTypes(args);
158 FCIMPL5(Object*, RuntimeFieldHandle::GetValue, ReflectFieldObject *pFieldUNSAFE, Object *instanceUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, ReflectClassBaseObject *pDeclaringTypeUNSAFE, CLR_BOOL *pDomainInitialized) {
167 REFLECTCLASSBASEREF pFieldType;
168 REFLECTCLASSBASEREF pDeclaringType;
169 REFLECTFIELDREF refField;
172 gc.target = ObjectToOBJECTREF(instanceUNSAFE);
173 gc.pFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
174 gc.pDeclaringType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDeclaringTypeUNSAFE);
175 gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
177 if ((gc.pFieldType == NULL) || (gc.refField == NULL))
178 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
180 TypeHandle fieldType = gc.pFieldType->GetType();
181 TypeHandle declaringType = (gc.pDeclaringType != NULL) ? gc.pDeclaringType->GetType() : TypeHandle();
184 if (declaringType.IsNull())
187 pAssem = gc.refField->GetField()->GetModule()->GetAssembly();
191 pAssem = declaringType.GetAssembly();
194 if (pAssem->IsIntrospectionOnly())
195 FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
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);
202 OBJECTREF rv = NULL; // not protected
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();
209 return OBJECTREFToObject(rv);
213 FCIMPL2(FC_BOOL_RET, ReflectionInvocation::CanValueSpecialCast, ReflectClassBaseObject *pValueTypeUNSAFE, ReflectClassBaseObject *pTargetTypeUNSAFE) {
216 PRECONDITION(CheckPointer(pValueTypeUNSAFE));
217 PRECONDITION(CheckPointer(pTargetTypeUNSAFE));
221 REFLECTCLASSBASEREF refValueType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pValueTypeUNSAFE);
222 REFLECTCLASSBASEREF refTargetType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTargetTypeUNSAFE);
224 TypeHandle valueType = refValueType->GetType();
225 TypeHandle targetType = refTargetType->GetType();
227 // we are here only if the target type is a primitive, an enum or a pointer
229 CorElementType targetCorElement = targetType.GetVerifierCorElementType();
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))) {
238 // it's an IntPtr, it's good.
241 // it's a System.Reflection.Pointer object
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))
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;
258 HELPER_METHOD_FRAME_END();
263 FCIMPL3(Object*, ReflectionInvocation::AllocateValueType, ReflectClassBaseObject *pTargetTypeUNSAFE, Object *valueUNSAFE, CLR_BOOL fForceTypeChange) {
266 PRECONDITION(CheckPointer(pTargetTypeUNSAFE));
267 PRECONDITION(CheckPointer(valueUNSAFE, NULL_OK));
273 REFLECTCLASSBASEREF refTargetType;
278 gc.value = ObjectToOBJECTREF(valueUNSAFE);
280 gc.refTargetType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTargetTypeUNSAFE);
282 TypeHandle targetType = gc.refTargetType->GetType();
284 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
285 CorElementType targetElementType = targetType.GetSignatureCorElementType();
286 if (InvokeUtil::IsPrimitiveType(targetElementType) || targetElementType == ELEMENT_TYPE_VALUETYPE)
288 MethodTable* allocMT = targetType.AsMethodTable();
289 if (gc.value != NULL)
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();
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
300 if (!(gc.value == NULL && Nullable::IsNullableType(targetType)))
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
307 gc.obj = allocMT->Allocate();
309 if (gc.value != NULL)
310 CopyValueClassUnchecked(gc.obj->UnBox(), gc.value->UnBox(), allocMT);
314 HELPER_METHOD_FRAME_END();
316 return OBJECTREFToObject(gc.obj);
320 FCIMPL7(void, RuntimeFieldHandle::SetValue, ReflectFieldObject *pFieldUNSAFE, Object *targetUNSAFE, Object *valueUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, DWORD attr, ReflectClassBaseObject *pDeclaringTypeUNSAFE, CLR_BOOL *pDomainInitialized) {
329 REFLECTCLASSBASEREF fieldType;
330 REFLECTCLASSBASEREF declaringType;
331 REFLECTFIELDREF refField;
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);
340 if ((gc.fieldType == NULL) || (gc.refField == NULL))
341 FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
343 TypeHandle fieldType = gc.fieldType->GetType();
344 TypeHandle declaringType = gc.declaringType != NULL ? gc.declaringType->GetType() : TypeHandle();
347 if (declaringType.IsNull())
350 pAssem = gc.refField->GetField()->GetModule()->GetAssembly();
354 pAssem = declaringType.GetAssembly();
357 if (pAssem->IsIntrospectionOnly())
358 FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
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);
365 FC_GC_POLL_NOT_NEEDED();
367 FieldDesc* pFieldDesc = gc.refField->GetField();
369 HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
371 //TODO: cleanup this function
372 InvokeUtil::SetValidField(fieldType.GetSignatureCorElementType(), fieldType, pFieldDesc, &gc.target, &gc.value, declaringType, pDomainInitialized);
374 HELPER_METHOD_FRAME_END();
379 FCIMPL1(Object*, RuntimeTypeHandle::Allocate, ReflectClassBaseObject* pTypeUNSAFE)
383 PRECONDITION(CheckPointer(pTypeUNSAFE));
387 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
388 TypeHandle type = refType->GetType();
390 // Handle the nullable<T> special case
391 if (Nullable::IsNullableType(type)) {
392 return OBJECTREFToObject(Nullable::BoxedNullableNull(type));
396 HELPER_METHOD_FRAME_BEGIN_RET_1(refType);
397 rv = AllocateObject(type.GetMethodTable());
398 HELPER_METHOD_FRAME_END();
399 return OBJECTREFToObject(rv);
404 FCIMPL5(Object*, RuntimeTypeHandle::CreateInstance, ReflectClassBaseObject* refThisUNSAFE,
406 CLR_BOOL wrapExceptions,
407 CLR_BOOL* pbCanBeCached,
408 MethodDesc** pConstructor) {
411 PRECONDITION(CheckPointer(refThisUNSAFE));
412 PRECONDITION(CheckPointer(pbCanBeCached));
413 PRECONDITION(CheckPointer(pConstructor));
414 PRECONDITION(*pbCanBeCached == false);
415 PRECONDITION(*pConstructor == NULL);
419 if (refThisUNSAFE == NULL)
420 FCThrow(kNullReferenceException);
425 REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(refThisUNSAFE);
426 TypeHandle thisTH = refThis->GetType();
428 Assembly *pAssem = thisTH.GetAssembly();
430 if (pAssem->IsIntrospectionOnly())
431 FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
433 if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
434 FCThrowRes(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
436 HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refThis);
440 // Get the type information associated with refThis
441 if (thisTH.IsNull() || thisTH.IsTypeDesc())
442 COMPlusThrow(kMissingMethodException,W("Arg_NoDefCTor"));
444 pVMT = thisTH.AsMethodTable();
446 pVMT->EnsureInstanceActive();
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();
454 void* pClassFactory = (void*)pSyncBlock->GetInteropInfo()->GetComClassFactory();
456 COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY);
458 // create an instance of the Com Object
459 rv = ((ComClassFactory*)pClassFactory)->CreateInstance(NULL);
461 #else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
463 COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY);
465 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
468 #endif // FEATURE_COMINTEROP
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"));
475 COMPlusThrow(kMissingMethodException,W("Acc_CreateAbst"));
477 else if (pVMT->ContainsGenericVariables()) {
478 COMPlusThrow(kArgumentException,W("Acc_CreateGeneric"));
481 if (pVMT->IsByRefLike())
482 COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike"));
484 if (pVMT->IsSharedByGenericInstantiations())
485 COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
487 if (!pVMT->HasDefaultConstructor())
489 // We didn't find the parameterless constructor,
490 // if this is a Value class we can simply allocate one and return it
492 if (!pVMT->IsValueType()) {
493 COMPlusThrow(kMissingMethodException,W("Arg_NoDefCTor"));
496 // Handle the nullable<T> special case
497 if (Nullable::IsNullableType(thisTH)) {
498 rv = Nullable::BoxedNullableNull(thisTH);
501 rv = pVMT->Allocate();
503 if (!pVMT->Collectible())
505 *pbCanBeCached = true;
508 else // !pVMT->HasDefaultConstructor()
510 pMeth = pVMT->GetDefaultConstructor();
512 // Validate the method can be called by this caller
513 DWORD attr = pMeth->GetAttrs();
515 if (!IsMdPublic(attr) && publicOnly)
516 COMPlusThrow(kMissingMethodException, W("Arg_NoDefCTor"));
518 // We've got the class, lets allocate it and call the constructor
520 bool remoting = false;
522 o = AllocateObject(pVMT);
525 MethodDescCallSite ctor(pMeth, &o);
527 // Copy "this" pointer
529 if (pVMT->IsValueType())
530 arg = PtrToArgSlot(o->UnBox());
532 arg = ObjToArgSlot(o);
535 TryCallMethod(&ctor, &arg, wrapExceptions);
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())
545 *pbCanBeCached = true;
546 *pConstructor = pMeth;
551 HELPER_METHOD_FRAME_END();
552 return OBJECTREFToObject(rv);
556 FCIMPL2(Object*, RuntimeTypeHandle::CreateInstanceForGenericType, ReflectClassBaseObject* pTypeUNSAFE, ReflectClassBaseObject* pParameterTypeUNSAFE) {
562 REFLECTCLASSBASEREF refType;
563 REFLECTCLASSBASEREF refParameterType;
567 gc.refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
568 gc.refParameterType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pParameterTypeUNSAFE);
571 TypeHandle genericType = gc.refType->GetType();
573 TypeHandle parameterHandle = gc.refParameterType->GetType();
575 _ASSERTE (genericType.HasInstantiation());
577 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
579 TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(¶meterHandle, 1));
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());
588 pMeth = pVMT->GetDefaultConstructor();
589 MethodDescCallSite ctor(pMeth);
591 // We've got the class, lets allocate it and call the constructor
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();
597 ARG_SLOT arg = ObjToArgSlot(gc.rv);
600 TryCallMethod(&ctor, &arg, true);
602 HELPER_METHOD_FRAME_END();
603 return OBJECTREFToObject(gc.rv);
607 NOINLINE FC_BOOL_RET IsInstanceOfTypeHelper(OBJECTREF obj, REFLECTCLASSBASEREF refType)
611 BOOL canCast = false;
613 FC_INNER_PROLOG(RuntimeTypeHandle::IsInstanceOfType);
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();
619 FC_RETURN_BOOL(canCast);
622 FCIMPL2(FC_BOOL_RET, RuntimeTypeHandle::IsInstanceOfType, ReflectClassBaseObject* pTypeUNSAFE, Object *objectUNSAFE) {
625 OBJECTREF obj = ObjectToOBJECTREF(objectUNSAFE);
626 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
628 // Null is not instance of anything in reflection world
630 FC_RETURN_BOOL(false);
633 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
635 switch (ObjIsInstanceOfNoGC(objectUNSAFE, refType->GetType())) {
636 case TypeHandle::CanCast:
637 FC_RETURN_BOOL(true);
638 case TypeHandle::CannotCast:
639 FC_RETURN_BOOL(false);
641 // fall through to the slow helper
645 FC_INNER_RETURN(FC_BOOL_RET, IsInstanceOfTypeHelper(obj, refType));
649 FCIMPL1(DWORD, ReflectionInvocation::GetSpecialSecurityFlags, ReflectMethodObject *pMethodUNSAFE) {
659 REFLECTMETHODREF refMethod;
663 gc.refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
666 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
668 MethodDesc* pMethod = gc.refMethod->GetMethod();
670 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
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();
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();
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;
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;
693 HELPER_METHOD_FRAME_END();
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 */
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
714 ByRefToNullable(unsigned aArgNum, void* aData, TypeHandle aType, ByRefToNullable* aNext) {
722 void CallDescrWorkerReflectionWrapper(CallDescrData * pCallDescrData, Frame * pFrame)
724 // Use static contracts b/c we have SEH.
725 STATIC_CONTRACT_THROWS;
726 STATIC_CONTRACT_GC_TRIGGERS;
727 STATIC_CONTRACT_MODE_ANY;
729 struct Param: public NotifyOfCHFFilterWrapperParam
731 CallDescrData * pCallDescrData;
734 param.pFrame = pFrame;
735 param.pCallDescrData = pCallDescrData;
737 PAL_TRY(Param *, pParam, ¶m)
739 CallDescrWorkerWithHandler(pParam->pCallDescrData);
741 PAL_EXCEPT_FILTER(ReflectionInvocationExceptionFilter)
743 // Should never reach here b/c handler should always continue search.
747 } // CallDescrWorkerReflectionWrapper
749 OBJECTREF InvokeArrayConstructor(ArrayTypeDesc* arrayDesc, MethodDesc* pMeth, PTRARRAYREF* objs, int argCnt)
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();
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);
768 // Validate all of the parameters. These all typed as integers
770 if (!ClrSafeInt<int>::multiply(sizeof(INT32), argCnt, allocSize))
771 COMPlusThrow(kArgumentException, IDS_EE_SIGTOOCOMPLEX);
773 INT32* indexes = (INT32*) _alloca((size_t)allocSize);
774 ZeroMemory(indexes, allocSize);
776 for (i=0; i<(DWORD)argCnt; i++)
778 if (!(*objs)->m_Array[i])
779 COMPlusThrowArgumentException(W("parameters"), W("Arg_NullIndex"));
781 MethodTable* pMT = ((*objs)->m_Array[i])->GetMethodTable();
782 CorElementType oType = TypeHandle(pMT).GetVerifierCorElementType();
784 if (!InvokeUtil::IsPrimitiveType(oType) || !InvokeUtil::CanPrimitiveWiden(ELEMENT_TYPE_I4,oType))
785 COMPlusThrow(kArgumentException,W("Arg_PrimWiden"));
787 memcpy(&indexes[i],(*objs)->m_Array[i]->UnBox(),pMT->GetNumInstanceFieldBytes());
790 return AllocateArrayEx(TypeHandle(arrayDesc), indexes, argCnt);
793 static BOOL IsActivationNeededForMethodInvoke(MethodDesc * pMD)
802 // The activation for non-generic instance methods is covered by non-null "this pointer"
803 if (!pMD->IsStatic() && !pMD->HasMethodInstantiation() && !pMD->IsInterface())
806 // We need to activate each time for domain neutral types
807 if (pMD->IsDomainNeutral())
810 // We need to activate the instance at least once
815 class ArgIteratorBaseForMethodInvoke
818 SIGNATURENATIVEREF * m_ppNativeSig;
820 FORCEINLINE CorElementType GetReturnType(TypeHandle * pthValueType)
823 return (*pthValueType = (*m_ppNativeSig)->GetReturnTypeHandle()).GetInternalCorElementType();
826 FORCEINLINE CorElementType GetNextArgumentType(DWORD iArg, TypeHandle * pthValueType)
829 return (*pthValueType = (*m_ppNativeSig)->GetArgumentAt(iArg)).GetInternalCorElementType();
832 FORCEINLINE void Reset()
834 LIMITED_METHOD_CONTRACT;
840 LIMITED_METHOD_CONTRACT;
841 return (*m_ppNativeSig)->HasThis();
846 LIMITED_METHOD_CONTRACT;
847 // param type methods are not supported for reflection invoke, so HasParamType is always false for them
853 LIMITED_METHOD_CONTRACT;
854 // vararg methods are not supported for reflection invoke, so IsVarArg is always false for them
860 LIMITED_METHOD_CONTRACT;
861 return (*m_ppNativeSig)->NumFixedArgs();
864 #ifdef FEATURE_INTERPRETER
867 LIMITED_METHOD_CONTRACT;
868 return IMAGE_CEE_CS_CALLCONV_DEFAULT;
870 #endif // FEATURE_INTERPRETER
873 class ArgIteratorForMethodInvoke : public ArgIteratorTemplate<ArgIteratorBaseForMethodInvoke>
876 ArgIteratorForMethodInvoke(SIGNATURENATIVEREF * ppNativeSig)
878 m_ppNativeSig = ppNativeSig;
880 DWORD dwFlags = (*m_ppNativeSig)->GetArgIteratorFlags();
882 // Use the cached values if they are available
883 if (dwFlags & SIZE_OF_ARG_STACK_COMPUTED)
886 m_nSizeOfArgStack = (*m_ppNativeSig)->GetSizeOfArgStack();
891 // Compute flags and stack argument size, and cache them for next invocation
896 if (IsActivationNeededForMethodInvoke((*m_ppNativeSig)->GetMethod()))
898 m_dwFlags |= METHOD_INVOKE_NEEDS_ACTIVATION;
901 (*m_ppNativeSig)->SetSizeOfArgStack(m_nSizeOfArgStack);
902 _ASSERTE((*m_ppNativeSig)->GetSizeOfArgStack() == m_nSizeOfArgStack);
904 // This has to be last
905 (*m_ppNativeSig)->SetArgIteratorFlags(m_dwFlags);
906 _ASSERTE((*m_ppNativeSig)->GetArgIteratorFlags() == m_dwFlags);
909 BOOL IsActivationNeeded()
911 LIMITED_METHOD_CONTRACT;
912 return (m_dwFlags & METHOD_INVOKE_NEEDS_ACTIVATION) != 0;
917 void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTREF targetException)
926 GCPROTECT_BEGIN(targetException);
928 #if defined(_DEBUG) && !defined(FEATURE_PAL)
929 if (IsWatsonEnabled())
931 if (!CLRException::IsPreallocatedExceptionObject(targetException))
933 // If the exception is not preallocated, we should be having the
934 // watson buckets in the throwable already.
935 if(!((EXCEPTIONREF)targetException)->AreWatsonBucketsPresent())
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.
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"));
947 // Exception is preallocated.
948 PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = GetThread()->GetExceptionState()->GetUEWatsonBucketTracker();
949 if ((IsThrowableThreadAbortException(targetException) && pUEWatsonBucketTracker->CapturedForThreadAbort())||
950 (pUEWatsonBucketTracker->CapturedAtReflectionInvocation()))
952 // ReflectionInvocationExceptionFilter would have captured
953 // the watson bucket details for preallocated exceptions
954 // in the UE watson bucket tracker.
956 if(pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
959 LOG((LF_EH, LL_INFO100, "InvokeImpl - No watson buckets available - preallocated exception likely raised within VM and not seen by managed code.\n"));
964 #endif // _DEBUG && !FEATURE_PAL
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();
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
975 OBJECTREF except = InvokeUtil::CreateTargetExcept(&targetException);
978 if (IsWatsonEnabled())
984 ZeroMemory(&gcTIE, sizeof(gcTIE));
985 GCPROTECT_BEGIN(gcTIE);
987 gcTIE.oExcept = except;
989 _ASSERTE(!CLRException::IsPreallocatedExceptionObject(gcTIE.oExcept));
991 // If the original exception was preallocated, then copy over the captured
992 // watson buckets to the TargetInvocationException object, if available.
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))
998 PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = GetThread()->GetExceptionState()->GetUEWatsonBucketTracker();
999 BOOL fCopyWatsonBuckets = TRUE;
1000 PTR_VOID pBuckets = pUEWatsonBucketTracker->RetrieveWatsonBuckets();
1001 if (pBuckets != NULL)
1003 // Copy the buckets to the exception object
1004 CopyWatsonBucketsToThrowable(pBuckets, gcTIE.oExcept);
1006 // Confirm that they are present.
1007 _ASSERTE(((EXCEPTIONREF)gcTIE.oExcept)->AreWatsonBucketsPresent());
1010 // Clear the UE watson bucket tracker since the bucketing
1011 // details are now in the TargetInvocationException object.
1012 pUEWatsonBucketTracker->ClearWatsonBucketDetails();
1015 // update "except" incase the reference to the object
1016 // was updated by the GC
1017 except = gcTIE.oExcept;
1020 #endif // !FEATURE_PAL
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.
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.
1029 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
1031 #endif // FEATURE_CORRUPTING_EXCEPTIONS
1037 FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
1038 Object *target, PTRArray *objs, SignatureNative* pSigUNSAFE,
1039 CLR_BOOL fConstructor, CLR_BOOL fWrapExceptions)
1046 SIGNATURENATIVEREF pSig;
1050 gc.target = ObjectToOBJECTREF(target);
1051 gc.args = (PTRARRAYREF)objs;
1052 gc.pSig = (SIGNATURENATIVEREF)pSigUNSAFE;
1055 MethodDesc* pMeth = gc.pSig->GetMethod();
1056 TypeHandle ownerType = gc.pSig->GetDeclaringType();
1058 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
1060 Assembly *pAssem = pMeth->GetAssembly();
1062 if (pAssem->IsIntrospectionOnly())
1063 COMPlusThrow(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY);
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);
1070 if (ownerType.IsSharedByGenericInstantiations())
1071 COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
1074 if (g_pConfig->ShouldInvokeHalt(pMeth))
1076 _ASSERTE(!"InvokeHalt");
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;
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(),
1093 gc.pSig->NumFixedArgs());
1097 MethodTable * pMT = ownerType.AsMethodTable();
1100 if (pMT != g_pStringClass)
1101 gc.retVal = pMT->Allocate();
1109 ArgIteratorForMethodInvoke argit(&gc.pSig);
1111 if (argit.IsActivationNeeded() || fForceActivationForRemoting)
1112 pMeth->EnsureActive();
1113 CONSISTENCY_CHECK(pMeth->CheckActivated());
1115 UINT nStackBytes = argit.SizeOfFrameArgumentArray();
1117 // Note that SizeOfFrameArgumentArray does overflow checks with sufficient margin to prevent overflows here
1118 SIZE_T nAllocaSize = TransitionBlock::GetNegSpaceSize() + sizeof(TransitionBlock) + nStackBytes;
1120 Thread * pThread = GET_THREAD();
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));
1126 LPBYTE pAlloc = (LPBYTE)_alloca(nAllocaSize);
1128 LPBYTE pTransitionBlock = pAlloc + TransitionBlock::GetNegSpaceSize();
1130 CallDescrData callDescrData;
1132 callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
1133 callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
1134 #ifdef CALLDESCR_ARGREGS
1135 callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters());
1137 #ifdef CALLDESCR_FPARGREGS
1138 callDescrData.pFloatArgumentRegisters = NULL;
1140 #ifdef CALLDESCR_REGTYPEMAP
1141 callDescrData.dwRegTypeMap = 0;
1143 callDescrData.fpReturnSize = argit.GetFPReturnSize();
1145 // This is duplicated logic from MethodDesc::GetCallTarget
1147 if (pMeth->IsVtableMethod())
1149 pTarget = pMeth->GetSingleCallableAddrOfVirtualizedCode(&gc.target, ownerType);
1153 pTarget = pMeth->GetSingleCallableAddrOfCode();
1155 callDescrData.pTarget = pTarget;
1157 // Build the arguments on the stack
1159 GCStress<cfg_any>::MaybeTrigger();
1161 FrameWithCookie<ProtectValueClassFrame> *pProtectValueClassFrame = NULL;
1162 ValueClassInfo *pValueClasses = NULL;
1163 ByRefToNullable* byRefToNullables = NULL;
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.
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();
1175 // Copy "this" pointer
1176 if (!pMeth->IsStatic()) {
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();
1187 pThisPtr = OBJECTREFToObject(gc.retVal);
1190 if (!pMeth->GetMethodTable()->IsValueType())
1191 pThisPtr = OBJECTREFToObject(gc.target);
1193 if (pMeth->IsUnboxingStub())
1194 pThisPtr = OBJECTREFToObject(gc.target);
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);
1206 pThisPtr = gc.target->UnBox();
1210 *((LPVOID*) (pTransitionBlock + argit.GetThisOffset())) = pThisPtr;
1213 // NO GC AFTER THIS POINT. The object references in the method frame are not protected.
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.
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.
1221 PVOID pRetBufStackCopy = NULL;
1226 GCForbidLoaderUseHolder forbidLoaderUse;
1229 // Take care of any return arguments
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())
1238 SIZE_T sz = pMT->GetNumInstanceFieldBytes();
1239 pRetBufStackCopy = _alloca(sz);
1240 memset(pRetBufStackCopy, 0, sz);
1242 pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pRetBufStackCopy, pMT, pValueClasses);
1243 *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBufStackCopy;
1247 PVOID pRetBuff = gc.retVal->GetData();
1248 *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBuff;
1253 UINT nNumArgs = gc.pSig->NumFixedArgs();
1254 for (UINT i = 0 ; i < nNumArgs; i++) {
1256 TypeHandle th = gc.pSig->GetArgumentAt(i);
1258 int ofs = argit.GetNextOffset();
1259 _ASSERTE(ofs != TransitionBlock::InvalidOffset);
1261 #ifdef CALLDESCR_REGTYPEMAP
1262 FillInRegTypeMap(ofs, argit.GetArgType(), (BYTE *)&callDescrData.dwRegTypeMap);
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).
1271 if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs()) &&
1272 (callDescrData.pFloatArgumentRegisters == NULL))
1274 callDescrData.pFloatArgumentRegisters = (FloatArgumentRegisters*) (pTransitionBlock +
1275 TransitionBlock::GetOffsetOfFloatArgumentRegisters());
1279 UINT structSize = argit.GetArgSize();
1281 bool needsStackCopy = false;
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()) {
1289 structSize = th.GetSize();
1290 needsStackCopy = true;
1292 #ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
1293 else if (argit.IsArgPassedByRef())
1295 needsStackCopy = true;
1299 ArgDestination argDest(pTransitionBlock, ofs, argit.GetArgLocDescForStructInRegs());
1303 MethodTable * pMT = th.GetMethodTable();
1304 _ASSERTE(pMT && pMT->IsValueType());
1306 PVOID pArgDst = argDest.GetDestinationAddress();
1308 PVOID pStackCopy = _alloca(structSize);
1309 *(PVOID *)pArgDst = pStackCopy;
1310 pArgDst = pStackCopy;
1312 if (!nullableType.IsNull())
1314 byRefToNullables = new(_alloca(sizeof(ByRefToNullable))) ByRefToNullable(i, pStackCopy, nullableType, byRefToNullables);
1317 // save the info into ValueClassInfo
1318 if (pMT->ContainsPointers())
1320 pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pStackCopy, pMT, pValueClasses);
1323 // We need a new ArgDestination that points to the stack copy
1324 argDest = ArgDestination(pStackCopy, 0, NULL);
1327 InvokeUtil::CopyArg(th, &(gc.args->m_Array[i]), &argDest);
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
1339 if (pValueClasses != NULL)
1341 pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie<ProtectValueClassFrame>)))
1342 FrameWithCookie<ProtectValueClassFrame>(pThread, pValueClasses);
1346 bool fExceptionThrown = false;
1347 if (fWrapExceptions)
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);
1354 EX_TRY_THREAD(pThread) {
1355 CallDescrWorkerReflectionWrapper(&callDescrData, &catchFrame);
1357 // Rethrow transient exceptions for constructors for backward compatibility
1358 if (fConstructor && GET_EXCEPTION()->IsTransient())
1363 // Abuse retval to store the exception object
1364 gc.retVal = GET_THROWABLE();
1365 _ASSERTE(gc.retVal);
1367 fExceptionThrown = true;
1368 } EX_END_CATCH(SwallowAllExceptions);
1370 catchFrame.Pop(pThread);
1374 CallDescrWorkerWithHandler(&callDescrData);
1378 // Now that we are safely out of the catch block, we can create and raise the
1379 // TargetInvocationException.
1380 if (fExceptionThrown)
1382 ThrowInvokeMethodException(pMeth, gc.retVal);
1385 // It is still illegal to do a GC here. The return type might have/contain GC pointers.
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;
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);
1399 if (retType == ELEMENT_TYPE_VALUETYPE)
1401 _ASSERTE(gc.retVal != NULL);
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)
1407 CopyValueClass(gc.retVal->GetData(), &callDescrData.returnValue, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
1409 else if (pRetBufStackCopy)
1411 CopyValueClass(gc.retVal->GetData(), pRetBufStackCopy, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
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.
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);
1422 gc.retVal = InvokeUtil::CreateObject(retTH, &callDescrData.returnValue);
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;
1431 if (pProtectValueClassFrame != NULL)
1432 pProtectValueClassFrame->Pop(pThread);
1434 END_INTERIOR_STACK_PROBE;
1438 HELPER_METHOD_FRAME_END();
1440 return OBJECTREFToObject(gc.retVal);
1445 StackCrawlMark* pStackMark;
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) {
1459 SkipStruct* pSkip = (SkipStruct*) data;
1461 MethodDesc *pFunc = frame->GetFunction();
1463 /* We asked to be called back only for functions */
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;
1476 if (pFunc->RequiresInstMethodDescArg())
1478 pSkip->pMeth = (MethodDesc *) frame->GetParamTypeArg();
1479 if (pSkip->pMeth == NULL)
1480 pSkip->pMeth = pFunc;
1483 pSkip->pMeth = pFunc;
1487 // Return the MethodInfo that represents the current method (two above this one)
1488 FCIMPL1(ReflectMethodObject*, RuntimeMethodHandle::GetCurrentMethod, StackCrawlMark* stackMark) {
1490 REFLECTMETHODREF pRet = NULL;
1492 HELPER_METHOD_FRAME_BEGIN_RET_0();
1494 skip.pStackMark = stackMark;
1496 StackWalkFunctions(GetThread(), SkipMethods, &skip);
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.
1502 if (skip.pMeth != NULL)
1503 pRet = skip.pMeth->LoadTypicalMethodDefinition()->GetStubMethodInfo();
1507 HELPER_METHOD_FRAME_END();
1509 return (ReflectMethodObject*)OBJECTREFToObject(pRet);
1513 static OBJECTREF DirectObjectFieldGet(FieldDesc *pField, TypeHandle fieldType, TypeHandle enclosingType, TypedByRef *pTarget, CLR_BOOL *pDomainInitialized) {
1519 PRECONDITION(CheckPointer(pField));
1524 OBJECTREF objref = NULL;
1525 GCPROTECT_BEGIN(objref);
1526 if (!pField->IsStatic()) {
1527 objref = ObjectToOBJECTREF(*((Object**)pTarget->data));
1530 InvokeUtil::ValidateObjectTarget(pField, enclosingType, &objref);
1531 refRet = InvokeUtil::GetFieldValue(pField, fieldType, &objref, enclosingType, pDomainInitialized);
1536 FCIMPL4(Object*, RuntimeFieldHandle::GetValueDirect, ReflectFieldObject *pFieldUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, TypedByRef *pTarget, ReflectClassBaseObject *pDeclaringTypeUNSAFE) {
1544 REFLECTCLASSBASEREF refFieldType;
1545 REFLECTCLASSBASEREF refDeclaringType;
1546 REFLECTFIELDREF refField;
1548 gc.refFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
1549 gc.refDeclaringType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pDeclaringTypeUNSAFE);
1550 gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
1552 if ((gc.refFieldType == NULL) || (gc.refField == NULL))
1553 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
1555 TypeHandle fieldType = gc.refFieldType->GetType();
1557 FieldDesc *pField = gc.refField->GetField();
1559 Assembly *pAssem = pField->GetModule()->GetAssembly();
1561 if (pAssem->IsIntrospectionOnly())
1562 FCThrowEx(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
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);
1569 OBJECTREF refRet = NULL;
1570 CorElementType fieldElType;
1572 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
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();
1579 // Verify the callee/caller access
1580 if (!pField->IsPublic() || (pEnclosingMT != NULL && !pEnclosingMT->IsExternallyVisible()))
1583 bool targetRemoted = false;
1586 RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType(targetRemoted));
1588 MethodTable* pInstanceMT = NULL;
1589 if (!pField->IsStatic())
1591 if (!targetType.IsTypeDesc())
1592 pInstanceMT = targetType.AsMethodTable();
1595 //TODO: missing check that the field is consistent
1597 // Perform the normal access check (caller vs field).
1598 InvokeUtil::CanAccessField(&sCtx,
1604 CLR_BOOL domainInitialized = FALSE;
1605 if (pField->IsStatic() || !targetType.IsValueType()) {
1606 refRet = DirectObjectFieldGet(pField, fieldType, TypeHandle(pEnclosingMT), pTarget, &domainInitialized);
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);
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
1618 fieldElType = fieldType.GetSignatureCorElementType();
1619 switch (fieldElType) {
1620 case ELEMENT_TYPE_VOID:
1621 _ASSERTE(!"Void used as Field Type!");
1622 COMPlusThrow(kInvalidProgramException);
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);
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);
1652 case ELEMENT_TYPE_PTR:
1654 p = ((BYTE*) pTarget->data) + pField->GetOffset();
1656 refRet = InvokeUtil::CreatePointer(fieldType, *(void **)p);
1662 _ASSERTE(!"Unknown Type");
1663 // this is really an impossible condition
1664 COMPlusThrow(kNotSupportedException);
1668 HELPER_METHOD_FRAME_END();
1669 return OBJECTREFToObject(refRet);
1673 static void DirectObjectFieldSet(FieldDesc *pField, TypeHandle fieldType, TypeHandle enclosingType, TypedByRef *pTarget, OBJECTREF *pValue, CLR_BOOL *pDomainInitialized) {
1679 PRECONDITION(CheckPointer(pField));
1680 PRECONDITION(!fieldType.IsNull());
1684 OBJECTREF objref = NULL;
1685 GCPROTECT_BEGIN(objref);
1686 if (!pField->IsStatic()) {
1687 objref = ObjectToOBJECTREF(*((Object**)pTarget->data));
1689 // Validate the target/fld type relationship
1690 InvokeUtil::ValidateObjectTarget(pField, enclosingType, &objref);
1692 InvokeUtil::ValidField(fieldType, pValue);
1693 InvokeUtil::SetValidField(pField->GetFieldType(), fieldType, pField, &objref, pValue, enclosingType, pDomainInitialized);
1697 FCIMPL5(void, RuntimeFieldHandle::SetValueDirect, ReflectFieldObject *pFieldUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE, TypedByRef *pTarget, Object *valueUNSAFE, ReflectClassBaseObject *pContextTypeUNSAFE) {
1706 REFLECTCLASSBASEREF pFieldType;
1707 REFLECTCLASSBASEREF pContextType;
1708 REFLECTFIELDREF refField;
1711 gc.oValue = ObjectToOBJECTREF(valueUNSAFE);
1712 gc.pFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
1713 gc.pContextType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pContextTypeUNSAFE);
1714 gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(pFieldUNSAFE);
1716 if ((gc.pFieldType == NULL) || (gc.refField == NULL))
1717 FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
1719 TypeHandle fieldType = gc.pFieldType->GetType();
1720 TypeHandle contextType = (gc.pContextType != NULL) ? gc.pContextType->GetType() : NULL;
1722 FieldDesc *pField = gc.refField->GetField();
1724 Assembly *pAssem = pField->GetModule()->GetAssembly();
1726 if (pAssem->IsIntrospectionOnly())
1727 FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
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);
1735 ARG_SLOT value = NULL;
1736 CorElementType fieldElType;
1738 HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
1740 // Find the Object and its type
1741 TypeHandle targetType = pTarget->type;
1742 MethodTable *pEnclosingMT = contextType.GetMethodTable();
1745 // Verify that the value passed can be widened into the target
1746 InvokeUtil::ValidField(fieldType, &gc.oValue);
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"));
1753 // Verify the callee/caller access
1754 if (!pField->IsPublic() || (pEnclosingMT != NULL && !pEnclosingMT->IsExternallyVisible()))
1756 // security and consistency checks
1758 bool targetRemoted = false;
1760 RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType(targetRemoted));
1762 MethodTable* pInstanceMT = NULL;
1763 if (!pField->IsStatic()) {
1764 if (!targetType.IsTypeDesc())
1765 pInstanceMT = targetType.AsMethodTable();
1768 //TODO: missing check that the field is consistent
1770 // Perform the normal access check (caller vs field).
1771 InvokeUtil::CanAccessField(&sCtx,
1779 CLR_BOOL domainInitialized = FALSE;
1780 if (pField->IsStatic() || !targetType.IsValueType()) {
1781 DirectObjectFieldSet(pField, fieldType, TypeHandle(pEnclosingMT), pTarget, &gc.oValue, &domainInitialized);
1785 if (gc.oValue == NULL && fieldType.IsValueType() && !Nullable::IsNullableType(fieldType))
1786 COMPlusThrowArgumentNull(W("value"));
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);
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);
1799 value = *(ARG_SLOT*)gc.oValue->UnBox();
1801 pDst = ((BYTE*) pTarget->data) + pField->GetOffset();
1803 switch (fieldElType) {
1804 case ELEMENT_TYPE_VOID:
1805 _ASSERTE(!"Void used as Field Type!");
1806 COMPlusThrow(kInvalidProgramException);
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);
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);
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);
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);
1832 case ELEMENT_TYPE_I:
1834 INT_PTR valuePtr = (INT_PTR) InvokeUtil::GetIntPtrValue(gc.oValue);
1835 VolatileStore((INT_PTR*) pDst, valuePtr);
1838 case ELEMENT_TYPE_U:
1840 UINT_PTR valuePtr = (UINT_PTR) InvokeUtil::GetIntPtrValue(gc.oValue);
1841 VolatileStore((UINT_PTR*) pDst, valuePtr);
1845 case ELEMENT_TYPE_PTR: // pointers
1846 if (gc.oValue != 0) {
1848 if (MscorlibBinder::IsClass(gc.oValue->GetMethodTable(), CLASS__POINTER)) {
1849 value = (size_t) InvokeUtil::GetPointerValue(gc.oValue);
1851 #pragma warning(disable: 4267) //work-around for compiler
1853 VolatileStore((size_t*) pDst, (size_t) value);
1855 #pragma warning(default: 4267)
1861 case ELEMENT_TYPE_FNPTR:
1864 if (gc.oValue != 0) {
1865 CorElementType objType = gc.oValue->GetTypeHandle().GetInternalCorElementType();
1866 InvokeUtil::CreatePrimitiveValue(objType, objType, gc.oValue, &value);
1869 #pragma warning(disable: 4267) //work-around for compiler
1871 VolatileStore((size_t*) pDst, (size_t) value);
1873 #pragma warning(default: 4267)
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);
1885 case ELEMENT_TYPE_VALUETYPE:
1887 _ASSERTE(!fieldType.IsTypeDesc());
1888 MethodTable* pMT = fieldType.AsMethodTable();
1890 // If we have a null value then we must create an empty field
1892 InitValueClass(pDst, pMT);
1894 pMT->UnBoxIntoUnchecked(pDst, gc.oValue);
1900 _ASSERTE(!"Unknown Type");
1901 // this is really an impossible condition
1902 COMPlusThrow(kNotSupportedException);
1906 HELPER_METHOD_FRAME_END();
1910 void QCALLTYPE ReflectionInvocation::CompileMethod(MethodDesc * pMD)
1914 // Argument is checked on the managed side
1915 PRECONDITION(pMD != NULL);
1917 if (!pMD->IsPointingToPrestub())
1921 pMD->DoPrestub(NULL);
1925 // This method triggers the class constructor for a give type
1926 FCIMPL1(void, ReflectionInvocation::RunClassConstructor, ReflectClassBaseObject *pTypeUNSAFE)
1930 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
1932 if (refType == NULL)
1933 FCThrowArgumentVoidEx(kArgumentException, NULL, W("InvalidOperation_HandleIsNotInitialized"));
1935 TypeHandle typeHnd = refType->GetType();
1936 if (typeHnd.IsTypeDesc())
1939 MethodTable *pMT = typeHnd.AsMethodTable();
1941 Assembly *pAssem = pMT->GetAssembly();
1943 if (pAssem->IsIntrospectionOnly())
1944 FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1946 if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1948 FCThrowResVoid(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
1951 if (!pMT->IsClassInited())
1953 HELPER_METHOD_FRAME_BEGIN_1(refType);
1955 // We perform the access check only on CoreCLR for backward compatibility.
1956 RefSecContext sCtx(InvokeUtil::GetInvocationAccessCheckType());
1957 InvokeUtil::CanAccessClass(&sCtx, pMT);
1959 pMT->CheckRestore();
1960 pMT->EnsureInstanceActive();
1961 pMT->CheckRunClassInitThrowing();
1963 HELPER_METHOD_FRAME_END();
1968 // This method triggers the module constructor for a give module
1969 FCIMPL1(void, ReflectionInvocation::RunModuleConstructor, ReflectModuleBaseObject *pModuleUNSAFE) {
1972 REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
1974 if(refModule == NULL)
1975 FCThrowArgumentVoidEx(kArgumentException, NULL, W("InvalidOperation_HandleIsNotInitialized"));
1977 Module *pModule = refModule->GetModule();
1979 Assembly *pAssem = pModule->GetAssembly();
1981 if (pAssem->IsIntrospectionOnly())
1982 FCThrowExVoid(kInvalidOperationException, IDS_EE_CODEEXECUTION_IN_INTROSPECTIVE_ASSEMBLY, NULL, NULL, NULL);
1984 if (pAssem->IsDynamic() && !pAssem->HasRunAccess())
1985 FCThrowResVoid(kNotSupportedException, W("NotSupported_DynamicAssemblyNoRunAccess"));
1987 DomainFile *pDomainFile = pModule->FindDomainFile(GetAppDomain());
1988 if (pDomainFile==NULL || !pDomainFile->IsActive())
1990 HELPER_METHOD_FRAME_BEGIN_1(refModule);
1991 if(pDomainFile==NULL)
1992 pDomainFile=pModule->GetDomainFile();
1993 pDomainFile->EnsureActive();
1994 HELPER_METHOD_FRAME_END();
1999 static void PrepareMethodHelper(MethodDesc * pMD)
2011 if (pMD->IsPointingToPrestub())
2012 pMD->DoPrestub(NULL);
2014 if (pMD->IsWrapperStub())
2016 pMD = pMD->GetWrappedMethodDesc();
2017 if (pMD->IsPointingToPrestub())
2018 pMD->DoPrestub(NULL);
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)
2028 PRECONDITION(CheckPointer(pMethodUNSAFE, NULL_OK));
2029 PRECONDITION(CheckPointer(pInstantiation, NULL_OK));
2033 REFLECTMETHODREF refMethod = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
2035 HELPER_METHOD_FRAME_BEGIN_1(refMethod);
2037 if (refMethod == NULL)
2038 COMPlusThrow(kArgumentException, W("InvalidOperation_HandleIsNotInitialized"));
2040 MethodDesc *pMD = refMethod->GetMethod();
2042 if (pMD->IsAbstract())
2043 COMPlusThrow(kArgumentException, W("Argument_CannotPrepareAbstract"));
2045 MethodTable * pExactMT = pMD->GetMethodTable();
2046 if (pInstantiation != NULL)
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"));
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"));
2060 TypeHandle thExactType = ClassLoader::LoadGenericInstantiationThrowing(pMD->GetModule(),
2061 pMD->GetMethodTable()->GetCl(),
2062 Instantiation(pInstantiation, pMD->GetNumGenericClassArgs()));
2063 pExactMT = thExactType.AsMethodTable();
2065 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD,
2068 Instantiation(&pInstantiation[pMD->GetNumGenericClassArgs()], pMD->GetNumGenericMethodArgs()),
2072 if (pMD->ContainsGenericVariables())
2073 COMPlusThrow(kArgumentException, W("Argument_InvalidGenericInstantiation"));
2075 PrepareMethodHelper(pMD);
2077 HELPER_METHOD_FRAME_END();
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)
2089 PRECONDITION(CheckPointer(delegateUNSAFE, NULL_OK));
2093 if (delegateUNSAFE == NULL)
2096 OBJECTREF delegate = ObjectToOBJECTREF(delegateUNSAFE);
2097 HELPER_METHOD_FRAME_BEGIN_1(delegate);
2099 MethodDesc *pMD = COMDelegate::GetMethodDesc(delegate);
2101 PrepareMethodHelper(pMD);
2103 HELPER_METHOD_FRAME_END();
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)
2114 Thread *pThread = GetThread();
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();
2121 if (current < limit)
2123 FCThrowVoid(kInsufficientExecutionStackException);
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)
2135 Thread *pThread = GetThread();
2137 // Same logic as EnsureSufficientExecutionStack
2138 UINT_PTR current = reinterpret_cast<UINT_PTR>(&pThread);
2139 UINT_PTR limit = pThread->GetCachedStackSufficientExecutionLimit();
2141 FC_RETURN_BOOL(current >= limit);
2145 struct ECWGCFContext
2151 // Crawl the stack looking for Thread Abort related information (whether we're executing inside a CER or an error handling clauses
2153 StackWalkAction ECWGCFCrawlCallBack(CrawlFrame* pCf, void* data)
2161 ECWGCFContext *pData = (ECWGCFContext *)data;
2163 Frame *pFrame = pCf->GetFrame();
2164 if (pFrame && pFrame->GetFunction() != NULL && pFrame != pData->pStartFrame)
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;
2172 MethodDesc *pMD = pCf->GetFunction();
2174 // Non-method frames don't interest us.
2176 return SWA_CONTINUE;
2178 if (!pMD->GetModule()->IsSystem())
2180 // We walk through some user code. This means that ExecuteCodeWithGuarantee is not at the bottom of stack.
2181 pData->fHandled = TRUE;
2185 return SWA_CONTINUE;
2190 BOOL fExceptionThrownInTryCode;
2191 BOOL fStackOverflow;
2192 struct ECWGC_GC *gc;
2195 fExceptionThrownInTryCode = FALSE;
2196 fStackOverflow = FALSE;
2200 LONG SODetectionFilter(EXCEPTION_POINTERS *ep, void* pv)
2202 WRAPPER_NO_CONTRACT;
2203 DefaultCatchFilterParam param(COMPLUS_EXCEPTION_EXECUTE_HANDLER);
2204 if (DefaultCatchFilter(ep, ¶m) == EXCEPTION_CONTINUE_EXECUTION)
2206 return EXCEPTION_CONTINUE_EXECUTION;
2209 // Record the fact that an exception occurred while running the try code.
2210 ECWGC_Param *pParam= (ECWGC_Param *)pv;
2211 pParam->fExceptionThrownInTryCode = TRUE;
2213 // We unwind the stack only in the case of a stack overflow.
2214 if (ep->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
2216 pParam->fStackOverflow = TRUE;
2217 return EXCEPTION_EXECUTE_HANDLER;
2220 return EXCEPTION_CONTINUE_SEARCH;
2225 DELEGATEREF codeDelegate;
2226 DELEGATEREF backoutDelegate;
2230 void ExecuteCodeWithGuaranteedCleanupBackout(ECWGC_GC *gc, BOOL fExceptionThrownInTryCode)
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;
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;
2246 PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(g_pExecuteBackoutCodeHelperMethod);
2248 DECLARE_ARGHOLDER_ARRAY(args, 3);
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);
2255 CALL_MANAGED_METHOD_NORET(args);
2258 void ExecuteCodeWithGuaranteedCleanupHelper (ECWGC_GC *gc)
2260 STATIC_CONTRACT_THROWS;
2261 STATIC_CONTRACT_MODE_COOPERATIVE;
2266 PAL_TRY(ECWGC_Param *, pParamOuter, ¶m)
2268 PAL_TRY(ECWGC_Param *, pParam, pParamOuter)
2270 PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pParam->gc->codeDelegate->GetMethodPtr());
2272 DECLARE_ARGHOLDER_ARRAY(args, 2);
2274 args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(pParam->gc->codeDelegate->GetTarget());
2275 args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(pParam->gc->userData);
2277 CALL_MANAGED_METHOD_NORET(args);
2279 PAL_EXCEPT_FILTER(SODetectionFilter)
2284 if (pParamOuter->fStackOverflow)
2291 ExecuteCodeWithGuaranteedCleanupBackout(gc, param.fExceptionThrownInTryCode);
2295 #ifdef FEATURE_STACK_PROBE
2296 if (param.fStackOverflow)
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);
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.
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.
2315 FCIMPL3(void, ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup, Object* codeDelegateUNSAFE, Object* backoutDelegateUNSAFE, Object* userDataUNSAFE)
2319 PRECONDITION(CheckPointer(codeDelegateUNSAFE, NULL_OK));
2320 PRECONDITION(CheckPointer(backoutDelegateUNSAFE, NULL_OK));
2321 PRECONDITION(CheckPointer(userDataUNSAFE, NULL_OK));
2327 gc.codeDelegate = (DELEGATEREF)ObjectToOBJECTREF(codeDelegateUNSAFE);
2328 gc.backoutDelegate = (DELEGATEREF)ObjectToOBJECTREF(backoutDelegateUNSAFE);
2329 gc.userData = ObjectToOBJECTREF(userDataUNSAFE);
2331 HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
2333 if (gc.codeDelegate == NULL)
2334 COMPlusThrowArgumentNull(W("code"));
2335 if (gc.backoutDelegate == NULL)
2336 COMPlusThrowArgumentNull(W("backoutCode"));
2339 ExecuteCodeWithGuaranteedCleanupHelper(&gc);
2341 HELPER_METHOD_FRAME_END();
2346 FCIMPL4(void, ReflectionInvocation::MakeTypedReference, TypedByRef * value, Object* targetUNSAFE, ArrayBase* fldsUNSAFE, ReflectClassBaseObject *pFieldTypeUNSAFE)
2350 PRECONDITION(CheckPointer(targetUNSAFE));
2351 PRECONDITION(CheckPointer(fldsUNSAFE));
2361 REFLECTCLASSBASEREF refFieldType;
2363 gc.target = (OBJECTREF) targetUNSAFE;
2364 gc.flds = (BASEARRAYREF) fldsUNSAFE;
2365 gc.refFieldType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pFieldTypeUNSAFE);
2367 TypeHandle fieldType = gc.refFieldType->GetType();
2369 HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
2370 GCPROTECT_BEGININTERIOR (value)
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();
2379 // Fields already are prohibted from having ArgIterator and RuntimeArgumentHandles
2380 _ASSERTE(!gc.target->GetTypeHandle().GetMethodTable()->IsByRefLike());
2383 value->data = ((BYTE *)(gc.target->GetAddress() + offset)) + sizeof(Object);
2384 value->type = fieldType;
2387 HELPER_METHOD_FRAME_END();
2391 FCIMPL2(void, ReflectionInvocation::SetTypedReference, TypedByRef * target, Object* objUNSAFE) {
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.
2399 HELPER_METHOD_FRAME_BEGIN_0();
2400 COMPlusThrow(kNotSupportedException);
2401 HELPER_METHOD_FRAME_END();
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) {
2411 OBJECTREF Obj = NULL;
2413 TypeHandle th(value->type);
2416 FCThrowRes(kArgumentNullException, W("ArgumentNull_TypedRefType"));
2418 MethodTable* pMT = th.GetMethodTable();
2419 PREFIX_ASSUME(NULL != pMT);
2421 if (pMT->IsValueType())
2423 // value->data is protected by the caller
2424 HELPER_METHOD_FRAME_BEGIN_RET_1(Obj);
2426 Obj = pMT->Box(value->data);
2428 HELPER_METHOD_FRAME_END();
2431 Obj = ObjectToOBJECTREF(*((Object**)value->data));
2434 return OBJECTREFToObject(Obj);
2439 FCIMPL1(FC_BOOL_RET, ReflectionInvocation::IsAddressInStack, void * ptr)
2442 FC_RETURN_BOOL(Thread::IsAddressInCurrentStack(ptr));
2447 FCIMPL2_IV(Object*, ReflectionInvocation::CreateEnum, ReflectClassBaseObject *pTypeUNSAFE, INT64 value) {
2450 REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
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()));
2460 HELPER_METHOD_FRAME_END();
2461 return OBJECTREFToObject(obj);
2465 #ifdef FEATURE_COMINTEROP
2467 static void TryGetClassFromProgID(STRINGREF className, STRINGREF server, OBJECTREF* pRefClass, DWORD bThrowOnError) {
2477 // NOTE: this call enables GC
2478 GetComClassFromProgID(className, server, pRefClass);
2487 EX_END_CATCH(SwallowAllExceptions)
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) {
2498 REFLECTCLASSBASEREF refClass = NULL;
2499 STRINGREF className = (STRINGREF) classNameUNSAFE;
2500 STRINGREF server = (STRINGREF) serverUNSAFE;
2502 HELPER_METHOD_FRAME_BEGIN_RET_2(className, server);
2504 GCPROTECT_BEGIN(refClass)
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.
2510 // Make sure a prog id was provided
2511 if (className == NULL)
2512 COMPlusThrowArgumentNull(W("progID"),W("ArgumentNull_String"));
2514 TryGetClassFromProgID(className, server, (OBJECTREF*) &refClass, bThrowOnError);
2517 HELPER_METHOD_FRAME_END();
2518 return OBJECTREFToObject(refClass);
2522 static void TryGetClassFromCLSID(GUID clsid, STRINGREF server, OBJECTREF* pRefClass, DWORD bThrowOnError) {
2532 // NOTE: this call enables GC
2533 GetComClassFromCLSID(clsid, server, pRefClass);
2542 EX_END_CATCH(SwallowAllExceptions)
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) {
2552 REFLECTCLASSBASEREF refClass;
2557 gc.server = (STRINGREF) serverUNSAFE;
2559 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc.server);
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.
2565 TryGetClassFromCLSID(clsid, gc.server, (OBJECTREF*) &gc.refClass, bThrowOnError);
2567 HELPER_METHOD_FRAME_END();
2568 return OBJECTREFToObject(gc.refClass);
2573 FCIMPL8(Object*, ReflectionInvocation::InvokeDispMethod, ReflectClassBaseObject* refThisUNSAFE,
2574 StringObject* nameUNSAFE,
2576 Object* targetUNSAFE,
2577 PTRArray* argsUNSAFE,
2578 PTRArray* byrefModifiersUNSAFE,
2580 PTRArray* namedParametersUNSAFE) {
2585 REFLECTCLASSBASEREF refThis;
2589 PTRARRAYREF byrefModifiers;
2590 PTRARRAYREF namedParameters;
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;
2602 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
2604 _ASSERTE(gc.target != NULL);
2605 _ASSERTE(gc.target->GetMethodTable()->IsComObjectType());
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;
2621 IUInvokeDispMethod(&gc.refThis,
2623 (OBJECTREF*)&gc.name,
2625 (OBJECTREF*)&gc.args,
2626 (OBJECTREF*)&gc.byrefModifiers,
2627 (OBJECTREF*)&gc.namedParameters,
2631 invokeAttr & BINDER_IgnoreReturn,
2632 invokeAttr & BINDER_IgnoreCase);
2634 HELPER_METHOD_FRAME_END();
2635 return OBJECTREFToObject(gc.RetObj);
2638 #endif // FEATURE_COMINTEROP
2640 FCIMPL2(void, ReflectionInvocation::GetGUID, ReflectClassBaseObject* refThisUNSAFE, GUID * result) {
2643 REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF) refThisUNSAFE;
2645 HELPER_METHOD_FRAME_BEGIN_1(refThis);
2646 GCPROTECT_BEGININTERIOR (result);
2648 if (result == NULL || refThis == NULL)
2649 COMPlusThrow(kNullReferenceException);
2651 TypeHandle type = refThis->GetType();
2652 if (type.IsTypeDesc()) {
2653 memset(result,0,sizeof(GUID));
2657 #ifdef FEATURE_COMINTEROP
2658 if (IsComObjectClass(type))
2660 SyncBlock* pSyncBlock = refThis->GetSyncBlock();
2662 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2663 ComClassFactory* pComClsFac = pSyncBlock->GetInteropInfo()->GetComClassFactory();
2666 memcpyNoGCRefs(result, &pComClsFac->m_rclsid, sizeof(GUID));
2669 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
2671 memset(result, 0, sizeof(GUID));
2676 #endif // FEATURE_COMINTEROP
2679 type.AsMethodTable()->GetGuid(&guid, TRUE);
2680 memcpyNoGCRefs(result, &guid, sizeof(GUID));
2684 HELPER_METHOD_FRAME_END();
2688 //*************************************************************************************************
2689 //*************************************************************************************************
2690 //*************************************************************************************************
2691 // ReflectionSerialization
2692 //*************************************************************************************************
2693 //*************************************************************************************************
2694 //*************************************************************************************************
2695 FCIMPL1(Object*, ReflectionSerialization::GetUninitializedObject, ReflectClassBaseObject* objTypeUNSAFE) {
2698 OBJECTREF retVal = NULL;
2699 REFLECTCLASSBASEREF objType = (REFLECTCLASSBASEREF) objTypeUNSAFE;
2701 HELPER_METHOD_FRAME_BEGIN_RET_NOPOLL();
2703 if (objType == NULL) {
2704 COMPlusThrowArgumentNull(W("type"), W("ArgumentNull_Type"));
2707 TypeHandle type = objType->GetType();
2709 // Don't allow arrays, pointers, byrefs or function pointers.
2710 if (type.IsTypeDesc())
2711 COMPlusThrow(kArgumentException, W("Argument_InvalidValue"));
2713 MethodTable *pMT = type.GetMethodTable();
2714 PREFIX_ASSUME(pMT != NULL);
2716 //We don't allow unitialized strings.
2717 if (pMT == g_pStringClass) {
2718 COMPlusThrow(kArgumentException, W("Argument_NoUninitializedStrings"));
2721 // if this is an abstract class or an interface type then we will
2723 if (pMT->IsAbstract()) {
2724 COMPlusThrow(kMemberAccessException,W("Acc_CreateAbst"));
2727 if (pMT->ContainsGenericVariables()) {
2728 COMPlusThrow(kMemberAccessException,W("Acc_CreateGeneric"));
2731 if (pMT->IsByRefLike()) {
2732 COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike"));
2735 // Never allow allocation of generics actually instantiated over __Canon
2736 if (pMT->IsSharedByGenericInstantiations()) {
2737 COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
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.
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
2749 // If it is a nullable, return the underlying type instead.
2750 if (Nullable::IsNullableType(pMT))
2751 pMT = pMT->GetInstantiation()[0].GetMethodTable();
2753 retVal = pMT->Allocate();
2755 HELPER_METHOD_FRAME_END();
2756 return OBJECTREFToObject(retVal);
2760 //*************************************************************************************************
2761 //*************************************************************************************************
2762 //*************************************************************************************************
2764 //*************************************************************************************************
2765 //*************************************************************************************************
2766 //*************************************************************************************************
2768 FCIMPL1(Object *, ReflectionEnum::InternalGetEnumUnderlyingType, ReflectClassBaseObject *target) {
2771 VALIDATEOBJECT(target);
2772 TypeHandle th = target->GetType();
2774 FCThrowArgument(NULL, NULL);
2776 OBJECTREF result = NULL;
2778 HELPER_METHOD_FRAME_BEGIN_RET_0();
2779 MethodTable *pMT = MscorlibBinder::GetElementType(th.AsMethodTable()->GetInternalCorElementType());
2780 result = pMT->GetManagedClassObject();
2781 HELPER_METHOD_FRAME_END();
2783 return OBJECTREFToObject(result);
2787 FCIMPL1(INT32, ReflectionEnum::InternalGetCorElementType, Object *pRefThis) {
2790 VALIDATEOBJECT(pRefThis);
2791 if (pRefThis == NULL)
2792 FCThrowArgumentNull(NULL);
2794 return pRefThis->GetMethodTable()->GetInternalCorElementType();
2798 //*******************************************************************************
2799 struct TempEnumValue
2805 //*******************************************************************************
2806 class TempEnumValueSorter : public CQuickSort<TempEnumValue>
2809 TempEnumValueSorter(TempEnumValue *pArray, SSIZE_T iCount)
2810 : CQuickSort<TempEnumValue>(pArray, iCount) { LIMITED_METHOD_CONTRACT; }
2812 int Compare(TempEnumValue *pFirst, TempEnumValue *pSecond)
2814 LIMITED_METHOD_CONTRACT;
2816 if (pFirst->value == pSecond->value)
2818 if (pFirst->value > pSecond->value)
2825 void QCALLTYPE ReflectionEnum::GetEnumValuesAndNames(EnregisteredTypeHandle pEnumType, QCall::ObjectHandleOnStack pReturnValues, QCall::ObjectHandleOnStack pReturnNames, BOOL fGetNames)
2831 TypeHandle th = TypeHandle::FromPtr(pEnumType);
2834 COMPlusThrow(kArgumentException, W("Arg_MustBeEnum"));
2836 MethodTable *pMT = th.AsMethodTable();
2838 IMDInternalImport *pImport = pMT->GetMDImport();
2840 StackSArray<TempEnumValue> temps;
2841 UINT64 previousValue = 0;
2843 HENUMInternalHolder fieldEnum(pImport);
2844 fieldEnum.EnumInit(mdtFieldDef, pMT->GetCl());
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.
2853 CorElementType type = pMT->GetInternalCorElementType();
2856 while (pImport->EnumNext(&fieldEnum, &field))
2859 IfFailThrow(pImport->GetFieldDefProps(field, &dwFlags));
2860 if (IsFdStatic(dwFlags))
2865 IfFailThrow(pImport->GetNameOfFieldDef(field, &temp.name));
2869 MDDefaultValue defaultValue;
2870 IfFailThrow(pImport->GetDefaultValue(field, &defaultValue));
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;
2878 case ELEMENT_TYPE_I1:
2879 value = *((INT8 *)pValue);
2882 case ELEMENT_TYPE_U1:
2883 case ELEMENT_TYPE_BOOLEAN:
2884 value = *((UINT8 *)pValue);
2887 case ELEMENT_TYPE_I2:
2888 value = *((INT16 *)pValue);
2891 case ELEMENT_TYPE_U2:
2892 case ELEMENT_TYPE_CHAR:
2893 value = *((UINT16 *)pValue);
2896 case ELEMENT_TYPE_I4:
2897 IN_WIN32(case ELEMENT_TYPE_I:)
2898 value = *((INT32 *)pValue);
2901 case ELEMENT_TYPE_U4:
2902 IN_WIN32(case ELEMENT_TYPE_U:)
2903 value = *((UINT32 *)pValue);
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);
2920 // Check to see if we are already sorted. This may seem extraneous, but is
2921 // actually probably the normal case.
2924 if (previousValue > value)
2926 previousValue = value;
2932 TempEnumValue * pTemps = &(temps[0]);
2933 DWORD cFields = temps.GetCount();
2937 TempEnumValueSorter sorter(pTemps, cFields);
2951 GCPROTECT_BEGIN(gc);
2954 gc.values = (I8ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_U8, cFields);
2956 INT64 *pToValues = gc.values->GetDirectPointerToNonObjectElements();
2958 for (DWORD i = 0; i < cFields; i++) {
2959 pToValues[i] = pTemps[i].value;
2962 pReturnValues.Set(gc.values);
2967 gc.names = (PTRARRAYREF) AllocateObjectArray(cFields, g_pStringClass);
2969 for (DWORD i = 0; i < cFields; i++) {
2970 STRINGREF str = StringObject::NewString(pTemps[i].name);
2971 gc.names->SetAt(i, str);
2974 pReturnNames.Set(gc.names);
2983 FCIMPL2_IV(Object*, ReflectionEnum::InternalBoxEnum, ReflectClassBaseObject* target, INT64 value) {
2986 VALIDATEOBJECT(target);
2987 OBJECTREF ret = NULL;
2989 MethodTable* pMT = target->GetType().AsMethodTable();
2990 HELPER_METHOD_FRAME_BEGIN_RET_0();
2992 ret = pMT->Box(ArgSlotEndianessFixup((ARG_SLOT*)&value, pMT->GetNumInstanceFieldBytes()));
2994 HELPER_METHOD_FRAME_END();
2995 return OBJECTREFToObject(ret);
2999 //*************************************************************************************************
3000 //*************************************************************************************************
3001 //*************************************************************************************************
3003 //*************************************************************************************************
3004 //*************************************************************************************************
3005 //*************************************************************************************************
3007 FCIMPL2(FC_BOOL_RET, ReflectionBinder::DBCanConvertPrimitive, ReflectClassBaseObject* source, ReflectClassBaseObject* target) {
3010 VALIDATEOBJECT(source);
3011 VALIDATEOBJECT(target);
3013 CorElementType tSRC = source->GetType().GetSignatureCorElementType();
3014 CorElementType tTRG = target->GetType().GetSignatureCorElementType();
3016 FC_RETURN_BOOL(InvokeUtil::IsPrimitiveType(tTRG) && InvokeUtil::CanPrimitiveWiden(tTRG, tSRC));
3020 FCIMPL2(FC_BOOL_RET, ReflectionBinder::DBCanConvertObjectPrimitive, Object* sourceObj, ReflectClassBaseObject* target) {
3023 VALIDATEOBJECT(sourceObj);
3024 VALIDATEOBJECT(target);
3027 FC_RETURN_BOOL(true);
3029 TypeHandle th(sourceObj->GetMethodTable());
3030 CorElementType tSRC = th.GetVerifierCorElementType();
3032 CorElementType tTRG = target->GetType().GetSignatureCorElementType();
3033 FC_RETURN_BOOL(InvokeUtil::IsPrimitiveType(tTRG) && InvokeUtil::CanPrimitiveWiden(tTRG, tSRC));
3037 FCIMPL2(FC_BOOL_RET, ReflectionEnum::InternalEquals, Object *pRefThis, Object* pRefTarget)
3041 VALIDATEOBJECT(pRefThis);
3043 if (pRefTarget == NULL) {
3044 FC_RETURN_BOOL(ret);
3047 if( pRefThis == pRefTarget)
3048 FC_RETURN_BOOL(true);
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);
3057 void * pThis = pRefThis->UnBox();
3058 void * pTarget = pRefTarget->UnBox();
3059 switch (pMTThis->GetNumInstanceFieldBytes()) {
3061 ret = (*(UINT8*)pThis == *(UINT8*)pTarget);
3064 ret = (*(UINT16*)pThis == *(UINT16*)pTarget);
3067 ret = (*(UINT32*)pThis == *(UINT32*)pTarget);
3070 ret = (*(UINT64*)pThis == *(UINT64*)pTarget);
3073 // should not reach here.
3074 UNREACHABLE_MSG("Incorrect Enum Type size!");
3078 FC_RETURN_BOOL(ret);
3082 // preform (this & flags) != flags
3083 FCIMPL2(FC_BOOL_RET, ReflectionEnum::InternalHasFlag, Object *pRefThis, Object* pRefFlags)
3087 VALIDATEOBJECT(pRefThis);
3091 _ASSERTE(pRefFlags != NULL); // Enum.cs would have thrown ArgumentNullException before calling into InternalHasFlag
3093 VALIDATEOBJECT(pRefFlags);
3095 void * pThis = pRefThis->UnBox();
3096 void * pFlags = pRefFlags->UnBox();
3098 MethodTable* pMTThis = pRefThis->GetMethodTable();
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
3103 switch (pMTThis->GetNumInstanceFieldBytes()) {
3105 cmp = ((*(UINT8*)pThis & *(UINT8*)pFlags) == *(UINT8*)pFlags);
3108 cmp = ((*(UINT16*)pThis & *(UINT16*)pFlags) == *(UINT16*)pFlags);
3111 cmp = ((*(UINT32*)pThis & *(UINT32*)pFlags) == *(UINT32*)pFlags);
3114 cmp = ((*(UINT64*)pThis & *(UINT64*)pFlags) == *(UINT64*)pFlags);
3117 // should not reach here.
3118 UNREACHABLE_MSG("Incorrect Enum Type size!");
3122 FC_RETURN_BOOL(cmp);
3126 // compare two boxed enums using their underlying enum type
3127 FCIMPL2(int, ReflectionEnum::InternalCompareTo, Object *pRefThis, Object* pRefTarget)
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
3134 VALIDATEOBJECT(pRefThis);
3136 if (pRefTarget == NULL) {
3137 return 1; // all values are greater than null
3140 if( pRefThis == pRefTarget)
3143 VALIDATEOBJECT(pRefTarget);
3145 //Make sure we are comparing same type.
3146 MethodTable* pMTThis = pRefThis->GetMethodTable();
3148 _ASSERTE(pMTThis->IsEnum());
3150 if ( pMTThis != pRefTarget->GetMethodTable()) {
3151 return retIncompatibleMethodTables; // error case, types incompatible
3154 void * pThis = pRefThis->UnBox();
3155 void * pTarget = pRefTarget->UnBox();
3157 #define CMPEXPR(x1,x2) ((x1) == (x2)) ? 0 : ((x1) < (x2)) ? -1 : 1
3159 switch (pMTThis->GetInternalCorElementType()) {
3161 case ELEMENT_TYPE_I1:
3163 INT8 i1 = *(INT8*)pThis;
3164 INT8 i2 = *(INT8*)pTarget;
3166 return CMPEXPR(i1,i2);
3170 case ELEMENT_TYPE_I2:
3172 INT16 i1 = *(INT16*)pThis;
3173 INT16 i2 = *(INT16*)pTarget;
3175 return CMPEXPR(i1,i2);
3180 case ELEMENT_TYPE_I4:
3181 IN_WIN32(case ELEMENT_TYPE_I:)
3183 INT32 i1 = *(INT32*)pThis;
3184 INT32 i2 = *(INT32*)pTarget;
3186 return CMPEXPR(i1,i2);
3191 case ELEMENT_TYPE_I8:
3192 IN_WIN64(case ELEMENT_TYPE_I:)
3194 INT64 i1 = *(INT64*)pThis;
3195 INT64 i2 = *(INT64*)pTarget;
3197 return CMPEXPR(i1,i2);
3201 case ELEMENT_TYPE_BOOLEAN:
3203 bool b1 = !!*(UINT8 *)pThis;
3204 bool b2 = !!*(UINT8 *)pTarget;
3206 return CMPEXPR(b1,b2);
3210 case ELEMENT_TYPE_U1:
3212 UINT8 u1 = *(UINT8 *)pThis;
3213 UINT8 u2 = *(UINT8 *)pTarget;
3215 return CMPEXPR(u1,u2);
3219 case ELEMENT_TYPE_U2:
3220 case ELEMENT_TYPE_CHAR:
3222 UINT16 u1 = *(UINT16 *)pThis;
3223 UINT16 u2 = *(UINT16 *)pTarget;
3225 return CMPEXPR(u1,u2);
3229 case ELEMENT_TYPE_U4:
3230 IN_WIN32(case ELEMENT_TYPE_U:)
3232 UINT32 u1 = *(UINT32 *)pThis;
3233 UINT32 u2 = *(UINT32 *)pTarget;
3235 return CMPEXPR(u1,u2);
3239 case ELEMENT_TYPE_U8:
3240 IN_WIN64(case ELEMENT_TYPE_U:)
3242 UINT64 u1 = *(UINT64*)pThis;
3243 UINT64 u2 = *(UINT64*)pTarget;
3245 return CMPEXPR(u1,u2);
3249 case ELEMENT_TYPE_R4:
3251 static_assert_no_msg(sizeof(float) == 4);
3253 float f1 = *(float*)pThis;
3254 float f2 = *(float*)pTarget;
3256 return CMPEXPR(f1,f2);
3260 case ELEMENT_TYPE_R8:
3262 static_assert_no_msg(sizeof(double) == 8);
3264 double d1 = *(double*)pThis;
3265 double d2 = *(double*)pTarget;
3267 return CMPEXPR(d1,d2);
3275 return retInvalidEnumType; // second error case -- unsupported enum type