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