| 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 | // FRAMES.CPP | 
|---|
| 5 |  | 
|---|
| 6 |  | 
|---|
| 7 |  | 
|---|
| 8 | #include "common.h" | 
|---|
| 9 | #include "log.h" | 
|---|
| 10 | #include "frames.h" | 
|---|
| 11 | #include "threads.h" | 
|---|
| 12 | #include "object.h" | 
|---|
| 13 | #include "method.hpp" | 
|---|
| 14 | #include "class.h" | 
|---|
| 15 | #include "excep.h" | 
|---|
| 16 | #include "stublink.h" | 
|---|
| 17 | #include "fieldmarshaler.h" | 
|---|
| 18 | #include "siginfo.hpp" | 
|---|
| 19 | #include "gcheaputilities.h" | 
|---|
| 20 | #include "dllimportcallback.h" | 
|---|
| 21 | #include "stackwalk.h" | 
|---|
| 22 | #include "dbginterface.h" | 
|---|
| 23 | #include "gms.h" | 
|---|
| 24 | #include "eeconfig.h" | 
|---|
| 25 | #include "ecall.h" | 
|---|
| 26 | #include "clsload.hpp" | 
|---|
| 27 | #include "cgensys.h" | 
|---|
| 28 | #include "virtualcallstub.h" | 
|---|
| 29 | #include "mdaassistants.h" | 
|---|
| 30 | #include "dllimport.h" | 
|---|
| 31 | #include "gcrefmap.h" | 
|---|
| 32 | #include "asmconstants.h" | 
|---|
| 33 |  | 
|---|
| 34 | #ifdef FEATURE_COMINTEROP | 
|---|
| 35 | #include "comtoclrcall.h" | 
|---|
| 36 | #endif // FEATURE_COMINTEROP | 
|---|
| 37 |  | 
|---|
| 38 | #ifdef FEATURE_INTERPRETER | 
|---|
| 39 | #include "interpreter.h" | 
|---|
| 40 | #endif // FEATURE_INTERPRETER | 
|---|
| 41 |  | 
|---|
| 42 | #include "argdestination.h" | 
|---|
| 43 |  | 
|---|
| 44 | #define CHECK_APP_DOMAIN    0 | 
|---|
| 45 |  | 
|---|
| 46 | //----------------------------------------------------------------------- | 
|---|
| 47 | #if _DEBUG | 
|---|
| 48 | //----------------------------------------------------------------------- | 
|---|
| 49 |  | 
|---|
| 50 | #ifndef DACCESS_COMPILE | 
|---|
| 51 |  | 
|---|
| 52 | unsigned dbgStubCtr = 0; | 
|---|
| 53 | unsigned dbgStubTrip = 0xFFFFFFFF; | 
|---|
| 54 |  | 
|---|
| 55 | void Frame::Log() { | 
|---|
| 56 | WRAPPER_NO_CONTRACT; | 
|---|
| 57 |  | 
|---|
| 58 | if (!LoggingOn(LF_STUBS, LL_INFO1000000)) | 
|---|
| 59 | return; | 
|---|
| 60 |  | 
|---|
| 61 | dbgStubCtr++; | 
|---|
| 62 | if (dbgStubCtr > dbgStubTrip) { | 
|---|
| 63 | dbgStubCtr++;      // basicly a nop to put a breakpoint on. | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | MethodDesc* method = GetFunction(); | 
|---|
| 67 |  | 
|---|
| 68 | #ifdef _TARGET_X86_ | 
|---|
| 69 | if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr()) | 
|---|
| 70 | method = ((UMThkCallFrame*) this)->GetUMEntryThunk()->GetMethod(); | 
|---|
| 71 | #endif | 
|---|
| 72 |  | 
|---|
| 73 | STRESS_LOG3(LF_STUBS, LL_INFO1000000, "STUBS: In Stub with Frame %p assoc Method %pM FrameType = %pV\n", this, method, *((void**) this)); | 
|---|
| 74 |  | 
|---|
| 75 | char buff[64]; | 
|---|
| 76 | const char* frameType; | 
|---|
| 77 | if (GetVTablePtr() == PrestubMethodFrame::GetMethodFrameVPtr()) | 
|---|
| 78 | frameType = "PreStub"; | 
|---|
| 79 | #ifdef _TARGET_X86_ | 
|---|
| 80 | else if (GetVTablePtr() == UMThkCallFrame::GetMethodFrameVPtr()) | 
|---|
| 81 | frameType = "UMThkCallFrame"; | 
|---|
| 82 | #endif | 
|---|
| 83 | else if (GetVTablePtr() == PInvokeCalliFrame::GetMethodFrameVPtr()) | 
|---|
| 84 | { | 
|---|
| 85 | sprintf_s(buff, COUNTOF(buff), "PInvoke CALLI target"FMT_ADDR, | 
|---|
| 86 | DBG_ADDR(((PInvokeCalliFrame*)this)->GetPInvokeCalliTarget())); | 
|---|
| 87 | frameType = buff; | 
|---|
| 88 | } | 
|---|
| 89 | else if (GetVTablePtr() == StubDispatchFrame::GetMethodFrameVPtr()) | 
|---|
| 90 | frameType = "StubDispatch"; | 
|---|
| 91 | else if (GetVTablePtr() == ExternalMethodFrame::GetMethodFrameVPtr()) | 
|---|
| 92 | frameType = "ExternalMethod"; | 
|---|
| 93 | else | 
|---|
| 94 | frameType = "Unknown"; | 
|---|
| 95 |  | 
|---|
| 96 | if (method != 0) | 
|---|
| 97 | LOG((LF_STUBS, LL_INFO1000000, | 
|---|
| 98 | "IN %s Stub Method = %s::%s SIG %s ESP of return"FMT_ADDR "\n", | 
|---|
| 99 | frameType, | 
|---|
| 100 | method->m_pszDebugClassName, | 
|---|
| 101 | method->m_pszDebugMethodName, | 
|---|
| 102 | method->m_pszDebugMethodSignature, | 
|---|
| 103 | DBG_ADDR(GetReturnAddressPtr()))); | 
|---|
| 104 | else | 
|---|
| 105 | LOG((LF_STUBS, LL_INFO1000000, | 
|---|
| 106 | "IN %s Stub Method UNKNOWN ESP of return"FMT_ADDR "\n", | 
|---|
| 107 | frameType, | 
|---|
| 108 | DBG_ADDR(GetReturnAddressPtr()) )); | 
|---|
| 109 |  | 
|---|
| 110 | _ASSERTE(GetThread()->PreemptiveGCDisabled()); | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 | //----------------------------------------------------------------------- | 
|---|
| 114 | // This function is used to log transitions in either direction | 
|---|
| 115 | // between unmanaged code and CLR/managed code. | 
|---|
| 116 | // This is typically done in a stub that sets up a Frame, which is | 
|---|
| 117 | // passed as an argument to this function. | 
|---|
| 118 |  | 
|---|
| 119 | void __stdcall Frame::LogTransition(Frame* frame) | 
|---|
| 120 | { | 
|---|
| 121 |  | 
|---|
| 122 | CONTRACTL { | 
|---|
| 123 | DEBUG_ONLY; | 
|---|
| 124 | NOTHROW; | 
|---|
| 125 | ENTRY_POINT; | 
|---|
| 126 | GC_NOTRIGGER; | 
|---|
| 127 | } CONTRACTL_END; | 
|---|
| 128 |  | 
|---|
| 129 | BEGIN_ENTRYPOINT_VOIDRET; | 
|---|
| 130 |  | 
|---|
| 131 | #ifdef _TARGET_X86_ | 
|---|
| 132 | // On x86, StubLinkerCPU::EmitMethodStubProlog calls Frame::LogTransition | 
|---|
| 133 | // but the caller of EmitMethodStubProlog sets the GSCookie later on. | 
|---|
| 134 | // So the cookie is not initialized by the point we get here. | 
|---|
| 135 | #else | 
|---|
| 136 | _ASSERTE(*frame->GetGSCookiePtr() == GetProcessGSCookie()); | 
|---|
| 137 | #endif | 
|---|
| 138 |  | 
|---|
| 139 | if (Frame::ShouldLogTransitions()) | 
|---|
| 140 | frame->Log(); | 
|---|
| 141 |  | 
|---|
| 142 | END_ENTRYPOINT_VOIDRET; | 
|---|
| 143 | } // void Frame::Log() | 
|---|
| 144 |  | 
|---|
| 145 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 146 |  | 
|---|
| 147 | //----------------------------------------------------------------------- | 
|---|
| 148 | #endif // _DEBUG | 
|---|
| 149 | //----------------------------------------------------------------------- | 
|---|
| 150 |  | 
|---|
| 151 |  | 
|---|
| 152 | // TODO [DAVBR]: For the full fix for VsWhidbey 450273, all the below | 
|---|
| 153 | // may be uncommented once isLegalManagedCodeCaller works properly | 
|---|
| 154 | // with non-return address inputs, and with non-DEBUG builds | 
|---|
| 155 | #if 0 | 
|---|
| 156 | //----------------------------------------------------------------------- | 
|---|
| 157 | // returns TRUE if retAddr, is a return address that can call managed code | 
|---|
| 158 |  | 
|---|
| 159 | bool isLegalManagedCodeCaller(PCODE retAddr) { | 
|---|
| 160 | WRAPPER_NO_CONTRACT; | 
|---|
| 161 | #ifdef _TARGET_X86_ | 
|---|
| 162 |  | 
|---|
| 163 | // we expect to be called from JITTED code or from special code sites inside | 
|---|
| 164 | // mscorwks like callDescr which we have put a NOP (0x90) so we know that they | 
|---|
| 165 | // are specially blessed. | 
|---|
| 166 | if (!ExecutionManager::IsManagedCode(retAddr) && | 
|---|
| 167 | ( | 
|---|
| 168 | #ifdef DACCESS_COMPILE | 
|---|
| 169 | !(PTR_BYTE(retAddr).IsValid()) || | 
|---|
| 170 | #endif | 
|---|
| 171 | ((*PTR_BYTE(retAddr) != 0x90) && | 
|---|
| 172 | (*PTR_BYTE(retAddr) != 0xcc)))) | 
|---|
| 173 | { | 
|---|
| 174 | LOG((LF_GC, LL_INFO10, "Bad caller to managed code: retAddr=0x%08x, *retAddr=0x%x\n", | 
|---|
| 175 | retAddr, *(BYTE*)PTR_BYTE(retAddr))); | 
|---|
| 176 |  | 
|---|
| 177 | return false; | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | // it better be a return address of some kind | 
|---|
| 181 | TADDR dummy; | 
|---|
| 182 | if (isRetAddr(retAddr, &dummy)) | 
|---|
| 183 | return true; | 
|---|
| 184 |  | 
|---|
| 185 | #ifndef DACCESS_COMPILE | 
|---|
| 186 | #ifdef DEBUGGING_SUPPORTED | 
|---|
| 187 | // The debugger could have dropped an INT3 on the instruction that made the call | 
|---|
| 188 | // Calls can be 2 to 7 bytes long | 
|---|
| 189 | if (CORDebuggerAttached()) { | 
|---|
| 190 | PTR_BYTE ptr = PTR_BYTE(retAddr); | 
|---|
| 191 | for (int i = -2; i >= -7; --i) | 
|---|
| 192 | if (ptr[i] == 0xCC) | 
|---|
| 193 | return true; | 
|---|
| 194 | return false; | 
|---|
| 195 | } | 
|---|
| 196 | #endif // DEBUGGING_SUPPORTED | 
|---|
| 197 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 198 |  | 
|---|
| 199 | _ASSERTE(! "Bad return address on stack"); | 
|---|
| 200 | return false; | 
|---|
| 201 | #else  // _TARGET_X86_ | 
|---|
| 202 | return true; | 
|---|
| 203 | #endif // _TARGET_X86_ | 
|---|
| 204 | } | 
|---|
| 205 | #endif //0 | 
|---|
| 206 |  | 
|---|
| 207 |  | 
|---|
| 208 | //----------------------------------------------------------------------- | 
|---|
| 209 | // Count of the number of frame types | 
|---|
| 210 | const size_t FRAME_TYPES_COUNT = | 
|---|
| 211 | #define FRAME_TYPE_NAME(frameType) +1 | 
|---|
| 212 | #include "frames.h" | 
|---|
| 213 | ; | 
|---|
| 214 |  | 
|---|
| 215 | #if defined (_DEBUG_IMPL)   // _DEBUG and !DAC | 
|---|
| 216 |  | 
|---|
| 217 | //----------------------------------------------------------------------- | 
|---|
| 218 | // Implementation of the global table of names.  On the DAC side, just the global pointer. | 
|---|
| 219 | //  On the runtime side, the array of names. | 
|---|
| 220 | #define FRAME_TYPE_NAME(x) {x::GetMethodFrameVPtr(), #x} , | 
|---|
| 221 | static FrameTypeName FrameTypeNameTable[] = { | 
|---|
| 222 | #include "frames.h" | 
|---|
| 223 | }; | 
|---|
| 224 |  | 
|---|
| 225 |  | 
|---|
| 226 | /* static */ | 
|---|
| 227 | PTR_CSTR Frame::GetFrameTypeName(TADDR vtbl) | 
|---|
| 228 | { | 
|---|
| 229 | LIMITED_METHOD_CONTRACT; | 
|---|
| 230 | for (size_t i=0; i<FRAME_TYPES_COUNT; ++i) | 
|---|
| 231 | { | 
|---|
| 232 | if (vtbl == FrameTypeNameTable[(int)i].vtbl) | 
|---|
| 233 | { | 
|---|
| 234 | return FrameTypeNameTable[(int)i].name; | 
|---|
| 235 | } | 
|---|
| 236 | } | 
|---|
| 237 |  | 
|---|
| 238 | return NULL; | 
|---|
| 239 | } // char* Frame::FrameTypeName() | 
|---|
| 240 |  | 
|---|
| 241 |  | 
|---|
| 242 | //----------------------------------------------------------------------- | 
|---|
| 243 |  | 
|---|
| 244 |  | 
|---|
| 245 | void Frame::LogFrame( | 
|---|
| 246 | int         LF,                     // Log facility for this call. | 
|---|
| 247 | int         LL)                     // Log Level for this call. | 
|---|
| 248 | { | 
|---|
| 249 | char        buf[32]; | 
|---|
| 250 | const char  *pFrameType; | 
|---|
| 251 | pFrameType = GetFrameTypeName(); | 
|---|
| 252 |  | 
|---|
| 253 | if (pFrameType == NULL) | 
|---|
| 254 | { | 
|---|
| 255 | pFrameType = GetFrameTypeName(GetVTablePtr()); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 | if (pFrameType == NULL) | 
|---|
| 259 | { | 
|---|
| 260 | _ASSERTE(! "New Frame type needs to be added to FrameTypeName()"); | 
|---|
| 261 | // Pointer is up to 17chars + vtbl@ = 22 chars | 
|---|
| 262 | sprintf_s(buf, COUNTOF(buf), "vtbl@%p", GetVTablePtr()); | 
|---|
| 263 | pFrameType = buf; | 
|---|
| 264 | } | 
|---|
| 265 |  | 
|---|
| 266 | LOG((LF, LL, "FRAME: addr:%p, next:%p, type:%s\n", | 
|---|
| 267 | this, m_Next, pFrameType)); | 
|---|
| 268 | } // void Frame::LogFrame() | 
|---|
| 269 |  | 
|---|
| 270 | void Frame::LogFrameChain( | 
|---|
| 271 | int         LF,                     // Log facility for this call. | 
|---|
| 272 | int         LL)                     // Log Level for this call. | 
|---|
| 273 | { | 
|---|
| 274 | if (!LoggingOn(LF, LL)) | 
|---|
| 275 | return; | 
|---|
| 276 |  | 
|---|
| 277 | Frame *pFrame = this; | 
|---|
| 278 | while (pFrame != FRAME_TOP) | 
|---|
| 279 | { | 
|---|
| 280 | pFrame->LogFrame(LF, LL); | 
|---|
| 281 | pFrame = pFrame->m_Next; | 
|---|
| 282 | } | 
|---|
| 283 | } // void Frame::LogFrameChain() | 
|---|
| 284 |  | 
|---|
| 285 | //----------------------------------------------------------------------- | 
|---|
| 286 | #endif // _DEBUG_IMPL | 
|---|
| 287 | //----------------------------------------------------------------------- | 
|---|
| 288 |  | 
|---|
| 289 | #ifndef DACCESS_COMPILE | 
|---|
| 290 |  | 
|---|
| 291 | // This hashtable contains the vtable value of every Frame type. | 
|---|
| 292 | static PtrHashMap* s_pFrameVTables = NULL; | 
|---|
| 293 |  | 
|---|
| 294 | // static | 
|---|
| 295 | void Frame::Init() | 
|---|
| 296 | { | 
|---|
| 297 | CONTRACTL | 
|---|
| 298 | { | 
|---|
| 299 | THROWS; | 
|---|
| 300 | GC_NOTRIGGER; | 
|---|
| 301 | MODE_ANY; | 
|---|
| 302 | } | 
|---|
| 303 | CONTRACTL_END; | 
|---|
| 304 | // create a table big enough for all the frame types, not in asynchronous mode, and with no lock owner | 
|---|
| 305 | s_pFrameVTables = ::new PtrHashMap; | 
|---|
| 306 | s_pFrameVTables->Init(2 * FRAME_TYPES_COUNT, FALSE, &g_lockTrustMeIAmThreadSafe); | 
|---|
| 307 | #define FRAME_TYPE_NAME(frameType)                          \ | 
|---|
| 308 | s_pFrameVTables->InsertValue(frameType::GetMethodFrameVPtr(), \ | 
|---|
| 309 | (LPVOID) frameType::GetMethodFrameVPtr()); | 
|---|
| 310 | #include "frames.h" | 
|---|
| 311 |  | 
|---|
| 312 | } // void Frame::Init() | 
|---|
| 313 |  | 
|---|
| 314 | // static | 
|---|
| 315 | void Frame::Term() | 
|---|
| 316 | { | 
|---|
| 317 | LIMITED_METHOD_CONTRACT; | 
|---|
| 318 | delete s_pFrameVTables; | 
|---|
| 319 | s_pFrameVTables = NULL; | 
|---|
| 320 | } | 
|---|
| 321 |  | 
|---|
| 322 | #endif // DACCESS_COMPILE | 
|---|
| 323 |  | 
|---|
| 324 | // Returns true if the Frame's VTablePtr is valid | 
|---|
| 325 |  | 
|---|
| 326 | // static | 
|---|
| 327 | bool Frame::HasValidVTablePtr(Frame * pFrame) | 
|---|
| 328 | { | 
|---|
| 329 | WRAPPER_NO_CONTRACT; | 
|---|
| 330 |  | 
|---|
| 331 | if (pFrame == NULL || pFrame == FRAME_TOP) | 
|---|
| 332 | return false; | 
|---|
| 333 |  | 
|---|
| 334 | #ifndef DACCESS_COMPILE | 
|---|
| 335 | TADDR vptr = pFrame->GetVTablePtr(); | 
|---|
| 336 | // | 
|---|
| 337 | // Helper MethodFrame,GCFrame,DebuggerSecurityCodeMarkFrame are the most | 
|---|
| 338 | // common frame types, explicitly check for them. | 
|---|
| 339 | // | 
|---|
| 340 | if (vptr == HelperMethodFrame::GetMethodFrameVPtr()) | 
|---|
| 341 | return true; | 
|---|
| 342 |  | 
|---|
| 343 | if (vptr == GCFrame::GetMethodFrameVPtr()) | 
|---|
| 344 | return true; | 
|---|
| 345 |  | 
|---|
| 346 | if (vptr == DebuggerSecurityCodeMarkFrame::GetMethodFrameVPtr()) | 
|---|
| 347 | return true; | 
|---|
| 348 |  | 
|---|
| 349 | // | 
|---|
| 350 | // otherwise consult the hashtable | 
|---|
| 351 | // | 
|---|
| 352 | if (s_pFrameVTables->LookupValue(vptr, (LPVOID) vptr) == (LPVOID) INVALIDENTRY) | 
|---|
| 353 | return false; | 
|---|
| 354 | #endif | 
|---|
| 355 |  | 
|---|
| 356 | return true; | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 | // Returns the location of the expected GSCookie, | 
|---|
| 360 | // Return NULL if the frame's vtable pointer is corrupt | 
|---|
| 361 | // | 
|---|
| 362 | // Note that Frame::GetGSCookiePtr is a virtual method, | 
|---|
| 363 | // and so it cannot be used without first checking if | 
|---|
| 364 | // the vtable is valid. | 
|---|
| 365 |  | 
|---|
| 366 | // static | 
|---|
| 367 | PTR_GSCookie Frame::SafeGetGSCookiePtr(Frame * pFrame) | 
|---|
| 368 | { | 
|---|
| 369 | WRAPPER_NO_CONTRACT; | 
|---|
| 370 |  | 
|---|
| 371 | _ASSERTE(pFrame != FRAME_TOP); | 
|---|
| 372 |  | 
|---|
| 373 | if (Frame::HasValidVTablePtr(pFrame)) | 
|---|
| 374 | return pFrame->GetGSCookiePtr(); | 
|---|
| 375 | else | 
|---|
| 376 | return NULL; | 
|---|
| 377 | } | 
|---|
| 378 |  | 
|---|
| 379 | //----------------------------------------------------------------------- | 
|---|
| 380 | #ifndef DACCESS_COMPILE | 
|---|
| 381 | //----------------------------------------------------------------------- | 
|---|
| 382 | // Link and Unlink this frame. | 
|---|
| 383 | //----------------------------------------------------------------------- | 
|---|
| 384 |  | 
|---|
| 385 | VOID Frame::Push() | 
|---|
| 386 | { | 
|---|
| 387 | CONTRACTL | 
|---|
| 388 | { | 
|---|
| 389 | NOTHROW; | 
|---|
| 390 | GC_NOTRIGGER; | 
|---|
| 391 | MODE_COOPERATIVE; | 
|---|
| 392 | SO_TOLERANT; | 
|---|
| 393 | } | 
|---|
| 394 | CONTRACTL_END; | 
|---|
| 395 |  | 
|---|
| 396 | Push(GetThread()); | 
|---|
| 397 | } | 
|---|
| 398 |  | 
|---|
| 399 | VOID Frame::Push(Thread *pThread) | 
|---|
| 400 | { | 
|---|
| 401 | CONTRACTL | 
|---|
| 402 | { | 
|---|
| 403 | NOTHROW; | 
|---|
| 404 | GC_NOTRIGGER; | 
|---|
| 405 | MODE_COOPERATIVE; | 
|---|
| 406 | SO_TOLERANT; | 
|---|
| 407 | } | 
|---|
| 408 | CONTRACTL_END; | 
|---|
| 409 |  | 
|---|
| 410 | _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie()); | 
|---|
| 411 |  | 
|---|
| 412 | m_Next = pThread->GetFrame(); | 
|---|
| 413 |  | 
|---|
| 414 | // GetOsPageSize() is used to relax the assert for cases where two Frames are | 
|---|
| 415 | // declared in the same source function. We cannot predict the order | 
|---|
| 416 | // in which the C compiler will lay them out in the stack frame. | 
|---|
| 417 | // So GetOsPageSize() is a guess of the maximum stack frame size of any method | 
|---|
| 418 | // with multiple Frames in mscorwks.dll | 
|---|
| 419 | _ASSERTE(((m_Next == FRAME_TOP) || | 
|---|
| 420 | (PBYTE(m_Next) + (2 * GetOsPageSize())) > PBYTE(this)) && | 
|---|
| 421 | "Pushing a frame out of order ?"); | 
|---|
| 422 |  | 
|---|
| 423 | _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun | 
|---|
| 424 | // corruptions. In that case, the Frame chain may be corrupted, | 
|---|
| 425 | // and the rest of the assert is not valid. | 
|---|
| 426 | // Note that the corrupted Frame chain will be detected | 
|---|
| 427 | // during stack-walking. | 
|---|
| 428 | !g_pConfig->fAssertOnFailFast() || | 
|---|
| 429 | (m_Next == FRAME_TOP) || | 
|---|
| 430 | (*m_Next->GetGSCookiePtr() == GetProcessGSCookie())); | 
|---|
| 431 |  | 
|---|
| 432 | pThread->SetFrame(this); | 
|---|
| 433 | } | 
|---|
| 434 |  | 
|---|
| 435 | VOID Frame::Pop() | 
|---|
| 436 | { | 
|---|
| 437 | CONTRACTL | 
|---|
| 438 | { | 
|---|
| 439 | NOTHROW; | 
|---|
| 440 | GC_NOTRIGGER; | 
|---|
| 441 | MODE_COOPERATIVE; | 
|---|
| 442 | SO_TOLERANT; | 
|---|
| 443 | } | 
|---|
| 444 | CONTRACTL_END; | 
|---|
| 445 |  | 
|---|
| 446 | Pop(GetThread()); | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | VOID Frame::Pop(Thread *pThread) | 
|---|
| 450 | { | 
|---|
| 451 | CONTRACTL | 
|---|
| 452 | { | 
|---|
| 453 | NOTHROW; | 
|---|
| 454 | GC_NOTRIGGER; | 
|---|
| 455 | MODE_COOPERATIVE; | 
|---|
| 456 | SO_TOLERANT; | 
|---|
| 457 | } | 
|---|
| 458 | CONTRACTL_END; | 
|---|
| 459 |  | 
|---|
| 460 | _ASSERTE(pThread->GetFrame() == this && "Popping a frame out of order ?"); | 
|---|
| 461 | _ASSERTE(*GetGSCookiePtr() == GetProcessGSCookie()); | 
|---|
| 462 | _ASSERTE(// If AssertOnFailFast is set, the test expects to do stack overrun | 
|---|
| 463 | // corruptions. In that case, the Frame chain may be corrupted, | 
|---|
| 464 | // and the rest of the assert is not valid. | 
|---|
| 465 | // Note that the corrupted Frame chain will be detected | 
|---|
| 466 | // during stack-walking. | 
|---|
| 467 | !g_pConfig->fAssertOnFailFast() || | 
|---|
| 468 | (m_Next == FRAME_TOP) || | 
|---|
| 469 | (*m_Next->GetGSCookiePtr() == GetProcessGSCookie())); | 
|---|
| 470 |  | 
|---|
| 471 | pThread->SetFrame(m_Next); | 
|---|
| 472 | m_Next = NULL; | 
|---|
| 473 | } | 
|---|
| 474 |  | 
|---|
| 475 | #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) | 
|---|
| 476 | void Frame::PopIfChained() | 
|---|
| 477 | { | 
|---|
| 478 | CONTRACTL | 
|---|
| 479 | { | 
|---|
| 480 | NOTHROW; | 
|---|
| 481 | GC_NOTRIGGER; | 
|---|
| 482 | MODE_COOPERATIVE; | 
|---|
| 483 | SO_TOLERANT; | 
|---|
| 484 | } | 
|---|
| 485 | CONTRACTL_END; | 
|---|
| 486 |  | 
|---|
| 487 | if (m_Next != NULL) | 
|---|
| 488 | { | 
|---|
| 489 | GCX_COOP(); | 
|---|
| 490 | // When the frame is destroyed, make sure it is no longer in the | 
|---|
| 491 | // frame chain managed by the Thread. | 
|---|
| 492 | Pop(); | 
|---|
| 493 | } | 
|---|
| 494 | } | 
|---|
| 495 | #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE | 
|---|
| 496 |  | 
|---|
| 497 | //----------------------------------------------------------------------- | 
|---|
| 498 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 499 | //--------------------------------------------------------------- | 
|---|
| 500 | // Get the extra param for shared generic code. | 
|---|
| 501 | //--------------------------------------------------------------- | 
|---|
| 502 | PTR_VOID TransitionFrame::GetParamTypeArg() | 
|---|
| 503 | { | 
|---|
| 504 | CONTRACTL | 
|---|
| 505 | { | 
|---|
| 506 | NOTHROW; | 
|---|
| 507 | GC_NOTRIGGER; | 
|---|
| 508 | MODE_ANY; | 
|---|
| 509 | SUPPORTS_DAC; | 
|---|
| 510 | } | 
|---|
| 511 | CONTRACTL_END; | 
|---|
| 512 |  | 
|---|
| 513 | // This gets called while creating stack traces during exception handling. | 
|---|
| 514 | // Using the ArgIterator constructor calls ArgIterator::Init which calls GetInitialOfsAdjust | 
|---|
| 515 | // which calls SizeOfArgStack, which thinks it may load value types. | 
|---|
| 516 | // However all these will have previously been loaded. | 
|---|
| 517 | // | 
|---|
| 518 | // I'm not entirely convinced this is the best places to put this: CrawlFrame::GetExactGenericArgsToken | 
|---|
| 519 | // may be another option. | 
|---|
| 520 | ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); | 
|---|
| 521 |  | 
|---|
| 522 | MethodDesc *pFunction = GetFunction(); | 
|---|
| 523 | _ASSERTE (pFunction->RequiresInstArg()); | 
|---|
| 524 |  | 
|---|
| 525 | MetaSig msig(pFunction); | 
|---|
| 526 | ArgIterator argit (&msig); | 
|---|
| 527 |  | 
|---|
| 528 | INT offs = argit.GetParamTypeArgOffset(); | 
|---|
| 529 |  | 
|---|
| 530 | TADDR taParamTypeArg = *PTR_TADDR(GetTransitionBlock() + offs); | 
|---|
| 531 | return PTR_VOID(taParamTypeArg); | 
|---|
| 532 | } | 
|---|
| 533 |  | 
|---|
| 534 | TADDR TransitionFrame::GetAddrOfThis() | 
|---|
| 535 | { | 
|---|
| 536 | WRAPPER_NO_CONTRACT; | 
|---|
| 537 | return GetTransitionBlock() + ArgIterator::GetThisOffset(); | 
|---|
| 538 | } | 
|---|
| 539 |  | 
|---|
| 540 | VASigCookie * TransitionFrame::GetVASigCookie() | 
|---|
| 541 | { | 
|---|
| 542 | #if defined(_TARGET_X86_) | 
|---|
| 543 | LIMITED_METHOD_CONTRACT; | 
|---|
| 544 | return dac_cast<PTR_VASigCookie>( | 
|---|
| 545 | *dac_cast<PTR_TADDR>(GetTransitionBlock() + | 
|---|
| 546 | sizeof(TransitionBlock))); | 
|---|
| 547 | #else | 
|---|
| 548 | WRAPPER_NO_CONTRACT; | 
|---|
| 549 | MetaSig msig(GetFunction()); | 
|---|
| 550 | ArgIterator argit(&msig); | 
|---|
| 551 | return PTR_VASigCookie( | 
|---|
| 552 | *dac_cast<PTR_TADDR>(GetTransitionBlock() + argit.GetVASigCookieOffset())); | 
|---|
| 553 | #endif | 
|---|
| 554 | } | 
|---|
| 555 |  | 
|---|
| 556 | #ifndef DACCESS_COMPILE | 
|---|
| 557 | PrestubMethodFrame::PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD) | 
|---|
| 558 | : FramedMethodFrame(pTransitionBlock, pMD) | 
|---|
| 559 | { | 
|---|
| 560 | LIMITED_METHOD_CONTRACT; | 
|---|
| 561 | } | 
|---|
| 562 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 563 |  | 
|---|
| 564 | BOOL PrestubMethodFrame::TraceFrame(Thread *thread, BOOL fromPatch, | 
|---|
| 565 | TraceDestination *trace, REGDISPLAY *regs) | 
|---|
| 566 | { | 
|---|
| 567 | WRAPPER_NO_CONTRACT; | 
|---|
| 568 |  | 
|---|
| 569 | // | 
|---|
| 570 | // We want to set a frame patch, unless we're already at the | 
|---|
| 571 | // frame patch, in which case we'll trace stable entrypoint which | 
|---|
| 572 | // should be set by now. | 
|---|
| 573 | // | 
|---|
| 574 |  | 
|---|
| 575 | if (fromPatch) | 
|---|
| 576 | { | 
|---|
| 577 | trace->InitForStub(GetFunction()->GetStableEntryPoint()); | 
|---|
| 578 | } | 
|---|
| 579 | else | 
|---|
| 580 | { | 
|---|
| 581 | trace->InitForStub(GetPreStubEntryPoint()); | 
|---|
| 582 | } | 
|---|
| 583 |  | 
|---|
| 584 | LOG((LF_CORDB, LL_INFO10000, | 
|---|
| 585 | "PrestubMethodFrame::TraceFrame: ip="FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) )); | 
|---|
| 586 |  | 
|---|
| 587 | return TRUE; | 
|---|
| 588 | } | 
|---|
| 589 |  | 
|---|
| 590 | #ifndef DACCESS_COMPILE | 
|---|
| 591 | //----------------------------------------------------------------------- | 
|---|
| 592 | // A rather specialized routine for the exclusive use of StubDispatch. | 
|---|
| 593 | //----------------------------------------------------------------------- | 
|---|
| 594 | StubDispatchFrame::StubDispatchFrame(TransitionBlock * pTransitionBlock) | 
|---|
| 595 | : FramedMethodFrame(pTransitionBlock, NULL) | 
|---|
| 596 | { | 
|---|
| 597 | LIMITED_METHOD_CONTRACT; | 
|---|
| 598 |  | 
|---|
| 599 | m_pRepresentativeMT = NULL; | 
|---|
| 600 | m_representativeSlot = 0; | 
|---|
| 601 |  | 
|---|
| 602 | m_pZapModule = NULL; | 
|---|
| 603 | m_pIndirection = NULL; | 
|---|
| 604 |  | 
|---|
| 605 | m_pGCRefMap = NULL; | 
|---|
| 606 | } | 
|---|
| 607 |  | 
|---|
| 608 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 609 |  | 
|---|
| 610 | MethodDesc* StubDispatchFrame::GetFunction() | 
|---|
| 611 | { | 
|---|
| 612 | CONTRACTL { | 
|---|
| 613 | NOTHROW; | 
|---|
| 614 | GC_NOTRIGGER; | 
|---|
| 615 | SO_TOLERANT; | 
|---|
| 616 | } CONTRACTL_END; | 
|---|
| 617 |  | 
|---|
| 618 | MethodDesc * pMD = m_pMD; | 
|---|
| 619 |  | 
|---|
| 620 | if (m_pMD == NULL) | 
|---|
| 621 | { | 
|---|
| 622 | if (m_pRepresentativeMT != NULL) | 
|---|
| 623 | { | 
|---|
| 624 | pMD = m_pRepresentativeMT->GetMethodDescForSlot(m_representativeSlot); | 
|---|
| 625 | #ifndef DACCESS_COMPILE | 
|---|
| 626 | m_pMD = pMD; | 
|---|
| 627 | #endif | 
|---|
| 628 | } | 
|---|
| 629 | } | 
|---|
| 630 |  | 
|---|
| 631 | return pMD; | 
|---|
| 632 | } | 
|---|
| 633 |  | 
|---|
| 634 | static PTR_BYTE FindGCRefMap(PTR_Module pZapModule, TADDR ptr) | 
|---|
| 635 | { | 
|---|
| 636 | LIMITED_METHOD_DAC_CONTRACT; | 
|---|
| 637 |  | 
|---|
| 638 | PEImageLayout *pNativeImage = pZapModule->GetNativeOrReadyToRunImage(); | 
|---|
| 639 |  | 
|---|
| 640 | RVA rva = pNativeImage->GetDataRva(ptr); | 
|---|
| 641 |  | 
|---|
| 642 | PTR_CORCOMPILE_IMPORT_SECTION pImportSection = pZapModule->GetImportSectionForRVA(rva); | 
|---|
| 643 | if (pImportSection == NULL) | 
|---|
| 644 | return NULL; | 
|---|
| 645 |  | 
|---|
| 646 | COUNT_T index = (rva - pImportSection->Section.VirtualAddress) / pImportSection->EntrySize; | 
|---|
| 647 |  | 
|---|
| 648 | PTR_BYTE pGCRefMap = dac_cast<PTR_BYTE>(pNativeImage->GetRvaData(pImportSection->AuxiliaryData)); | 
|---|
| 649 | _ASSERTE(pGCRefMap != NULL); | 
|---|
| 650 |  | 
|---|
| 651 | // GCRefMap starts with lookup index to limit size of linear scan that follows. | 
|---|
| 652 | PTR_BYTE p = pGCRefMap + dac_cast<PTR_DWORD>(pGCRefMap)[index / GCREFMAP_LOOKUP_STRIDE]; | 
|---|
| 653 | COUNT_T remaining = index % GCREFMAP_LOOKUP_STRIDE; | 
|---|
| 654 |  | 
|---|
| 655 | while (remaining > 0) | 
|---|
| 656 | { | 
|---|
| 657 | while ((*p & 0x80) != 0) | 
|---|
| 658 | p++; | 
|---|
| 659 | p++; | 
|---|
| 660 |  | 
|---|
| 661 | remaining--; | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | return p; | 
|---|
| 665 | } | 
|---|
| 666 |  | 
|---|
| 667 | PTR_BYTE StubDispatchFrame::GetGCRefMap() | 
|---|
| 668 | { | 
|---|
| 669 | CONTRACTL | 
|---|
| 670 | { | 
|---|
| 671 | NOTHROW; | 
|---|
| 672 | GC_NOTRIGGER; | 
|---|
| 673 | } | 
|---|
| 674 | CONTRACTL_END; | 
|---|
| 675 |  | 
|---|
| 676 | PTR_BYTE pGCRefMap = m_pGCRefMap; | 
|---|
| 677 |  | 
|---|
| 678 | if (pGCRefMap == NULL) | 
|---|
| 679 | { | 
|---|
| 680 | if (m_pIndirection != NULL) | 
|---|
| 681 | { | 
|---|
| 682 | if (m_pZapModule == NULL) | 
|---|
| 683 | { | 
|---|
| 684 | m_pZapModule = ExecutionManager::FindModuleForGCRefMap(m_pIndirection); | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | if (m_pZapModule != NULL) | 
|---|
| 688 | { | 
|---|
| 689 | pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection); | 
|---|
| 690 | } | 
|---|
| 691 |  | 
|---|
| 692 | #ifndef DACCESS_COMPILE | 
|---|
| 693 | if (pGCRefMap != NULL) | 
|---|
| 694 | { | 
|---|
| 695 | m_pGCRefMap = pGCRefMap; | 
|---|
| 696 | } | 
|---|
| 697 | else | 
|---|
| 698 | { | 
|---|
| 699 | // Clear the indirection to avoid retrying | 
|---|
| 700 | m_pIndirection = NULL; | 
|---|
| 701 | } | 
|---|
| 702 | #endif | 
|---|
| 703 | } | 
|---|
| 704 | } | 
|---|
| 705 |  | 
|---|
| 706 | return pGCRefMap; | 
|---|
| 707 | } | 
|---|
| 708 |  | 
|---|
| 709 | void StubDispatchFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 710 | { | 
|---|
| 711 | CONTRACTL | 
|---|
| 712 | { | 
|---|
| 713 | NOTHROW; | 
|---|
| 714 | GC_NOTRIGGER; | 
|---|
| 715 | } | 
|---|
| 716 | CONTRACTL_END | 
|---|
| 717 |  | 
|---|
| 718 | FramedMethodFrame::GcScanRoots(fn, sc); | 
|---|
| 719 |  | 
|---|
| 720 | PTR_BYTE pGCRefMap = GetGCRefMap(); | 
|---|
| 721 | if (pGCRefMap != NULL) | 
|---|
| 722 | { | 
|---|
| 723 | PromoteCallerStackUsingGCRefMap(fn, sc, pGCRefMap); | 
|---|
| 724 | } | 
|---|
| 725 | else | 
|---|
| 726 | { | 
|---|
| 727 | PromoteCallerStack(fn, sc); | 
|---|
| 728 | } | 
|---|
| 729 | } | 
|---|
| 730 |  | 
|---|
| 731 | BOOL StubDispatchFrame::TraceFrame(Thread *thread, BOOL fromPatch, | 
|---|
| 732 | TraceDestination *trace, REGDISPLAY *regs) | 
|---|
| 733 | { | 
|---|
| 734 | WRAPPER_NO_CONTRACT; | 
|---|
| 735 |  | 
|---|
| 736 | // | 
|---|
| 737 | // We want to set a frame patch, unless we're already at the | 
|---|
| 738 | // frame patch, in which case we'll trace stable entrypoint which | 
|---|
| 739 | // should be set by now. | 
|---|
| 740 | // | 
|---|
| 741 |  | 
|---|
| 742 | if (fromPatch) | 
|---|
| 743 | { | 
|---|
| 744 | trace->InitForStub(GetFunction()->GetStableEntryPoint()); | 
|---|
| 745 | } | 
|---|
| 746 | else | 
|---|
| 747 | { | 
|---|
| 748 | trace->InitForStub(GetPreStubEntryPoint()); | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | LOG((LF_CORDB, LL_INFO10000, | 
|---|
| 752 | "StubDispatchFrame::TraceFrame: ip="FMT_ADDR "\n", DBG_ADDR(trace->GetAddress()) )); | 
|---|
| 753 |  | 
|---|
| 754 | return TRUE; | 
|---|
| 755 | } | 
|---|
| 756 |  | 
|---|
| 757 | Frame::Interception StubDispatchFrame::GetInterception() | 
|---|
| 758 | { | 
|---|
| 759 | LIMITED_METHOD_CONTRACT; | 
|---|
| 760 |  | 
|---|
| 761 | return INTERCEPTION_NONE; | 
|---|
| 762 | } | 
|---|
| 763 |  | 
|---|
| 764 | #ifndef DACCESS_COMPILE | 
|---|
| 765 | ExternalMethodFrame::ExternalMethodFrame(TransitionBlock * pTransitionBlock) | 
|---|
| 766 | : FramedMethodFrame(pTransitionBlock, NULL) | 
|---|
| 767 | { | 
|---|
| 768 | LIMITED_METHOD_CONTRACT; | 
|---|
| 769 |  | 
|---|
| 770 | m_pIndirection = NULL; | 
|---|
| 771 | m_pZapModule = NULL; | 
|---|
| 772 |  | 
|---|
| 773 | m_pGCRefMap = NULL; | 
|---|
| 774 | } | 
|---|
| 775 | #endif // !DACCESS_COMPILE | 
|---|
| 776 |  | 
|---|
| 777 | void ExternalMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 778 | { | 
|---|
| 779 | CONTRACTL | 
|---|
| 780 | { | 
|---|
| 781 | NOTHROW; | 
|---|
| 782 | GC_NOTRIGGER; | 
|---|
| 783 | } | 
|---|
| 784 | CONTRACTL_END | 
|---|
| 785 |  | 
|---|
| 786 | FramedMethodFrame::GcScanRoots(fn, sc); | 
|---|
| 787 | PromoteCallerStackUsingGCRefMap(fn, sc, GetGCRefMap()); | 
|---|
| 788 | } | 
|---|
| 789 |  | 
|---|
| 790 | PTR_BYTE ExternalMethodFrame::GetGCRefMap() | 
|---|
| 791 | { | 
|---|
| 792 | LIMITED_METHOD_DAC_CONTRACT; | 
|---|
| 793 |  | 
|---|
| 794 | PTR_BYTE pGCRefMap = m_pGCRefMap; | 
|---|
| 795 |  | 
|---|
| 796 | if (pGCRefMap == NULL) | 
|---|
| 797 | { | 
|---|
| 798 | if (m_pIndirection != NULL) | 
|---|
| 799 | { | 
|---|
| 800 | pGCRefMap = FindGCRefMap(m_pZapModule, m_pIndirection); | 
|---|
| 801 | #ifndef DACCESS_COMPILE | 
|---|
| 802 | m_pGCRefMap = pGCRefMap; | 
|---|
| 803 | #endif | 
|---|
| 804 | } | 
|---|
| 805 | } | 
|---|
| 806 |  | 
|---|
| 807 | _ASSERTE(pGCRefMap != NULL); | 
|---|
| 808 | return pGCRefMap; | 
|---|
| 809 | } | 
|---|
| 810 |  | 
|---|
| 811 | Frame::Interception ExternalMethodFrame::GetInterception() | 
|---|
| 812 | { | 
|---|
| 813 | LIMITED_METHOD_CONTRACT; | 
|---|
| 814 |  | 
|---|
| 815 | return INTERCEPTION_NONE; | 
|---|
| 816 | } | 
|---|
| 817 |  | 
|---|
| 818 | Frame::Interception PrestubMethodFrame::GetInterception() | 
|---|
| 819 | { | 
|---|
| 820 | LIMITED_METHOD_DAC_CONTRACT; | 
|---|
| 821 |  | 
|---|
| 822 | // | 
|---|
| 823 | // The only direct kind of interception done by the prestub | 
|---|
| 824 | // is class initialization. | 
|---|
| 825 | // | 
|---|
| 826 |  | 
|---|
| 827 | return INTERCEPTION_PRESTUB; | 
|---|
| 828 | } | 
|---|
| 829 |  | 
|---|
| 830 | #ifdef FEATURE_READYTORUN | 
|---|
| 831 |  | 
|---|
| 832 | #ifndef DACCESS_COMPILE | 
|---|
| 833 | DynamicHelperFrame::DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags) | 
|---|
| 834 | : FramedMethodFrame(pTransitionBlock, NULL) | 
|---|
| 835 | { | 
|---|
| 836 | LIMITED_METHOD_CONTRACT; | 
|---|
| 837 |  | 
|---|
| 838 | m_dynamicHelperFrameFlags = dynamicHelperFrameFlags; | 
|---|
| 839 | } | 
|---|
| 840 | #endif // !DACCESS_COMPILE | 
|---|
| 841 |  | 
|---|
| 842 | void DynamicHelperFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 843 | { | 
|---|
| 844 | CONTRACTL | 
|---|
| 845 | { | 
|---|
| 846 | NOTHROW; | 
|---|
| 847 | GC_NOTRIGGER; | 
|---|
| 848 | } | 
|---|
| 849 | CONTRACTL_END | 
|---|
| 850 |  | 
|---|
| 851 | FramedMethodFrame::GcScanRoots(fn, sc); | 
|---|
| 852 |  | 
|---|
| 853 | PTR_PTR_Object pArgumentRegisters = dac_cast<PTR_PTR_Object>(GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()); | 
|---|
| 854 |  | 
|---|
| 855 | if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg) | 
|---|
| 856 | { | 
|---|
| 857 | TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters(); | 
|---|
| 858 | #ifdef _TARGET_X86_ | 
|---|
| 859 | // x86 is special as always | 
|---|
| 860 | pArgument += offsetof(ArgumentRegisters, ECX); | 
|---|
| 861 | #endif | 
|---|
| 862 | (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN); | 
|---|
| 863 | } | 
|---|
| 864 |  | 
|---|
| 865 | if (m_dynamicHelperFrameFlags & DynamicHelperFrameFlags_ObjectArg2) | 
|---|
| 866 | { | 
|---|
| 867 | TADDR pArgument = GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters(); | 
|---|
| 868 | #ifdef _TARGET_X86_ | 
|---|
| 869 | // x86 is special as always | 
|---|
| 870 | pArgument += offsetof(ArgumentRegisters, EDX); | 
|---|
| 871 | #else | 
|---|
| 872 | pArgument += sizeof(TADDR); | 
|---|
| 873 | #endif | 
|---|
| 874 | (*fn)(dac_cast<PTR_PTR_Object>(pArgument), sc, CHECK_APP_DOMAIN); | 
|---|
| 875 | } | 
|---|
| 876 | } | 
|---|
| 877 |  | 
|---|
| 878 | #endif // FEATURE_READYTORUN | 
|---|
| 879 |  | 
|---|
| 880 |  | 
|---|
| 881 | #ifndef DACCESS_COMPILE | 
|---|
| 882 |  | 
|---|
| 883 | #ifdef FEATURE_COMINTEROP | 
|---|
| 884 | //----------------------------------------------------------------------- | 
|---|
| 885 | // A rather specialized routine for the exclusive use of the COM PreStub. | 
|---|
| 886 | //----------------------------------------------------------------------- | 
|---|
| 887 | VOID | 
|---|
| 888 | ComPrestubMethodFrame::Init() | 
|---|
| 889 | { | 
|---|
| 890 | WRAPPER_NO_CONTRACT; | 
|---|
| 891 |  | 
|---|
| 892 | // Initializes the frame's VPTR. This assumes C++ puts the vptr | 
|---|
| 893 | // at offset 0 for a class not using MI, but this is no different | 
|---|
| 894 | // than the assumption that COM Classic makes. | 
|---|
| 895 | *((TADDR*)this) = GetMethodFrameVPtr(); | 
|---|
| 896 | *GetGSCookiePtr() = GetProcessGSCookie(); | 
|---|
| 897 | } | 
|---|
| 898 | #endif // FEATURE_COMINTEROP | 
|---|
| 899 |  | 
|---|
| 900 | //----------------------------------------------------------------------- | 
|---|
| 901 | // GCFrames | 
|---|
| 902 | //----------------------------------------------------------------------- | 
|---|
| 903 |  | 
|---|
| 904 |  | 
|---|
| 905 | //-------------------------------------------------------------------- | 
|---|
| 906 | // This constructor pushes a new GCFrame on the frame chain. | 
|---|
| 907 | //-------------------------------------------------------------------- | 
|---|
| 908 | GCFrame::GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) | 
|---|
| 909 | { | 
|---|
| 910 | CONTRACTL | 
|---|
| 911 | { | 
|---|
| 912 | NOTHROW; | 
|---|
| 913 | GC_NOTRIGGER; | 
|---|
| 914 | MODE_COOPERATIVE; | 
|---|
| 915 | SO_TOLERANT; | 
|---|
| 916 | } | 
|---|
| 917 | CONTRACTL_END; | 
|---|
| 918 |  | 
|---|
| 919 | Init(GetThread(), pObjRefs, numObjRefs, maybeInterior); | 
|---|
| 920 | } | 
|---|
| 921 |  | 
|---|
| 922 | GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) | 
|---|
| 923 | { | 
|---|
| 924 | CONTRACTL | 
|---|
| 925 | { | 
|---|
| 926 | NOTHROW; | 
|---|
| 927 | GC_NOTRIGGER; | 
|---|
| 928 | MODE_COOPERATIVE; | 
|---|
| 929 | SO_TOLERANT; | 
|---|
| 930 | } | 
|---|
| 931 | CONTRACTL_END; | 
|---|
| 932 |  | 
|---|
| 933 | Init(pThread, pObjRefs, numObjRefs, maybeInterior); | 
|---|
| 934 | } | 
|---|
| 935 |  | 
|---|
| 936 | void GCFrame::Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) | 
|---|
| 937 | { | 
|---|
| 938 | CONTRACTL | 
|---|
| 939 | { | 
|---|
| 940 | NOTHROW; | 
|---|
| 941 | GC_NOTRIGGER; | 
|---|
| 942 | MODE_COOPERATIVE; | 
|---|
| 943 | SO_TOLERANT; | 
|---|
| 944 | } | 
|---|
| 945 | CONTRACTL_END; | 
|---|
| 946 |  | 
|---|
| 947 | #ifdef USE_CHECKED_OBJECTREFS | 
|---|
| 948 | if (!maybeInterior) { | 
|---|
| 949 | UINT i; | 
|---|
| 950 | for(i = 0; i < numObjRefs; i++) | 
|---|
| 951 | Thread::ObjectRefProtected(&pObjRefs[i]); | 
|---|
| 952 |  | 
|---|
| 953 | for (i = 0; i < numObjRefs; i++) { | 
|---|
| 954 | pObjRefs[i].Validate(); | 
|---|
| 955 | } | 
|---|
| 956 | } | 
|---|
| 957 |  | 
|---|
| 958 | #if 0  // We'll want to restore this goodness check at some time. For now, the fact that we use | 
|---|
| 959 | // this as temporary backstops in our loader exception conversions means we're highly | 
|---|
| 960 | // exposed to infinite stack recursion should the loader be invoked during a stackwalk. | 
|---|
| 961 | // So we'll do without. | 
|---|
| 962 |  | 
|---|
| 963 | if (g_pConfig->GetGCStressLevel() != 0 && IsProtectedByGCFrame(pObjRefs)) { | 
|---|
| 964 | _ASSERTE(! "This objectref is already protected by a GCFrame. Protecting it twice will corrupt the GC."); | 
|---|
| 965 | } | 
|---|
| 966 | #endif | 
|---|
| 967 |  | 
|---|
| 968 | #endif | 
|---|
| 969 |  | 
|---|
| 970 | m_pObjRefs      = pObjRefs; | 
|---|
| 971 | m_numObjRefs    = numObjRefs; | 
|---|
| 972 | m_pCurThread    = pThread; | 
|---|
| 973 | m_MaybeInterior = maybeInterior; | 
|---|
| 974 |  | 
|---|
| 975 | Frame::Push(m_pCurThread); | 
|---|
| 976 | } | 
|---|
| 977 |  | 
|---|
| 978 |  | 
|---|
| 979 | // | 
|---|
| 980 | // GCFrame Object Scanning | 
|---|
| 981 | // | 
|---|
| 982 | // This handles scanning/promotion of GC objects that were | 
|---|
| 983 | // protected by the programmer explicitly protecting it in a GC Frame | 
|---|
| 984 | // via the GCPROTECTBEGIN / GCPROTECTEND facility... | 
|---|
| 985 | // | 
|---|
| 986 |  | 
|---|
| 987 | #endif // !DACCESS_COMPILE | 
|---|
| 988 |  | 
|---|
| 989 | void GCFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 990 | { | 
|---|
| 991 | WRAPPER_NO_CONTRACT; | 
|---|
| 992 |  | 
|---|
| 993 | PTR_PTR_Object pRefs = dac_cast<PTR_PTR_Object>(m_pObjRefs); | 
|---|
| 994 |  | 
|---|
| 995 | for (UINT i = 0;i < m_numObjRefs; i++)  { | 
|---|
| 996 |  | 
|---|
| 997 | LOG((LF_GC, INFO3, "GC Protection Frame Promoting"FMT_ADDR "to", | 
|---|
| 998 | DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) )); | 
|---|
| 999 | if (m_MaybeInterior) | 
|---|
| 1000 | PromoteCarefully(fn, pRefs + i, sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); | 
|---|
| 1001 | else | 
|---|
| 1002 | (*fn)(pRefs + i, sc, 0); | 
|---|
| 1003 | LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(m_pObjRefs[i])) )); | 
|---|
| 1004 | } | 
|---|
| 1005 | } | 
|---|
| 1006 |  | 
|---|
| 1007 |  | 
|---|
| 1008 | #ifndef DACCESS_COMPILE | 
|---|
| 1009 | //-------------------------------------------------------------------- | 
|---|
| 1010 | // Pops the GCFrame and cancels the GC protection. | 
|---|
| 1011 | //-------------------------------------------------------------------- | 
|---|
| 1012 | VOID GCFrame::Pop() | 
|---|
| 1013 | { | 
|---|
| 1014 | WRAPPER_NO_CONTRACT; | 
|---|
| 1015 |  | 
|---|
| 1016 | Frame::Pop(m_pCurThread); | 
|---|
| 1017 | #ifdef _DEBUG | 
|---|
| 1018 | m_pCurThread->EnableStressHeap(); | 
|---|
| 1019 | for(UINT i = 0; i < m_numObjRefs; i++) | 
|---|
| 1020 | Thread::ObjectRefNew(&m_pObjRefs[i]);       // Unprotect them | 
|---|
| 1021 | #endif | 
|---|
| 1022 | } | 
|---|
| 1023 |  | 
|---|
| 1024 | #ifdef FEATURE_INTERPRETER | 
|---|
| 1025 | // Methods of IntepreterFrame. | 
|---|
| 1026 | InterpreterFrame::InterpreterFrame(Interpreter* interp) | 
|---|
| 1027 | : Frame(), m_interp(interp) | 
|---|
| 1028 | { | 
|---|
| 1029 | Push(); | 
|---|
| 1030 | } | 
|---|
| 1031 |  | 
|---|
| 1032 |  | 
|---|
| 1033 | MethodDesc* InterpreterFrame::GetFunction() | 
|---|
| 1034 | { | 
|---|
| 1035 | return m_interp->GetMethodDesc(); | 
|---|
| 1036 | } | 
|---|
| 1037 |  | 
|---|
| 1038 | void InterpreterFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 1039 | { | 
|---|
| 1040 | return m_interp->GCScanRoots(fn, sc); | 
|---|
| 1041 | } | 
|---|
| 1042 |  | 
|---|
| 1043 | #endif // FEATURE_INTERPRETER | 
|---|
| 1044 |  | 
|---|
| 1045 | #if defined(_DEBUG) && !defined (DACCESS_COMPILE) | 
|---|
| 1046 |  | 
|---|
| 1047 | struct IsProtectedByGCFrameStruct | 
|---|
| 1048 | { | 
|---|
| 1049 | OBJECTREF       *ppObjectRef; | 
|---|
| 1050 | UINT             count; | 
|---|
| 1051 | }; | 
|---|
| 1052 |  | 
|---|
| 1053 | static StackWalkAction IsProtectedByGCFrameStackWalkFramesCallback( | 
|---|
| 1054 | CrawlFrame      *pCF, | 
|---|
| 1055 | VOID            *pData | 
|---|
| 1056 | ) | 
|---|
| 1057 | { | 
|---|
| 1058 | DEBUG_ONLY_FUNCTION; | 
|---|
| 1059 | WRAPPER_NO_CONTRACT; | 
|---|
| 1060 |  | 
|---|
| 1061 | IsProtectedByGCFrameStruct *pd = (IsProtectedByGCFrameStruct*)pData; | 
|---|
| 1062 | Frame *pFrame = pCF->GetFrame(); | 
|---|
| 1063 | if (pFrame) { | 
|---|
| 1064 | if (pFrame->Protects(pd->ppObjectRef)) { | 
|---|
| 1065 | pd->count++; | 
|---|
| 1066 | } | 
|---|
| 1067 | } | 
|---|
| 1068 | return SWA_CONTINUE; | 
|---|
| 1069 | } | 
|---|
| 1070 |  | 
|---|
| 1071 | BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef) | 
|---|
| 1072 | { | 
|---|
| 1073 | DEBUG_ONLY_FUNCTION; | 
|---|
| 1074 | WRAPPER_NO_CONTRACT; | 
|---|
| 1075 |  | 
|---|
| 1076 | // Just report TRUE if GCStress is not on.  This satisfies the asserts that use this | 
|---|
| 1077 | // code without the cost of actually determining it. | 
|---|
| 1078 | if (!GCStress<cfg_any>::IsEnabled()) | 
|---|
| 1079 | return TRUE; | 
|---|
| 1080 |  | 
|---|
| 1081 | if (ppObjectRef == NULL) { | 
|---|
| 1082 | return TRUE; | 
|---|
| 1083 | } | 
|---|
| 1084 |  | 
|---|
| 1085 | CONTRACT_VIOLATION(ThrowsViolation); | 
|---|
| 1086 | ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE (); | 
|---|
| 1087 | IsProtectedByGCFrameStruct d = {ppObjectRef, 0}; | 
|---|
| 1088 | GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d); | 
|---|
| 1089 | if (d.count > 1) { | 
|---|
| 1090 | _ASSERTE(! "Multiple GCFrames protecting the same pointer. This will cause GC corruption!"); | 
|---|
| 1091 | } | 
|---|
| 1092 | return d.count != 0; | 
|---|
| 1093 | } | 
|---|
| 1094 | #endif // _DEBUG | 
|---|
| 1095 |  | 
|---|
| 1096 | #endif //!DACCESS_COMPILE | 
|---|
| 1097 |  | 
|---|
| 1098 | #ifdef FEATURE_HIJACK | 
|---|
| 1099 |  | 
|---|
| 1100 | void HijackFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 1101 | { | 
|---|
| 1102 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1103 |  | 
|---|
| 1104 | ReturnKind returnKind = m_Thread->GetHijackReturnKind(); | 
|---|
| 1105 | _ASSERTE(IsValidReturnKind(returnKind)); | 
|---|
| 1106 |  | 
|---|
| 1107 | int regNo = 0; | 
|---|
| 1108 | bool moreRegisters = false; | 
|---|
| 1109 |  | 
|---|
| 1110 | do | 
|---|
| 1111 | { | 
|---|
| 1112 | ReturnKind r = ExtractRegReturnKind(returnKind, regNo, moreRegisters); | 
|---|
| 1113 | PTR_PTR_Object objPtr = dac_cast<PTR_PTR_Object>(&m_Args->ReturnValue[regNo]); | 
|---|
| 1114 |  | 
|---|
| 1115 | switch (r) | 
|---|
| 1116 | { | 
|---|
| 1117 | #ifdef _TARGET_X86_ | 
|---|
| 1118 | case RT_Float: // Fall through | 
|---|
| 1119 | #endif | 
|---|
| 1120 | case RT_Scalar: | 
|---|
| 1121 | // nothing to report | 
|---|
| 1122 | break; | 
|---|
| 1123 |  | 
|---|
| 1124 | case RT_Object: | 
|---|
| 1125 | LOG((LF_GC, INFO3, "Hijack Frame Promoting Object"FMT_ADDR "to", | 
|---|
| 1126 | DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr)))); | 
|---|
| 1127 | (*fn)(objPtr, sc, CHECK_APP_DOMAIN); | 
|---|
| 1128 | LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr)))); | 
|---|
| 1129 | break; | 
|---|
| 1130 |  | 
|---|
| 1131 | case RT_ByRef: | 
|---|
| 1132 | LOG((LF_GC, INFO3, "Hijack Frame Carefully Promoting pointer"FMT_ADDR "to", | 
|---|
| 1133 | DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr)))); | 
|---|
| 1134 | PromoteCarefully(fn, objPtr, sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN); | 
|---|
| 1135 | LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*objPtr)))); | 
|---|
| 1136 | break; | 
|---|
| 1137 |  | 
|---|
| 1138 | default: | 
|---|
| 1139 | _ASSERTE(! "Impossible two bit encoding"); | 
|---|
| 1140 | } | 
|---|
| 1141 |  | 
|---|
| 1142 | regNo++; | 
|---|
| 1143 | } while (moreRegisters); | 
|---|
| 1144 | } | 
|---|
| 1145 |  | 
|---|
| 1146 | #endif // FEATURE_HIJACK | 
|---|
| 1147 |  | 
|---|
| 1148 | void ProtectByRefsFrame::GcScanRoots(promote_func *fn, ScanContext *sc) | 
|---|
| 1149 | { | 
|---|
| 1150 | CONTRACTL | 
|---|
| 1151 | { | 
|---|
| 1152 | NOTHROW; | 
|---|
| 1153 | GC_NOTRIGGER; | 
|---|
| 1154 | } | 
|---|
| 1155 | CONTRACTL_END | 
|---|
| 1156 |  | 
|---|
| 1157 | ByRefInfo *pByRefInfos = m_brInfo; | 
|---|
| 1158 | while (pByRefInfos) | 
|---|
| 1159 | { | 
|---|
| 1160 | if (!CorIsPrimitiveType(pByRefInfos->typ)) | 
|---|
| 1161 | { | 
|---|
| 1162 | TADDR pData = PTR_HOST_MEMBER_TADDR(ByRefInfo, pByRefInfos, data); | 
|---|
| 1163 |  | 
|---|
| 1164 | if (pByRefInfos->typeHandle.IsValueType()) | 
|---|
| 1165 | { | 
|---|
| 1166 | ReportPointersFromValueType(fn, sc, pByRefInfos->typeHandle.GetMethodTable(), PTR_VOID(pData)); | 
|---|
| 1167 | } | 
|---|
| 1168 | else | 
|---|
| 1169 | { | 
|---|
| 1170 | PTR_PTR_Object ppObject = PTR_PTR_Object(pData); | 
|---|
| 1171 |  | 
|---|
| 1172 | LOG((LF_GC, INFO3, "ProtectByRefs Frame Promoting"FMT_ADDR "to ", DBG_ADDR(*ppObject))); | 
|---|
| 1173 |  | 
|---|
| 1174 | (*fn)(ppObject, sc, CHECK_APP_DOMAIN); | 
|---|
| 1175 |  | 
|---|
| 1176 | LOG((LF_GC, INFO3, FMT_ADDR "\n", DBG_ADDR(*ppObject) )); | 
|---|
| 1177 | } | 
|---|
| 1178 | } | 
|---|
| 1179 | pByRefInfos = pByRefInfos->pNext; | 
|---|
| 1180 | } | 
|---|
| 1181 | } | 
|---|
| 1182 |  | 
|---|
| 1183 | void ProtectValueClassFrame::GcScanRoots(promote_func *fn, ScanContext *sc) | 
|---|
| 1184 | { | 
|---|
| 1185 | CONTRACTL | 
|---|
| 1186 | { | 
|---|
| 1187 | NOTHROW; | 
|---|
| 1188 | GC_NOTRIGGER; | 
|---|
| 1189 | } | 
|---|
| 1190 | CONTRACTL_END | 
|---|
| 1191 |  | 
|---|
| 1192 | ValueClassInfo *pVCInfo = m_pVCInfo; | 
|---|
| 1193 | while (pVCInfo != NULL) | 
|---|
| 1194 | { | 
|---|
| 1195 | _ASSERTE(pVCInfo->pMT->IsValueType()); | 
|---|
| 1196 | ReportPointersFromValueType(fn, sc, pVCInfo->pMT, pVCInfo->pData); | 
|---|
| 1197 | pVCInfo = pVCInfo->pNext; | 
|---|
| 1198 | } | 
|---|
| 1199 | } | 
|---|
| 1200 |  | 
|---|
| 1201 | // | 
|---|
| 1202 | // Promote Caller Stack | 
|---|
| 1203 | // | 
|---|
| 1204 | // | 
|---|
| 1205 |  | 
|---|
| 1206 | void TransitionFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc) | 
|---|
| 1207 | { | 
|---|
| 1208 | WRAPPER_NO_CONTRACT; | 
|---|
| 1209 |  | 
|---|
| 1210 | // I believe this is the contract: | 
|---|
| 1211 | //CONTRACTL | 
|---|
| 1212 | //{ | 
|---|
| 1213 | //    INSTANCE_CHECK; | 
|---|
| 1214 | //    NOTHROW; | 
|---|
| 1215 | //    GC_NOTRIGGER; | 
|---|
| 1216 | //    FORBID_FAULT; | 
|---|
| 1217 | //    MODE_ANY; | 
|---|
| 1218 | //} | 
|---|
| 1219 | //CONTRACTL_END | 
|---|
| 1220 |  | 
|---|
| 1221 | MethodDesc *pFunction; | 
|---|
| 1222 |  | 
|---|
| 1223 | LOG((LF_GC, INFO3, "    Promoting method caller Arguments\n")); | 
|---|
| 1224 |  | 
|---|
| 1225 | // We're going to have to look at the signature to determine | 
|---|
| 1226 | // which arguments a are pointers....First we need the function | 
|---|
| 1227 | pFunction = GetFunction(); | 
|---|
| 1228 | if (pFunction == NULL) | 
|---|
| 1229 | return; | 
|---|
| 1230 |  | 
|---|
| 1231 | // Now get the signature... | 
|---|
| 1232 | Signature callSignature = pFunction->GetSignature(); | 
|---|
| 1233 | if (callSignature.IsEmpty()) | 
|---|
| 1234 | { | 
|---|
| 1235 | return; | 
|---|
| 1236 | } | 
|---|
| 1237 |  | 
|---|
| 1238 | //If not "vararg" calling convention, assume "default" calling convention | 
|---|
| 1239 | if (!MetaSig::IsVarArg(pFunction->GetModule(), callSignature)) | 
|---|
| 1240 | { | 
|---|
| 1241 | SigTypeContext typeContext(pFunction); | 
|---|
| 1242 | PCCOR_SIGNATURE pSig; | 
|---|
| 1243 | DWORD cbSigSize; | 
|---|
| 1244 | pFunction->GetSig(&pSig, &cbSigSize); | 
|---|
| 1245 |  | 
|---|
| 1246 | MetaSig msig(pSig, cbSigSize, pFunction->GetModule(), &typeContext); | 
|---|
| 1247 |  | 
|---|
| 1248 | if (pFunction->RequiresInstArg() && !SuppressParamTypeArg()) | 
|---|
| 1249 | msig.SetHasParamTypeArg(); | 
|---|
| 1250 |  | 
|---|
| 1251 | PromoteCallerStackHelper (fn, sc, pFunction, &msig); | 
|---|
| 1252 | } | 
|---|
| 1253 | else | 
|---|
| 1254 | { | 
|---|
| 1255 | VASigCookie *varArgSig = GetVASigCookie(); | 
|---|
| 1256 |  | 
|---|
| 1257 | //Note: no instantiations needed for varargs | 
|---|
| 1258 | MetaSig msig(varArgSig->signature, | 
|---|
| 1259 | varArgSig->pModule, | 
|---|
| 1260 | NULL); | 
|---|
| 1261 | PromoteCallerStackHelper (fn, sc, pFunction, &msig); | 
|---|
| 1262 | } | 
|---|
| 1263 | } | 
|---|
| 1264 |  | 
|---|
| 1265 | void TransitionFrame::PromoteCallerStackHelper(promote_func* fn, ScanContext* sc, | 
|---|
| 1266 | MethodDesc *pFunction, MetaSig *pmsig) | 
|---|
| 1267 | { | 
|---|
| 1268 | WRAPPER_NO_CONTRACT; | 
|---|
| 1269 | // I believe this is the contract: | 
|---|
| 1270 | //CONTRACTL | 
|---|
| 1271 | //{ | 
|---|
| 1272 | //    INSTANCE_CHECK; | 
|---|
| 1273 | //    NOTHROW; | 
|---|
| 1274 | //    GC_NOTRIGGER; | 
|---|
| 1275 | //    FORBID_FAULT; | 
|---|
| 1276 | //    MODE_ANY; | 
|---|
| 1277 | //} | 
|---|
| 1278 | //CONTRACTL_END | 
|---|
| 1279 |  | 
|---|
| 1280 | ArgIterator argit(pmsig); | 
|---|
| 1281 |  | 
|---|
| 1282 | TADDR pTransitionBlock = GetTransitionBlock(); | 
|---|
| 1283 |  | 
|---|
| 1284 | // promote 'this' for non-static methods | 
|---|
| 1285 | if (argit.HasThis() && pFunction != NULL) | 
|---|
| 1286 | { | 
|---|
| 1287 | BOOL interior = pFunction->GetMethodTable()->IsValueType() && !pFunction->IsUnboxingStub(); | 
|---|
| 1288 |  | 
|---|
| 1289 | PTR_PTR_VOID pThis = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetThisOffset()); | 
|---|
| 1290 | LOG((LF_GC, INFO3, | 
|---|
| 1291 | "    'this' Argument at "FMT_ADDR "promoted from"FMT_ADDR "\n", | 
|---|
| 1292 | DBG_ADDR(pThis), DBG_ADDR(*pThis) )); | 
|---|
| 1293 |  | 
|---|
| 1294 | if (interior) | 
|---|
| 1295 | PromoteCarefully(fn, PTR_PTR_Object(pThis), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); | 
|---|
| 1296 | else | 
|---|
| 1297 | (fn)(PTR_PTR_Object(pThis), sc, CHECK_APP_DOMAIN); | 
|---|
| 1298 | } | 
|---|
| 1299 |  | 
|---|
| 1300 | if (argit.HasRetBuffArg()) | 
|---|
| 1301 | { | 
|---|
| 1302 | PTR_PTR_VOID pRetBuffArg = dac_cast<PTR_PTR_VOID>(pTransitionBlock + argit.GetRetBuffArgOffset()); | 
|---|
| 1303 | LOG((LF_GC, INFO3, "    ret buf Argument promoted from"FMT_ADDR "\n", DBG_ADDR(*pRetBuffArg) )); | 
|---|
| 1304 | PromoteCarefully(fn, PTR_PTR_Object(pRetBuffArg), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); | 
|---|
| 1305 | } | 
|---|
| 1306 |  | 
|---|
| 1307 | int argOffset; | 
|---|
| 1308 | while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) | 
|---|
| 1309 | { | 
|---|
| 1310 | ArgDestination argDest(dac_cast<PTR_VOID>(pTransitionBlock), argOffset, argit.GetArgLocDescForStructInRegs()); | 
|---|
| 1311 | pmsig->GcScanRoots(&argDest, fn, sc); | 
|---|
| 1312 | } | 
|---|
| 1313 | } | 
|---|
| 1314 |  | 
|---|
| 1315 | #ifdef _TARGET_X86_ | 
|---|
| 1316 | UINT TransitionFrame::CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap) | 
|---|
| 1317 | { | 
|---|
| 1318 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1319 |  | 
|---|
| 1320 | GCRefMapDecoder decoder(pGCRefMap); | 
|---|
| 1321 | return decoder.ReadStackPop() * sizeof(TADDR); | 
|---|
| 1322 | } | 
|---|
| 1323 | #endif | 
|---|
| 1324 |  | 
|---|
| 1325 | void TransitionFrame::PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap) | 
|---|
| 1326 | { | 
|---|
| 1327 | WRAPPER_NO_CONTRACT; | 
|---|
| 1328 |  | 
|---|
| 1329 | GCRefMapDecoder decoder(pGCRefMap); | 
|---|
| 1330 |  | 
|---|
| 1331 | #ifdef _TARGET_X86_ | 
|---|
| 1332 | // Skip StackPop | 
|---|
| 1333 | decoder.ReadStackPop(); | 
|---|
| 1334 | #endif | 
|---|
| 1335 |  | 
|---|
| 1336 | TADDR pTransitionBlock = GetTransitionBlock(); | 
|---|
| 1337 |  | 
|---|
| 1338 | while (!decoder.AtEnd()) | 
|---|
| 1339 | { | 
|---|
| 1340 | int pos = decoder.CurrentPos(); | 
|---|
| 1341 | int token = decoder.ReadToken(); | 
|---|
| 1342 |  | 
|---|
| 1343 | int ofs; | 
|---|
| 1344 |  | 
|---|
| 1345 | #ifdef _TARGET_X86_ | 
|---|
| 1346 | ofs = (pos < NUM_ARGUMENT_REGISTERS) ? | 
|---|
| 1347 | (TransitionBlock::GetOffsetOfArgumentRegisters() + ARGUMENTREGISTERS_SIZE - (pos + 1) * sizeof(TADDR)) : | 
|---|
| 1348 | (TransitionBlock::GetOffsetOfArgs() + (pos - NUM_ARGUMENT_REGISTERS) * sizeof(TADDR)); | 
|---|
| 1349 | #else | 
|---|
| 1350 | ofs = TransitionBlock::GetOffsetOfArgumentRegisters() + pos * sizeof(TADDR); | 
|---|
| 1351 | #endif | 
|---|
| 1352 |  | 
|---|
| 1353 | PTR_TADDR ppObj = dac_cast<PTR_TADDR>(pTransitionBlock + ofs); | 
|---|
| 1354 |  | 
|---|
| 1355 | switch (token) | 
|---|
| 1356 | { | 
|---|
| 1357 | case GCREFMAP_SKIP: | 
|---|
| 1358 | break; | 
|---|
| 1359 | case GCREFMAP_REF: | 
|---|
| 1360 | fn(dac_cast<PTR_PTR_Object>(ppObj), sc, CHECK_APP_DOMAIN); | 
|---|
| 1361 | break; | 
|---|
| 1362 | case GCREFMAP_INTERIOR: | 
|---|
| 1363 | PromoteCarefully(fn, dac_cast<PTR_PTR_Object>(ppObj), sc, GC_CALL_INTERIOR | GC_CALL_CHECK_APP_DOMAIN); | 
|---|
| 1364 | break; | 
|---|
| 1365 | case GCREFMAP_METHOD_PARAM: | 
|---|
| 1366 | if (sc->promotion) | 
|---|
| 1367 | { | 
|---|
| 1368 | #ifndef DACCESS_COMPILE | 
|---|
| 1369 | MethodDesc *pMDReal = dac_cast<PTR_MethodDesc>(*ppObj); | 
|---|
| 1370 | if (pMDReal != NULL) | 
|---|
| 1371 | GcReportLoaderAllocator(fn, sc, pMDReal->GetLoaderAllocator()); | 
|---|
| 1372 | #endif | 
|---|
| 1373 | } | 
|---|
| 1374 | break; | 
|---|
| 1375 | case GCREFMAP_TYPE_PARAM: | 
|---|
| 1376 | if (sc->promotion) | 
|---|
| 1377 | { | 
|---|
| 1378 | #ifndef DACCESS_COMPILE | 
|---|
| 1379 | MethodTable *pMTReal = dac_cast<PTR_MethodTable>(*ppObj); | 
|---|
| 1380 | if (pMTReal != NULL) | 
|---|
| 1381 | GcReportLoaderAllocator(fn, sc, pMTReal->GetLoaderAllocator()); | 
|---|
| 1382 | #endif | 
|---|
| 1383 | } | 
|---|
| 1384 | break; | 
|---|
| 1385 | case GCREFMAP_VASIG_COOKIE: | 
|---|
| 1386 | { | 
|---|
| 1387 | VASigCookie *varArgSig = dac_cast<PTR_VASigCookie>(*ppObj); | 
|---|
| 1388 |  | 
|---|
| 1389 | //Note: no instantiations needed for varargs | 
|---|
| 1390 | MetaSig msig(varArgSig->signature, | 
|---|
| 1391 | varArgSig->pModule, | 
|---|
| 1392 | NULL); | 
|---|
| 1393 | PromoteCallerStackHelper (fn, sc, NULL, &msig); | 
|---|
| 1394 | } | 
|---|
| 1395 | break; | 
|---|
| 1396 | default: | 
|---|
| 1397 | _ASSERTE(! "Unknown GCREFMAP token"); | 
|---|
| 1398 | break; | 
|---|
| 1399 | } | 
|---|
| 1400 | } | 
|---|
| 1401 | } | 
|---|
| 1402 |  | 
|---|
| 1403 | void PInvokeCalliFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc) | 
|---|
| 1404 | { | 
|---|
| 1405 | WRAPPER_NO_CONTRACT; | 
|---|
| 1406 |  | 
|---|
| 1407 | LOG((LF_GC, INFO3, "    Promoting CALLI caller Arguments\n")); | 
|---|
| 1408 |  | 
|---|
| 1409 | // get the signature | 
|---|
| 1410 | VASigCookie *varArgSig = GetVASigCookie(); | 
|---|
| 1411 | if (varArgSig->signature.IsEmpty()) | 
|---|
| 1412 | { | 
|---|
| 1413 | return; | 
|---|
| 1414 | } | 
|---|
| 1415 |  | 
|---|
| 1416 | // no instantiations needed for varargs | 
|---|
| 1417 | MetaSig msig(varArgSig->signature, | 
|---|
| 1418 | varArgSig->pModule, | 
|---|
| 1419 | NULL); | 
|---|
| 1420 | PromoteCallerStackHelper(fn, sc, NULL, &msig); | 
|---|
| 1421 | } | 
|---|
| 1422 |  | 
|---|
| 1423 | #ifndef DACCESS_COMPILE | 
|---|
| 1424 | PInvokeCalliFrame::PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) | 
|---|
| 1425 | : FramedMethodFrame(pTransitionBlock, NULL) | 
|---|
| 1426 | { | 
|---|
| 1427 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1428 |  | 
|---|
| 1429 | m_pVASigCookie = pVASigCookie; | 
|---|
| 1430 | m_pUnmanagedTarget = pUnmanagedTarget; | 
|---|
| 1431 | } | 
|---|
| 1432 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 1433 |  | 
|---|
| 1434 | #ifdef FEATURE_COMINTEROP | 
|---|
| 1435 |  | 
|---|
| 1436 | #ifndef DACCESS_COMPILE | 
|---|
| 1437 | ComPlusMethodFrame::ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD) | 
|---|
| 1438 | : FramedMethodFrame(pTransitionBlock, pMD) | 
|---|
| 1439 | { | 
|---|
| 1440 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1441 | } | 
|---|
| 1442 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 1443 |  | 
|---|
| 1444 | //virtual | 
|---|
| 1445 | void ComPlusMethodFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 1446 | { | 
|---|
| 1447 | WRAPPER_NO_CONTRACT; | 
|---|
| 1448 |  | 
|---|
| 1449 | // ComPlusMethodFrame is only used in the event call / late bound call code path where we do not have IL stub | 
|---|
| 1450 | // so we need to promote the arguments and return value manually. | 
|---|
| 1451 |  | 
|---|
| 1452 | FramedMethodFrame::GcScanRoots(fn, sc); | 
|---|
| 1453 | PromoteCallerStack(fn, sc); | 
|---|
| 1454 |  | 
|---|
| 1455 | MetaSig::RETURNTYPE returnType = GetFunction()->ReturnsObject(); | 
|---|
| 1456 |  | 
|---|
| 1457 | // Promote the returned object | 
|---|
| 1458 | if(returnType == MetaSig::RETOBJ) | 
|---|
| 1459 | (*fn)(GetReturnObjectPtr(), sc, CHECK_APP_DOMAIN); | 
|---|
| 1460 | else if (returnType == MetaSig::RETBYREF) | 
|---|
| 1461 | PromoteCarefully(fn, GetReturnObjectPtr(), sc, GC_CALL_INTERIOR|CHECK_APP_DOMAIN); | 
|---|
| 1462 | } | 
|---|
| 1463 | #endif // FEATURE_COMINTEROP | 
|---|
| 1464 |  | 
|---|
| 1465 | #if defined (_DEBUG) && !defined (DACCESS_COMPILE) | 
|---|
| 1466 | // For IsProtectedByGCFrame, we need to know whether a given object ref is protected | 
|---|
| 1467 | // by a ComPlusMethodFrame or a ComMethodFrame. Since GCScanRoots for those frames are | 
|---|
| 1468 | // quite complicated, we don't want to duplicate their logic so we call GCScanRoots with | 
|---|
| 1469 | // IsObjRefProtected (a fake promote function) and an extended ScanContext to do the checking. | 
|---|
| 1470 |  | 
|---|
| 1471 | struct IsObjRefProtectedScanContext : public ScanContext | 
|---|
| 1472 | { | 
|---|
| 1473 | OBJECTREF * oref_to_check; | 
|---|
| 1474 | BOOL        oref_protected; | 
|---|
| 1475 | IsObjRefProtectedScanContext (OBJECTREF * oref) | 
|---|
| 1476 | { | 
|---|
| 1477 | thread_under_crawl = GetThread (); | 
|---|
| 1478 | promotion = TRUE; | 
|---|
| 1479 | oref_to_check = oref; | 
|---|
| 1480 | oref_protected = FALSE; | 
|---|
| 1481 | } | 
|---|
| 1482 | }; | 
|---|
| 1483 |  | 
|---|
| 1484 | void IsObjRefProtected (Object** ppObj, ScanContext* sc, uint32_t) | 
|---|
| 1485 | { | 
|---|
| 1486 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1487 | IsObjRefProtectedScanContext * orefProtectedSc = (IsObjRefProtectedScanContext *)sc; | 
|---|
| 1488 | if (ppObj == (Object **)(orefProtectedSc->oref_to_check)) | 
|---|
| 1489 | orefProtectedSc->oref_protected = TRUE; | 
|---|
| 1490 | } | 
|---|
| 1491 |  | 
|---|
| 1492 | BOOL TransitionFrame::Protects(OBJECTREF * ppORef) | 
|---|
| 1493 | { | 
|---|
| 1494 | WRAPPER_NO_CONTRACT; | 
|---|
| 1495 | IsObjRefProtectedScanContext sc (ppORef); | 
|---|
| 1496 | // Set the stack limit for the scan to the SP of the managed frame above the transition frame | 
|---|
| 1497 | sc.stack_limit = GetSP(); | 
|---|
| 1498 | GcScanRoots (IsObjRefProtected, &sc); | 
|---|
| 1499 | return sc.oref_protected; | 
|---|
| 1500 | } | 
|---|
| 1501 | #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE) | 
|---|
| 1502 |  | 
|---|
| 1503 | //+---------------------------------------------------------------------------- | 
|---|
| 1504 | // | 
|---|
| 1505 | //  Method:     TPMethodFrame::GcScanRoots    public | 
|---|
| 1506 | // | 
|---|
| 1507 | //  Synopsis:   GC protects arguments on the stack | 
|---|
| 1508 | // | 
|---|
| 1509 |  | 
|---|
| 1510 | // | 
|---|
| 1511 | //+---------------------------------------------------------------------------- | 
|---|
| 1512 |  | 
|---|
| 1513 | #ifdef FEATURE_COMINTEROP | 
|---|
| 1514 |  | 
|---|
| 1515 | #ifdef _TARGET_X86_ | 
|---|
| 1516 | // Return the # of stack bytes pushed by the unmanaged caller. | 
|---|
| 1517 | UINT ComMethodFrame::GetNumCallerStackBytes() | 
|---|
| 1518 | { | 
|---|
| 1519 | WRAPPER_NO_CONTRACT; | 
|---|
| 1520 | SUPPORTS_DAC; | 
|---|
| 1521 |  | 
|---|
| 1522 | ComCallMethodDesc* pCMD = PTR_ComCallMethodDesc((TADDR)GetDatum()); | 
|---|
| 1523 | PREFIX_ASSUME(pCMD != NULL); | 
|---|
| 1524 | // assumes __stdcall | 
|---|
| 1525 | // compute the callee pop stack bytes | 
|---|
| 1526 | return pCMD->GetNumStackBytes(); | 
|---|
| 1527 | } | 
|---|
| 1528 | #endif // _TARGET_X86_ | 
|---|
| 1529 |  | 
|---|
| 1530 | #ifndef DACCESS_COMPILE | 
|---|
| 1531 | void ComMethodFrame::DoSecondPassHandlerCleanup(Frame * pCurFrame) | 
|---|
| 1532 | { | 
|---|
| 1533 | LIMITED_METHOD_CONTRACT; | 
|---|
| 1534 |  | 
|---|
| 1535 | // Find ComMethodFrame, noting any ContextTransitionFrame along the way | 
|---|
| 1536 |  | 
|---|
| 1537 | while ((pCurFrame != FRAME_TOP) && | 
|---|
| 1538 | (pCurFrame->GetVTablePtr() != ComMethodFrame::GetMethodFrameVPtr())) | 
|---|
| 1539 | { | 
|---|
| 1540 | if (pCurFrame->GetVTablePtr() == ContextTransitionFrame::GetMethodFrameVPtr()) | 
|---|
| 1541 | { | 
|---|
| 1542 | // If there is a context transition before we find a ComMethodFrame, do nothing.  Expect that | 
|---|
| 1543 | // the AD transition code will perform the corresponding work after it pops its context | 
|---|
| 1544 | // transition frame and before it rethrows the exception. | 
|---|
| 1545 | return; | 
|---|
| 1546 | } | 
|---|
| 1547 | pCurFrame = pCurFrame->PtrNextFrame(); | 
|---|
| 1548 | } | 
|---|
| 1549 |  | 
|---|
| 1550 | if (pCurFrame == FRAME_TOP) | 
|---|
| 1551 | return; | 
|---|
| 1552 |  | 
|---|
| 1553 | ComMethodFrame * pComMethodFrame = (ComMethodFrame *)pCurFrame; | 
|---|
| 1554 |  | 
|---|
| 1555 | _ASSERTE(pComMethodFrame != NULL); | 
|---|
| 1556 | Thread * pThread = GetThread(); | 
|---|
| 1557 | GCX_COOP_THREAD_EXISTS(pThread); | 
|---|
| 1558 | // Unwind the frames till the entry frame (which was ComMethodFrame) | 
|---|
| 1559 | pCurFrame = pThread->GetFrame(); | 
|---|
| 1560 | while ((pCurFrame != NULL) && (pCurFrame <= pComMethodFrame)) | 
|---|
| 1561 | { | 
|---|
| 1562 | pCurFrame->ExceptionUnwind(); | 
|---|
| 1563 | pCurFrame = pCurFrame->PtrNextFrame(); | 
|---|
| 1564 | } | 
|---|
| 1565 |  | 
|---|
| 1566 | // At this point, pCurFrame would be the ComMethodFrame's predecessor frame | 
|---|
| 1567 | // that we need to reset to. | 
|---|
| 1568 | _ASSERTE((pCurFrame != NULL) && (pComMethodFrame->PtrNextFrame() == pCurFrame)); | 
|---|
| 1569 | pThread->SetFrame(pCurFrame); | 
|---|
| 1570 | } | 
|---|
| 1571 | #endif // !DACCESS_COMPILE | 
|---|
| 1572 |  | 
|---|
| 1573 | #endif // FEATURE_COMINTEROP | 
|---|
| 1574 |  | 
|---|
| 1575 |  | 
|---|
| 1576 | #ifdef _TARGET_X86_ | 
|---|
| 1577 |  | 
|---|
| 1578 | PTR_UMEntryThunk UMThkCallFrame::GetUMEntryThunk() | 
|---|
| 1579 | { | 
|---|
| 1580 | LIMITED_METHOD_DAC_CONTRACT; | 
|---|
| 1581 | return dac_cast<PTR_UMEntryThunk>(GetDatum()); | 
|---|
| 1582 | } | 
|---|
| 1583 |  | 
|---|
| 1584 | #ifdef DACCESS_COMPILE | 
|---|
| 1585 | void UMThkCallFrame::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) | 
|---|
| 1586 | { | 
|---|
| 1587 | WRAPPER_NO_CONTRACT; | 
|---|
| 1588 | UnmanagedToManagedFrame::EnumMemoryRegions(flags); | 
|---|
| 1589 |  | 
|---|
| 1590 | // Pieces of the UMEntryThunk need to be saved. | 
|---|
| 1591 | UMEntryThunk *pThunk = GetUMEntryThunk(); | 
|---|
| 1592 | DacEnumMemoryRegion(dac_cast<TADDR>(pThunk), sizeof(UMEntryThunk)); | 
|---|
| 1593 |  | 
|---|
| 1594 | UMThunkMarshInfo *pMarshInfo = pThunk->GetUMThunkMarshInfo(); | 
|---|
| 1595 | DacEnumMemoryRegion(dac_cast<TADDR>(pMarshInfo), sizeof(UMThunkMarshInfo)); | 
|---|
| 1596 | } | 
|---|
| 1597 | #endif | 
|---|
| 1598 |  | 
|---|
| 1599 | #endif // _TARGET_X86_ | 
|---|
| 1600 |  | 
|---|
| 1601 | #ifndef DACCESS_COMPILE | 
|---|
| 1602 |  | 
|---|
| 1603 | #if defined(_MSC_VER) && defined(_TARGET_X86_) | 
|---|
| 1604 | #pragma optimize("y", on)   // Small critical routines, don't put in EBP frame | 
|---|
| 1605 | #endif | 
|---|
| 1606 |  | 
|---|
| 1607 | // Initialization of HelperMethodFrame. | 
|---|
| 1608 | void HelperMethodFrame::Push() | 
|---|
| 1609 | { | 
|---|
| 1610 | CONTRACTL { | 
|---|
| 1611 | if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS; | 
|---|
| 1612 | GC_TRIGGERS; | 
|---|
| 1613 | MODE_COOPERATIVE; | 
|---|
| 1614 | SO_TOLERANT; | 
|---|
| 1615 | } CONTRACTL_END; | 
|---|
| 1616 |  | 
|---|
| 1617 | // | 
|---|
| 1618 | // Finish initialization | 
|---|
| 1619 | // | 
|---|
| 1620 |  | 
|---|
| 1621 | // Compiler would not inline GetGSCookiePtr() because of it is virtual method. | 
|---|
| 1622 | // Inline it manually and verify that it gives same result. | 
|---|
| 1623 | _ASSERTE(GetGSCookiePtr() == (((GSCookie *)(this)) - 1)); | 
|---|
| 1624 | *(((GSCookie *)(this)) - 1) = GetProcessGSCookie(); | 
|---|
| 1625 |  | 
|---|
| 1626 | _ASSERTE(!m_MachState.isValid()); | 
|---|
| 1627 |  | 
|---|
| 1628 | Thread * pThread = ::GetThread(); | 
|---|
| 1629 | m_pThread = pThread; | 
|---|
| 1630 |  | 
|---|
| 1631 | // Push the frame | 
|---|
| 1632 | Frame::Push(pThread); | 
|---|
| 1633 |  | 
|---|
| 1634 | if (!pThread->HasThreadStateOpportunistic(Thread::TS_AbortRequested)) | 
|---|
| 1635 | return; | 
|---|
| 1636 |  | 
|---|
| 1637 | // Outline the slow path for better perf | 
|---|
| 1638 | PushSlowHelper(); | 
|---|
| 1639 | } | 
|---|
| 1640 |  | 
|---|
| 1641 | void HelperMethodFrame::Pop() | 
|---|
| 1642 | { | 
|---|
| 1643 | CONTRACTL { | 
|---|
| 1644 | if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS; | 
|---|
| 1645 | GC_TRIGGERS; | 
|---|
| 1646 | MODE_COOPERATIVE; | 
|---|
| 1647 | SO_TOLERANT; | 
|---|
| 1648 | } CONTRACTL_END; | 
|---|
| 1649 |  | 
|---|
| 1650 | Thread * pThread = m_pThread; | 
|---|
| 1651 |  | 
|---|
| 1652 | if ((m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) || !pThread->HasThreadStateOpportunistic(Thread::TS_AbortInitiated)) | 
|---|
| 1653 | { | 
|---|
| 1654 | Frame::Pop(pThread); | 
|---|
| 1655 | return; | 
|---|
| 1656 | } | 
|---|
| 1657 |  | 
|---|
| 1658 | // Outline the slow path for better perf | 
|---|
| 1659 | PopSlowHelper(); | 
|---|
| 1660 | } | 
|---|
| 1661 |  | 
|---|
| 1662 | #if defined(_MSC_VER) && defined(_TARGET_X86_) | 
|---|
| 1663 | #pragma optimize("", on)     // Go back to command line default optimizations | 
|---|
| 1664 | #endif | 
|---|
| 1665 |  | 
|---|
| 1666 | NOINLINE void HelperMethodFrame::PushSlowHelper() | 
|---|
| 1667 | { | 
|---|
| 1668 | CONTRACTL { | 
|---|
| 1669 | if (m_Attribs & FRAME_ATTR_NO_THREAD_ABORT) NOTHROW; else THROWS; | 
|---|
| 1670 | GC_TRIGGERS; | 
|---|
| 1671 | MODE_COOPERATIVE; | 
|---|
| 1672 | SO_TOLERANT; | 
|---|
| 1673 | } CONTRACTL_END; | 
|---|
| 1674 |  | 
|---|
| 1675 | if (!(m_Attribs & FRAME_ATTR_NO_THREAD_ABORT)) | 
|---|
| 1676 | { | 
|---|
| 1677 | if (m_pThread->IsAbortRequested()) | 
|---|
| 1678 | { | 
|---|
| 1679 | m_pThread->HandleThreadAbort(); | 
|---|
| 1680 | } | 
|---|
| 1681 |  | 
|---|
| 1682 | } | 
|---|
| 1683 | } | 
|---|
| 1684 |  | 
|---|
| 1685 | NOINLINE void HelperMethodFrame::PopSlowHelper() | 
|---|
| 1686 | { | 
|---|
| 1687 | CONTRACTL { | 
|---|
| 1688 | THROWS; | 
|---|
| 1689 | GC_TRIGGERS; | 
|---|
| 1690 | MODE_COOPERATIVE; | 
|---|
| 1691 | SO_TOLERANT; | 
|---|
| 1692 | } CONTRACTL_END; | 
|---|
| 1693 |  | 
|---|
| 1694 | m_pThread->HandleThreadAbort(); | 
|---|
| 1695 | Frame::Pop(m_pThread); | 
|---|
| 1696 | } | 
|---|
| 1697 |  | 
|---|
| 1698 | #endif // #ifndef DACCESS_COMPILE | 
|---|
| 1699 |  | 
|---|
| 1700 | MethodDesc* HelperMethodFrame::GetFunction() | 
|---|
| 1701 | { | 
|---|
| 1702 | WRAPPER_NO_CONTRACT; | 
|---|
| 1703 |  | 
|---|
| 1704 | #ifndef DACCESS_COMPILE | 
|---|
| 1705 | InsureInit(false, NULL); | 
|---|
| 1706 | return m_pMD; | 
|---|
| 1707 | #else | 
|---|
| 1708 | if (m_MachState.isValid()) | 
|---|
| 1709 | { | 
|---|
| 1710 | return m_pMD; | 
|---|
| 1711 | } | 
|---|
| 1712 | else | 
|---|
| 1713 | { | 
|---|
| 1714 | return ECall::MapTargetBackToMethod(m_FCallEntry); | 
|---|
| 1715 | } | 
|---|
| 1716 | #endif | 
|---|
| 1717 | } | 
|---|
| 1718 |  | 
|---|
| 1719 | //--------------------------------------------------------------------------------------- | 
|---|
| 1720 | // | 
|---|
| 1721 | // Ensures the HelperMethodFrame gets initialized, if not already. | 
|---|
| 1722 | // | 
|---|
| 1723 | // Arguments: | 
|---|
| 1724 | //      * initialInit - | 
|---|
| 1725 | //         * true: ensure the simple, first stage of initialization has been completed. | 
|---|
| 1726 | //             This is used when the HelperMethodFrame is first created. | 
|---|
| 1727 | //         * false: complete any initialization that was left to do, if any. | 
|---|
| 1728 | //      * unwindState - [out] DAC builds use this to return the unwound machine state. | 
|---|
| 1729 | //      * hostCallPreference - (See code:HelperMethodFrame::HostCallPreference.) | 
|---|
| 1730 | // | 
|---|
| 1731 | // Return Value: | 
|---|
| 1732 | //     Normally, the function always returns TRUE meaning the initialization succeeded. | 
|---|
| 1733 | // | 
|---|
| 1734 | //     However, if hostCallPreference is NoHostCalls, AND if a callee (like | 
|---|
| 1735 | //     LazyMachState::unwindLazyState) needed to acquire a JIT reader lock and was unable | 
|---|
| 1736 | //     to do so (lest it re-enter the host), then InsureInit will abort and return FALSE. | 
|---|
| 1737 | //     So any callers that specify hostCallPreference = NoHostCalls (which is not the | 
|---|
| 1738 | //     default), should check for FALSE return, and refuse to use the HMF in that case. | 
|---|
| 1739 | //     Currently only asynchronous calls made by profilers use that code path. | 
|---|
| 1740 | // | 
|---|
| 1741 |  | 
|---|
| 1742 | BOOL HelperMethodFrame::InsureInit(bool initialInit, | 
|---|
| 1743 | MachState * unwindState, | 
|---|
| 1744 | HostCallPreference hostCallPreference /* = AllowHostCalls */) | 
|---|
| 1745 | { | 
|---|
| 1746 | CONTRACTL { | 
|---|
| 1747 | NOTHROW; | 
|---|
| 1748 | GC_NOTRIGGER; | 
|---|
| 1749 | SO_TOLERANT; | 
|---|
| 1750 | if ((hostCallPreference == AllowHostCalls) && !m_MachState.isValid()) { HOST_CALLS; } else { HOST_NOCALLS; } | 
|---|
| 1751 | SUPPORTS_DAC; | 
|---|
| 1752 | } CONTRACTL_END; | 
|---|
| 1753 |  | 
|---|
| 1754 | if (m_MachState.isValid()) | 
|---|
| 1755 | { | 
|---|
| 1756 | return TRUE; | 
|---|
| 1757 | } | 
|---|
| 1758 |  | 
|---|
| 1759 | _ASSERTE(m_Attribs != 0xCCCCCCCC); | 
|---|
| 1760 |  | 
|---|
| 1761 | #ifndef DACCESS_COMPILE | 
|---|
| 1762 | if (!initialInit) | 
|---|
| 1763 | { | 
|---|
| 1764 | m_pMD = ECall::MapTargetBackToMethod(m_FCallEntry); | 
|---|
| 1765 |  | 
|---|
| 1766 | // if this is an FCall, we should find it | 
|---|
| 1767 | _ASSERTE(m_FCallEntry == 0 || m_pMD != 0); | 
|---|
| 1768 | } | 
|---|
| 1769 | #endif | 
|---|
| 1770 |  | 
|---|
| 1771 | // Because TRUE FCalls can be called from via reflection, com-interop, etc., | 
|---|
| 1772 | // we can't rely on the fact that we are called from jitted code to find the | 
|---|
| 1773 | // caller of the FCALL.   Thus FCalls must erect the frame directly in the | 
|---|
| 1774 | // FCall.  For JIT helpers, however, we can rely on this, and so they can | 
|---|
| 1775 | // be sneakier and defer the HelperMethodFrame setup to a called worker method. | 
|---|
| 1776 |  | 
|---|
| 1777 | // Work with a copy so that we only write the values once. | 
|---|
| 1778 | // this avoids race conditions. | 
|---|
| 1779 | LazyMachState* lazy = &m_MachState; | 
|---|
| 1780 | DWORD threadId = m_pThread->GetOSThreadId(); | 
|---|
| 1781 | MachState unwound; | 
|---|
| 1782 |  | 
|---|
| 1783 | if (!initialInit && | 
|---|
| 1784 | m_FCallEntry == 0 && | 
|---|
| 1785 | !(m_Attribs & Frame::FRAME_ATTR_EXACT_DEPTH)) // Jit Helper | 
|---|
| 1786 | { | 
|---|
| 1787 | LazyMachState::unwindLazyState( | 
|---|
| 1788 | lazy, | 
|---|
| 1789 | &unwound, | 
|---|
| 1790 | threadId, | 
|---|
| 1791 | 0, | 
|---|
| 1792 | hostCallPreference); | 
|---|
| 1793 |  | 
|---|
| 1794 | #if !defined(DACCESS_COMPILE) | 
|---|
| 1795 | if (!unwound.isValid()) | 
|---|
| 1796 | { | 
|---|
| 1797 | // This only happens if LazyMachState::unwindLazyState had to abort as a | 
|---|
| 1798 | // result of failing to take a reader lock (because we told it not to yield, | 
|---|
| 1799 | // but the writer lock was already held).  Since we've not yet updated | 
|---|
| 1800 | // m_MachState, this HelperMethodFrame will still be considered not fully | 
|---|
| 1801 | // initialized (so a future call into InsureInit() will attempt to complete | 
|---|
| 1802 | // initialization again). | 
|---|
| 1803 | // | 
|---|
| 1804 | // Note that, in DAC builds, the contract with LazyMachState::unwindLazyState | 
|---|
| 1805 | // is a bit different, and it's expected that LazyMachState::unwindLazyState | 
|---|
| 1806 | // will commonly return an unwound state with _pRetAddr==NULL (which counts | 
|---|
| 1807 | // as an "invalid" MachState). So have DAC builds deliberately fall through | 
|---|
| 1808 | // rather than aborting when unwound is invalid. | 
|---|
| 1809 | _ASSERTE(hostCallPreference == NoHostCalls); | 
|---|
| 1810 | return FALSE; | 
|---|
| 1811 | } | 
|---|
| 1812 | #endif // !defined(DACCESS_COMPILE) | 
|---|
| 1813 | } | 
|---|
| 1814 | else if (!initialInit && | 
|---|
| 1815 | (m_Attribs & Frame::FRAME_ATTR_CAPTURE_DEPTH_2) != 0) | 
|---|
| 1816 | { | 
|---|
| 1817 | // explictly told depth | 
|---|
| 1818 | LazyMachState::unwindLazyState(lazy, &unwound, threadId, 2); | 
|---|
| 1819 | } | 
|---|
| 1820 | else | 
|---|
| 1821 | { | 
|---|
| 1822 | // True FCall | 
|---|
| 1823 | LazyMachState::unwindLazyState(lazy, &unwound, threadId, 1); | 
|---|
| 1824 | } | 
|---|
| 1825 |  | 
|---|
| 1826 | _ASSERTE(unwound.isValid()); | 
|---|
| 1827 |  | 
|---|
| 1828 | #if !defined(DACCESS_COMPILE) | 
|---|
| 1829 | lazy->setLazyStateFromUnwind(&unwound); | 
|---|
| 1830 | #else  // DACCESS_COMPILE | 
|---|
| 1831 | if (unwindState) | 
|---|
| 1832 | { | 
|---|
| 1833 | *unwindState = unwound; | 
|---|
| 1834 | } | 
|---|
| 1835 | #endif // DACCESS_COMPILE | 
|---|
| 1836 |  | 
|---|
| 1837 | return TRUE; | 
|---|
| 1838 | } | 
|---|
| 1839 |  | 
|---|
| 1840 |  | 
|---|
| 1841 | #include "comdelegate.h" | 
|---|
| 1842 |  | 
|---|
| 1843 | Assembly* SecureDelegateFrame::GetAssembly() | 
|---|
| 1844 | { | 
|---|
| 1845 | WRAPPER_NO_CONTRACT; | 
|---|
| 1846 |  | 
|---|
| 1847 | #if !defined(DACCESS_COMPILE) | 
|---|
| 1848 | // obtain the frame off the delegate pointer | 
|---|
| 1849 | DELEGATEREF delegate = (DELEGATEREF) GetThis(); | 
|---|
| 1850 | _ASSERTE(delegate); | 
|---|
| 1851 | if (!delegate->IsWrapperDelegate()) | 
|---|
| 1852 | { | 
|---|
| 1853 | MethodDesc* pMethod = (MethodDesc*) delegate->GetMethodPtrAux(); | 
|---|
| 1854 | Assembly* pAssembly = pMethod->GetAssembly(); | 
|---|
| 1855 | _ASSERTE(pAssembly != NULL); | 
|---|
| 1856 | return pAssembly; | 
|---|
| 1857 | } | 
|---|
| 1858 | else | 
|---|
| 1859 | return NULL; | 
|---|
| 1860 | #else | 
|---|
| 1861 | DacNotImpl(); | 
|---|
| 1862 | return NULL; | 
|---|
| 1863 | #endif | 
|---|
| 1864 | } | 
|---|
| 1865 |  | 
|---|
| 1866 | BOOL SecureDelegateFrame::TraceFrame(Thread *thread, BOOL fromPatch, TraceDestination *trace, REGDISPLAY *regs) | 
|---|
| 1867 | { | 
|---|
| 1868 | WRAPPER_NO_CONTRACT; | 
|---|
| 1869 |  | 
|---|
| 1870 | _ASSERTE(!fromPatch); | 
|---|
| 1871 |  | 
|---|
| 1872 | // Unlike multicast delegates, secure delegates only call one method.  So, we should just return false here | 
|---|
| 1873 | // and let the step out logic continue to the caller of the secure delegate stub. | 
|---|
| 1874 | LOG((LF_CORDB, LL_INFO1000, "SDF::TF: return FALSE\n")); | 
|---|
| 1875 |  | 
|---|
| 1876 | return FALSE; | 
|---|
| 1877 | } | 
|---|
| 1878 |  | 
|---|
| 1879 | BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch, | 
|---|
| 1880 | TraceDestination *trace, REGDISPLAY *regs) | 
|---|
| 1881 | { | 
|---|
| 1882 | CONTRACTL | 
|---|
| 1883 | { | 
|---|
| 1884 | THROWS; | 
|---|
| 1885 | GC_NOTRIGGER; | 
|---|
| 1886 | MODE_COOPERATIVE; | 
|---|
| 1887 | } | 
|---|
| 1888 | CONTRACTL_END; | 
|---|
| 1889 |  | 
|---|
| 1890 | _ASSERTE(!fromPatch); | 
|---|
| 1891 |  | 
|---|
| 1892 | #ifdef DACCESS_COMPILE | 
|---|
| 1893 | return FALSE; | 
|---|
| 1894 |  | 
|---|
| 1895 | #else // !DACCESS_COMPILE | 
|---|
| 1896 | LOG((LF_CORDB,LL_INFO10000, "MulticastFrame::TF FromPatch:0x%x, at 0x%x\n", fromPatch, GetControlPC(regs))); | 
|---|
| 1897 |  | 
|---|
| 1898 | // At this point we have no way to recover the Stub object from the control pc.  We can't use the MD stored | 
|---|
| 1899 | // in the MulticastFrame because it points to the dummy Invoke() method, not the method we want to call. | 
|---|
| 1900 |  | 
|---|
| 1901 | BYTE *pbDel = NULL; | 
|---|
| 1902 | int delegateCount = 0; | 
|---|
| 1903 |  | 
|---|
| 1904 | #if defined(_TARGET_X86_) | 
|---|
| 1905 | // At this point the counter hasn't been incremented yet. | 
|---|
| 1906 | delegateCount = *regs->GetEdiLocation() + 1; | 
|---|
| 1907 | pbDel = *(BYTE **)( (size_t)*regs->GetEsiLocation() + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); | 
|---|
| 1908 | #elif defined(_TARGET_AMD64_) | 
|---|
| 1909 | // At this point the counter hasn't been incremented yet. | 
|---|
| 1910 | delegateCount = (int)regs->pCurrentContext->Rdi + 1; | 
|---|
| 1911 | pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->Rsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); | 
|---|
| 1912 | #elif defined(_TARGET_ARM_) | 
|---|
| 1913 | // At this point the counter has not yet been incremented. Counter is in R7, frame pointer in R4. | 
|---|
| 1914 | delegateCount = regs->pCurrentContext->R7 + 1; | 
|---|
| 1915 | pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->R4) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); | 
|---|
| 1916 | #else | 
|---|
| 1917 | delegateCount = 0; | 
|---|
| 1918 | PORTABILITY_ASSERT( "MulticastFrame::TraceFrame (frames.cpp)"); | 
|---|
| 1919 | #endif | 
|---|
| 1920 |  | 
|---|
| 1921 | int totalDelegateCount = (int)*(size_t*)(pbDel + DelegateObject::GetOffsetOfInvocationCount()); | 
|---|
| 1922 |  | 
|---|
| 1923 | _ASSERTE( COMDelegate::IsTrueMulticastDelegate( ObjectToOBJECTREF((Object*)pbDel) ) ); | 
|---|
| 1924 |  | 
|---|
| 1925 | if (delegateCount == totalDelegateCount) | 
|---|
| 1926 | { | 
|---|
| 1927 | LOG((LF_CORDB, LL_INFO1000, "MF::TF: Executed all stubs, should return\n")); | 
|---|
| 1928 | // We've executed all the stubs, so we should return | 
|---|
| 1929 | return FALSE; | 
|---|
| 1930 | } | 
|---|
| 1931 | else | 
|---|
| 1932 | { | 
|---|
| 1933 | // We're going to execute stub delegateCount next, so go and grab it. | 
|---|
| 1934 | BYTE *pbDelInvocationList = *(BYTE **)(pbDel + DelegateObject::GetOffsetOfInvocationList()); | 
|---|
| 1935 |  | 
|---|
| 1936 | pbDel = *(BYTE**)( ((ArrayBase *)pbDelInvocationList)->GetDataPtr() + | 
|---|
| 1937 | ((ArrayBase *)pbDelInvocationList)->GetComponentSize()*delegateCount); | 
|---|
| 1938 |  | 
|---|
| 1939 | _ASSERTE(pbDel); | 
|---|
| 1940 | return DelegateInvokeStubManager::TraceDelegateObject(pbDel, trace); | 
|---|
| 1941 | } | 
|---|
| 1942 | #endif // !DACCESS_COMPILE | 
|---|
| 1943 | } | 
|---|
| 1944 |  | 
|---|
| 1945 | #ifndef DACCESS_COMPILE | 
|---|
| 1946 |  | 
|---|
| 1947 | VOID InlinedCallFrame::Init() | 
|---|
| 1948 | { | 
|---|
| 1949 | WRAPPER_NO_CONTRACT; | 
|---|
| 1950 |  | 
|---|
| 1951 | *((TADDR *)this) = GetMethodFrameVPtr(); | 
|---|
| 1952 |  | 
|---|
| 1953 | // GetGSCookiePtr contains a virtual call and this is a perf critical method so we don't want to call it in ret builds | 
|---|
| 1954 | GSCookie *ptrGS = (GSCookie *)((BYTE *)this - sizeof(GSCookie)); | 
|---|
| 1955 | _ASSERTE(ptrGS == GetGSCookiePtr()); | 
|---|
| 1956 |  | 
|---|
| 1957 | *ptrGS = GetProcessGSCookie(); | 
|---|
| 1958 |  | 
|---|
| 1959 | m_Datum = NULL; | 
|---|
| 1960 | m_pCallSiteSP = NULL; | 
|---|
| 1961 | m_pCallerReturnAddress = NULL; | 
|---|
| 1962 | } | 
|---|
| 1963 |  | 
|---|
| 1964 |  | 
|---|
| 1965 |  | 
|---|
| 1966 | void UnmanagedToManagedFrame::ExceptionUnwind() | 
|---|
| 1967 | { | 
|---|
| 1968 | WRAPPER_NO_CONTRACT; | 
|---|
| 1969 |  | 
|---|
| 1970 | AppDomain::ExceptionUnwind(this); | 
|---|
| 1971 | } | 
|---|
| 1972 |  | 
|---|
| 1973 | #endif // !DACCESS_COMPILE | 
|---|
| 1974 |  | 
|---|
| 1975 | void ContextTransitionFrame::GcScanRoots(promote_func *fn, ScanContext* sc) | 
|---|
| 1976 | { | 
|---|
| 1977 | WRAPPER_NO_CONTRACT; | 
|---|
| 1978 |  | 
|---|
| 1979 | // Don't check app domains here - m_LastThrownObjectInParentContext is in the parent frame's app domain | 
|---|
| 1980 | (*fn)(dac_cast<PTR_PTR_Object>(PTR_HOST_MEMBER_TADDR(ContextTransitionFrame, this, m_LastThrownObjectInParentContext)), sc, 0); | 
|---|
| 1981 | LOG((LF_GC, INFO3, "    "FMT_ADDR "\n", DBG_ADDR(m_LastThrownObjectInParentContext) )); | 
|---|
| 1982 |  | 
|---|
| 1983 | // don't need to worry about the object moving as it is stored in a weak handle | 
|---|
| 1984 | // but do need to report it so it doesn't get collected if the only reference to | 
|---|
| 1985 | // it is in this frame. So only do something if are in promotion phase. And if are | 
|---|
| 1986 | // in reloc phase this could cause invalid refs as the object may have been moved. | 
|---|
| 1987 | if (! sc->promotion) | 
|---|
| 1988 | return; | 
|---|
| 1989 |  | 
|---|
| 1990 | // The dac only cares about strong references at the moment.  Since this is always | 
|---|
| 1991 | // in a weak ref, we don't report it here. | 
|---|
| 1992 | } | 
|---|
| 1993 |  | 
|---|
| 1994 |  | 
|---|
| 1995 | PCODE UnmanagedToManagedFrame::GetReturnAddress() | 
|---|
| 1996 | { | 
|---|
| 1997 | WRAPPER_NO_CONTRACT; | 
|---|
| 1998 |  | 
|---|
| 1999 | PCODE pRetAddr = Frame::GetReturnAddress(); | 
|---|
| 2000 |  | 
|---|
| 2001 | if (InlinedCallFrame::FrameHasActiveCall(m_Next) && | 
|---|
| 2002 | pRetAddr == m_Next->GetReturnAddress()) | 
|---|
| 2003 | { | 
|---|
| 2004 | // there's actually no unmanaged code involved - we were called directly | 
|---|
| 2005 | // from managed code using an InlinedCallFrame | 
|---|
| 2006 | return NULL; | 
|---|
| 2007 | } | 
|---|
| 2008 | else | 
|---|
| 2009 | { | 
|---|
| 2010 | return pRetAddr; | 
|---|
| 2011 | } | 
|---|
| 2012 | } | 
|---|
| 2013 |  | 
|---|