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 ** File: callhelpers.h 7 ** Purpose: Provides helpers for making managed calls 8 ** 9 10 ===========================================================*/ 11 #ifndef __CALLHELPERS_H__ 12 #define __CALLHELPERS_H__ 13 14 struct CallDescrData 15 { 16 // 17 // Input arguments 18 // 19 LPVOID pSrc; 20 UINT32 numStackSlots; 21 #ifdef CALLDESCR_ARGREGS 22 const ArgumentRegisters * pArgumentRegisters; 23 #endif 24 #ifdef CALLDESCR_FPARGREGS 25 const FloatArgumentRegisters * pFloatArgumentRegisters; 26 #endif 27 #ifdef CALLDESCR_REGTYPEMAP 28 UINT64 dwRegTypeMap; 29 #endif 30 UINT32 fpReturnSize; 31 PCODE pTarget; 32 33 // 34 // Return value 35 // 36 #ifdef ENREGISTERED_RETURNTYPE_MAXSIZE 37 // Use UINT64 to ensure proper alignment 38 UINT64 returnValue[ENREGISTERED_RETURNTYPE_MAXSIZE / sizeof(UINT64)]; 39 #else 40 UINT64 returnValue; 41 #endif 42 }; 43 44 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) 45 46 extern "C" void STDCALL CallDescrWorkerInternal(CallDescrData * pCallDescrData); 47 48 #if !defined(_WIN64) && defined(_DEBUG) 49 void CallDescrWorker(CallDescrData * pCallDescrData); 50 #else 51 #define CallDescrWorker(pCallDescrData) CallDescrWorkerInternal(pCallDescrData) 52 #endif 53 54 void CallDescrWorkerWithHandler( 55 CallDescrData * pCallDescrData, 56 BOOL fCriticalCall = FALSE); 57 58 void DispatchCall( 59 CallDescrData * pCallDescrData, 60 OBJECTREF * pRefException, 61 ContextTransitionFrame* pFrame = NULL 62 #ifdef FEATURE_CORRUPTING_EXCEPTIONS 63 , CorruptionSeverity * pSeverity = NULL 64 #endif // FEATURE_CORRUPTING_EXCEPTIONS 65 ); 66 67 // Helper for VM->managed calls with simple signatures. 68 void * DispatchCallSimple( 69 SIZE_T *pSrc, 70 DWORD numStackSlotsToCopy, 71 PCODE pTargetAddress, 72 DWORD dwDispatchCallSimpleFlags); 73 74 bool IsCerRootMethod(MethodDesc *pMD); 75 76 class MethodDescCallSite 77 { 78 private: 79 MethodDesc* m_pMD; 80 PCODE m_pCallTarget; 81 MetaSig m_methodSig; 82 ArgIterator m_argIt; 83 84 #ifdef _DEBUG LogWeakAssert()85 __declspec(noinline) void LogWeakAssert() 86 { 87 LIMITED_METHOD_CONTRACT; 88 LOG((LF_ASSERT, LL_WARNING, "%s::%s\n", m_pMD->m_pszDebugClassName, m_pMD->m_pszDebugMethodName)); 89 } 90 #endif // _DEBUG 91 DefaultInit(OBJECTREF * porProtectedThis)92 void DefaultInit(OBJECTREF* porProtectedThis) 93 { 94 CONTRACTL 95 { 96 MODE_ANY; 97 GC_TRIGGERS; 98 THROWS; 99 } 100 CONTRACTL_END; 101 102 #ifdef _DEBUG 103 // 104 // Make sure we are passing in a 'this' if and only if it is required 105 // 106 if (m_pMD->IsVtableMethod()) 107 { 108 CONSISTENCY_CHECK_MSG(NULL != porProtectedThis, "You did not pass in the 'this' object for a vtable method"); 109 } 110 else 111 { 112 if (NULL != porProtectedThis) 113 { 114 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AssertOnUnneededThis)) 115 { 116 CONSISTENCY_CHECK_MSG(NULL == porProtectedThis, "You passed in a 'this' object to a non-vtable method."); 117 } 118 else 119 { 120 LogWeakAssert(); 121 } 122 123 } 124 } 125 #endif // _DEBUG 126 127 m_pCallTarget = m_pMD->GetCallTarget(porProtectedThis); 128 129 m_argIt.ForceSigWalk(); 130 } 131 132 #ifdef FEATURE_INTERPRETER 133 public: 134 ARG_SLOT CallTargetWorker(const ARG_SLOT *pArguments, bool transitionToPreemptive = false); 135 #else 136 ARG_SLOT CallTargetWorker(const ARG_SLOT *pArguments); 137 #endif 138 139 public: 140 // Used to avoid touching metadata for mscorlib methods. 141 // instance methods must pass in the 'this' object 142 // static methods must pass null 143 MethodDescCallSite(BinderMethodID id, OBJECTREF* porProtectedThis = NULL) : m_pMD(MscorlibBinder::GetMethod (id))144 m_pMD( 145 MscorlibBinder::GetMethod(id) 146 ), 147 m_methodSig(id), 148 m_argIt(&m_methodSig) 149 { 150 CONTRACTL 151 { 152 THROWS; 153 GC_TRIGGERS; 154 MODE_COOPERATIVE; 155 } 156 CONTRACTL_END; 157 DefaultInit(porProtectedThis); 158 } 159 160 // Used to avoid touching metadata for mscorlib methods. 161 // instance methods must pass in the 'this' object 162 // static methods must pass null MethodDescCallSite(BinderMethodID id,OBJECTHANDLE hThis)163 MethodDescCallSite(BinderMethodID id, OBJECTHANDLE hThis) : 164 m_pMD( 165 MscorlibBinder::GetMethod(id) 166 ), 167 m_methodSig(id), 168 m_argIt(&m_methodSig) 169 { 170 WRAPPER_NO_CONTRACT; 171 172 DefaultInit((OBJECTREF*)hThis); 173 } 174 175 // instance methods must pass in the 'this' object 176 // static methods must pass null 177 MethodDescCallSite(MethodDesc* pMD, OBJECTREF* porProtectedThis = NULL) : m_pMD(pMD)178 m_pMD(pMD), 179 m_methodSig(pMD), 180 m_argIt(&m_methodSig) 181 { 182 CONTRACTL 183 { 184 THROWS; 185 GC_TRIGGERS; 186 MODE_COOPERATIVE; 187 } 188 CONTRACTL_END; 189 190 if (porProtectedThis == NULL) 191 { 192 // We don't have a "this" pointer - ensure that we have activated the containing module 193 m_pMD->EnsureActive(); 194 } 195 196 DefaultInit(porProtectedThis); 197 } 198 199 // instance methods must pass in the 'this' object 200 // static methods must pass null MethodDescCallSite(MethodDesc * pMD,OBJECTHANDLE hThis)201 MethodDescCallSite(MethodDesc* pMD, OBJECTHANDLE hThis) : 202 m_pMD(pMD), 203 m_methodSig(pMD), 204 m_argIt(&m_methodSig) 205 { 206 WRAPPER_NO_CONTRACT; 207 208 if (hThis == NULL) 209 { 210 // We don't have a "this" pointer - ensure that we have activated the containing module 211 m_pMD->EnsureActive(); 212 } 213 214 DefaultInit((OBJECTREF*)hThis); 215 } 216 217 // instance methods must pass in the 'this' object 218 // static methods must pass null 219 MethodDescCallSite(MethodDesc* pMD, LPHARDCODEDMETASIG pwzSignature, OBJECTREF* porProtectedThis = NULL) : m_pMD(pMD)220 m_pMD(pMD), 221 m_methodSig(pwzSignature), 222 m_argIt(&m_methodSig) 223 { 224 WRAPPER_NO_CONTRACT; 225 226 if (porProtectedThis == NULL) 227 { 228 // We don't have a "this" pointer - ensure that we have activated the containing module 229 m_pMD->EnsureActive(); 230 } 231 232 DefaultInit(porProtectedThis); 233 } 234 235 // 236 // Only use this constructor if you're certain you know where 237 // you're going and it cannot be affected by generics/virtual 238 // dispatch/etc.. 239 // MethodDescCallSite(MethodDesc * pMD,PCODE pCallTarget)240 MethodDescCallSite(MethodDesc* pMD, PCODE pCallTarget) : 241 m_pMD(pMD), 242 m_pCallTarget(pCallTarget), 243 m_methodSig(pMD), 244 m_argIt(&m_methodSig) 245 { 246 CONTRACTL 247 { 248 THROWS; 249 GC_TRIGGERS; 250 MODE_ANY; 251 } 252 CONTRACTL_END; 253 254 m_pMD->EnsureActive(); 255 256 m_argIt.ForceSigWalk(); 257 } 258 259 #ifdef FEATURE_INTERPRETER MethodDescCallSite(MethodDesc * pMD,MetaSig * pSig,PCODE pCallTarget)260 MethodDescCallSite(MethodDesc* pMD, MetaSig* pSig, PCODE pCallTarget) : 261 m_pMD(pMD), 262 m_pCallTarget(pCallTarget), 263 m_methodSig(*pSig), 264 m_argIt(pSig) 265 { 266 CONTRACTL 267 { 268 THROWS; 269 GC_TRIGGERS; 270 MODE_ANY; 271 } 272 CONTRACTL_END; 273 274 m_pMD->EnsureActive(); 275 276 m_argIt.ForceSigWalk(); 277 } 278 #endif // FEATURE_INTERPRETER 279 GetMetaSig()280 MetaSig* GetMetaSig() 281 { 282 return &m_methodSig; 283 } 284 285 // 286 // Call_RetXXX definition macros: 287 // 288 // These macros provide type protection for the return value from calls to managed 289 // code. This should help to prevent errors like what we're seeing on 64bit where 290 // the JIT64 is returning the BOOL as 1byte with the rest of the ARG_SLOT still 291 // polluted by the remnants of its last value. Previously we would cast to a (BOOL) 292 // and end up having if((BOOL)pMD->Call(...)) statements always being true. 293 // 294 295 // Use OTHER_ELEMENT_TYPE when defining CallXXX_RetXXX variations where the return type 296 // is not in CorElementType (like LPVOID) or the return type can be one of a number of 297 // CorElementTypes, like XXX_RetObjPtr which is used for all kinds of Object* return 298 // types, or XXX_RetArgSlot which is unspecified. 299 #define OTHER_ELEMENT_TYPE -1 300 301 // Note "permitvaluetypes" is not really used for anything 302 #define MDCALLDEF(wrappedmethod, permitvaluetypes, ext, rettype, eltype) \ 303 FORCEINLINE rettype wrappedmethod##ext (const ARG_SLOT* pArguments) \ 304 { \ 305 WRAPPER_NO_CONTRACT; \ 306 { \ 307 GCX_FORBID(); /* arg array is not protected */ \ 308 CONSISTENCY_CHECK(eltype == OTHER_ELEMENT_TYPE || \ 309 eltype == m_methodSig.GetReturnType()); \ 310 } \ 311 ARG_SLOT retval; \ 312 retval = CallTargetWorker(pArguments); \ 313 return *(rettype *)ArgSlotEndianessFixup(&retval, sizeof(rettype)); \ 314 } 315 316 #define MDCALLDEF_REFTYPE(wrappedmethod, permitvaluetypes, ext, ptrtype, reftype) \ 317 FORCEINLINE reftype wrappedmethod##ext (const ARG_SLOT* pArguments) \ 318 { \ 319 WRAPPER_NO_CONTRACT; \ 320 { \ 321 GCX_FORBID(); /* arg array is not protected */ \ 322 CONSISTENCY_CHECK(MetaSig::RETOBJ == m_pMD->ReturnsObject(true)); \ 323 } \ 324 ARG_SLOT retval; \ 325 retval = CallTargetWorker(pArguments); \ 326 return ObjectTo##reftype(*(ptrtype *) \ 327 ArgSlotEndianessFixup(&retval, sizeof(ptrtype))); \ 328 } 329 330 331 // The MDCALLDEF_XXX_VOID macros take a customized assertion and calls the worker without 332 // returning a value, this is the macro that _should_ be used to define the CallXXX variations 333 // (without _RetXXX extension) so that misuse will be caught at compile time. 334 335 #define MDCALLDEF_VOID(wrappedmethod, permitvaluetypes) \ 336 FORCEINLINE void wrappedmethod (const ARG_SLOT* pArguments) \ 337 { \ 338 WRAPPER_NO_CONTRACT; \ 339 CallTargetWorker(pArguments); \ 340 } 341 342 #define MDCALLDEFF_STD_RETTYPES(wrappedmethod,permitvaluetypes) \ 343 MDCALLDEF_VOID(wrappedmethod,permitvaluetypes) \ 344 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetBool, CLR_BOOL, ELEMENT_TYPE_BOOLEAN) \ 345 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetChar, CLR_CHAR, ELEMENT_TYPE_CHAR) \ 346 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetI1, CLR_I1, ELEMENT_TYPE_I1) \ 347 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetU1, CLR_U1, ELEMENT_TYPE_U1) \ 348 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetI2, CLR_I2, ELEMENT_TYPE_I2) \ 349 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetU2, CLR_U2, ELEMENT_TYPE_U2) \ 350 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetI4, CLR_I4, ELEMENT_TYPE_I4) \ 351 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetU4, CLR_U4, ELEMENT_TYPE_U4) \ 352 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetI8, CLR_I8, ELEMENT_TYPE_I8) \ 353 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetU8, CLR_U8, ELEMENT_TYPE_U8) \ 354 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetR4, CLR_R4, ELEMENT_TYPE_R4) \ 355 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetR8, CLR_R8, ELEMENT_TYPE_R8) \ 356 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetI, CLR_I, ELEMENT_TYPE_I) \ 357 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetU, CLR_U, ELEMENT_TYPE_U) \ 358 MDCALLDEF(wrappedmethod,permitvaluetypes, _RetArgSlot,ARG_SLOT, OTHER_ELEMENT_TYPE) 359 360 361 public: 362 //-------------------------------------------------------------------- 363 // Invoke a method. Arguments are packaged up in right->left order 364 // which each array element corresponding to one argument. 365 // 366 // Can throw a COM+ exception. 367 // 368 // All the appropriate "virtual" semantics (include thunking like context 369 // proxies) occurs inside Call. 370 // 371 // Call should never be called on interface MethodDesc's. The exception 372 // to this rule is when calling on a COM object. In that case the call 373 // needs to go through an interface MD and CallOnInterface is there 374 // for that. 375 //-------------------------------------------------------------------- 376 377 // 378 // NOTE on Call methods 379 // MethodDesc::Call uses a virtual portable calling convention 380 // Arguments are put left-to-right in the ARG_SLOT array, in the following order: 381 // - this pointer (if any) 382 // - return buffer address (if signature.HasRetBuffArg()) 383 // - all other fixed arguments (left-to-right) 384 // Vararg is not supported yet. 385 // 386 // The args that fit in an ARG_SLOT are inline. The ones that don't fit in an ARG_SLOT are allocated somewhere else 387 // (usually on the stack) and a pointer to that area is put in the corresponding ARG_SLOT 388 // ARG_SLOT is guaranteed to be big enough to fit all basic types and pointer types. Basically, one has 389 // to check only for aggregate value-types and 80-bit floating point values or greater. 390 // 391 // Calls with value type parameters must use the CallXXXWithValueTypes 392 // variants. Using the WithValueTypes variant indicates that the caller 393 // has gc-protected the contents of value types of size greater than 394 // ENREGISTERED_PARAMTYPE_MAXSIZE (when it is defined, which is currently 395 // only on AMD64). ProtectValueClassFrame can be used to accomplish this, 396 // see CallDescrWithObjectArray in stackbuildersink.cpp. 397 // 398 // Not all usages of MethodDesc::CallXXX have been ported to the new convention. The end goal is to port them all and get 399 // rid of the non-portable BYTE* version. 400 // 401 // We have converted all usage of CallXXX in the runtime to some more specific CallXXX_RetXXX type (CallXXX usages 402 // where the return value is unused remain CallXXX). In most cases we were able to use something more specific than 403 // CallXXX_RetArgSlot (which is the equivalent of the old behavior). It is recommended that as you add usages of 404 // CallXXX in the future you try to avoid CallXXX_RetArgSlot whenever possible. 405 // 406 // If the return value is unused you can use the CallXXX syntax which has a void return and is not protected 407 // by any assertions around the return value type. This should protect against people trying to use the old 408 // semantics of ->Call as if they try to assign the return value to something they'll get a compile time error. 409 // 410 // If you are unable to be sure of the return type at runtime and are just blindly casting then continue to use 411 // CallXXX_RetArgSlot, Do not for instance use CallXXX_RetI4 as a mechanism to cast the result to an I4 as it will 412 // also try to assert the fact that the callee managed method actually does return an I4. 413 // 414 415 // All forms of CallXXX should have at least the CallXXX_RetArgSlot definition which maps to the old behavior 416 // - MDCALL_ARG_____STD_RETTYPES includes CallXXX_RetArgSlot 417 // - MDCALL_ARG_SIG_STD_RETTYPES includes CallXXX_RetArgSlot 418 419 // XXX Call_RetXXX(const ARG_SLOT* pArguments); 420 MDCALLDEFF_STD_RETTYPES(Call, FALSE) 421 MDCALLDEF( Call, FALSE, _RetHR, HRESULT, OTHER_ELEMENT_TYPE) 422 MDCALLDEF( Call, FALSE, _RetObjPtr, Object*, OTHER_ELEMENT_TYPE) 423 MDCALLDEF_REFTYPE( Call, FALSE, _RetOBJECTREF, Object*, OBJECTREF) 424 MDCALLDEF_REFTYPE( Call, FALSE, _RetSTRINGREF, StringObject*, STRINGREF) 425 MDCALLDEF( Call, FALSE, _RetLPVOID, LPVOID, OTHER_ELEMENT_TYPE) 426 427 // XXX CallWithValueTypes_RetXXX(const ARG_SLOT* pArguments); 428 MDCALLDEF_VOID( CallWithValueTypes, TRUE) 429 MDCALLDEF( CallWithValueTypes, TRUE, _RetArgSlot, ARG_SLOT, OTHER_ELEMENT_TYPE) 430 MDCALLDEF_REFTYPE( CallWithValueTypes, TRUE, _RetOBJECTREF, Object*, OBJECTREF) 431 MDCALLDEF( CallWithValueTypes, TRUE, _RetOleColor, OLE_COLOR, OTHER_ELEMENT_TYPE) 432 #undef OTHER_ELEMENT_TYPE 433 #undef MDCALL_ARG_SIG_STD_RETTYPES 434 #undef MDCALLDEF 435 #undef MDCALLDEF_REFTYPE 436 #undef MDCALLDEF_VOID 437 }; // MethodDescCallSite 438 439 440 #ifdef CALLDESCR_REGTYPEMAP 441 void FillInRegTypeMap(int argOffset, CorElementType typ, BYTE * pMap); 442 #endif // CALLDESCR_REGTYPEMAP 443 444 445 /***********************************************************************/ 446 /* Macros used to indicate a call to managed code is starting/ending */ 447 /***********************************************************************/ 448 449 enum EEToManagedCallFlags 450 { 451 EEToManagedDefault = 0x0000, 452 EEToManagedCriticalCall = 0x0001, 453 }; 454 455 #define BEGIN_CALL_TO_MANAGED() \ 456 BEGIN_CALL_TO_MANAGEDEX(EEToManagedDefault) 457 458 #define BEGIN_CALL_TO_MANAGEDEX(flags) \ 459 { \ 460 MAKE_CURRENT_THREAD_AVAILABLE(); \ 461 DECLARE_CPFH_EH_RECORD(CURRENT_THREAD); \ 462 _ASSERTE(CURRENT_THREAD); \ 463 _ASSERTE(!CURRENT_THREAD->IsAbortPrevented() || \ 464 CURRENT_THREAD->IsAbortCheckDisabled()); \ 465 _ASSERTE((CURRENT_THREAD->m_StateNC & Thread::TSNC_OwnsSpinLock) == 0); \ 466 /* This bit should never be set when we call into managed code. The */ \ 467 /* stack walking code explicitly clears this around any potential calls */ \ 468 /* into managed code. */ \ 469 _ASSERTE(!IsStackWalkerThread()); \ 470 /* If this isn't a critical transition, we need to check to see if a */ \ 471 /* thread abort has been requested */ \ 472 if (!(flags & EEToManagedCriticalCall)) \ 473 { \ 474 TESTHOOKCALL(AppDomainCanBeUnloaded(CURRENT_THREAD->GetDomain()->GetId().m_dwId,FALSE)); \ 475 if (CURRENT_THREAD->IsAbortRequested()) { \ 476 CURRENT_THREAD->HandleThreadAbort(); \ 477 } \ 478 } \ 479 BEGIN_SO_TOLERANT_CODE(CURRENT_THREAD); \ 480 INSTALL_COMPLUS_EXCEPTION_HANDLER_NO_DECLARE(); 481 482 #define END_CALL_TO_MANAGED() \ 483 UNINSTALL_COMPLUS_EXCEPTION_HANDLER(); \ 484 END_SO_TOLERANT_CODE; \ 485 } 486 487 /***********************************************************************/ 488 /* Macros that provide abstraction to the usage of DispatchCallSimple */ 489 /***********************************************************************/ 490 491 enum DispatchCallSimpleFlags 492 { 493 DispatchCallSimple_CriticalCall = 0x0001, 494 DispatchCallSimple_CatchHandlerFoundNotification = 0x0002, 495 }; 496 497 #define ARGHOLDER_TYPE LPVOID 498 #define OBJECTREF_TO_ARGHOLDER(x) (LPVOID)OBJECTREFToObject(x) 499 #define STRINGREF_TO_ARGHOLDER(x) (LPVOID)STRINGREFToObject(x) 500 #define PTR_TO_ARGHOLDER(x) (LPVOID)x 501 #define DWORD_TO_ARGHOLDER(x) (LPVOID)(SIZE_T)x 502 503 #define INIT_VARIABLES(count) \ 504 DWORD __numArgs = count; \ 505 DWORD __dwDispatchCallSimpleFlags = 0; \ 506 507 #define PREPARE_NONVIRTUAL_CALLSITE(id) \ 508 static PCODE s_pAddr##id = NULL; \ 509 PCODE __pSlot = VolatileLoad(&s_pAddr##id); \ 510 if ( __pSlot == NULL ) \ 511 { \ 512 MethodDesc *pMeth = MscorlibBinder::GetMethod(id); \ 513 _ASSERTE(pMeth); \ 514 __pSlot = pMeth->GetMultiCallableAddrOfCode(); \ 515 VolatileStore(&s_pAddr##id, __pSlot); \ 516 } 517 518 #define PREPARE_VIRTUAL_CALLSITE(id, objref) \ 519 MethodDesc *__pMeth = MscorlibBinder::GetMethod(id); \ 520 PCODE __pSlot = __pMeth->GetCallTarget(&objref); 521 522 #define PREPARE_VIRTUAL_CALLSITE_USING_METHODDESC(pMD, objref) \ 523 PCODE __pSlot = pMD->GetCallTarget(&objref); 524 525 #ifdef _DEBUG 526 #define SIMPLE_VIRTUAL_METHOD_CHECK(slotNumber, methodTable) \ 527 { \ 528 MethodDesc* __pMeth = methodTable->GetMethodDescForSlot(slotNumber); \ 529 _ASSERTE(__pMeth); \ 530 _ASSERTE(!__pMeth->HasMethodInstantiation() && \ 531 !__pMeth->GetMethodTable()->IsInterface()); \ 532 } 533 #else 534 #define SIMPLE_VIRTUAL_METHOD_CHECK(slotNumber, objref) 535 #endif 536 537 // a simple virtual method is a non-interface/non-generic method 538 // Note: objref has to be protected! 539 #define PREPARE_SIMPLE_VIRTUAL_CALLSITE(id, objref) \ 540 static WORD s_slot##id = MethodTable::NO_SLOT; \ 541 WORD __slot = VolatileLoad(&s_slot##id); \ 542 if (__slot == MethodTable::NO_SLOT) \ 543 { \ 544 MethodDesc *pMeth = MscorlibBinder::GetMethod(id); \ 545 _ASSERTE(pMeth); \ 546 __slot = pMeth->GetSlot(); \ 547 VolatileStore(&s_slot##id, __slot); \ 548 } \ 549 PREPARE_SIMPLE_VIRTUAL_CALLSITE_USING_SLOT(__slot, objref) \ 550 551 // a simple virtual method is a non-interface/non-generic method 552 #define PREPARE_SIMPLE_VIRTUAL_CALLSITE_USING_SLOT(slotNumber, objref) \ 553 MethodTable* __pObjMT = (objref)->GetMethodTable(); \ 554 SIMPLE_VIRTUAL_METHOD_CHECK(slotNumber, __pObjMT); \ 555 PCODE __pSlot = (PCODE) __pObjMT->GetRestoredSlot(slotNumber); 556 557 #define PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pMD) \ 558 PCODE __pSlot = (pMD)->GetSingleCallableAddrOfCode(); 559 560 #define PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode) \ 561 PCODE __pSlot = pCode; 562 563 #define CRITICAL_CALLSITE \ 564 __dwDispatchCallSimpleFlags |= DispatchCallSimple_CriticalCall; 565 566 // This flag should be used for callsites that catch exception up the stack inside the VM. The most common causes are 567 // such as END_DOMAIN_TRANSITION or EX_CATCH. Catching exceptions in the managed code is properly instrumented and 568 // does not need this notification. 569 // 570 // The notification is what enables both the managed �unhandled exception� dialog and the �user unhandled� dialog when 571 // JMC is turned on. Many things that VS puts up the unhandled exception dialog for are actually cases where the native 572 // exception was caught, for example catching exceptions at the thread base. JMC requires further accuracy - in that case 573 // VS is checking to see if an exception escaped particular ranges of managed code frames. 574 #define CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE \ 575 __dwDispatchCallSimpleFlags |= DispatchCallSimple_CatchHandlerFoundNotification; 576 577 #define PERFORM_CALL \ 578 void * __retval = NULL; \ 579 __retval = DispatchCallSimple(__pArgs, \ 580 __numStackSlotsToCopy, \ 581 __pSlot, \ 582 __dwDispatchCallSimpleFlags);\ 583 584 #ifdef CALLDESCR_ARGREGS 585 586 #if defined(_TARGET_X86_) 587 588 // Arguments on x86 are passed backward 589 #define ARGNUM_0 1 590 #define ARGNUM_1 0 591 #define ARGNUM_N(n) __numArgs - n + 1 592 593 #else 594 595 #define ARGNUM_0 0 596 #define ARGNUM_1 1 597 #define ARGNUM_N(n) n 598 599 #endif 600 601 #define PRECALL_PREP(args) \ 602 DWORD __numStackSlotsToCopy = (__numArgs > NUM_ARGUMENT_REGISTERS) ? (__numArgs - NUM_ARGUMENT_REGISTERS) : 0; \ 603 SIZE_T * __pArgs = (SIZE_T *)args; 604 605 #define DECLARE_ARGHOLDER_ARRAY(arg, count) \ 606 INIT_VARIABLES(count) \ 607 ARGHOLDER_TYPE arg[(count <= NUM_ARGUMENT_REGISTERS ? NUM_ARGUMENT_REGISTERS : count)]; 608 609 #else // CALLDESCR_ARGREGS 610 611 #define ARGNUM_0 0 612 #define ARGNUM_1 1 613 #define ARGNUM_N(n) n 614 615 #define PRECALL_PREP(args) \ 616 DWORD __numStackSlotsToCopy = (__numArgs > NUM_ARGUMENT_REGISTERS) ? __numArgs : NUM_ARGUMENT_REGISTERS; \ 617 SIZE_T * __pArgs = (SIZE_T *)args; 618 619 #define DECLARE_ARGHOLDER_ARRAY(arg, count) \ 620 INIT_VARIABLES(count) \ 621 ARGHOLDER_TYPE arg[(count <= NUM_ARGUMENT_REGISTERS ? NUM_ARGUMENT_REGISTERS : count)]; 622 623 #endif // CALLDESCR_ARGREGS 624 625 626 #define CALL_MANAGED_METHOD(ret, rettype, args) \ 627 PRECALL_PREP(args) \ 628 PERFORM_CALL \ 629 ret = *(rettype *)(&__retval); 630 631 #define CALL_MANAGED_METHOD_NORET(args) \ 632 PRECALL_PREP(args) \ 633 PERFORM_CALL 634 635 #define CALL_MANAGED_METHOD_RETREF(ret, reftype, args) \ 636 PRECALL_PREP(args) \ 637 PERFORM_CALL \ 638 ret = (reftype)ObjectToOBJECTREF((Object *)__retval); 639 640 #define ARGNUM_2 ARGNUM_N(2) 641 #define ARGNUM_3 ARGNUM_N(3) 642 #define ARGNUM_4 ARGNUM_N(4) 643 #define ARGNUM_5 ARGNUM_N(5) 644 #define ARGNUM_6 ARGNUM_N(6) 645 #define ARGNUM_7 ARGNUM_N(7) 646 #define ARGNUM_8 ARGNUM_N(8) 647 648 649 void CallDefaultConstructor(OBJECTREF ref); 650 651 #endif //!DACCESS_COMPILE && !CROSSGEN_COMPILE 652 653 #endif // __CALLHELPERS_H__ 654