| 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.H |
| 5 | |
| 6 | |
| 7 | // |
| 8 | // These C++ classes expose activation frames to the rest of the EE. |
| 9 | // Activation frames are actually created by JIT-generated or stub-generated |
| 10 | // code on the machine stack. Thus, the layout of the Frame classes and |
| 11 | // the JIT/Stub code generators are tightly interwined. |
| 12 | // |
| 13 | // IMPORTANT: Since frames are not actually constructed by C++, |
| 14 | // don't try to define constructor/destructor functions. They won't get |
| 15 | // called. |
| 16 | // |
| 17 | // IMPORTANT: Not all methods have full-fledged activation frames (in |
| 18 | // particular, the JIT may create frameless methods.) This is one reason |
| 19 | // why Frame doesn't expose a public "Next()" method: such a method would |
| 20 | // skip frameless method calls. You must instead use one of the |
| 21 | // StackWalk methods. |
| 22 | // |
| 23 | // |
| 24 | // The following is the hierarchy of frames: |
| 25 | // |
| 26 | // Frame - the root class. There are no actual instances |
| 27 | // | of Frames. |
| 28 | // | |
| 29 | // +-GCFrame - this frame doesn't represent a method call. |
| 30 | // | it's sole purpose is to let the EE gc-protect |
| 31 | // | object references that it is manipulating. |
| 32 | // | |
| 33 | // +- FaultingExceptionFrame - this frame was placed on a method which faulted |
| 34 | // | to save additional state information |
| 35 | // | |
| 36 | #ifdef FEATURE_HIJACK |
| 37 | // | |
| 38 | // +-HijackFrame - if a method's return address is hijacked, we |
| 39 | // | construct one of these to allow crawling back |
| 40 | // | to where the return should have gone. |
| 41 | // | |
| 42 | // +-ResumableFrame - this abstract frame provides the context necessary to |
| 43 | // | | allow garbage collection during handling of |
| 44 | // | | a resumable exception (e.g. during edit-and-continue, |
| 45 | // | | or under GCStress4). |
| 46 | // | | |
| 47 | // | +-RedirectedThreadFrame - this frame is used for redirecting threads during suspension |
| 48 | // | |
| 49 | #endif // FEATURE_HIJACK |
| 50 | // | |
| 51 | // | |
| 52 | // | |
| 53 | // +-InlinedCallFrame - if a call to unmanaged code is hoisted into |
| 54 | // | a JIT'ted caller, the calling method keeps |
| 55 | // | this frame linked throughout its activation. |
| 56 | // | |
| 57 | // +-HelperMethodFrame - frame used allow stack crawling inside jit helpers and fcalls |
| 58 | // | | |
| 59 | // + +-HelperMethodFrame_1OBJ- reports additional object references |
| 60 | // | | |
| 61 | // + +-HelperMethodFrame_2OBJ- reports additional object references |
| 62 | // | | |
| 63 | // + +-HelperMethodFrame_3OBJ- reports additional object references |
| 64 | // | | |
| 65 | // + +-HelperMethodFrame_PROTECTOBJ - reports additional object references |
| 66 | // | |
| 67 | // +-TransitionFrame - this abstract frame represents a transition from |
| 68 | // | | one or more nested frameless method calls |
| 69 | // | | to either a EE runtime helper function or |
| 70 | // | | a framed method. |
| 71 | // | | |
| 72 | // | +-StubHelperFrame - for instantiating stubs that need to grow stack arguments |
| 73 | // | | |
| 74 | // | +-SecureDelegateFrame - represents a call Delegate.Invoke for secure delegate |
| 75 | // | | |
| 76 | // | +-MulticastFrame - this frame protects arguments to a MulticastDelegate |
| 77 | // | Invoke() call while calling each subscriber. |
| 78 | // | |
| 79 | // | +-FramedMethodFrame - this abstract frame represents a call to a method |
| 80 | // | | that generates a full-fledged frame. |
| 81 | // | | |
| 82 | #ifdef FEATURE_COMINTEROP |
| 83 | // | | |
| 84 | // | +-ComPlusMethodFrame - represents a CLR to COM call using the generic worker |
| 85 | // | | |
| 86 | #endif //FEATURE_COMINTEROP |
| 87 | // | | |
| 88 | // | +-PInvokeCalliFrame - protects arguments when a call to GetILStubForCalli is made |
| 89 | // | | to get or create IL stub for an unmanaged CALLI |
| 90 | // | | |
| 91 | // | +-PrestubMethodFrame - represents a call to a prestub |
| 92 | // | | |
| 93 | // | +-StubDispatchFrame - represents a call into the virtual call stub manager |
| 94 | // | | |
| 95 | // | | |
| 96 | // | +-ExternalMethodFrame - represents a call from an ExternalMethdThunk |
| 97 | // | | |
| 98 | // | +-TPMethodFrame - for calls on transparent proxy |
| 99 | // | |
| 100 | // +-UnmanagedToManagedFrame - this frame represents a transition from |
| 101 | // | | unmanaged code back to managed code. It's |
| 102 | // | | main functions are to stop COM+ exception |
| 103 | // | | propagation and to expose unmanaged parameters. |
| 104 | // | | |
| 105 | #ifdef FEATURE_COMINTEROP |
| 106 | // | | |
| 107 | // | +-ComMethodFrame - this frame represents a transition from |
| 108 | // | | com to com+ |
| 109 | // | | |
| 110 | // | +-ComPrestubMethodFrame - prestub frame for calls from COM to CLR |
| 111 | // | |
| 112 | #endif //FEATURE_COMINTEROP |
| 113 | #ifdef _TARGET_X86_ |
| 114 | // | +-UMThkCallFrame - this frame represents an unmanaged->managed |
| 115 | // | transition through N/Direct |
| 116 | #endif |
| 117 | // | |
| 118 | // +-ContextTransitionFrame - this frame is used to mark an appdomain transition |
| 119 | // | |
| 120 | // | |
| 121 | // +-TailCallFrame - padding for tailcalls |
| 122 | // | |
| 123 | // +-ProtectByRefsFrame |
| 124 | // | |
| 125 | // +-ProtectValueClassFrame |
| 126 | // | |
| 127 | // +-DebuggerClassInitMarkFrame - marker frame to indicate that "class init" code is running |
| 128 | // | |
| 129 | // +-DebuggerSecurityCodeMarkFrame - marker frame to indicate that security code is running |
| 130 | // | |
| 131 | // +-DebuggerExitFrame - marker frame to indicate that a "break" IL instruction is being executed |
| 132 | // | |
| 133 | // +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and |
| 134 | // | swallow a managed exception |
| 135 | // | |
| 136 | #ifdef DEBUGGING_SUPPORTED |
| 137 | // +-FuncEvalFrame - frame for debugger function evaluation |
| 138 | #endif // DEBUGGING_SUPPORTED |
| 139 | // | |
| 140 | // | |
| 141 | // +-ExceptionFilterFrame - this frame wraps call to exception filter |
| 142 | // |
| 143 | //------------------------------------------------------------------------ |
| 144 | #if 0 |
| 145 | //------------------------------------------------------------------------ |
| 146 | |
| 147 | This is the list of Interop stubs & transition helpers with information |
| 148 | regarding what (if any) Frame they used and where they were set up: |
| 149 | |
| 150 | P/Invoke: |
| 151 | JIT inlined: The code to call the method is inlined into the caller by the JIT. |
| 152 | InlinedCallFrame is erected by the JITted code. |
| 153 | Requires marshaling: The stub does not erect any frames explicitly but contains |
| 154 | an unmanaged CALLI which turns it into the JIT inlined case. |
| 155 | |
| 156 | Delegate over a native function pointer: |
| 157 | The same as P/Invoke but the raw JIT inlined case is not present (the call always |
| 158 | goes through an IL stub). |
| 159 | |
| 160 | Calli: |
| 161 | The same as P/Invoke. |
| 162 | PInvokeCalliFrame is erected in stub generated by GenerateGetStubForPInvokeCalli |
| 163 | before calling to GetILStubForCalli which generates the IL stub. This happens only |
| 164 | the first time a call via the corresponding VASigCookie is made. |
| 165 | |
| 166 | ClrToCom: |
| 167 | Late-bound or eventing: The stub is generated by GenerateGenericComplusWorker |
| 168 | (x86) or exists statically as GenericComPlusCallStub[RetBuffArg] (64-bit), |
| 169 | and it erects a ComPlusMethodFrame frame. |
| 170 | Early-bound: The stub does not erect any frames explicitly but contains an |
| 171 | unmanaged CALLI which turns it into the JIT inlined case. |
| 172 | |
| 173 | ComToClr: |
| 174 | Normal stub: |
| 175 | Interpreted: The stub is generated by ComCall::CreateGenericComCallStub |
| 176 | (in ComToClrCall.cpp) and it erects a ComMethodFrame frame. |
| 177 | Prestub: |
| 178 | The prestub is ComCallPreStub (in ComCallableWrapper.cpp) and it erects |
| 179 | a ComPrestubMethodFrame frame. |
| 180 | |
| 181 | Reverse P/Invoke (used for C++ exports & fixups as well as delegates |
| 182 | obtained from function pointers): |
| 183 | Normal stub: |
| 184 | x86: The stub is generated by UMEntryThunk::CompileUMThunkWorker |
| 185 | (in DllImportCallback.cpp) and it is frameless. It calls directly |
| 186 | the managed target or to IL stub if marshaling is required. |
| 187 | non-x86: The stub exists statically as UMThunkStub and calls to IL stub. |
| 188 | Prestub: |
| 189 | The prestub is generated by GenerateUMThunkPrestub (x86) or exists statically |
| 190 | as TheUMEntryPrestub (64-bit), and it erects an UMThkCallFrame frame. |
| 191 | |
| 192 | Reverse P/Invoke AppDomain selector stub: |
| 193 | The asm helper is IJWNOADThunkJumpTarget (in asmhelpers.asm) and it is frameless. |
| 194 | |
| 195 | //------------------------------------------------------------------------ |
| 196 | #endif // 0 |
| 197 | //------------------------------------------------------------------------ |
| 198 | |
| 199 | #ifndef FRAME_ABSTRACT_TYPE_NAME |
| 200 | #define FRAME_ABSTRACT_TYPE_NAME(frameType) |
| 201 | #endif |
| 202 | #ifndef FRAME_TYPE_NAME |
| 203 | #define FRAME_TYPE_NAME(frameType) |
| 204 | #endif |
| 205 | |
| 206 | FRAME_ABSTRACT_TYPE_NAME(FrameBase) |
| 207 | FRAME_ABSTRACT_TYPE_NAME(Frame) |
| 208 | FRAME_ABSTRACT_TYPE_NAME(TransitionFrame) |
| 209 | #ifdef FEATURE_HIJACK |
| 210 | FRAME_TYPE_NAME(ResumableFrame) |
| 211 | FRAME_TYPE_NAME(RedirectedThreadFrame) |
| 212 | #endif // FEATURE_HIJACK |
| 213 | FRAME_TYPE_NAME(FaultingExceptionFrame) |
| 214 | #ifdef DEBUGGING_SUPPORTED |
| 215 | FRAME_TYPE_NAME(FuncEvalFrame) |
| 216 | #endif // DEBUGGING_SUPPORTED |
| 217 | FRAME_TYPE_NAME(HelperMethodFrame) |
| 218 | FRAME_TYPE_NAME(HelperMethodFrame_1OBJ) |
| 219 | FRAME_TYPE_NAME(HelperMethodFrame_2OBJ) |
| 220 | FRAME_TYPE_NAME(HelperMethodFrame_3OBJ) |
| 221 | FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ) |
| 222 | FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame) |
| 223 | FRAME_TYPE_NAME(SecureDelegateFrame) |
| 224 | FRAME_TYPE_NAME(MulticastFrame) |
| 225 | FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame) |
| 226 | #ifdef FEATURE_COMINTEROP |
| 227 | FRAME_TYPE_NAME(ComMethodFrame) |
| 228 | FRAME_TYPE_NAME(ComPlusMethodFrame) |
| 229 | FRAME_TYPE_NAME(ComPrestubMethodFrame) |
| 230 | #endif // FEATURE_COMINTEROP |
| 231 | FRAME_TYPE_NAME(PInvokeCalliFrame) |
| 232 | #ifdef FEATURE_HIJACK |
| 233 | FRAME_TYPE_NAME(HijackFrame) |
| 234 | #endif // FEATURE_HIJACK |
| 235 | FRAME_TYPE_NAME(PrestubMethodFrame) |
| 236 | FRAME_TYPE_NAME(StubDispatchFrame) |
| 237 | FRAME_TYPE_NAME(ExternalMethodFrame) |
| 238 | #ifdef FEATURE_READYTORUN |
| 239 | FRAME_TYPE_NAME(DynamicHelperFrame) |
| 240 | #endif |
| 241 | #if !defined(_TARGET_X86_) |
| 242 | FRAME_TYPE_NAME(StubHelperFrame) |
| 243 | #endif |
| 244 | FRAME_TYPE_NAME(GCFrame) |
| 245 | #ifdef FEATURE_INTERPRETER |
| 246 | FRAME_TYPE_NAME(InterpreterFrame) |
| 247 | #endif // FEATURE_INTERPRETER |
| 248 | FRAME_TYPE_NAME(ProtectByRefsFrame) |
| 249 | FRAME_TYPE_NAME(ProtectValueClassFrame) |
| 250 | FRAME_TYPE_NAME(DebuggerClassInitMarkFrame) |
| 251 | FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame) |
| 252 | FRAME_TYPE_NAME(DebuggerExitFrame) |
| 253 | FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame) |
| 254 | #ifdef _TARGET_X86_ |
| 255 | FRAME_TYPE_NAME(UMThkCallFrame) |
| 256 | #endif |
| 257 | FRAME_TYPE_NAME(InlinedCallFrame) |
| 258 | FRAME_TYPE_NAME(ContextTransitionFrame) |
| 259 | FRAME_TYPE_NAME(TailCallFrame) |
| 260 | FRAME_TYPE_NAME(ExceptionFilterFrame) |
| 261 | #if defined(_DEBUG) |
| 262 | FRAME_TYPE_NAME(AssumeByrefFromJITStack) |
| 263 | #endif // _DEBUG |
| 264 | |
| 265 | #undef FRAME_ABSTRACT_TYPE_NAME |
| 266 | #undef FRAME_TYPE_NAME |
| 267 | |
| 268 | //------------------------------------------------------------------------ |
| 269 | |
| 270 | #ifndef __frames_h__ |
| 271 | #define __frames_h__ |
| 272 | #if defined(_MSC_VER) && defined(_TARGET_X86_) && !defined(FPO_ON) |
| 273 | #pragma optimize("y", on) // Small critical routines, don't put in EBP frame |
| 274 | #define FPO_ON 1 |
| 275 | #define FRAMES_TURNED_FPO_ON 1 |
| 276 | #endif |
| 277 | |
| 278 | #include "util.hpp" |
| 279 | #include "vars.hpp" |
| 280 | #include "regdisp.h" |
| 281 | #include "object.h" |
| 282 | #include <stddef.h> |
| 283 | #include "siginfo.hpp" |
| 284 | #include "method.hpp" |
| 285 | #include "stackwalk.h" |
| 286 | #include "stubmgr.h" |
| 287 | #include "gms.h" |
| 288 | #include "threads.h" |
| 289 | #include "callingconvention.h" |
| 290 | |
| 291 | // Forward references |
| 292 | class Frame; |
| 293 | class FieldMarshaler; |
| 294 | class FramedMethodFrame; |
| 295 | typedef VPTR(class FramedMethodFrame) PTR_FramedMethodFrame; |
| 296 | struct HijackArgs; |
| 297 | class UMEntryThunk; |
| 298 | class UMThunkMarshInfo; |
| 299 | class Marshaler; |
| 300 | struct ResolveCacheElem; |
| 301 | #if defined(DACCESS_COMPILE) |
| 302 | class DacDbiInterfaceImpl; |
| 303 | #endif // DACCESS_COMPILE |
| 304 | #ifdef FEATURE_COMINTEROP |
| 305 | class ComMethodFrame; |
| 306 | class ComCallMethodDesc; |
| 307 | #endif // FEATURE_COMINTEROP |
| 308 | |
| 309 | // Note: the value (-1) is used to generate the largest possible pointer value: this keeps frame addresses |
| 310 | // increasing upward. Because we want to ensure that we don't accidentally change this, we have a C_ASSERT |
| 311 | // in stackwalk.cpp. Since it requires constant values as args, we need to define FRAME_TOP in two steps. |
| 312 | // First we define FRAME_TOP_VALUE which we'll use when we do the compile-time check, then we'll define |
| 313 | // FRAME_TOP in terms of FRAME_TOP_VALUE. Defining FRAME_TOP as a PTR_Frame means we don't have to type cast |
| 314 | // whenever we compare it to a PTR_Frame value (the usual use of the value). |
| 315 | #define FRAME_TOP_VALUE ~0 // we want to say -1 here, but gcc has trouble with the signed value |
| 316 | #define FRAME_TOP (PTR_Frame(FRAME_TOP_VALUE)) |
| 317 | |
| 318 | #ifndef DACCESS_COMPILE |
| 319 | |
| 320 | #if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE) |
| 321 | |
| 322 | #define DEFINE_DTOR(klass) \ |
| 323 | public: \ |
| 324 | virtual ~klass() { PopIfChained(); } |
| 325 | |
| 326 | #else |
| 327 | |
| 328 | #define DEFINE_DTOR(klass) |
| 329 | |
| 330 | #endif // FEATURE_PAL && !CROSSGEN_COMPILE |
| 331 | |
| 332 | #define DEFINE_VTABLE_GETTER(klass) \ |
| 333 | public: \ |
| 334 | static TADDR GetMethodFrameVPtr() { \ |
| 335 | LIMITED_METHOD_CONTRACT; \ |
| 336 | klass boilerplate(false); \ |
| 337 | return *((TADDR*)&boilerplate); \ |
| 338 | } \ |
| 339 | klass(bool dummy) { LIMITED_METHOD_CONTRACT; } |
| 340 | |
| 341 | #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \ |
| 342 | DEFINE_VTABLE_GETTER(klass) \ |
| 343 | DEFINE_DTOR(klass) |
| 344 | |
| 345 | #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \ |
| 346 | DEFINE_VTABLE_GETTER(klass) \ |
| 347 | protected: \ |
| 348 | klass() { LIMITED_METHOD_CONTRACT; } |
| 349 | |
| 350 | #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \ |
| 351 | DEFINE_VTABLE_GETTER_AND_DTOR(klass) \ |
| 352 | protected: \ |
| 353 | klass() { LIMITED_METHOD_CONTRACT; } |
| 354 | |
| 355 | #else |
| 356 | |
| 357 | #define DEFINE_VTABLE_GETTER(klass) \ |
| 358 | public: \ |
| 359 | static TADDR GetMethodFrameVPtr() { \ |
| 360 | LIMITED_METHOD_CONTRACT; \ |
| 361 | return klass::VPtrTargetVTable(); \ |
| 362 | } \ |
| 363 | |
| 364 | #define DEFINE_VTABLE_GETTER_AND_DTOR(klass) \ |
| 365 | DEFINE_VTABLE_GETTER(klass) \ |
| 366 | |
| 367 | #define DEFINE_VTABLE_GETTER_AND_CTOR(klass) \ |
| 368 | DEFINE_VTABLE_GETTER(klass) \ |
| 369 | |
| 370 | #define DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(klass) \ |
| 371 | DEFINE_VTABLE_GETTER_AND_CTOR(klass) \ |
| 372 | |
| 373 | #endif // #ifndef DACCESS_COMPILE |
| 374 | |
| 375 | //----------------------------------------------------------------------------- |
| 376 | // For reporting on types of frames at runtime. |
| 377 | class FrameTypeName |
| 378 | { |
| 379 | public: |
| 380 | TADDR vtbl; |
| 381 | PTR_CSTR name; |
| 382 | }; |
| 383 | typedef DPTR(FrameTypeName) PTR_FrameTypeName; |
| 384 | |
| 385 | //----------------------------------------------------------------------------- |
| 386 | // Frame depends on the location of its vtable within the object. This |
| 387 | // superclass ensures that the vtable for Frame objects is in the same |
| 388 | // location under both MSVC and GCC. |
| 389 | //----------------------------------------------------------------------------- |
| 390 | |
| 391 | class FrameBase |
| 392 | { |
| 393 | VPTR_BASE_VTABLE_CLASS(FrameBase) |
| 394 | |
| 395 | public: |
| 396 | FrameBase() {LIMITED_METHOD_CONTRACT; } |
| 397 | |
| 398 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) { |
| 399 | LIMITED_METHOD_CONTRACT; |
| 400 | // Nothing to protect |
| 401 | } |
| 402 | |
| 403 | #ifdef DACCESS_COMPILE |
| 404 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) = 0; |
| 405 | #endif |
| 406 | }; |
| 407 | |
| 408 | //------------------------------------------------------------------------ |
| 409 | // Frame defines methods common to all frame types. There are no actual |
| 410 | // instances of root frames. |
| 411 | //------------------------------------------------------------------------ |
| 412 | |
| 413 | class Frame : public FrameBase |
| 414 | { |
| 415 | friend class CheckAsmOffsets; |
| 416 | #ifdef DACCESS_COMPILE |
| 417 | friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
| 418 | #endif |
| 419 | |
| 420 | VPTR_ABSTRACT_VTABLE_CLASS(Frame, FrameBase) |
| 421 | |
| 422 | public: |
| 423 | |
| 424 | //------------------------------------------------------------------------ |
| 425 | // Special characteristics of a frame |
| 426 | //------------------------------------------------------------------------ |
| 427 | enum FrameAttribs { |
| 428 | FRAME_ATTR_NONE = 0, |
| 429 | FRAME_ATTR_EXCEPTION = 1, // This frame caused an exception |
| 430 | FRAME_ATTR_OUT_OF_LINE = 2, // The exception out of line (IP of the frame is not correct) |
| 431 | FRAME_ATTR_FAULTED = 4, // Exception caused by Win32 fault |
| 432 | FRAME_ATTR_RESUMABLE = 8, // We may resume from this frame |
| 433 | FRAME_ATTR_CAPTURE_DEPTH_2 = 0x10, // This is a helperMethodFrame and the capture occurred at depth 2 |
| 434 | FRAME_ATTR_EXACT_DEPTH = 0x20, // This is a helperMethodFrame and a jit helper, but only crawl to the given depth |
| 435 | FRAME_ATTR_NO_THREAD_ABORT = 0x40, // This is a helperMethodFrame that should not trigger thread aborts on entry |
| 436 | }; |
| 437 | virtual unsigned GetFrameAttribs() |
| 438 | { |
| 439 | LIMITED_METHOD_DAC_CONTRACT; |
| 440 | return FRAME_ATTR_NONE; |
| 441 | } |
| 442 | |
| 443 | //------------------------------------------------------------------------ |
| 444 | // Performs cleanup on an exception unwind |
| 445 | //------------------------------------------------------------------------ |
| 446 | #ifndef DACCESS_COMPILE |
| 447 | virtual void ExceptionUnwind() |
| 448 | { |
| 449 | // Nothing to do here. |
| 450 | LIMITED_METHOD_CONTRACT; |
| 451 | } |
| 452 | #endif |
| 453 | |
| 454 | // Should be overridden to return TRUE if the frame contains register |
| 455 | // state of the caller. |
| 456 | virtual BOOL NeedsUpdateRegDisplay() |
| 457 | { |
| 458 | return FALSE; |
| 459 | } |
| 460 | |
| 461 | //------------------------------------------------------------------------ |
| 462 | // Is this a frame used on transition to native code from jitted code? |
| 463 | //------------------------------------------------------------------------ |
| 464 | virtual BOOL IsTransitionToNativeFrame() |
| 465 | { |
| 466 | LIMITED_METHOD_CONTRACT; |
| 467 | return FALSE; |
| 468 | } |
| 469 | |
| 470 | virtual MethodDesc *GetFunction() |
| 471 | { |
| 472 | LIMITED_METHOD_DAC_CONTRACT; |
| 473 | return NULL; |
| 474 | } |
| 475 | |
| 476 | virtual Assembly *GetAssembly() |
| 477 | { |
| 478 | WRAPPER_NO_CONTRACT; |
| 479 | MethodDesc *pMethod = GetFunction(); |
| 480 | if (pMethod != NULL) |
| 481 | return pMethod->GetModule()->GetAssembly(); |
| 482 | else |
| 483 | return NULL; |
| 484 | } |
| 485 | |
| 486 | // indicate the current X86 IP address within the current method |
| 487 | // return 0 if the information is not available |
| 488 | virtual PTR_BYTE GetIP() |
| 489 | { |
| 490 | LIMITED_METHOD_CONTRACT; |
| 491 | return NULL; |
| 492 | } |
| 493 | |
| 494 | // DACCESS: GetReturnAddressPtr should return the |
| 495 | // target address of the return address in the frame. |
| 496 | virtual TADDR GetReturnAddressPtr() |
| 497 | { |
| 498 | LIMITED_METHOD_DAC_CONTRACT; |
| 499 | return NULL; |
| 500 | } |
| 501 | |
| 502 | virtual PCODE GetReturnAddress() |
| 503 | { |
| 504 | WRAPPER_NO_CONTRACT; |
| 505 | TADDR ptr = GetReturnAddressPtr(); |
| 506 | return (ptr != NULL) ? *PTR_PCODE(ptr) : NULL; |
| 507 | } |
| 508 | |
| 509 | AppDomain *GetReturnDomain() |
| 510 | { |
| 511 | LIMITED_METHOD_CONTRACT; |
| 512 | return NULL; |
| 513 | } |
| 514 | |
| 515 | #ifndef DACCESS_COMPILE |
| 516 | virtual Object **GetReturnExecutionContextAddr() |
| 517 | { |
| 518 | LIMITED_METHOD_CONTRACT; |
| 519 | return NULL; |
| 520 | } |
| 521 | |
| 522 | void SetReturnAddress(TADDR val) |
| 523 | { |
| 524 | WRAPPER_NO_CONTRACT; |
| 525 | TADDR ptr = GetReturnAddressPtr(); |
| 526 | _ASSERTE(ptr != NULL); |
| 527 | *(TADDR*)ptr = val; |
| 528 | } |
| 529 | #endif // #ifndef DACCESS_COMPILE |
| 530 | |
| 531 | PTR_GSCookie GetGSCookiePtr() |
| 532 | { |
| 533 | WRAPPER_NO_CONTRACT; |
| 534 | return dac_cast<PTR_GSCookie>(dac_cast<TADDR>(this) + GetOffsetOfGSCookie()); |
| 535 | } |
| 536 | |
| 537 | static int GetOffsetOfGSCookie() |
| 538 | { |
| 539 | LIMITED_METHOD_DAC_CONTRACT; |
| 540 | return -(int)sizeof(GSCookie); |
| 541 | } |
| 542 | |
| 543 | static bool HasValidVTablePtr(Frame * pFrame); |
| 544 | static PTR_GSCookie SafeGetGSCookiePtr(Frame * pFrame); |
| 545 | static void Init(); |
| 546 | static void Term(); |
| 547 | |
| 548 | // Callers, note that the REGDISPLAY parameter is actually in/out. While |
| 549 | // UpdateRegDisplay is generally used to fill out the REGDISPLAY parameter, some |
| 550 | // overrides (e.g., code:ResumableFrame::UpdateRegDisplay) will actually READ what |
| 551 | // you pass in. So be sure to pass in a valid or zeroed out REGDISPLAY. |
| 552 | virtual void UpdateRegDisplay(const PREGDISPLAY) |
| 553 | { |
| 554 | LIMITED_METHOD_DAC_CONTRACT; |
| 555 | return; |
| 556 | } |
| 557 | |
| 558 | //------------------------------------------------------------------------ |
| 559 | // Debugger support |
| 560 | //------------------------------------------------------------------------ |
| 561 | |
| 562 | |
| 563 | public: |
| 564 | enum ETransitionType |
| 565 | { |
| 566 | TT_NONE, |
| 567 | TT_M2U, // we can safely cast to a FramedMethodFrame |
| 568 | TT_U2M, // we can safely cast to a UnmanagedToManagedFrame |
| 569 | TT_AppDomain, // transitioniting between AppDomains. |
| 570 | TT_InternalCall, // calling into the CLR (ecall/fcall). |
| 571 | }; |
| 572 | |
| 573 | // Get the type of transition. |
| 574 | // M-->U, U-->M |
| 575 | virtual ETransitionType GetTransitionType() |
| 576 | { |
| 577 | LIMITED_METHOD_DAC_CONTRACT; |
| 578 | return TT_NONE; |
| 579 | } |
| 580 | |
| 581 | enum |
| 582 | { |
| 583 | TYPE_INTERNAL, |
| 584 | TYPE_ENTRY, |
| 585 | TYPE_EXIT, |
| 586 | TYPE_CONTEXT_CROSS, |
| 587 | TYPE_INTERCEPTION, |
| 588 | TYPE_SECURITY, |
| 589 | TYPE_CALL, |
| 590 | TYPE_FUNC_EVAL, |
| 591 | TYPE_MULTICAST, |
| 592 | |
| 593 | // HMFs and derived classes should use this so the profiling API knows it needs |
| 594 | // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host. |
| 595 | TYPE_HELPER_METHOD_FRAME, |
| 596 | |
| 597 | TYPE_COUNT |
| 598 | }; |
| 599 | |
| 600 | virtual int GetFrameType() |
| 601 | { |
| 602 | LIMITED_METHOD_DAC_CONTRACT; |
| 603 | return TYPE_INTERNAL; |
| 604 | }; |
| 605 | |
| 606 | // When stepping into a method, various other methods may be called. |
| 607 | // These are refererred to as interceptors. They are all invoked |
| 608 | // with frames of various types. GetInterception() indicates whether |
| 609 | // the frame was set up for execution of such interceptors |
| 610 | |
| 611 | enum Interception |
| 612 | { |
| 613 | INTERCEPTION_NONE, |
| 614 | INTERCEPTION_CLASS_INIT, |
| 615 | INTERCEPTION_EXCEPTION, |
| 616 | INTERCEPTION_CONTEXT, |
| 617 | INTERCEPTION_SECURITY, |
| 618 | INTERCEPTION_PRESTUB, |
| 619 | INTERCEPTION_OTHER, |
| 620 | |
| 621 | INTERCEPTION_COUNT |
| 622 | }; |
| 623 | |
| 624 | virtual Interception GetInterception() |
| 625 | { |
| 626 | LIMITED_METHOD_DAC_CONTRACT; |
| 627 | return INTERCEPTION_NONE; |
| 628 | } |
| 629 | |
| 630 | // Return information about an unmanaged call the frame |
| 631 | // will make. |
| 632 | // ip - the unmanaged routine which will be called |
| 633 | // returnIP - the address in the stub which the unmanaged routine |
| 634 | // will return to. |
| 635 | // returnSP - the location returnIP is pushed onto the stack |
| 636 | // during the call. |
| 637 | // |
| 638 | virtual void GetUnmanagedCallSite(TADDR* ip, |
| 639 | TADDR* returnIP, |
| 640 | TADDR* returnSP) |
| 641 | { |
| 642 | LIMITED_METHOD_CONTRACT; |
| 643 | if (ip) |
| 644 | *ip = NULL; |
| 645 | |
| 646 | if (returnIP) |
| 647 | *returnIP = NULL; |
| 648 | |
| 649 | if (returnSP) |
| 650 | *returnSP = NULL; |
| 651 | } |
| 652 | |
| 653 | // Return where the frame will execute next - the result is filled |
| 654 | // into the given "trace" structure. The frame is responsible for |
| 655 | // detecting where it is in its execution lifetime. |
| 656 | virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 657 | TraceDestination *trace, REGDISPLAY *regs) |
| 658 | { |
| 659 | LIMITED_METHOD_CONTRACT; |
| 660 | LOG((LF_CORDB, LL_INFO10000, |
| 661 | "Default TraceFrame always returns false.\n" )); |
| 662 | return FALSE; |
| 663 | } |
| 664 | |
| 665 | #ifdef DACCESS_COMPILE |
| 666 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
| 667 | { |
| 668 | WRAPPER_NO_CONTRACT; |
| 669 | DAC_ENUM_VTHIS(); |
| 670 | |
| 671 | // Many frames store a MethodDesc pointer in m_Datum |
| 672 | // so pick that up automatically. |
| 673 | MethodDesc* func = GetFunction(); |
| 674 | if (func) |
| 675 | { |
| 676 | func->EnumMemoryRegions(flags); |
| 677 | } |
| 678 | |
| 679 | // Include the NegSpace |
| 680 | GSCookie * pGSCookie = GetGSCookiePtr(); |
| 681 | _ASSERTE(FitsIn<ULONG32>(PBYTE(pGSCookie) - PBYTE(this))); |
| 682 | ULONG32 negSpaceSize = static_cast<ULONG32>(PBYTE(pGSCookie) - PBYTE(this)); |
| 683 | DacEnumMemoryRegion(dac_cast<TADDR>(this) - negSpaceSize, negSpaceSize); |
| 684 | } |
| 685 | #endif |
| 686 | |
| 687 | //--------------------------------------------------------------- |
| 688 | // Expose key offsets and values for stub generation. |
| 689 | //--------------------------------------------------------------- |
| 690 | static BYTE GetOffsetOfNextLink() |
| 691 | { |
| 692 | WRAPPER_NO_CONTRACT; |
| 693 | size_t ofs = offsetof(class Frame, m_Next); |
| 694 | _ASSERTE(FitsInI1(ofs)); |
| 695 | return (BYTE)ofs; |
| 696 | } |
| 697 | |
| 698 | // get your VTablePointer (can be used to check what type the frame is) |
| 699 | TADDR GetVTablePtr() |
| 700 | { |
| 701 | LIMITED_METHOD_DAC_CONTRACT; |
| 702 | return VPTR_HOST_VTABLE_TO_TADDR(*(LPVOID*)this); |
| 703 | } |
| 704 | |
| 705 | #if defined(_DEBUG) && !defined(DACCESS_COMPILE) |
| 706 | virtual BOOL Protects(OBJECTREF *ppObjectRef) |
| 707 | { |
| 708 | LIMITED_METHOD_CONTRACT; |
| 709 | return FALSE; |
| 710 | } |
| 711 | #endif |
| 712 | |
| 713 | #ifndef DACCESS_COMPILE |
| 714 | // Link and Unlink this frame |
| 715 | VOID Push(); |
| 716 | VOID Pop(); |
| 717 | VOID Push(Thread *pThread); |
| 718 | VOID Pop(Thread *pThread); |
| 719 | #endif // DACCESS_COMPILE |
| 720 | |
| 721 | #ifdef _DEBUG_IMPL |
| 722 | void Log(); |
| 723 | static BOOL ShouldLogTransitions() { WRAPPER_NO_CONTRACT; return LoggingOn(LF_STUBS, LL_INFO1000000); } |
| 724 | static void __stdcall LogTransition(Frame* frame); |
| 725 | void LogFrame(int LF, int LL); // General purpose logging. |
| 726 | void LogFrameChain(int LF, int LL); // Log the whole chain. |
| 727 | virtual const char* GetFrameTypeName() {return NULL;} |
| 728 | static PTR_CSTR GetFrameTypeName(TADDR vtbl); |
| 729 | #endif |
| 730 | |
| 731 | //------------------------------------------------------------------------ |
| 732 | // Returns the address of a security object or |
| 733 | // null if there is no space for an object on this frame. |
| 734 | //------------------------------------------------------------------------ |
| 735 | virtual OBJECTREF *GetAddrOfSecurityDesc() |
| 736 | { |
| 737 | LIMITED_METHOD_CONTRACT; |
| 738 | return NULL; |
| 739 | } |
| 740 | |
| 741 | private: |
| 742 | // Pointer to the next frame up the stack. |
| 743 | |
| 744 | protected: |
| 745 | PTR_Frame m_Next; // offset +4 |
| 746 | |
| 747 | public: |
| 748 | PTR_Frame PtrNextFrame() { return m_Next; } |
| 749 | |
| 750 | private: |
| 751 | // Because JIT-method activations cannot be expressed as Frames, |
| 752 | // everyone must use the StackCrawler to walk the frame chain |
| 753 | // reliably. We'll expose the Next method only to the StackCrawler |
| 754 | // to prevent mistakes. |
| 755 | /*<TODO>@NICE: Restrict "friendship" again to the StackWalker method; |
| 756 | not done because of circular dependency with threads.h</TODO> |
| 757 | */ |
| 758 | // friend Frame* Thread::StackWalkFrames(PSTACKWALKFRAMESCALLBACK pCallback, VOID *pData); |
| 759 | friend class Thread; |
| 760 | friend void CrawlFrame::GotoNextFrame(); |
| 761 | friend class StackFrameIterator; |
| 762 | friend class TailCallFrame; |
| 763 | friend class AppDomain; |
| 764 | friend VOID RealCOMPlusThrow(OBJECTREF |
| 765 | #ifdef FEATURE_CORRUPTING_EXCEPTIONS |
| 766 | , CorruptionSeverity severity |
| 767 | #endif // FEATURE_CORRUPTING_EXCEPTIONS |
| 768 | ); |
| 769 | friend FCDECL0(VOID, JIT_StressGC); |
| 770 | #ifdef _DEBUG |
| 771 | friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo); |
| 772 | #endif |
| 773 | #ifdef _WIN64 |
| 774 | friend Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubSecretArg); |
| 775 | #endif |
| 776 | #ifdef WIN64EXCEPTIONS |
| 777 | friend class ExceptionTracker; |
| 778 | #endif |
| 779 | #if defined(DACCESS_COMPILE) |
| 780 | friend class DacDbiInterfaceImpl; |
| 781 | #endif // DACCESS_COMPILE |
| 782 | |
| 783 | PTR_Frame Next() |
| 784 | { |
| 785 | LIMITED_METHOD_DAC_CONTRACT; |
| 786 | return m_Next; |
| 787 | } |
| 788 | |
| 789 | protected: |
| 790 | // Frame is considered an abstract class: this protected constructor |
| 791 | // causes any attempt to instantiate one to fail at compile-time. |
| 792 | Frame() |
| 793 | : m_Next(dac_cast<PTR_Frame>(nullptr)) |
| 794 | { |
| 795 | LIMITED_METHOD_CONTRACT; |
| 796 | } |
| 797 | |
| 798 | #if defined(FEATURE_PAL) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
| 799 | virtual ~Frame() { LIMITED_METHOD_CONTRACT; } |
| 800 | |
| 801 | void PopIfChained(); |
| 802 | #endif // FEATURE_PAL && !DACCESS_COMPILE && !CROSSGEN_COMPILE |
| 803 | }; |
| 804 | |
| 805 | |
| 806 | //----------------------------------------------------------------------------- |
| 807 | // This frame provides context for a frame that |
| 808 | // took an exception that is going to be resumed. |
| 809 | // |
| 810 | // It is necessary to create this frame if garbage |
| 811 | // collection may happen during handling of the |
| 812 | // exception. The FRAME_ATTR_RESUMABLE flag tells |
| 813 | // the GC that the preceding frame needs to be treated |
| 814 | // like the top of stack (with the important implication that |
| 815 | // caller-save-regsiters will be potential roots). |
| 816 | //----------------------------------------------------------------------------- |
| 817 | #ifdef FEATURE_HIJACK |
| 818 | //----------------------------------------------------------------------------- |
| 819 | |
| 820 | class ResumableFrame : public Frame |
| 821 | { |
| 822 | VPTR_VTABLE_CLASS(ResumableFrame, Frame) |
| 823 | |
| 824 | public: |
| 825 | #ifndef DACCESS_COMPILE |
| 826 | ResumableFrame(T_CONTEXT* regs) { |
| 827 | LIMITED_METHOD_CONTRACT; |
| 828 | m_Regs = regs; |
| 829 | } |
| 830 | #endif |
| 831 | |
| 832 | virtual TADDR GetReturnAddressPtr(); |
| 833 | |
| 834 | virtual BOOL NeedsUpdateRegDisplay() |
| 835 | { |
| 836 | return TRUE; |
| 837 | } |
| 838 | |
| 839 | virtual void UpdateRegDisplay(const PREGDISPLAY pRD); |
| 840 | |
| 841 | virtual unsigned GetFrameAttribs() { |
| 842 | LIMITED_METHOD_DAC_CONTRACT; |
| 843 | return FRAME_ATTR_RESUMABLE; // Treat the next frame as the top frame. |
| 844 | } |
| 845 | |
| 846 | T_CONTEXT *GetContext() { |
| 847 | LIMITED_METHOD_DAC_CONTRACT; |
| 848 | return (m_Regs); |
| 849 | } |
| 850 | |
| 851 | #ifdef DACCESS_COMPILE |
| 852 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
| 853 | { |
| 854 | WRAPPER_NO_CONTRACT; |
| 855 | Frame::EnumMemoryRegions(flags); |
| 856 | m_Regs.EnumMem(); |
| 857 | } |
| 858 | #endif |
| 859 | |
| 860 | protected: |
| 861 | PTR_CONTEXT m_Regs; |
| 862 | |
| 863 | // Keep as last entry in class |
| 864 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ResumableFrame) |
| 865 | }; |
| 866 | |
| 867 | |
| 868 | //----------------------------------------------------------------------------- |
| 869 | // RedirectedThreadFrame |
| 870 | //----------------------------------------------------------------------------- |
| 871 | |
| 872 | class RedirectedThreadFrame : public ResumableFrame |
| 873 | { |
| 874 | VPTR_VTABLE_CLASS(RedirectedThreadFrame, ResumableFrame) |
| 875 | VPTR_UNIQUE(VPTR_UNIQUE_RedirectedThreadFrame) |
| 876 | |
| 877 | public: |
| 878 | #ifndef DACCESS_COMPILE |
| 879 | RedirectedThreadFrame(T_CONTEXT *regs) : ResumableFrame(regs) { |
| 880 | LIMITED_METHOD_CONTRACT; |
| 881 | } |
| 882 | |
| 883 | virtual void ExceptionUnwind(); |
| 884 | #endif |
| 885 | |
| 886 | // Keep as last entry in class |
| 887 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(RedirectedThreadFrame) |
| 888 | }; |
| 889 | |
| 890 | typedef DPTR(RedirectedThreadFrame) PTR_RedirectedThreadFrame; |
| 891 | |
| 892 | inline BOOL ISREDIRECTEDTHREAD(Thread * thread) |
| 893 | { |
| 894 | WRAPPER_NO_CONTRACT; |
| 895 | return (thread->GetFrame() != FRAME_TOP && |
| 896 | thread->GetFrame()->GetVTablePtr() == |
| 897 | RedirectedThreadFrame::GetMethodFrameVPtr()); |
| 898 | } |
| 899 | |
| 900 | inline T_CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) |
| 901 | { |
| 902 | WRAPPER_NO_CONTRACT; |
| 903 | _ASSERTE(ISREDIRECTEDTHREAD(thread)); |
| 904 | return dac_cast<PTR_RedirectedThreadFrame>(thread->GetFrame())->GetContext(); |
| 905 | } |
| 906 | |
| 907 | //------------------------------------------------------------------------ |
| 908 | #else // FEATURE_HIJACK |
| 909 | //------------------------------------------------------------------------ |
| 910 | |
| 911 | inline BOOL ISREDIRECTEDTHREAD(Thread * thread) { LIMITED_METHOD_CONTRACT; return FALSE; } |
| 912 | inline CONTEXT * GETREDIRECTEDCONTEXT(Thread * thread) { LIMITED_METHOD_CONTRACT; return (CONTEXT*) NULL; } |
| 913 | |
| 914 | //------------------------------------------------------------------------ |
| 915 | #endif // FEATURE_HIJACK |
| 916 | //------------------------------------------------------------------------ |
| 917 | // This frame represents a transition from one or more nested frameless |
| 918 | // method calls to either a EE runtime helper function or a framed method. |
| 919 | // Because most stackwalks from the EE start with a full-fledged frame, |
| 920 | // anything but the most trivial call into the EE has to push this |
| 921 | // frame in order to prevent the frameless methods inbetween from |
| 922 | // getting lost. |
| 923 | //------------------------------------------------------------------------ |
| 924 | |
| 925 | class TransitionFrame : public Frame |
| 926 | { |
| 927 | VPTR_ABSTRACT_VTABLE_CLASS(TransitionFrame, Frame) |
| 928 | |
| 929 | public: |
| 930 | virtual TADDR GetTransitionBlock() = 0; |
| 931 | |
| 932 | // DACCESS: GetReturnAddressPtr should return the |
| 933 | // target address of the return address in the frame. |
| 934 | virtual TADDR GetReturnAddressPtr() |
| 935 | { |
| 936 | LIMITED_METHOD_DAC_CONTRACT; |
| 937 | return GetTransitionBlock() + TransitionBlock::GetOffsetOfReturnAddress(); |
| 938 | } |
| 939 | |
| 940 | //--------------------------------------------------------------- |
| 941 | // Get the "this" object. |
| 942 | //--------------------------------------------------------------- |
| 943 | OBJECTREF GetThis() |
| 944 | { |
| 945 | WRAPPER_NO_CONTRACT; |
| 946 | Object* obj = PTR_Object(*PTR_TADDR(GetAddrOfThis())); |
| 947 | return ObjectToOBJECTREF(obj); |
| 948 | } |
| 949 | |
| 950 | PTR_OBJECTREF GetThisPtr() |
| 951 | { |
| 952 | WRAPPER_NO_CONTRACT; |
| 953 | return PTR_OBJECTREF(GetAddrOfThis()); |
| 954 | } |
| 955 | |
| 956 | //--------------------------------------------------------------- |
| 957 | // Get the extra info for shared generic code. |
| 958 | //--------------------------------------------------------------- |
| 959 | PTR_VOID GetParamTypeArg(); |
| 960 | |
| 961 | //--------------------------------------------------------------- |
| 962 | // Gets value indicating whether the generic parameter type |
| 963 | // argument should be supressed. |
| 964 | //--------------------------------------------------------------- |
| 965 | virtual BOOL SuppressParamTypeArg() |
| 966 | { |
| 967 | return FALSE; |
| 968 | } |
| 969 | |
| 970 | protected: // we don't want people using this directly |
| 971 | //--------------------------------------------------------------- |
| 972 | // Get the address of the "this" object. WARNING!!! Whether or not "this" |
| 973 | // is gc-protected is depends on the frame type!!! |
| 974 | //--------------------------------------------------------------- |
| 975 | TADDR GetAddrOfThis(); |
| 976 | |
| 977 | public: |
| 978 | //--------------------------------------------------------------- |
| 979 | // For vararg calls, return cookie. |
| 980 | //--------------------------------------------------------------- |
| 981 | VASigCookie *GetVASigCookie(); |
| 982 | |
| 983 | CalleeSavedRegisters *GetCalleeSavedRegisters() |
| 984 | { |
| 985 | LIMITED_METHOD_DAC_CONTRACT; |
| 986 | return dac_cast<PTR_CalleeSavedRegisters>( |
| 987 | GetTransitionBlock() + TransitionBlock::GetOffsetOfCalleeSavedRegisters()); |
| 988 | } |
| 989 | |
| 990 | ArgumentRegisters *GetArgumentRegisters() |
| 991 | { |
| 992 | LIMITED_METHOD_DAC_CONTRACT; |
| 993 | return dac_cast<PTR_ArgumentRegisters>( |
| 994 | GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()); |
| 995 | } |
| 996 | |
| 997 | TADDR GetSP() |
| 998 | { |
| 999 | LIMITED_METHOD_DAC_CONTRACT; |
| 1000 | return GetTransitionBlock() + sizeof(TransitionBlock); |
| 1001 | } |
| 1002 | |
| 1003 | virtual BOOL NeedsUpdateRegDisplay() |
| 1004 | { |
| 1005 | return TRUE; |
| 1006 | } |
| 1007 | |
| 1008 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 1009 | #ifdef _TARGET_X86_ |
| 1010 | void UpdateRegDisplayHelper(const PREGDISPLAY, UINT cbStackPop); |
| 1011 | #endif |
| 1012 | |
| 1013 | #if defined (_DEBUG) && !defined (DACCESS_COMPILE) |
| 1014 | virtual BOOL Protects(OBJECTREF *ppORef); |
| 1015 | #endif //defined (_DEBUG) && defined (DACCESS_COMPILE) |
| 1016 | |
| 1017 | // For use by classes deriving from FramedMethodFrame. |
| 1018 | void PromoteCallerStack(promote_func* fn, ScanContext* sc); |
| 1019 | |
| 1020 | void PromoteCallerStackHelper(promote_func* fn, ScanContext* sc, |
| 1021 | MethodDesc * pMD, MetaSig *pmsig); |
| 1022 | |
| 1023 | void PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanContext* sc, PTR_BYTE pGCRefMap); |
| 1024 | |
| 1025 | #ifdef _TARGET_X86_ |
| 1026 | UINT CbStackPopUsingGCRefMap(PTR_BYTE pGCRefMap); |
| 1027 | #endif |
| 1028 | |
| 1029 | protected: |
| 1030 | TransitionFrame() |
| 1031 | { |
| 1032 | LIMITED_METHOD_CONTRACT; |
| 1033 | } |
| 1034 | }; |
| 1035 | |
| 1036 | //----------------------------------------------------------------------- |
| 1037 | // TransitionFrames for exceptions |
| 1038 | //----------------------------------------------------------------------- |
| 1039 | |
| 1040 | // The define USE_FEF controls how this class is used. Look for occurances |
| 1041 | // of USE_FEF. |
| 1042 | |
| 1043 | class FaultingExceptionFrame : public Frame |
| 1044 | { |
| 1045 | friend class CheckAsmOffsets; |
| 1046 | |
| 1047 | #ifndef WIN64EXCEPTIONS |
| 1048 | #ifdef _TARGET_X86_ |
| 1049 | DWORD m_Esp; |
| 1050 | CalleeSavedRegisters m_regs; |
| 1051 | TADDR m_ReturnAddress; |
| 1052 | #else // _TARGET_X86_ |
| 1053 | #error "Unsupported architecture" |
| 1054 | #endif // _TARGET_X86_ |
| 1055 | #else // WIN64EXCEPTIONS |
| 1056 | BOOL m_fFilterExecuted; // Flag for FirstCallToHandler |
| 1057 | TADDR m_ReturnAddress; |
| 1058 | T_CONTEXT m_ctx; |
| 1059 | #endif // !WIN64EXCEPTIONS |
| 1060 | |
| 1061 | VPTR_VTABLE_CLASS(FaultingExceptionFrame, Frame) |
| 1062 | |
| 1063 | public: |
| 1064 | #ifndef DACCESS_COMPILE |
| 1065 | FaultingExceptionFrame() { |
| 1066 | LIMITED_METHOD_CONTRACT; |
| 1067 | } |
| 1068 | #endif |
| 1069 | |
| 1070 | virtual TADDR GetReturnAddressPtr() |
| 1071 | { |
| 1072 | LIMITED_METHOD_DAC_CONTRACT; |
| 1073 | return PTR_HOST_MEMBER_TADDR(FaultingExceptionFrame, this, m_ReturnAddress); |
| 1074 | } |
| 1075 | |
| 1076 | void Init(T_CONTEXT *pContext); |
| 1077 | void InitAndLink(T_CONTEXT *pContext); |
| 1078 | |
| 1079 | Interception GetInterception() |
| 1080 | { |
| 1081 | LIMITED_METHOD_DAC_CONTRACT; |
| 1082 | return INTERCEPTION_EXCEPTION; |
| 1083 | } |
| 1084 | |
| 1085 | unsigned GetFrameAttribs() |
| 1086 | { |
| 1087 | LIMITED_METHOD_DAC_CONTRACT; |
| 1088 | return FRAME_ATTR_EXCEPTION | FRAME_ATTR_FAULTED; |
| 1089 | } |
| 1090 | |
| 1091 | #ifndef WIN64EXCEPTIONS |
| 1092 | CalleeSavedRegisters *GetCalleeSavedRegisters() |
| 1093 | { |
| 1094 | #ifdef _TARGET_X86_ |
| 1095 | LIMITED_METHOD_DAC_CONTRACT; |
| 1096 | return &m_regs; |
| 1097 | #else |
| 1098 | PORTABILITY_ASSERT("GetCalleeSavedRegisters" ); |
| 1099 | #endif // _TARGET_X86_ |
| 1100 | } |
| 1101 | #endif // WIN64EXCEPTIONS |
| 1102 | |
| 1103 | #ifdef WIN64EXCEPTIONS |
| 1104 | T_CONTEXT *GetExceptionContext () |
| 1105 | { |
| 1106 | LIMITED_METHOD_CONTRACT; |
| 1107 | return &m_ctx; |
| 1108 | } |
| 1109 | |
| 1110 | BOOL * GetFilterExecutedFlag() |
| 1111 | { |
| 1112 | LIMITED_METHOD_CONTRACT; |
| 1113 | return &m_fFilterExecuted; |
| 1114 | } |
| 1115 | #endif // WIN64EXCEPTIONS |
| 1116 | |
| 1117 | virtual BOOL NeedsUpdateRegDisplay() |
| 1118 | { |
| 1119 | return TRUE; |
| 1120 | } |
| 1121 | |
| 1122 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 1123 | |
| 1124 | // Keep as last entry in class |
| 1125 | DEFINE_VTABLE_GETTER_AND_DTOR(FaultingExceptionFrame) |
| 1126 | }; |
| 1127 | |
| 1128 | //----------------------------------------------------------------------- |
| 1129 | // Frame for debugger function evaluation |
| 1130 | // |
| 1131 | // This frame holds a ptr to a DebuggerEval object which contains a copy |
| 1132 | // of the thread's context at the time it was hijacked for the func |
| 1133 | // eval. |
| 1134 | // |
| 1135 | // UpdateRegDisplay updates all registers inthe REGDISPLAY, not just |
| 1136 | // the callee saved registers, because we can hijack for a func eval |
| 1137 | // at any point in a thread's execution. |
| 1138 | // |
| 1139 | //----------------------------------------------------------------------- |
| 1140 | |
| 1141 | #ifdef DEBUGGING_SUPPORTED |
| 1142 | class DebuggerEval; |
| 1143 | typedef DPTR(class DebuggerEval) PTR_DebuggerEval; |
| 1144 | |
| 1145 | class FuncEvalFrame : public Frame |
| 1146 | { |
| 1147 | VPTR_VTABLE_CLASS(FuncEvalFrame, Frame) |
| 1148 | |
| 1149 | TADDR m_ReturnAddress; |
| 1150 | PTR_DebuggerEval m_pDebuggerEval; |
| 1151 | |
| 1152 | BOOL m_showFrame; |
| 1153 | |
| 1154 | public: |
| 1155 | #ifndef DACCESS_COMPILE |
| 1156 | FuncEvalFrame(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) |
| 1157 | { |
| 1158 | LIMITED_METHOD_CONTRACT; |
| 1159 | m_pDebuggerEval = pDebuggerEval; |
| 1160 | m_ReturnAddress = returnAddress; |
| 1161 | m_showFrame = showFrame; |
| 1162 | } |
| 1163 | #endif |
| 1164 | |
| 1165 | virtual BOOL IsTransitionToNativeFrame() |
| 1166 | { |
| 1167 | LIMITED_METHOD_CONTRACT; |
| 1168 | return FALSE; |
| 1169 | } |
| 1170 | |
| 1171 | virtual int GetFrameType() |
| 1172 | { |
| 1173 | LIMITED_METHOD_DAC_CONTRACT; |
| 1174 | return TYPE_FUNC_EVAL; |
| 1175 | } |
| 1176 | |
| 1177 | virtual unsigned GetFrameAttribs(); |
| 1178 | |
| 1179 | virtual BOOL NeedsUpdateRegDisplay() |
| 1180 | { |
| 1181 | return TRUE; |
| 1182 | } |
| 1183 | |
| 1184 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 1185 | |
| 1186 | virtual DebuggerEval * GetDebuggerEval(); |
| 1187 | |
| 1188 | virtual TADDR GetReturnAddressPtr(); |
| 1189 | |
| 1190 | /* |
| 1191 | * ShowFrame |
| 1192 | * |
| 1193 | * Returns if this frame should be returned as part of a stack trace to a debugger or not. |
| 1194 | * |
| 1195 | */ |
| 1196 | BOOL ShowFrame() |
| 1197 | { |
| 1198 | LIMITED_METHOD_CONTRACT; |
| 1199 | |
| 1200 | return m_showFrame; |
| 1201 | } |
| 1202 | |
| 1203 | // Keep as last entry in class |
| 1204 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(FuncEvalFrame) |
| 1205 | }; |
| 1206 | |
| 1207 | typedef VPTR(FuncEvalFrame) PTR_FuncEvalFrame; |
| 1208 | #endif // DEBUGGING_SUPPORTED |
| 1209 | |
| 1210 | //---------------------------------------------------------------------------------------------- |
| 1211 | // A HelperMethodFrame is created by jit helper (Modified slightly it could be used |
| 1212 | // for native routines). This frame just does the callee saved register fixup. |
| 1213 | // It does NOT protect arguments; you must use GCPROTECT or one of the HelperMethodFrame |
| 1214 | // subclases. (see JitInterface for sample use, YOU CAN'T RETURN WHILE IN THE PROTECTED STATE!) |
| 1215 | //---------------------------------------------------------------------------------------------- |
| 1216 | |
| 1217 | class HelperMethodFrame : public Frame |
| 1218 | { |
| 1219 | VPTR_VTABLE_CLASS(HelperMethodFrame, Frame); |
| 1220 | |
| 1221 | public: |
| 1222 | #ifndef DACCESS_COMPILE |
| 1223 | // Lazy initialization of HelperMethodFrame. Need to |
| 1224 | // call InsureInit to complete initialization |
| 1225 | // If this is an FCall, the first param is the entry point for the FCALL. |
| 1226 | // The MethodDesc will be looked up form this (lazily), and this method |
| 1227 | // will be used in stack reporting, if this is not an FCall pass a 0 |
| 1228 | FORCEINLINE HelperMethodFrame(void* fCallFtnEntry, unsigned attribs = 0) |
| 1229 | { |
| 1230 | WRAPPER_NO_CONTRACT; |
| 1231 | // Most of the initialization is actually done in HelperMethodFrame::Push() |
| 1232 | INDEBUG(memset(&m_Attribs, 0xCC, sizeof(HelperMethodFrame) - offsetof(HelperMethodFrame, m_Attribs));) |
| 1233 | m_Attribs = attribs; |
| 1234 | m_FCallEntry = (TADDR)fCallFtnEntry; |
| 1235 | } |
| 1236 | #endif // DACCESS_COMPILE |
| 1237 | |
| 1238 | virtual int GetFrameType() |
| 1239 | { |
| 1240 | LIMITED_METHOD_DAC_CONTRACT; |
| 1241 | return TYPE_HELPER_METHOD_FRAME; |
| 1242 | }; |
| 1243 | |
| 1244 | virtual PCODE GetReturnAddress() |
| 1245 | { |
| 1246 | LIMITED_METHOD_DAC_CONTRACT; |
| 1247 | |
| 1248 | if (!m_MachState.isValid()) |
| 1249 | { |
| 1250 | #if defined(DACCESS_COMPILE) |
| 1251 | MachState unwoundState; |
| 1252 | InsureInit(false, &unwoundState); |
| 1253 | return unwoundState.GetRetAddr(); |
| 1254 | #else // !DACCESS_COMPILE |
| 1255 | _ASSERTE(!"HMF's should always be initialized in the non-DAC world." ); |
| 1256 | return NULL; |
| 1257 | |
| 1258 | #endif // !DACCESS_COMPILE |
| 1259 | } |
| 1260 | |
| 1261 | return m_MachState.GetRetAddr(); |
| 1262 | } |
| 1263 | |
| 1264 | virtual MethodDesc* GetFunction(); |
| 1265 | |
| 1266 | virtual BOOL NeedsUpdateRegDisplay() |
| 1267 | { |
| 1268 | return TRUE; |
| 1269 | } |
| 1270 | |
| 1271 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 1272 | |
| 1273 | virtual Interception GetInterception() |
| 1274 | { |
| 1275 | WRAPPER_NO_CONTRACT; |
| 1276 | LIMITED_METHOD_DAC_CONTRACT; |
| 1277 | if (GetFrameAttribs() & FRAME_ATTR_EXCEPTION) |
| 1278 | return(INTERCEPTION_EXCEPTION); |
| 1279 | return(INTERCEPTION_NONE); |
| 1280 | } |
| 1281 | |
| 1282 | virtual ETransitionType GetTransitionType() |
| 1283 | { |
| 1284 | LIMITED_METHOD_DAC_CONTRACT; |
| 1285 | return TT_InternalCall; |
| 1286 | } |
| 1287 | |
| 1288 | #ifdef _DEBUG |
| 1289 | void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck) |
| 1290 | { |
| 1291 | m_pDoneCheck = pDoneCheck; |
| 1292 | } |
| 1293 | |
| 1294 | BOOL HaveDoneConfirmStateCheck() |
| 1295 | { |
| 1296 | LIMITED_METHOD_CONTRACT; |
| 1297 | _ASSERTE(m_pDoneCheck != NULL); |
| 1298 | return *m_pDoneCheck; |
| 1299 | } |
| 1300 | |
| 1301 | void SetHaveDoneConfirmStateCheck() |
| 1302 | { |
| 1303 | LIMITED_METHOD_CONTRACT; |
| 1304 | _ASSERTE(m_pDoneCheck != NULL); |
| 1305 | *m_pDoneCheck = TRUE; |
| 1306 | } |
| 1307 | #endif |
| 1308 | |
| 1309 | virtual unsigned GetFrameAttribs() |
| 1310 | { |
| 1311 | LIMITED_METHOD_DAC_CONTRACT; |
| 1312 | return(m_Attribs); |
| 1313 | } |
| 1314 | |
| 1315 | #ifdef DACCESS_COMPILE |
| 1316 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
| 1317 | { |
| 1318 | WRAPPER_NO_CONTRACT; |
| 1319 | Frame::EnumMemoryRegions(flags); |
| 1320 | } |
| 1321 | #endif |
| 1322 | |
| 1323 | #ifndef DACCESS_COMPILE |
| 1324 | void Push(); |
| 1325 | void Pop(); |
| 1326 | |
| 1327 | FORCEINLINE void Poll() |
| 1328 | { |
| 1329 | WRAPPER_NO_CONTRACT; |
| 1330 | if (m_pThread->CatchAtSafePointOpportunistic()) |
| 1331 | CommonTripThread(); |
| 1332 | } |
| 1333 | #endif // DACCESS_COMPILE |
| 1334 | |
| 1335 | BOOL InsureInit(bool initialInit, struct MachState* unwindState, HostCallPreference hostCallPreference = AllowHostCalls); |
| 1336 | |
| 1337 | LazyMachState * MachineState() { |
| 1338 | LIMITED_METHOD_CONTRACT; |
| 1339 | return &m_MachState; |
| 1340 | } |
| 1341 | |
| 1342 | Thread * GetThread() { |
| 1343 | LIMITED_METHOD_CONTRACT; |
| 1344 | return m_pThread; |
| 1345 | } |
| 1346 | |
| 1347 | private: |
| 1348 | // Slow paths of Push/Pop are factored into a separate functions for better perf. |
| 1349 | NOINLINE void PushSlowHelper(); |
| 1350 | NOINLINE void PopSlowHelper(); |
| 1351 | |
| 1352 | protected: |
| 1353 | PTR_MethodDesc m_pMD; |
| 1354 | unsigned m_Attribs; |
| 1355 | INDEBUG(BOOL* m_pDoneCheck;) |
| 1356 | PTR_Thread m_pThread; |
| 1357 | TADDR m_FCallEntry; // used to determine our identity for stack traces |
| 1358 | |
| 1359 | LazyMachState m_MachState; // pRetAddr points to the return address and the stack arguments |
| 1360 | |
| 1361 | // Keep as last entry in class |
| 1362 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame) |
| 1363 | }; |
| 1364 | |
| 1365 | // Restores registers saved in m_MachState |
| 1366 | EXTERN_C int __fastcall HelperMethodFrameRestoreState( |
| 1367 | INDEBUG_COMMA(HelperMethodFrame *pFrame) |
| 1368 | MachState *pState |
| 1369 | ); |
| 1370 | |
| 1371 | |
| 1372 | // workhorse for our promotion efforts |
| 1373 | inline void DoPromote(promote_func *fn, ScanContext* sc, OBJECTREF *address, BOOL interior) |
| 1374 | { |
| 1375 | WRAPPER_NO_CONTRACT; |
| 1376 | |
| 1377 | // We use OBJECTREF_TO_UNCHECKED_OBJECTREF since address may be an interior pointer |
| 1378 | LOG((LF_GC, INFO3, |
| 1379 | " Promoting pointer argument at" FMT_ADDR "from" FMT_ADDR "to " , |
| 1380 | DBG_ADDR(address), DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) )); |
| 1381 | |
| 1382 | if (interior) |
| 1383 | PromoteCarefully(fn, PTR_PTR_Object(address), sc); |
| 1384 | else |
| 1385 | (*fn) (PTR_PTR_Object(address), sc, 0); |
| 1386 | |
| 1387 | LOG((LF_GC, INFO3, " " FMT_ADDR "\n" , DBG_ADDR(OBJECTREF_TO_UNCHECKED_OBJECTREF(*address)) )); |
| 1388 | } |
| 1389 | |
| 1390 | |
| 1391 | //----------------------------------------------------------------------------- |
| 1392 | // a HelplerMethodFrames that also report additional object references |
| 1393 | //----------------------------------------------------------------------------- |
| 1394 | |
| 1395 | class HelperMethodFrame_1OBJ : public HelperMethodFrame |
| 1396 | { |
| 1397 | VPTR_VTABLE_CLASS(HelperMethodFrame_1OBJ, HelperMethodFrame) |
| 1398 | |
| 1399 | public: |
| 1400 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
| 1401 | HelperMethodFrame_1OBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* aGCPtr1) |
| 1402 | : HelperMethodFrame(fCallFtnEntry, attribs) |
| 1403 | { |
| 1404 | LIMITED_METHOD_CONTRACT; |
| 1405 | gcPtrs[0] = aGCPtr1; |
| 1406 | INDEBUG(Thread::ObjectRefProtected(aGCPtr1);) |
| 1407 | INDEBUG((*aGCPtr1).Validate ();) |
| 1408 | } |
| 1409 | #endif |
| 1410 | |
| 1411 | void SetProtectedObject(PTR_OBJECTREF objPtr) |
| 1412 | { |
| 1413 | LIMITED_METHOD_CONTRACT; |
| 1414 | gcPtrs[0] = objPtr; |
| 1415 | INDEBUG(Thread::ObjectRefProtected(objPtr);) |
| 1416 | } |
| 1417 | |
| 1418 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 1419 | { |
| 1420 | WRAPPER_NO_CONTRACT; |
| 1421 | DoPromote(fn, sc, gcPtrs[0], FALSE); |
| 1422 | HelperMethodFrame::GcScanRoots(fn, sc); |
| 1423 | } |
| 1424 | |
| 1425 | #ifdef _DEBUG |
| 1426 | #ifndef DACCESS_COMPILE |
| 1427 | void Pop() |
| 1428 | { |
| 1429 | WRAPPER_NO_CONTRACT; |
| 1430 | HelperMethodFrame::Pop(); |
| 1431 | Thread::ObjectRefNew(gcPtrs[0]); |
| 1432 | } |
| 1433 | #endif // DACCESS_COMPILE |
| 1434 | |
| 1435 | BOOL Protects(OBJECTREF *ppORef) |
| 1436 | { |
| 1437 | LIMITED_METHOD_CONTRACT; |
| 1438 | return (ppORef == gcPtrs[0]) ? TRUE : FALSE; |
| 1439 | } |
| 1440 | |
| 1441 | #endif |
| 1442 | |
| 1443 | private: |
| 1444 | PTR_OBJECTREF gcPtrs[1]; |
| 1445 | |
| 1446 | // Keep as last entry in class |
| 1447 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_1OBJ) |
| 1448 | }; |
| 1449 | |
| 1450 | |
| 1451 | //----------------------------------------------------------------------------- |
| 1452 | // HelperMethodFrame_2OBJ |
| 1453 | //----------------------------------------------------------------------------- |
| 1454 | |
| 1455 | class HelperMethodFrame_2OBJ : public HelperMethodFrame |
| 1456 | { |
| 1457 | VPTR_VTABLE_CLASS(HelperMethodFrame_2OBJ, HelperMethodFrame) |
| 1458 | |
| 1459 | public: |
| 1460 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
| 1461 | HelperMethodFrame_2OBJ( |
| 1462 | void* fCallFtnEntry, |
| 1463 | unsigned attribs, |
| 1464 | OBJECTREF* aGCPtr1, |
| 1465 | OBJECTREF* aGCPtr2) |
| 1466 | : HelperMethodFrame(fCallFtnEntry, attribs) |
| 1467 | { |
| 1468 | LIMITED_METHOD_CONTRACT; |
| 1469 | gcPtrs[0] = aGCPtr1; |
| 1470 | gcPtrs[1] = aGCPtr2; |
| 1471 | INDEBUG(Thread::ObjectRefProtected(aGCPtr1);) |
| 1472 | INDEBUG(Thread::ObjectRefProtected(aGCPtr2);) |
| 1473 | INDEBUG((*aGCPtr1).Validate ();) |
| 1474 | INDEBUG((*aGCPtr2).Validate ();) |
| 1475 | } |
| 1476 | #endif |
| 1477 | |
| 1478 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 1479 | { |
| 1480 | WRAPPER_NO_CONTRACT; |
| 1481 | DoPromote(fn, sc, gcPtrs[0], FALSE); |
| 1482 | DoPromote(fn, sc, gcPtrs[1], FALSE); |
| 1483 | HelperMethodFrame::GcScanRoots(fn, sc); |
| 1484 | } |
| 1485 | |
| 1486 | #ifdef _DEBUG |
| 1487 | #ifndef DACCESS_COMPILE |
| 1488 | void Pop() |
| 1489 | { |
| 1490 | WRAPPER_NO_CONTRACT; |
| 1491 | HelperMethodFrame::Pop(); |
| 1492 | Thread::ObjectRefNew(gcPtrs[0]); |
| 1493 | Thread::ObjectRefNew(gcPtrs[1]); |
| 1494 | } |
| 1495 | #endif // DACCESS_COMPILE |
| 1496 | |
| 1497 | BOOL Protects(OBJECTREF *ppORef) |
| 1498 | { |
| 1499 | LIMITED_METHOD_CONTRACT; |
| 1500 | return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1]) ? TRUE : FALSE; |
| 1501 | } |
| 1502 | #endif |
| 1503 | |
| 1504 | private: |
| 1505 | PTR_OBJECTREF gcPtrs[2]; |
| 1506 | |
| 1507 | // Keep as last entry in class |
| 1508 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_2OBJ) |
| 1509 | }; |
| 1510 | |
| 1511 | //----------------------------------------------------------------------------- |
| 1512 | // HelperMethodFrame_3OBJ |
| 1513 | //----------------------------------------------------------------------------- |
| 1514 | |
| 1515 | class HelperMethodFrame_3OBJ : public HelperMethodFrame |
| 1516 | { |
| 1517 | VPTR_VTABLE_CLASS(HelperMethodFrame_3OBJ, HelperMethodFrame) |
| 1518 | |
| 1519 | public: |
| 1520 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
| 1521 | HelperMethodFrame_3OBJ( |
| 1522 | void* fCallFtnEntry, |
| 1523 | unsigned attribs, |
| 1524 | OBJECTREF* aGCPtr1, |
| 1525 | OBJECTREF* aGCPtr2, |
| 1526 | OBJECTREF* aGCPtr3) |
| 1527 | : HelperMethodFrame(fCallFtnEntry, attribs) |
| 1528 | { |
| 1529 | LIMITED_METHOD_CONTRACT; |
| 1530 | gcPtrs[0] = aGCPtr1; |
| 1531 | gcPtrs[1] = aGCPtr2; |
| 1532 | gcPtrs[2] = aGCPtr3; |
| 1533 | INDEBUG(Thread::ObjectRefProtected(aGCPtr1);) |
| 1534 | INDEBUG(Thread::ObjectRefProtected(aGCPtr2);) |
| 1535 | INDEBUG(Thread::ObjectRefProtected(aGCPtr3);) |
| 1536 | INDEBUG((*aGCPtr1).Validate();) |
| 1537 | INDEBUG((*aGCPtr2).Validate();) |
| 1538 | INDEBUG((*aGCPtr3).Validate();) |
| 1539 | } |
| 1540 | #endif |
| 1541 | |
| 1542 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 1543 | { |
| 1544 | WRAPPER_NO_CONTRACT; |
| 1545 | DoPromote(fn, sc, gcPtrs[0], FALSE); |
| 1546 | DoPromote(fn, sc, gcPtrs[1], FALSE); |
| 1547 | DoPromote(fn, sc, gcPtrs[2], FALSE); |
| 1548 | HelperMethodFrame::GcScanRoots(fn, sc); |
| 1549 | } |
| 1550 | |
| 1551 | #ifdef _DEBUG |
| 1552 | #ifndef DACCESS_COMPILE |
| 1553 | void Pop() |
| 1554 | { |
| 1555 | WRAPPER_NO_CONTRACT; |
| 1556 | HelperMethodFrame::Pop(); |
| 1557 | Thread::ObjectRefNew(gcPtrs[0]); |
| 1558 | Thread::ObjectRefNew(gcPtrs[1]); |
| 1559 | Thread::ObjectRefNew(gcPtrs[2]); |
| 1560 | } |
| 1561 | #endif // DACCESS_COMPILE |
| 1562 | |
| 1563 | BOOL Protects(OBJECTREF *ppORef) |
| 1564 | { |
| 1565 | LIMITED_METHOD_CONTRACT; |
| 1566 | return (ppORef == gcPtrs[0] || ppORef == gcPtrs[1] || ppORef == gcPtrs[2]) ? TRUE : FALSE; |
| 1567 | } |
| 1568 | #endif |
| 1569 | |
| 1570 | private: |
| 1571 | PTR_OBJECTREF gcPtrs[3]; |
| 1572 | |
| 1573 | // Keep as last entry in class |
| 1574 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_3OBJ) |
| 1575 | }; |
| 1576 | |
| 1577 | |
| 1578 | //----------------------------------------------------------------------------- |
| 1579 | // HelperMethodFrame_PROTECTOBJ |
| 1580 | //----------------------------------------------------------------------------- |
| 1581 | |
| 1582 | class HelperMethodFrame_PROTECTOBJ : public HelperMethodFrame |
| 1583 | { |
| 1584 | VPTR_VTABLE_CLASS(HelperMethodFrame_PROTECTOBJ, HelperMethodFrame) |
| 1585 | |
| 1586 | public: |
| 1587 | #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) |
| 1588 | HelperMethodFrame_PROTECTOBJ(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) |
| 1589 | : HelperMethodFrame(fCallFtnEntry, attribs) |
| 1590 | { |
| 1591 | LIMITED_METHOD_CONTRACT; |
| 1592 | m_pObjRefs = pObjRefs; |
| 1593 | m_numObjRefs = numObjRefs; |
| 1594 | #ifdef _DEBUG |
| 1595 | for (UINT i = 0; i < m_numObjRefs; i++) { |
| 1596 | Thread::ObjectRefProtected(&m_pObjRefs[i]); |
| 1597 | m_pObjRefs[i].Validate(); |
| 1598 | } |
| 1599 | #endif |
| 1600 | } |
| 1601 | #endif |
| 1602 | |
| 1603 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 1604 | { |
| 1605 | WRAPPER_NO_CONTRACT; |
| 1606 | for (UINT i = 0; i < m_numObjRefs; i++) { |
| 1607 | DoPromote(fn, sc, &m_pObjRefs[i], FALSE); |
| 1608 | } |
| 1609 | HelperMethodFrame::GcScanRoots(fn, sc); |
| 1610 | } |
| 1611 | |
| 1612 | #ifdef _DEBUG |
| 1613 | #ifndef DACCESS_COMPILE |
| 1614 | void Pop() |
| 1615 | { |
| 1616 | WRAPPER_NO_CONTRACT; |
| 1617 | HelperMethodFrame::Pop(); |
| 1618 | for (UINT i = 0; i < m_numObjRefs; i++) { |
| 1619 | Thread::ObjectRefNew(&m_pObjRefs[i]); |
| 1620 | } |
| 1621 | } |
| 1622 | #endif // DACCESS_COMPILE |
| 1623 | |
| 1624 | BOOL Protects(OBJECTREF *ppORef) |
| 1625 | { |
| 1626 | LIMITED_METHOD_CONTRACT; |
| 1627 | for (UINT i = 0; i < m_numObjRefs; i++) { |
| 1628 | if (ppORef == &m_pObjRefs[i]) |
| 1629 | return TRUE; |
| 1630 | } |
| 1631 | return FALSE; |
| 1632 | } |
| 1633 | #endif |
| 1634 | |
| 1635 | private: |
| 1636 | PTR_OBJECTREF m_pObjRefs; |
| 1637 | UINT m_numObjRefs; |
| 1638 | |
| 1639 | // Keep as last entry in class |
| 1640 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HelperMethodFrame_PROTECTOBJ) |
| 1641 | }; |
| 1642 | |
| 1643 | class FramedMethodFrame : public TransitionFrame |
| 1644 | { |
| 1645 | VPTR_ABSTRACT_VTABLE_CLASS(FramedMethodFrame, TransitionFrame) |
| 1646 | |
| 1647 | TADDR m_pTransitionBlock; |
| 1648 | |
| 1649 | protected: |
| 1650 | PTR_MethodDesc m_pMD; |
| 1651 | |
| 1652 | public: |
| 1653 | #ifndef DACCESS_COMPILE |
| 1654 | FramedMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD) |
| 1655 | : m_pTransitionBlock(dac_cast<TADDR>(pTransitionBlock)), m_pMD(pMD) |
| 1656 | { |
| 1657 | LIMITED_METHOD_CONTRACT; |
| 1658 | } |
| 1659 | #endif // DACCESS_COMPILE |
| 1660 | |
| 1661 | virtual TADDR GetTransitionBlock() |
| 1662 | { |
| 1663 | LIMITED_METHOD_DAC_CONTRACT; |
| 1664 | return m_pTransitionBlock; |
| 1665 | } |
| 1666 | |
| 1667 | virtual MethodDesc *GetFunction() |
| 1668 | { |
| 1669 | LIMITED_METHOD_DAC_CONTRACT; |
| 1670 | return m_pMD; |
| 1671 | } |
| 1672 | |
| 1673 | #ifndef DACCESS_COMPILE |
| 1674 | void SetFunction(MethodDesc *pMD) |
| 1675 | { |
| 1676 | CONTRACTL |
| 1677 | { |
| 1678 | NOTHROW; |
| 1679 | GC_NOTRIGGER; |
| 1680 | MODE_COOPERATIVE; // Frame MethodDesc should be always updated in cooperative mode to avoid racing with GC stackwalk |
| 1681 | SO_TOLERANT; |
| 1682 | } |
| 1683 | CONTRACTL_END; |
| 1684 | |
| 1685 | m_pMD = pMD; |
| 1686 | } |
| 1687 | #endif |
| 1688 | |
| 1689 | virtual ETransitionType GetTransitionType() |
| 1690 | { |
| 1691 | LIMITED_METHOD_DAC_CONTRACT; |
| 1692 | return TT_M2U; // we can safely cast to a FramedMethodFrame |
| 1693 | } |
| 1694 | |
| 1695 | int GetFrameType() |
| 1696 | { |
| 1697 | LIMITED_METHOD_DAC_CONTRACT; |
| 1698 | return TYPE_CALL; |
| 1699 | } |
| 1700 | |
| 1701 | #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS |
| 1702 | static int GetFPArgOffset(int iArg) |
| 1703 | { |
| 1704 | #ifdef _TARGET_AMD64_ |
| 1705 | // Floating point spill area is between return value and transition block for frames that need it |
| 1706 | // (code:TPMethodFrame and code:ComPlusMethodFrame) |
| 1707 | return -(4 * 0x10 /* floating point args */ + 0x8 /* alignment pad */ + TransitionBlock::GetNegSpaceSize()) + (iArg * 0x10); |
| 1708 | #endif |
| 1709 | } |
| 1710 | #endif |
| 1711 | |
| 1712 | // |
| 1713 | // GetReturnObjectPtr and GetReturnValuePtr are only valid on frames |
| 1714 | // that allocate |
| 1715 | // |
| 1716 | PTR_PTR_Object GetReturnObjectPtr() |
| 1717 | { |
| 1718 | LIMITED_METHOD_DAC_CONTRACT; |
| 1719 | return PTR_PTR_Object(GetReturnValuePtr()); |
| 1720 | } |
| 1721 | |
| 1722 | // Get return value address |
| 1723 | PTR_VOID GetReturnValuePtr() |
| 1724 | { |
| 1725 | LIMITED_METHOD_DAC_CONTRACT; |
| 1726 | #ifdef COM_STUBS_SEPARATE_FP_LOCATIONS |
| 1727 | TADDR p = GetTransitionBlock() + GetFPArgOffset(0); |
| 1728 | #else |
| 1729 | TADDR p = GetTransitionBlock() - TransitionBlock::GetNegSpaceSize(); |
| 1730 | #endif |
| 1731 | // Return value is right before the transition block (or floating point spill area on AMD64) for frames that need it |
| 1732 | // (code:TPMethodFrame and code:ComPlusMethodFrame) |
| 1733 | #ifdef ENREGISTERED_RETURNTYPE_MAXSIZE |
| 1734 | p -= ENREGISTERED_RETURNTYPE_MAXSIZE; |
| 1735 | #else |
| 1736 | p -= sizeof(ARG_SLOT); |
| 1737 | #endif |
| 1738 | return dac_cast<PTR_VOID>(p); |
| 1739 | } |
| 1740 | |
| 1741 | protected: |
| 1742 | FramedMethodFrame() |
| 1743 | { |
| 1744 | LIMITED_METHOD_CONTRACT; |
| 1745 | } |
| 1746 | }; |
| 1747 | |
| 1748 | //+---------------------------------------------------------------------------- |
| 1749 | // |
| 1750 | // Class: TPMethodFrame private |
| 1751 | // |
| 1752 | // Synopsis: This frame is pushed onto the stack for calls on transparent |
| 1753 | // proxy |
| 1754 | // |
| 1755 | // |
| 1756 | //+---------------------------------------------------------------------------- |
| 1757 | |
| 1758 | //------------------------------------------------------------------------ |
| 1759 | // This represents a call Delegate.Invoke for secure delegate |
| 1760 | // It's only used to gc-protect the arguments during the call. |
| 1761 | // Actually the only reason to have this frame is so a proper |
| 1762 | // Assembly can be reported |
| 1763 | //------------------------------------------------------------------------ |
| 1764 | |
| 1765 | class SecureDelegateFrame : public TransitionFrame |
| 1766 | { |
| 1767 | VPTR_VTABLE_CLASS(SecureDelegateFrame, TransitionFrame) |
| 1768 | |
| 1769 | PTR_MethodDesc m_pMD; |
| 1770 | TransitionBlock m_TransitionBlock; |
| 1771 | |
| 1772 | public: |
| 1773 | virtual MethodDesc* GetFunction() |
| 1774 | { |
| 1775 | LIMITED_METHOD_CONTRACT; |
| 1776 | return m_pMD; |
| 1777 | } |
| 1778 | |
| 1779 | virtual TADDR GetTransitionBlock() |
| 1780 | { |
| 1781 | LIMITED_METHOD_DAC_CONTRACT; |
| 1782 | return PTR_HOST_MEMBER_TADDR(SecureDelegateFrame, this, |
| 1783 | m_TransitionBlock); |
| 1784 | } |
| 1785 | |
| 1786 | static BYTE GetOffsetOfDatum() |
| 1787 | { |
| 1788 | LIMITED_METHOD_DAC_CONTRACT; |
| 1789 | return offsetof(SecureDelegateFrame, m_pMD); |
| 1790 | } |
| 1791 | |
| 1792 | static int GetOffsetOfTransitionBlock() |
| 1793 | { |
| 1794 | LIMITED_METHOD_DAC_CONTRACT; |
| 1795 | return offsetof(SecureDelegateFrame, m_TransitionBlock); |
| 1796 | } |
| 1797 | |
| 1798 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 1799 | { |
| 1800 | WRAPPER_NO_CONTRACT; |
| 1801 | TransitionFrame::GcScanRoots(fn, sc); |
| 1802 | PromoteCallerStack(fn, sc); |
| 1803 | } |
| 1804 | |
| 1805 | virtual Assembly *GetAssembly(); |
| 1806 | |
| 1807 | int GetFrameType() |
| 1808 | { |
| 1809 | LIMITED_METHOD_DAC_CONTRACT; |
| 1810 | return TYPE_MULTICAST; |
| 1811 | } |
| 1812 | |
| 1813 | // For the debugger: |
| 1814 | // Our base class, FramedMethodFrame, is a M2U transition; |
| 1815 | // but Delegate.Invoke isn't. So override and fix it here. |
| 1816 | // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace. |
| 1817 | virtual ETransitionType GetTransitionType() |
| 1818 | { |
| 1819 | LIMITED_METHOD_DAC_CONTRACT; |
| 1820 | return TT_NONE; |
| 1821 | } |
| 1822 | |
| 1823 | virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 1824 | TraceDestination *trace, REGDISPLAY *regs); |
| 1825 | |
| 1826 | // Keep as last entry in class |
| 1827 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(SecureDelegateFrame) |
| 1828 | }; |
| 1829 | |
| 1830 | |
| 1831 | //------------------------------------------------------------------------ |
| 1832 | // This represents a call Multicast.Invoke. It's only used to gc-protect |
| 1833 | // the arguments during the iteration. |
| 1834 | //------------------------------------------------------------------------ |
| 1835 | |
| 1836 | class MulticastFrame : public SecureDelegateFrame |
| 1837 | { |
| 1838 | VPTR_VTABLE_CLASS(MulticastFrame, SecureDelegateFrame) |
| 1839 | |
| 1840 | public: |
| 1841 | |
| 1842 | virtual Assembly *GetAssembly() |
| 1843 | { |
| 1844 | WRAPPER_NO_CONTRACT; |
| 1845 | return Frame::GetAssembly(); |
| 1846 | } |
| 1847 | |
| 1848 | int GetFrameType() |
| 1849 | { |
| 1850 | LIMITED_METHOD_DAC_CONTRACT; |
| 1851 | return TYPE_MULTICAST; |
| 1852 | } |
| 1853 | |
| 1854 | virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 1855 | TraceDestination *trace, REGDISPLAY *regs); |
| 1856 | |
| 1857 | // Keep as last entry in class |
| 1858 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame) |
| 1859 | }; |
| 1860 | |
| 1861 | |
| 1862 | //----------------------------------------------------------------------- |
| 1863 | // Transition frame from unmanaged to managed |
| 1864 | //----------------------------------------------------------------------- |
| 1865 | |
| 1866 | class UnmanagedToManagedFrame : public Frame |
| 1867 | { |
| 1868 | friend class CheckAsmOffsets; |
| 1869 | |
| 1870 | VPTR_ABSTRACT_VTABLE_CLASS_AND_CTOR(UnmanagedToManagedFrame, Frame) |
| 1871 | |
| 1872 | public: |
| 1873 | |
| 1874 | // DACCESS: GetReturnAddressPtr should return the |
| 1875 | // target address of the return address in the frame. |
| 1876 | virtual TADDR GetReturnAddressPtr() |
| 1877 | { |
| 1878 | LIMITED_METHOD_DAC_CONTRACT; |
| 1879 | return PTR_HOST_MEMBER_TADDR(UnmanagedToManagedFrame, this, |
| 1880 | m_ReturnAddress); |
| 1881 | } |
| 1882 | |
| 1883 | virtual PCODE GetReturnAddress(); |
| 1884 | |
| 1885 | // Retrieves pointer to the lowest-addressed argument on |
| 1886 | // the stack. Depending on the calling convention, this |
| 1887 | // may or may not be the first argument. |
| 1888 | TADDR GetPointerToArguments() |
| 1889 | { |
| 1890 | LIMITED_METHOD_DAC_CONTRACT; |
| 1891 | return dac_cast<TADDR>(this) + GetOffsetOfArgs(); |
| 1892 | } |
| 1893 | |
| 1894 | // Exposes an offset for stub generation. |
| 1895 | static BYTE GetOffsetOfArgs() |
| 1896 | { |
| 1897 | LIMITED_METHOD_DAC_CONTRACT; |
| 1898 | #if defined(_TARGET_ARM_) || defined(_TARGET_ARM64_) |
| 1899 | size_t ofs = offsetof(UnmanagedToManagedFrame, m_argumentRegisters); |
| 1900 | #else |
| 1901 | size_t ofs = sizeof(UnmanagedToManagedFrame); |
| 1902 | #endif |
| 1903 | _ASSERTE(FitsInI1(ofs)); |
| 1904 | return (BYTE)ofs; |
| 1905 | } |
| 1906 | |
| 1907 | // depends on the sub frames to return approp. type here |
| 1908 | TADDR GetDatum() |
| 1909 | { |
| 1910 | LIMITED_METHOD_DAC_CONTRACT; |
| 1911 | return m_pvDatum; |
| 1912 | } |
| 1913 | |
| 1914 | static int GetOffsetOfDatum() |
| 1915 | { |
| 1916 | LIMITED_METHOD_CONTRACT; |
| 1917 | return offsetof(UnmanagedToManagedFrame, m_pvDatum); |
| 1918 | } |
| 1919 | |
| 1920 | #ifdef _TARGET_X86_ |
| 1921 | static int GetOffsetOfCalleeSavedRegisters() |
| 1922 | { |
| 1923 | LIMITED_METHOD_CONTRACT; |
| 1924 | return offsetof(UnmanagedToManagedFrame, m_calleeSavedRegisters); |
| 1925 | } |
| 1926 | #endif |
| 1927 | |
| 1928 | int GetFrameType() |
| 1929 | { |
| 1930 | LIMITED_METHOD_DAC_CONTRACT; |
| 1931 | return TYPE_ENTRY; |
| 1932 | } |
| 1933 | |
| 1934 | //------------------------------------------------------------------------ |
| 1935 | // For the debugger. |
| 1936 | //------------------------------------------------------------------------ |
| 1937 | virtual ETransitionType GetTransitionType() |
| 1938 | { |
| 1939 | LIMITED_METHOD_DAC_CONTRACT; |
| 1940 | return TT_U2M; |
| 1941 | } |
| 1942 | |
| 1943 | //------------------------------------------------------------------------ |
| 1944 | // Performs cleanup on an exception unwind |
| 1945 | //------------------------------------------------------------------------ |
| 1946 | #ifndef DACCESS_COMPILE |
| 1947 | virtual void ExceptionUnwind(); |
| 1948 | #endif |
| 1949 | |
| 1950 | protected: |
| 1951 | TADDR m_pvDatum; // type depends on the sub class |
| 1952 | |
| 1953 | #if defined(_TARGET_X86_) |
| 1954 | CalleeSavedRegisters m_calleeSavedRegisters; |
| 1955 | TADDR m_ReturnAddress; |
| 1956 | #elif defined(_TARGET_ARM_) |
| 1957 | TADDR m_R11; // R11 chain |
| 1958 | TADDR m_ReturnAddress; |
| 1959 | ArgumentRegisters m_argumentRegisters; |
| 1960 | #elif defined (_TARGET_ARM64_) |
| 1961 | TADDR m_fp; |
| 1962 | TADDR m_ReturnAddress; |
| 1963 | TADDR m_x8; // ret buff arg |
| 1964 | ArgumentRegisters m_argumentRegisters; |
| 1965 | #else |
| 1966 | TADDR m_ReturnAddress; // return address into unmanaged code |
| 1967 | #endif |
| 1968 | }; |
| 1969 | |
| 1970 | #ifdef FEATURE_COMINTEROP |
| 1971 | |
| 1972 | //------------------------------------------------------------------------ |
| 1973 | // This frame represents a transition from COM to COM+ |
| 1974 | //------------------------------------------------------------------------ |
| 1975 | |
| 1976 | class ComMethodFrame : public UnmanagedToManagedFrame |
| 1977 | { |
| 1978 | VPTR_VTABLE_CLASS(ComMethodFrame, UnmanagedToManagedFrame) |
| 1979 | VPTR_UNIQUE(VPTR_UNIQUE_ComMethodFrame) |
| 1980 | |
| 1981 | public: |
| 1982 | |
| 1983 | #ifdef _TARGET_X86_ |
| 1984 | // Return the # of stack bytes pushed by the unmanaged caller. |
| 1985 | UINT GetNumCallerStackBytes(); |
| 1986 | #endif |
| 1987 | |
| 1988 | PTR_ComCallMethodDesc GetComCallMethodDesc() |
| 1989 | { |
| 1990 | LIMITED_METHOD_CONTRACT; |
| 1991 | return dac_cast<PTR_ComCallMethodDesc>(m_pvDatum); |
| 1992 | } |
| 1993 | |
| 1994 | #ifndef DACCESS_COMPILE |
| 1995 | static void DoSecondPassHandlerCleanup(Frame * pCurFrame); |
| 1996 | #endif // !DACCESS_COMPILE |
| 1997 | |
| 1998 | protected: |
| 1999 | // Keep as last entry in class |
| 2000 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComMethodFrame) |
| 2001 | }; |
| 2002 | |
| 2003 | typedef DPTR(class ComMethodFrame) PTR_ComMethodFrame; |
| 2004 | |
| 2005 | //------------------------------------------------------------------------ |
| 2006 | // This represents a generic call from CLR to COM |
| 2007 | //------------------------------------------------------------------------ |
| 2008 | |
| 2009 | class ComPlusMethodFrame : public FramedMethodFrame |
| 2010 | { |
| 2011 | VPTR_VTABLE_CLASS(ComPlusMethodFrame, FramedMethodFrame) |
| 2012 | |
| 2013 | public: |
| 2014 | ComPlusMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMethodDesc); |
| 2015 | |
| 2016 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2017 | |
| 2018 | virtual BOOL IsTransitionToNativeFrame() |
| 2019 | { |
| 2020 | LIMITED_METHOD_CONTRACT; |
| 2021 | return TRUE; |
| 2022 | } |
| 2023 | |
| 2024 | int GetFrameType() |
| 2025 | { |
| 2026 | LIMITED_METHOD_DAC_CONTRACT; |
| 2027 | return TYPE_EXIT; |
| 2028 | } |
| 2029 | |
| 2030 | void GetUnmanagedCallSite(TADDR* ip, |
| 2031 | TADDR* returnIP, |
| 2032 | TADDR* returnSP); |
| 2033 | |
| 2034 | BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 2035 | TraceDestination *trace, REGDISPLAY *regs); |
| 2036 | |
| 2037 | // Keep as last entry in class |
| 2038 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPlusMethodFrame) |
| 2039 | }; |
| 2040 | |
| 2041 | #endif // FEATURE_COMINTEROP |
| 2042 | |
| 2043 | //------------------------------------------------------------------------ |
| 2044 | // This represents a call from a helper to GetILStubForCalli |
| 2045 | //------------------------------------------------------------------------ |
| 2046 | |
| 2047 | class PInvokeCalliFrame : public FramedMethodFrame |
| 2048 | { |
| 2049 | VPTR_VTABLE_CLASS(PInvokeCalliFrame, FramedMethodFrame) |
| 2050 | |
| 2051 | PTR_VASigCookie m_pVASigCookie; |
| 2052 | PCODE m_pUnmanagedTarget; |
| 2053 | |
| 2054 | public: |
| 2055 | PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget); |
| 2056 | |
| 2057 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 2058 | { |
| 2059 | WRAPPER_NO_CONTRACT; |
| 2060 | FramedMethodFrame::GcScanRoots(fn, sc); |
| 2061 | PromoteCallerStack(fn, sc); |
| 2062 | } |
| 2063 | |
| 2064 | void PromoteCallerStack(promote_func* fn, ScanContext* sc); |
| 2065 | |
| 2066 | // not a method |
| 2067 | virtual MethodDesc *GetFunction() |
| 2068 | { |
| 2069 | LIMITED_METHOD_DAC_CONTRACT; |
| 2070 | return NULL; |
| 2071 | } |
| 2072 | |
| 2073 | int GetFrameType() |
| 2074 | { |
| 2075 | LIMITED_METHOD_DAC_CONTRACT; |
| 2076 | return TYPE_INTERCEPTION; |
| 2077 | } |
| 2078 | |
| 2079 | PCODE GetPInvokeCalliTarget() |
| 2080 | { |
| 2081 | LIMITED_METHOD_CONTRACT; |
| 2082 | return m_pUnmanagedTarget; |
| 2083 | } |
| 2084 | |
| 2085 | PTR_VASigCookie GetVASigCookie() |
| 2086 | { |
| 2087 | LIMITED_METHOD_CONTRACT; |
| 2088 | return m_pVASigCookie; |
| 2089 | } |
| 2090 | |
| 2091 | #ifdef _TARGET_X86_ |
| 2092 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 2093 | #endif // _TARGET_X86_ |
| 2094 | |
| 2095 | BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 2096 | TraceDestination *trace, REGDISPLAY *regs) |
| 2097 | { |
| 2098 | WRAPPER_NO_CONTRACT; |
| 2099 | |
| 2100 | trace->InitForUnmanaged(GetPInvokeCalliTarget()); |
| 2101 | return TRUE; |
| 2102 | } |
| 2103 | |
| 2104 | // Keep as last entry in class |
| 2105 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PInvokeCalliFrame) |
| 2106 | }; |
| 2107 | |
| 2108 | // Some context-related forwards. |
| 2109 | #ifdef FEATURE_HIJACK |
| 2110 | //------------------------------------------------------------------------ |
| 2111 | // This frame represents a hijacked return. If we crawl back through it, |
| 2112 | // it gets us back to where the return should have gone (and eventually will |
| 2113 | // go). |
| 2114 | //------------------------------------------------------------------------ |
| 2115 | class HijackFrame : public Frame |
| 2116 | { |
| 2117 | VPTR_VTABLE_CLASS(HijackFrame, Frame) |
| 2118 | VPTR_UNIQUE(VPTR_UNIQUE_HijackFrame); |
| 2119 | |
| 2120 | public: |
| 2121 | // DACCESS: GetReturnAddressPtr should return the |
| 2122 | // target address of the return address in the frame. |
| 2123 | virtual TADDR GetReturnAddressPtr() |
| 2124 | { |
| 2125 | LIMITED_METHOD_DAC_CONTRACT; |
| 2126 | return PTR_HOST_MEMBER_TADDR(HijackFrame, this, |
| 2127 | m_ReturnAddress); |
| 2128 | } |
| 2129 | |
| 2130 | virtual BOOL NeedsUpdateRegDisplay() |
| 2131 | { |
| 2132 | LIMITED_METHOD_CONTRACT; |
| 2133 | return TRUE; |
| 2134 | } |
| 2135 | |
| 2136 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 2137 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2138 | |
| 2139 | // HijackFrames are created by trip functions. See OnHijackTripThread() |
| 2140 | // They are real C++ objects on the stack. |
| 2141 | // So, it's a public function -- but that doesn't mean you should make some. |
| 2142 | HijackFrame(LPVOID returnAddress, Thread *thread, HijackArgs *args); |
| 2143 | |
| 2144 | protected: |
| 2145 | |
| 2146 | TADDR m_ReturnAddress; |
| 2147 | PTR_Thread m_Thread; |
| 2148 | DPTR(HijackArgs) m_Args; |
| 2149 | |
| 2150 | // Keep as last entry in class |
| 2151 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(HijackFrame) |
| 2152 | }; |
| 2153 | |
| 2154 | #endif // FEATURE_HIJACK |
| 2155 | |
| 2156 | //------------------------------------------------------------------------ |
| 2157 | // This represents a call to a method prestub. Because the prestub |
| 2158 | // can do gc and throw exceptions while building the replacement |
| 2159 | // stub, we need this frame to keep things straight. |
| 2160 | //------------------------------------------------------------------------ |
| 2161 | |
| 2162 | class PrestubMethodFrame : public FramedMethodFrame |
| 2163 | { |
| 2164 | VPTR_VTABLE_CLASS(PrestubMethodFrame, FramedMethodFrame) |
| 2165 | |
| 2166 | public: |
| 2167 | PrestubMethodFrame(TransitionBlock * pTransitionBlock, MethodDesc * pMD); |
| 2168 | |
| 2169 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc) |
| 2170 | { |
| 2171 | WRAPPER_NO_CONTRACT; |
| 2172 | FramedMethodFrame::GcScanRoots(fn, sc); |
| 2173 | PromoteCallerStack(fn, sc); |
| 2174 | } |
| 2175 | |
| 2176 | BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 2177 | TraceDestination *trace, REGDISPLAY *regs); |
| 2178 | |
| 2179 | int GetFrameType() |
| 2180 | { |
| 2181 | LIMITED_METHOD_DAC_CONTRACT; |
| 2182 | return TYPE_INTERCEPTION; |
| 2183 | } |
| 2184 | |
| 2185 | // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None. |
| 2186 | ETransitionType GetTransitionType() |
| 2187 | { |
| 2188 | LIMITED_METHOD_DAC_CONTRACT; |
| 2189 | return TT_NONE; |
| 2190 | } |
| 2191 | |
| 2192 | Interception GetInterception(); |
| 2193 | |
| 2194 | // Keep as last entry in class |
| 2195 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(PrestubMethodFrame) |
| 2196 | }; |
| 2197 | |
| 2198 | //------------------------------------------------------------------------ |
| 2199 | // This represents a call into the virtual call stub manager |
| 2200 | // Because the stub manager can do gc and throw exceptions while |
| 2201 | // building the resolve and dispatch stubs and needs to communicate |
| 2202 | // if we need to setup for a methodDesc call or do a direct call |
| 2203 | // we need this frame to keep things straight. |
| 2204 | //------------------------------------------------------------------------ |
| 2205 | |
| 2206 | class StubDispatchFrame : public FramedMethodFrame |
| 2207 | { |
| 2208 | VPTR_VTABLE_CLASS(StubDispatchFrame, FramedMethodFrame) |
| 2209 | |
| 2210 | // Representative MethodTable * and slot. They are used to |
| 2211 | // compute the MethodDesc* lazily |
| 2212 | PTR_MethodTable m_pRepresentativeMT; |
| 2213 | UINT32 m_representativeSlot; |
| 2214 | |
| 2215 | // Indirection cell and containing module. Used to compute pGCRefMap lazily. |
| 2216 | PTR_Module m_pZapModule; |
| 2217 | TADDR m_pIndirection; |
| 2218 | |
| 2219 | // Cached pointer to native ref data. |
| 2220 | PTR_BYTE m_pGCRefMap; |
| 2221 | |
| 2222 | public: |
| 2223 | StubDispatchFrame(TransitionBlock * pTransitionBlock); |
| 2224 | |
| 2225 | MethodDesc* GetFunction(); |
| 2226 | |
| 2227 | // Returns this frame GC ref map if it has one |
| 2228 | PTR_BYTE GetGCRefMap(); |
| 2229 | |
| 2230 | #ifdef _TARGET_X86_ |
| 2231 | virtual void UpdateRegDisplay(const PREGDISPLAY pRD); |
| 2232 | virtual PCODE GetReturnAddress(); |
| 2233 | #endif // _TARGET_X86_ |
| 2234 | |
| 2235 | PCODE GetUnadjustedReturnAddress() |
| 2236 | { |
| 2237 | LIMITED_METHOD_DAC_CONTRACT; |
| 2238 | return FramedMethodFrame::GetReturnAddress(); |
| 2239 | } |
| 2240 | |
| 2241 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2242 | |
| 2243 | #ifndef DACCESS_COMPILE |
| 2244 | void SetRepresentativeSlot(MethodTable * pMT, UINT32 representativeSlot) |
| 2245 | { |
| 2246 | LIMITED_METHOD_CONTRACT; |
| 2247 | |
| 2248 | m_pRepresentativeMT = pMT; |
| 2249 | m_representativeSlot = representativeSlot; |
| 2250 | } |
| 2251 | |
| 2252 | void SetCallSite(Module * pZapModule, TADDR pIndirection) |
| 2253 | { |
| 2254 | LIMITED_METHOD_CONTRACT; |
| 2255 | |
| 2256 | m_pZapModule = pZapModule; |
| 2257 | m_pIndirection = pIndirection; |
| 2258 | } |
| 2259 | |
| 2260 | void SetForNullReferenceException() |
| 2261 | { |
| 2262 | LIMITED_METHOD_CONTRACT; |
| 2263 | |
| 2264 | // Nothing to do. Everything is initialized in Init. |
| 2265 | } |
| 2266 | #endif |
| 2267 | |
| 2268 | BOOL TraceFrame(Thread *thread, BOOL fromPatch, |
| 2269 | TraceDestination *trace, REGDISPLAY *regs); |
| 2270 | |
| 2271 | int GetFrameType() |
| 2272 | { |
| 2273 | LIMITED_METHOD_CONTRACT; |
| 2274 | return TYPE_CALL; |
| 2275 | } |
| 2276 | |
| 2277 | Interception GetInterception(); |
| 2278 | |
| 2279 | virtual BOOL SuppressParamTypeArg() |
| 2280 | { |
| 2281 | // |
| 2282 | // Shared default interface methods (i.e. virtual interface methods with an implementation) require |
| 2283 | // an instantiation argument. But if we're in the stub dispatch frame, we haven't actually resolved |
| 2284 | // the method yet (we could end up in class's override of this method, for example). |
| 2285 | // |
| 2286 | // So we need to pretent that unresolved default interface methods are like any other interface |
| 2287 | // methods and don't have an instantiation argument. |
| 2288 | // |
| 2289 | // See code:CEEInfo::getMethodSigInternal |
| 2290 | // |
| 2291 | assert(GetFunction()->GetMethodTable()->IsInterface()); |
| 2292 | return TRUE; |
| 2293 | } |
| 2294 | |
| 2295 | private: |
| 2296 | friend class VirtualCallStubManager; |
| 2297 | |
| 2298 | // Keep as last entry in class |
| 2299 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubDispatchFrame) |
| 2300 | }; |
| 2301 | |
| 2302 | typedef VPTR(class StubDispatchFrame) PTR_StubDispatchFrame; |
| 2303 | |
| 2304 | |
| 2305 | //------------------------------------------------------------------------ |
| 2306 | // This represents a call from an ExternalMethodThunk or a VirtualImportThunk |
| 2307 | // Because the resolving of the target address can do gc and/or |
| 2308 | // throw exceptions we need this frame to report the gc references. |
| 2309 | //------------------------------------------------------------------------ |
| 2310 | |
| 2311 | class ExternalMethodFrame : public FramedMethodFrame |
| 2312 | { |
| 2313 | VPTR_VTABLE_CLASS(ExternalMethodFrame, FramedMethodFrame) |
| 2314 | |
| 2315 | // Indirection and containing module. Used to compute pGCRefMap lazily. |
| 2316 | PTR_Module m_pZapModule; |
| 2317 | TADDR m_pIndirection; |
| 2318 | |
| 2319 | // Cached pointer to native ref data. |
| 2320 | PTR_BYTE m_pGCRefMap; |
| 2321 | |
| 2322 | public: |
| 2323 | ExternalMethodFrame(TransitionBlock * pTransitionBlock); |
| 2324 | |
| 2325 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2326 | |
| 2327 | // Returns this frame GC ref map if it has one |
| 2328 | PTR_BYTE GetGCRefMap(); |
| 2329 | |
| 2330 | #ifndef DACCESS_COMPILE |
| 2331 | void SetCallSite(Module * pZapModule, TADDR pIndirection) |
| 2332 | { |
| 2333 | LIMITED_METHOD_CONTRACT; |
| 2334 | |
| 2335 | m_pZapModule = pZapModule; |
| 2336 | m_pIndirection = pIndirection; |
| 2337 | } |
| 2338 | #endif |
| 2339 | |
| 2340 | int GetFrameType() |
| 2341 | { |
| 2342 | LIMITED_METHOD_CONTRACT; |
| 2343 | return TYPE_CALL; |
| 2344 | } |
| 2345 | |
| 2346 | Interception GetInterception(); |
| 2347 | |
| 2348 | #ifdef _TARGET_X86_ |
| 2349 | virtual void UpdateRegDisplay(const PREGDISPLAY pRD); |
| 2350 | #endif |
| 2351 | |
| 2352 | // Keep as last entry in class |
| 2353 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExternalMethodFrame) |
| 2354 | }; |
| 2355 | |
| 2356 | typedef VPTR(class ExternalMethodFrame) PTR_ExternalMethodFrame; |
| 2357 | |
| 2358 | #ifdef FEATURE_READYTORUN |
| 2359 | class DynamicHelperFrame : public FramedMethodFrame |
| 2360 | { |
| 2361 | VPTR_VTABLE_CLASS(DynamicHelperFrame, FramedMethodFrame) |
| 2362 | |
| 2363 | int m_dynamicHelperFrameFlags; |
| 2364 | |
| 2365 | public: |
| 2366 | DynamicHelperFrame(TransitionBlock * pTransitionBlock, int dynamicHelperFrameFlags); |
| 2367 | |
| 2368 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2369 | |
| 2370 | #ifdef _TARGET_X86_ |
| 2371 | virtual void UpdateRegDisplay(const PREGDISPLAY pRD); |
| 2372 | #endif |
| 2373 | |
| 2374 | virtual ETransitionType GetTransitionType() |
| 2375 | { |
| 2376 | LIMITED_METHOD_DAC_CONTRACT; |
| 2377 | return TT_InternalCall; |
| 2378 | } |
| 2379 | |
| 2380 | // Keep as last entry in class |
| 2381 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(DynamicHelperFrame) |
| 2382 | }; |
| 2383 | |
| 2384 | typedef VPTR(class DynamicHelperFrame) PTR_DynamicHelperFrame; |
| 2385 | #endif // FEATURE_READYTORUN |
| 2386 | |
| 2387 | //------------------------------------------------------------------------ |
| 2388 | // This frame is used for instantiating stubs when the argument transform |
| 2389 | // is too complex to generate a tail-calling stub. |
| 2390 | //------------------------------------------------------------------------ |
| 2391 | #if !defined(_TARGET_X86_) |
| 2392 | class StubHelperFrame : public TransitionFrame |
| 2393 | { |
| 2394 | friend class CheckAsmOffsets; |
| 2395 | friend class StubLinkerCPU; |
| 2396 | |
| 2397 | VPTR_VTABLE_CLASS(StubHelperFrame, TransitionFrame) |
| 2398 | VPTR_UNIQUE(VPTR_UNIQUE_StubHelperFrame) |
| 2399 | |
| 2400 | TransitionBlock m_TransitionBlock; |
| 2401 | |
| 2402 | virtual TADDR GetTransitionBlock() |
| 2403 | { |
| 2404 | LIMITED_METHOD_DAC_CONTRACT; |
| 2405 | return PTR_HOST_MEMBER_TADDR(StubHelperFrame, this, |
| 2406 | m_TransitionBlock); |
| 2407 | } |
| 2408 | |
| 2409 | static int GetOffsetOfTransitionBlock() |
| 2410 | { |
| 2411 | LIMITED_METHOD_DAC_CONTRACT; |
| 2412 | return offsetof(StubHelperFrame, m_TransitionBlock); |
| 2413 | } |
| 2414 | |
| 2415 | private: |
| 2416 | // Keep as last entry in class |
| 2417 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(StubHelperFrame) |
| 2418 | }; |
| 2419 | #endif // _TARGET_X86_ |
| 2420 | |
| 2421 | #ifdef FEATURE_COMINTEROP |
| 2422 | |
| 2423 | //------------------------------------------------------------------------ |
| 2424 | // This represents a com to com+ call method prestub. |
| 2425 | // we need to catch exceptions etc. so this frame is not the same |
| 2426 | // as the prestub method frame |
| 2427 | // Note that in rare IJW cases, the immediate caller could be a managed method |
| 2428 | // which pinvoke-inlined a call to a COM interface, which happenned to be |
| 2429 | // implemented by a managed function via COM-interop. |
| 2430 | //------------------------------------------------------------------------ |
| 2431 | class ComPrestubMethodFrame : public ComMethodFrame |
| 2432 | { |
| 2433 | friend class CheckAsmOffsets; |
| 2434 | |
| 2435 | VPTR_VTABLE_CLASS(ComPrestubMethodFrame, ComMethodFrame) |
| 2436 | |
| 2437 | public: |
| 2438 | // Set the vptr and GSCookie |
| 2439 | VOID Init(); |
| 2440 | |
| 2441 | int GetFrameType() |
| 2442 | { |
| 2443 | LIMITED_METHOD_DAC_CONTRACT; |
| 2444 | return TYPE_INTERCEPTION; |
| 2445 | } |
| 2446 | |
| 2447 | // ComPrestubMethodFrame should return the same interception type as |
| 2448 | // code:PrestubMethodFrame.GetInterception. |
| 2449 | virtual Interception GetInterception() |
| 2450 | { |
| 2451 | LIMITED_METHOD_DAC_CONTRACT; |
| 2452 | return INTERCEPTION_PRESTUB; |
| 2453 | } |
| 2454 | |
| 2455 | // Our base class is a a M2U TransitionType; but we're not. So override and set us back to None. |
| 2456 | virtual ETransitionType GetTransitionType() |
| 2457 | { |
| 2458 | LIMITED_METHOD_DAC_CONTRACT; |
| 2459 | return TT_NONE; |
| 2460 | } |
| 2461 | |
| 2462 | virtual void ExceptionUnwind() |
| 2463 | { |
| 2464 | } |
| 2465 | |
| 2466 | private: |
| 2467 | // Keep as last entry in class |
| 2468 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ComPrestubMethodFrame) |
| 2469 | }; |
| 2470 | |
| 2471 | #endif // FEATURE_COMINTEROP |
| 2472 | |
| 2473 | |
| 2474 | //------------------------------------------------------------------------ |
| 2475 | // This frame protects object references for the EE's convenience. |
| 2476 | // This frame type actually is created from C++. |
| 2477 | //------------------------------------------------------------------------ |
| 2478 | class GCFrame : public Frame |
| 2479 | { |
| 2480 | VPTR_VTABLE_CLASS(GCFrame, Frame) |
| 2481 | |
| 2482 | public: |
| 2483 | |
| 2484 | |
| 2485 | //-------------------------------------------------------------------- |
| 2486 | // This constructor pushes a new GCFrame on the frame chain. |
| 2487 | //-------------------------------------------------------------------- |
| 2488 | #ifndef DACCESS_COMPILE |
| 2489 | GCFrame() { |
| 2490 | LIMITED_METHOD_CONTRACT; |
| 2491 | }; |
| 2492 | |
| 2493 | GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior); |
| 2494 | GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior); |
| 2495 | #endif |
| 2496 | void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior); |
| 2497 | |
| 2498 | |
| 2499 | //-------------------------------------------------------------------- |
| 2500 | // Pops the GCFrame and cancels the GC protection. Also |
| 2501 | // trashes the contents of pObjRef's in _DEBUG. |
| 2502 | //-------------------------------------------------------------------- |
| 2503 | VOID Pop(); |
| 2504 | |
| 2505 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2506 | |
| 2507 | #ifdef _DEBUG |
| 2508 | virtual BOOL Protects(OBJECTREF *ppORef) |
| 2509 | { |
| 2510 | LIMITED_METHOD_CONTRACT; |
| 2511 | for (UINT i = 0; i < m_numObjRefs; i++) { |
| 2512 | if (ppORef == m_pObjRefs + i) { |
| 2513 | return TRUE; |
| 2514 | } |
| 2515 | } |
| 2516 | return FALSE; |
| 2517 | } |
| 2518 | #endif |
| 2519 | |
| 2520 | #ifndef DACCESS_COMPILE |
| 2521 | void *operator new (size_t sz, void* p) |
| 2522 | { |
| 2523 | LIMITED_METHOD_CONTRACT; |
| 2524 | return p ; |
| 2525 | } |
| 2526 | #endif |
| 2527 | |
| 2528 | #if defined(_DEBUG_IMPL) |
| 2529 | const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame" ; } |
| 2530 | #endif |
| 2531 | |
| 2532 | private: |
| 2533 | PTR_OBJECTREF m_pObjRefs; |
| 2534 | UINT m_numObjRefs; |
| 2535 | PTR_Thread m_pCurThread; |
| 2536 | BOOL m_MaybeInterior; |
| 2537 | |
| 2538 | // Keep as last entry in class |
| 2539 | DEFINE_VTABLE_GETTER_AND_DTOR(GCFrame) |
| 2540 | }; |
| 2541 | |
| 2542 | #ifdef FEATURE_INTERPRETER |
| 2543 | class InterpreterFrame: public Frame |
| 2544 | { |
| 2545 | VPTR_VTABLE_CLASS(InterpreterFrame, Frame) |
| 2546 | |
| 2547 | class Interpreter* m_interp; |
| 2548 | |
| 2549 | public: |
| 2550 | |
| 2551 | #ifndef DACCESS_COMPILE |
| 2552 | InterpreterFrame(class Interpreter* interp); |
| 2553 | |
| 2554 | class Interpreter* GetInterpreter() { return m_interp; } |
| 2555 | |
| 2556 | // Override. |
| 2557 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 2558 | |
| 2559 | MethodDesc* GetFunction(); |
| 2560 | #endif |
| 2561 | |
| 2562 | DEFINE_VTABLE_GETTER_AND_DTOR(InterpreterFrame) |
| 2563 | |
| 2564 | }; |
| 2565 | |
| 2566 | typedef VPTR(class InterpreterFrame) PTR_InterpreterFrame; |
| 2567 | #endif // FEATURE_INTERPRETER |
| 2568 | |
| 2569 | |
| 2570 | //----------------------------------------------------------------------------- |
| 2571 | |
| 2572 | struct ByRefInfo; |
| 2573 | typedef DPTR(ByRefInfo) PTR_ByRefInfo; |
| 2574 | |
| 2575 | struct ByRefInfo |
| 2576 | { |
| 2577 | PTR_ByRefInfo pNext; |
| 2578 | INT32 argIndex; |
| 2579 | CorElementType typ; |
| 2580 | TypeHandle typeHandle; |
| 2581 | char data[1]; |
| 2582 | }; |
| 2583 | |
| 2584 | //----------------------------------------------------------------------------- |
| 2585 | // ProtectByRefsFrame |
| 2586 | //----------------------------------------------------------------------------- |
| 2587 | |
| 2588 | class ProtectByRefsFrame : public Frame |
| 2589 | { |
| 2590 | VPTR_VTABLE_CLASS(ProtectByRefsFrame, Frame) |
| 2591 | |
| 2592 | public: |
| 2593 | #ifndef DACCESS_COMPILE |
| 2594 | ProtectByRefsFrame(Thread *pThread, ByRefInfo *brInfo) |
| 2595 | : m_brInfo(brInfo) |
| 2596 | { |
| 2597 | WRAPPER_NO_CONTRACT; |
| 2598 | Frame::Push(pThread); |
| 2599 | } |
| 2600 | #endif |
| 2601 | |
| 2602 | virtual void GcScanRoots(promote_func *fn, ScanContext *sc); |
| 2603 | |
| 2604 | private: |
| 2605 | PTR_ByRefInfo m_brInfo; |
| 2606 | |
| 2607 | // Keep as last entry in class |
| 2608 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ProtectByRefsFrame) |
| 2609 | }; |
| 2610 | |
| 2611 | |
| 2612 | //----------------------------------------------------------------------------- |
| 2613 | |
| 2614 | struct ValueClassInfo; |
| 2615 | typedef DPTR(struct ValueClassInfo) PTR_ValueClassInfo; |
| 2616 | |
| 2617 | struct ValueClassInfo |
| 2618 | { |
| 2619 | PTR_ValueClassInfo pNext; |
| 2620 | PTR_MethodTable pMT; |
| 2621 | PTR_VOID pData; |
| 2622 | |
| 2623 | ValueClassInfo(PTR_VOID aData, PTR_MethodTable aMT, PTR_ValueClassInfo aNext) |
| 2624 | : pNext(aNext), pMT(aMT), pData(aData) |
| 2625 | { |
| 2626 | } |
| 2627 | }; |
| 2628 | |
| 2629 | //----------------------------------------------------------------------------- |
| 2630 | // ProtectValueClassFrame |
| 2631 | //----------------------------------------------------------------------------- |
| 2632 | |
| 2633 | |
| 2634 | class ProtectValueClassFrame : public Frame |
| 2635 | { |
| 2636 | VPTR_VTABLE_CLASS(ProtectValueClassFrame, Frame) |
| 2637 | |
| 2638 | public: |
| 2639 | #ifndef DACCESS_COMPILE |
| 2640 | ProtectValueClassFrame() |
| 2641 | : m_pVCInfo(NULL) |
| 2642 | { |
| 2643 | WRAPPER_NO_CONTRACT; |
| 2644 | Frame::Push(); |
| 2645 | } |
| 2646 | |
| 2647 | ProtectValueClassFrame(Thread *pThread, ValueClassInfo *vcInfo) |
| 2648 | : m_pVCInfo(vcInfo) |
| 2649 | { |
| 2650 | WRAPPER_NO_CONTRACT; |
| 2651 | Frame::Push(pThread); |
| 2652 | } |
| 2653 | #endif |
| 2654 | |
| 2655 | virtual void GcScanRoots(promote_func *fn, ScanContext *sc); |
| 2656 | |
| 2657 | ValueClassInfo ** GetValueClassInfoList() |
| 2658 | { |
| 2659 | LIMITED_METHOD_CONTRACT; |
| 2660 | return &m_pVCInfo; |
| 2661 | } |
| 2662 | |
| 2663 | private: |
| 2664 | |
| 2665 | ValueClassInfo *m_pVCInfo; |
| 2666 | |
| 2667 | // Keep as last entry in class |
| 2668 | DEFINE_VTABLE_GETTER_AND_DTOR(ProtectValueClassFrame) |
| 2669 | }; |
| 2670 | |
| 2671 | |
| 2672 | #ifdef _DEBUG |
| 2673 | BOOL IsProtectedByGCFrame(OBJECTREF *ppObjectRef); |
| 2674 | #endif |
| 2675 | |
| 2676 | |
| 2677 | //------------------------------------------------------------------------ |
| 2678 | // DebuggerClassInitMarkFrame is a small frame whose only purpose in |
| 2679 | // life is to mark for the debugger that "class initialization code" is |
| 2680 | // being run. It does nothing useful except return good values from |
| 2681 | // GetFrameType and GetInterception. |
| 2682 | //------------------------------------------------------------------------ |
| 2683 | |
| 2684 | class DebuggerClassInitMarkFrame : public Frame |
| 2685 | { |
| 2686 | VPTR_VTABLE_CLASS(DebuggerClassInitMarkFrame, Frame) |
| 2687 | |
| 2688 | public: |
| 2689 | |
| 2690 | #ifndef DACCESS_COMPILE |
| 2691 | DebuggerClassInitMarkFrame() |
| 2692 | { |
| 2693 | WRAPPER_NO_CONTRACT; |
| 2694 | Push(); |
| 2695 | }; |
| 2696 | #endif |
| 2697 | |
| 2698 | virtual int GetFrameType() |
| 2699 | { |
| 2700 | LIMITED_METHOD_DAC_CONTRACT; |
| 2701 | return TYPE_INTERCEPTION; |
| 2702 | } |
| 2703 | |
| 2704 | virtual Interception GetInterception() |
| 2705 | { |
| 2706 | LIMITED_METHOD_DAC_CONTRACT; |
| 2707 | return INTERCEPTION_CLASS_INIT; |
| 2708 | } |
| 2709 | |
| 2710 | // Keep as last entry in class |
| 2711 | DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame) |
| 2712 | }; |
| 2713 | |
| 2714 | |
| 2715 | //------------------------------------------------------------------------ |
| 2716 | // DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in |
| 2717 | // life is to mark for the debugger that "security code" is |
| 2718 | // being run. It does nothing useful except return good values from |
| 2719 | // GetFrameType and GetInterception. |
| 2720 | //------------------------------------------------------------------------ |
| 2721 | |
| 2722 | class DebuggerSecurityCodeMarkFrame : public Frame |
| 2723 | { |
| 2724 | VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame) |
| 2725 | |
| 2726 | public: |
| 2727 | #ifndef DACCESS_COMPILE |
| 2728 | DebuggerSecurityCodeMarkFrame() |
| 2729 | { |
| 2730 | WRAPPER_NO_CONTRACT; |
| 2731 | Push(); |
| 2732 | } |
| 2733 | #endif |
| 2734 | |
| 2735 | virtual int GetFrameType() |
| 2736 | { |
| 2737 | LIMITED_METHOD_DAC_CONTRACT; |
| 2738 | return TYPE_INTERCEPTION; |
| 2739 | } |
| 2740 | |
| 2741 | virtual Interception GetInterception() |
| 2742 | { |
| 2743 | LIMITED_METHOD_DAC_CONTRACT; |
| 2744 | return INTERCEPTION_SECURITY; |
| 2745 | } |
| 2746 | |
| 2747 | // Keep as last entry in class |
| 2748 | DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame) |
| 2749 | }; |
| 2750 | |
| 2751 | //------------------------------------------------------------------------ |
| 2752 | // DebuggerExitFrame is a small frame whose only purpose in |
| 2753 | // life is to mark for the debugger that there is an exit transiton on |
| 2754 | // the stack. This is special cased for the "break" IL instruction since |
| 2755 | // it is an fcall using a helper frame which returns TYPE_CALL instead of |
| 2756 | // an ecall (as in System.Diagnostics.Debugger.Break()) which returns |
| 2757 | // TYPE_EXIT. This just makes the two consistent for debugging services. |
| 2758 | //------------------------------------------------------------------------ |
| 2759 | |
| 2760 | class DebuggerExitFrame : public Frame |
| 2761 | { |
| 2762 | VPTR_VTABLE_CLASS(DebuggerExitFrame, Frame) |
| 2763 | |
| 2764 | public: |
| 2765 | #ifndef DACCESS_COMPILE |
| 2766 | DebuggerExitFrame() |
| 2767 | { |
| 2768 | WRAPPER_NO_CONTRACT; |
| 2769 | Push(); |
| 2770 | } |
| 2771 | #endif |
| 2772 | |
| 2773 | virtual int GetFrameType() |
| 2774 | { |
| 2775 | LIMITED_METHOD_DAC_CONTRACT; |
| 2776 | return TYPE_EXIT; |
| 2777 | } |
| 2778 | |
| 2779 | // Return information about an unmanaged call the frame |
| 2780 | // will make. |
| 2781 | // ip - the unmanaged routine which will be called |
| 2782 | // returnIP - the address in the stub which the unmanaged routine |
| 2783 | // will return to. |
| 2784 | // returnSP - the location returnIP is pushed onto the stack |
| 2785 | // during the call. |
| 2786 | // |
| 2787 | virtual void GetUnmanagedCallSite(TADDR* ip, |
| 2788 | TADDR* returnIP, |
| 2789 | TADDR* returnSP) |
| 2790 | { |
| 2791 | LIMITED_METHOD_CONTRACT; |
| 2792 | if (ip) |
| 2793 | *ip = NULL; |
| 2794 | |
| 2795 | if (returnIP) |
| 2796 | *returnIP = NULL; |
| 2797 | |
| 2798 | if (returnSP) |
| 2799 | *returnSP = NULL; |
| 2800 | } |
| 2801 | |
| 2802 | // Keep as last entry in class |
| 2803 | DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerExitFrame) |
| 2804 | }; |
| 2805 | |
| 2806 | //--------------------------------------------------------------------------------------- |
| 2807 | // |
| 2808 | // DebuggerU2MCatchHandlerFrame is a small frame whose only purpose in life is to mark for the debugger |
| 2809 | // that there is catch handler inside the runtime which may catch and swallow managed exceptions. The |
| 2810 | // debugger needs this frame to send a CatchHandlerFound (CHF) notification. Without this frame, the |
| 2811 | // debugger doesn't know where a managed exception is caught. |
| 2812 | // |
| 2813 | // Notes: |
| 2814 | // Currently this frame is only used in code:DispatchInfo.InvokeMember, which is an U2M transition. |
| 2815 | // |
| 2816 | |
| 2817 | class DebuggerU2MCatchHandlerFrame : public Frame |
| 2818 | { |
| 2819 | VPTR_VTABLE_CLASS(DebuggerU2MCatchHandlerFrame, Frame) |
| 2820 | |
| 2821 | public: |
| 2822 | #ifndef DACCESS_COMPILE |
| 2823 | DebuggerU2MCatchHandlerFrame() |
| 2824 | { |
| 2825 | WRAPPER_NO_CONTRACT; |
| 2826 | Frame::Push(); |
| 2827 | } |
| 2828 | |
| 2829 | DebuggerU2MCatchHandlerFrame(Thread * pThread) |
| 2830 | { |
| 2831 | WRAPPER_NO_CONTRACT; |
| 2832 | Frame::Push(pThread); |
| 2833 | } |
| 2834 | #endif |
| 2835 | |
| 2836 | ETransitionType GetTransitionType() |
| 2837 | { |
| 2838 | LIMITED_METHOD_DAC_CONTRACT; |
| 2839 | return TT_U2M; |
| 2840 | } |
| 2841 | |
| 2842 | // Keep as last entry in class |
| 2843 | DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerU2MCatchHandlerFrame) |
| 2844 | }; |
| 2845 | |
| 2846 | |
| 2847 | class UMThunkMarshInfo; |
| 2848 | typedef DPTR(class UMThunkMarshInfo) PTR_UMThunkMarshInfo; |
| 2849 | |
| 2850 | class UMEntryThunk; |
| 2851 | typedef DPTR(class UMEntryThunk) PTR_UMEntryThunk; |
| 2852 | |
| 2853 | #if defined(_TARGET_X86_) |
| 2854 | //------------------------------------------------------------------------ |
| 2855 | // This frame guards an unmanaged->managed transition thru a UMThk |
| 2856 | //------------------------------------------------------------------------ |
| 2857 | |
| 2858 | class UMThkCallFrame : public UnmanagedToManagedFrame |
| 2859 | { |
| 2860 | VPTR_VTABLE_CLASS(UMThkCallFrame, UnmanagedToManagedFrame) |
| 2861 | |
| 2862 | public: |
| 2863 | |
| 2864 | #ifdef DACCESS_COMPILE |
| 2865 | virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
| 2866 | #endif |
| 2867 | |
| 2868 | PTR_UMEntryThunk GetUMEntryThunk(); |
| 2869 | |
| 2870 | static int GetOffsetOfUMEntryThunk() |
| 2871 | { |
| 2872 | WRAPPER_NO_CONTRACT; |
| 2873 | return GetOffsetOfDatum(); |
| 2874 | } |
| 2875 | |
| 2876 | protected: |
| 2877 | |
| 2878 | // Keep as last entry in class |
| 2879 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(UMThkCallFrame) |
| 2880 | }; |
| 2881 | #endif // _TARGET_X86_ && !FEATURE_PAL |
| 2882 | |
| 2883 | #if defined(_TARGET_X86_) && defined(FEATURE_COMINTEROP) |
| 2884 | //------------------------------------------------------------------------- |
| 2885 | // Exception handler for COM to managed frame |
| 2886 | // and the layout of the exception registration record structure in the stack |
| 2887 | // the layout is similar to the NT's EXCEPTIONREGISTRATION record |
| 2888 | // followed by the UnmanagedToManagedFrame specific info |
| 2889 | |
| 2890 | struct ComToManagedExRecord |
| 2891 | { |
| 2892 | EXCEPTION_REGISTRATION_RECORD m_ExReg; |
| 2893 | ArgumentRegisters m_argRegs; |
| 2894 | GSCookie m_gsCookie; |
| 2895 | UMThkCallFrame m_frame; |
| 2896 | |
| 2897 | UnmanagedToManagedFrame * GetCurrFrame() |
| 2898 | { |
| 2899 | LIMITED_METHOD_CONTRACT; |
| 2900 | return &m_frame; |
| 2901 | } |
| 2902 | }; |
| 2903 | #endif // _TARGET_X86_ && FEATURE_COMINTEROP |
| 2904 | |
| 2905 | |
| 2906 | //------------------------------------------------------------------------ |
| 2907 | // This frame is pushed by any JIT'ted method that contains one or more |
| 2908 | // inlined N/Direct calls. Note that the JIT'ted method keeps it pushed |
| 2909 | // the whole time to amortize the pushing cost across the entire method. |
| 2910 | //------------------------------------------------------------------------ |
| 2911 | |
| 2912 | typedef DPTR(class InlinedCallFrame) PTR_InlinedCallFrame; |
| 2913 | |
| 2914 | class InlinedCallFrame : public Frame |
| 2915 | { |
| 2916 | VPTR_VTABLE_CLASS(InlinedCallFrame, Frame) |
| 2917 | |
| 2918 | public: |
| 2919 | virtual MethodDesc *GetFunction() |
| 2920 | { |
| 2921 | WRAPPER_NO_CONTRACT; |
| 2922 | if (FrameHasActiveCall(this) && HasFunction()) |
| 2923 | return PTR_MethodDesc(m_Datum); |
| 2924 | else |
| 2925 | return NULL; |
| 2926 | } |
| 2927 | |
| 2928 | BOOL HasFunction() |
| 2929 | { |
| 2930 | WRAPPER_NO_CONTRACT; |
| 2931 | |
| 2932 | #ifdef _WIN64 |
| 2933 | // See code:GenericPInvokeCalliHelper |
| 2934 | return ((m_Datum != NULL) && !(dac_cast<TADDR>(m_Datum) & 0x1)); |
| 2935 | #else // _WIN64 |
| 2936 | return ((dac_cast<TADDR>(m_Datum) & ~0xffff) != 0); |
| 2937 | #endif // _WIN64 |
| 2938 | } |
| 2939 | |
| 2940 | // Retrieves the return address into the code that called out |
| 2941 | // to managed code |
| 2942 | virtual TADDR GetReturnAddressPtr() |
| 2943 | { |
| 2944 | WRAPPER_NO_CONTRACT; |
| 2945 | |
| 2946 | if (FrameHasActiveCall(this)) |
| 2947 | return PTR_HOST_MEMBER_TADDR(InlinedCallFrame, this, |
| 2948 | m_pCallerReturnAddress); |
| 2949 | else |
| 2950 | return NULL; |
| 2951 | } |
| 2952 | |
| 2953 | virtual BOOL NeedsUpdateRegDisplay() |
| 2954 | { |
| 2955 | WRAPPER_NO_CONTRACT; |
| 2956 | return FrameHasActiveCall(this); |
| 2957 | } |
| 2958 | |
| 2959 | // Given a methodDesc representing an ILStub for a pinvoke call, |
| 2960 | // this method will return the MethodDesc for the actual interop |
| 2961 | // method if the current InlinedCallFrame is inactive. |
| 2962 | PTR_MethodDesc GetActualInteropMethodDesc() |
| 2963 | { |
| 2964 | #if defined(_TARGET_X86_) || defined(_TARGET_ARM_) |
| 2965 | // Important: This code relies on the way JIT lays out frames. Keep it in sync |
| 2966 | // with code:Compiler.lvaAssignFrameOffsets. |
| 2967 | // |
| 2968 | // | ... | |
| 2969 | // +--------------------+ |
| 2970 | // | lvaStubArgumentVar | <= filled with EAX in prolog | |
| 2971 | // +--------------------+ | |
| 2972 | // | | | |
| 2973 | // | InlinedCallFrame | | |
| 2974 | // | | <= m_pCrawl.pFrame | to lower addresses |
| 2975 | // +--------------------+ V |
| 2976 | // | ... | |
| 2977 | // |
| 2978 | // Extract the actual MethodDesc to report from the InlinedCallFrame. |
| 2979 | TADDR addr = dac_cast<TADDR>(this) + sizeof(InlinedCallFrame); |
| 2980 | return PTR_MethodDesc(*PTR_TADDR(addr)); |
| 2981 | #elif defined(_WIN64) |
| 2982 | // On 64bit, the actual interop MethodDesc is saved off in a field off the InlinedCrawlFrame |
| 2983 | // which is populated by the JIT. Refer to JIT_InitPInvokeFrame for details. |
| 2984 | return PTR_MethodDesc(m_StubSecretArg); |
| 2985 | #else |
| 2986 | _ASSERTE(!"NYI - Interop method reporting for this architecture!" ); |
| 2987 | return NULL; |
| 2988 | #endif // defined(_TARGET_X86_) || defined(_TARGET_ARM_) |
| 2989 | } |
| 2990 | |
| 2991 | virtual void UpdateRegDisplay(const PREGDISPLAY); |
| 2992 | |
| 2993 | // m_Datum contains MethodDesc ptr or |
| 2994 | // - on AMD64: CALLI target address (if lowest bit is set) |
| 2995 | // - on X86: argument stack size (if value is <64k) |
| 2996 | // See code:HasFunction. |
| 2997 | PTR_NDirectMethodDesc m_Datum; |
| 2998 | |
| 2999 | #ifdef _WIN64 |
| 3000 | // IL stubs fill this field with the incoming secret argument when they erect |
| 3001 | // InlinedCallFrame so we know which interop method was invoked even if the frame |
| 3002 | // is not active at the moment. |
| 3003 | PTR_VOID m_StubSecretArg; |
| 3004 | #endif // _WIN64 |
| 3005 | |
| 3006 | protected: |
| 3007 | // X86: ESP after pushing the outgoing arguments, and just before calling |
| 3008 | // out to unmanaged code. |
| 3009 | // Other platforms: the field stays set throughout the declaring method. |
| 3010 | PTR_VOID m_pCallSiteSP; |
| 3011 | |
| 3012 | // EIP where the unmanaged call will return to. This will be a pointer into |
| 3013 | // the code of the managed frame which has the InlinedCallFrame |
| 3014 | // This is set to NULL in the method prolog. It gets set just before the |
| 3015 | // call to the target and reset back to NULL after the stop-for-GC check |
| 3016 | // following the call. |
| 3017 | TADDR m_pCallerReturnAddress; |
| 3018 | |
| 3019 | // This is used only for EBP. Hence, a stackwalk will miss the other |
| 3020 | // callee-saved registers for the method with the InlinedCallFrame. |
| 3021 | // To prevent GC-holes, we do not keep any GC references in callee-saved |
| 3022 | // registers across an NDirect call. |
| 3023 | TADDR m_pCalleeSavedFP; |
| 3024 | |
| 3025 | public: |
| 3026 | //--------------------------------------------------------------- |
| 3027 | // Expose key offsets and values for stub generation. |
| 3028 | //--------------------------------------------------------------- |
| 3029 | |
| 3030 | static void GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo * pEEInfo); |
| 3031 | |
| 3032 | // Is the specified frame an InlinedCallFrame which has an active call |
| 3033 | // inside it right now? |
| 3034 | static BOOL FrameHasActiveCall(Frame *pFrame) |
| 3035 | { |
| 3036 | WRAPPER_NO_CONTRACT; |
| 3037 | SUPPORTS_DAC; |
| 3038 | return pFrame && |
| 3039 | pFrame != FRAME_TOP && |
| 3040 | InlinedCallFrame::GetMethodFrameVPtr() == pFrame->GetVTablePtr() && |
| 3041 | dac_cast<TADDR>(dac_cast<PTR_InlinedCallFrame>(pFrame)->m_pCallerReturnAddress) != NULL; |
| 3042 | } |
| 3043 | |
| 3044 | // Marks the frame as inactive. |
| 3045 | void Reset() |
| 3046 | { |
| 3047 | m_pCallerReturnAddress = NULL; |
| 3048 | } |
| 3049 | |
| 3050 | int GetFrameType() |
| 3051 | { |
| 3052 | LIMITED_METHOD_DAC_CONTRACT; |
| 3053 | return TYPE_EXIT; |
| 3054 | } |
| 3055 | |
| 3056 | virtual BOOL IsTransitionToNativeFrame() |
| 3057 | { |
| 3058 | LIMITED_METHOD_CONTRACT; |
| 3059 | return TRUE; |
| 3060 | } |
| 3061 | |
| 3062 | PTR_VOID GetCallSiteSP() |
| 3063 | { |
| 3064 | LIMITED_METHOD_CONTRACT; |
| 3065 | return m_pCallSiteSP; |
| 3066 | } |
| 3067 | |
| 3068 | TADDR GetCalleeSavedFP() |
| 3069 | { |
| 3070 | LIMITED_METHOD_DAC_CONTRACT; |
| 3071 | return m_pCalleeSavedFP; |
| 3072 | } |
| 3073 | |
| 3074 | // Set the vptr and GSCookie |
| 3075 | VOID Init(); |
| 3076 | |
| 3077 | // Keep as last entry in class |
| 3078 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(InlinedCallFrame) |
| 3079 | }; |
| 3080 | |
| 3081 | //------------------------------------------------------------------------ |
| 3082 | // This frame is used to mark a Context/AppDomain Transition |
| 3083 | //------------------------------------------------------------------------ |
| 3084 | |
| 3085 | class ContextTransitionFrame : public Frame |
| 3086 | { |
| 3087 | private: |
| 3088 | PTR_Object m_LastThrownObjectInParentContext; |
| 3089 | ULONG_PTR m_LockCount; // Number of locks the thread takes |
| 3090 | // before the transition. |
| 3091 | VPTR_VTABLE_CLASS(ContextTransitionFrame, Frame) |
| 3092 | |
| 3093 | public: |
| 3094 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 3095 | |
| 3096 | OBJECTREF GetLastThrownObjectInParentContext() |
| 3097 | { |
| 3098 | return ObjectToOBJECTREF(m_LastThrownObjectInParentContext); |
| 3099 | } |
| 3100 | |
| 3101 | void SetLastThrownObjectInParentContext(OBJECTREF lastThrownObject) |
| 3102 | { |
| 3103 | m_LastThrownObjectInParentContext = OBJECTREFToObject(lastThrownObject); |
| 3104 | } |
| 3105 | |
| 3106 | void SetLockCount(DWORD lockCount) |
| 3107 | { |
| 3108 | LIMITED_METHOD_CONTRACT; |
| 3109 | m_LockCount = lockCount; |
| 3110 | } |
| 3111 | DWORD GetLockCount() |
| 3112 | { |
| 3113 | LIMITED_METHOD_CONTRACT; |
| 3114 | return (DWORD) m_LockCount; |
| 3115 | } |
| 3116 | |
| 3117 | |
| 3118 | // Let debugger know that we're transitioning between AppDomains. |
| 3119 | ETransitionType GetTransitionType() |
| 3120 | { |
| 3121 | LIMITED_METHOD_DAC_CONTRACT; |
| 3122 | return TT_AppDomain; |
| 3123 | } |
| 3124 | |
| 3125 | #ifndef DACCESS_COMPILE |
| 3126 | ContextTransitionFrame() |
| 3127 | : m_LastThrownObjectInParentContext(NULL) |
| 3128 | , m_LockCount(0) |
| 3129 | { |
| 3130 | LIMITED_METHOD_CONTRACT; |
| 3131 | } |
| 3132 | #endif |
| 3133 | |
| 3134 | // Keep as last entry in class |
| 3135 | DEFINE_VTABLE_GETTER_AND_DTOR(ContextTransitionFrame) |
| 3136 | }; |
| 3137 | |
| 3138 | // TODO [DAVBR]: For the full fix for VsWhidbey 450273, this |
| 3139 | // may be uncommented once isLegalManagedCodeCaller works properly |
| 3140 | // with non-return address inputs, and with non-DEBUG builds |
| 3141 | //bool isLegalManagedCodeCaller(TADDR retAddr); |
| 3142 | bool isRetAddr(TADDR retAddr, TADDR* whereCalled); |
| 3143 | |
| 3144 | //------------------------------------------------------------------------ |
| 3145 | #ifdef _TARGET_X86_ |
| 3146 | // This frame is used as padding for virtual stub dispatch tailcalls. |
| 3147 | // When A calls B via virtual stub dispatch, the stub dispatch stub resolves |
| 3148 | // the target code for B and jumps to it. If A wants to do a tail call, |
| 3149 | // it does not get a chance to unwind its frame since the virtual stub dispatch |
| 3150 | // stub is not set up to return the address of the target code (rather |
| 3151 | // than just jumping to it). |
| 3152 | // To do a tail call, A calls JIT_TailCall, which unwinds A's frame |
| 3153 | // and sets up a TailCallFrame. It then calls the stub dispatch stub |
| 3154 | // which disassembles the caller (JIT_TailCall, in this case) to get some information, |
| 3155 | // resolves the target code for B, and then jumps to B. |
| 3156 | // If B also does a virtual stub dispatch tail call, then we reuse the |
| 3157 | // existing TailCallFrame instead of setting up a second one. |
| 3158 | // |
| 3159 | // We could eliminate TailCallFrame if we factor the VSD stub to return |
| 3160 | // the target code address. This is currently not a very important scenario |
| 3161 | // as tail calls on interface calls are uncommon. |
| 3162 | #else |
| 3163 | // This frame is used as padding for tailcalls which require more space |
| 3164 | // than the caller has in it's incoming argument space. |
| 3165 | // To do a tail call from A to B, A calls JIT_TailCall, which unwinds A's frame |
| 3166 | // and sets up a TailCallFrame and the arguments. It then jumps to B. |
| 3167 | // If B also does a tail call, then we reuse the |
| 3168 | // existing TailCallFrame instead of setting up a second one. |
| 3169 | // |
| 3170 | // This is also used whenever value types that aren't enregisterable are |
| 3171 | // passed by value instead of ref. This is currently not a very important |
| 3172 | // scenario as tail calls are uncommon. |
| 3173 | #endif |
| 3174 | //------------------------------------------------------------------------ |
| 3175 | |
| 3176 | class TailCallFrame : public Frame |
| 3177 | { |
| 3178 | VPTR_VTABLE_CLASS(TailCallFrame, Frame) |
| 3179 | |
| 3180 | #if defined(_TARGET_X86_) |
| 3181 | TADDR m_CallerAddress; // the address the tailcall was initiated from |
| 3182 | CalleeSavedRegisters m_regs; // callee saved registers - the stack walk assumes that all non-JIT frames have them |
| 3183 | TADDR m_ReturnAddress; // the return address of the tailcall |
| 3184 | #elif defined(_TARGET_AMD64_) |
| 3185 | TADDR m_pGCLayout; |
| 3186 | TADDR m_padding; // code:StubLinkerCPU::CreateTailCallCopyArgsThunk expects the size of TailCallFrame to be 16-byte aligned |
| 3187 | CalleeSavedRegisters m_calleeSavedRegisters; |
| 3188 | TADDR m_ReturnAddress; |
| 3189 | #elif defined(_TARGET_ARM_) |
| 3190 | union { |
| 3191 | CalleeSavedRegisters m_calleeSavedRegisters; |
| 3192 | // alias saved link register as m_ReturnAddress |
| 3193 | struct { |
| 3194 | INT32 r4, r5, r6, r7, r8, r9, r10; |
| 3195 | INT32 r11; |
| 3196 | TADDR m_ReturnAddress; |
| 3197 | }; |
| 3198 | }; |
| 3199 | #else |
| 3200 | TADDR m_ReturnAddress; |
| 3201 | #endif |
| 3202 | |
| 3203 | public: |
| 3204 | #ifndef CROSSGEN_COMPILE |
| 3205 | #if !defined(_TARGET_X86_) |
| 3206 | |
| 3207 | #ifndef DACCESS_COMPILE |
| 3208 | TailCallFrame(T_CONTEXT * pContext, Thread * pThread) |
| 3209 | { |
| 3210 | InitFromContext(pContext); |
| 3211 | m_Next = pThread->GetFrame(); |
| 3212 | } |
| 3213 | |
| 3214 | void InitFromContext(T_CONTEXT * pContext); |
| 3215 | |
| 3216 | // Architecture-specific method to initialize a CONTEXT record as if the first |
| 3217 | // part of the TailCallHelperStub had executed |
| 3218 | static TailCallFrame * AdjustContextForTailCallHelperStub(_CONTEXT * pContext, size_t cbNewArgArea, Thread * pThread); |
| 3219 | #endif |
| 3220 | |
| 3221 | static TailCallFrame * GetFrameFromContext(CONTEXT * pContext); |
| 3222 | #endif // !_TARGET_X86_ |
| 3223 | |
| 3224 | #if defined(_TARGET_X86_) |
| 3225 | static TailCallFrame* FindTailCallFrame(Frame* pFrame) |
| 3226 | { |
| 3227 | LIMITED_METHOD_CONTRACT; |
| 3228 | // loop through the frame chain |
| 3229 | while (pFrame->GetVTablePtr() != TailCallFrame::GetMethodFrameVPtr()) |
| 3230 | pFrame = pFrame->m_Next; |
| 3231 | return (TailCallFrame*)pFrame; |
| 3232 | } |
| 3233 | |
| 3234 | TADDR GetCallerAddress() |
| 3235 | { |
| 3236 | LIMITED_METHOD_CONTRACT; |
| 3237 | return m_CallerAddress; |
| 3238 | } |
| 3239 | #endif // _TARGET_X86_ |
| 3240 | |
| 3241 | virtual TADDR GetReturnAddressPtr() |
| 3242 | { |
| 3243 | LIMITED_METHOD_DAC_CONTRACT; |
| 3244 | return PTR_HOST_MEMBER_TADDR(TailCallFrame, this, |
| 3245 | m_ReturnAddress); |
| 3246 | } |
| 3247 | |
| 3248 | virtual BOOL NeedsUpdateRegDisplay() |
| 3249 | { |
| 3250 | return TRUE; |
| 3251 | } |
| 3252 | |
| 3253 | virtual void UpdateRegDisplay(const PREGDISPLAY pRD); |
| 3254 | #endif // !CROSSGEN_COMPILE |
| 3255 | #ifdef _TARGET_AMD64_ |
| 3256 | void SetGCLayout(TADDR pGCLayout) |
| 3257 | { |
| 3258 | LIMITED_METHOD_CONTRACT; |
| 3259 | m_pGCLayout = pGCLayout; |
| 3260 | } |
| 3261 | |
| 3262 | virtual void GcScanRoots(promote_func *fn, ScanContext* sc); |
| 3263 | #else |
| 3264 | void SetGCLayout(TADDR pGCLayout) |
| 3265 | { |
| 3266 | LIMITED_METHOD_CONTRACT; |
| 3267 | _ASSERTE(pGCLayout == NULL); |
| 3268 | } |
| 3269 | #endif |
| 3270 | |
| 3271 | private: |
| 3272 | // Keep as last entry in class |
| 3273 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(TailCallFrame) |
| 3274 | }; |
| 3275 | |
| 3276 | //------------------------------------------------------------------------ |
| 3277 | // ExceptionFilterFrame is a small frame whose only purpose in |
| 3278 | // life is to set SHADOW_SP_FILTER_DONE during unwind from exception filter. |
| 3279 | //------------------------------------------------------------------------ |
| 3280 | |
| 3281 | class ExceptionFilterFrame : public Frame |
| 3282 | { |
| 3283 | VPTR_VTABLE_CLASS(ExceptionFilterFrame, Frame) |
| 3284 | size_t* m_pShadowSP; |
| 3285 | |
| 3286 | public: |
| 3287 | #ifndef DACCESS_COMPILE |
| 3288 | ExceptionFilterFrame(size_t* pShadowSP) |
| 3289 | { |
| 3290 | WRAPPER_NO_CONTRACT; |
| 3291 | m_pShadowSP = pShadowSP; |
| 3292 | Push(); |
| 3293 | } |
| 3294 | |
| 3295 | void Pop() |
| 3296 | { |
| 3297 | // Nothing to do here. |
| 3298 | WRAPPER_NO_CONTRACT; |
| 3299 | SetFilterDone(); |
| 3300 | Frame::Pop(); |
| 3301 | } |
| 3302 | |
| 3303 | void SetFilterDone() |
| 3304 | { |
| 3305 | LIMITED_METHOD_CONTRACT; |
| 3306 | |
| 3307 | // Mark the filter as having completed |
| 3308 | if (m_pShadowSP) |
| 3309 | { |
| 3310 | // Make sure that CallJitEHFilterHelper marked us as being in the filter. |
| 3311 | _ASSERTE(*m_pShadowSP & ICodeManager::SHADOW_SP_IN_FILTER); |
| 3312 | *m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE; |
| 3313 | } |
| 3314 | } |
| 3315 | #endif |
| 3316 | |
| 3317 | private: |
| 3318 | // Keep as last entry in class |
| 3319 | DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame) |
| 3320 | }; |
| 3321 | |
| 3322 | #ifdef _DEBUG |
| 3323 | // We use IsProtectedByGCFrame to check if some OBJECTREF pointers are protected |
| 3324 | // against GC. That function doesn't know if a byref is from managed stack thus |
| 3325 | // protected by JIT. AssumeByrefFromJITStack is used to bypass that check if an |
| 3326 | // OBJECTRef pointer is passed from managed code to an FCall and it's in stack. |
| 3327 | class AssumeByrefFromJITStack : public Frame |
| 3328 | { |
| 3329 | VPTR_VTABLE_CLASS(AssumeByrefFromJITStack, Frame) |
| 3330 | public: |
| 3331 | #ifndef DACCESS_COMPILE |
| 3332 | AssumeByrefFromJITStack(OBJECTREF *pObjRef) |
| 3333 | { |
| 3334 | m_pObjRef = pObjRef; |
| 3335 | } |
| 3336 | #endif |
| 3337 | |
| 3338 | BOOL Protects(OBJECTREF *ppORef) |
| 3339 | { |
| 3340 | LIMITED_METHOD_CONTRACT; |
| 3341 | return ppORef == m_pObjRef; |
| 3342 | } |
| 3343 | |
| 3344 | private: |
| 3345 | OBJECTREF *m_pObjRef; |
| 3346 | |
| 3347 | // Keep as last entry in class |
| 3348 | DEFINE_VTABLE_GETTER_AND_DTOR(AssumeByrefFromJITStack) |
| 3349 | }; //AssumeByrefFromJITStack |
| 3350 | |
| 3351 | #endif //_DEBUG |
| 3352 | |
| 3353 | //----------------------------------------------------------------------------- |
| 3354 | // FrameWithCookie is used to declare a Frame in source code with a cookie |
| 3355 | // immediately preceeding it. |
| 3356 | // This is just a specialized version of GSCookieFor<T> |
| 3357 | // |
| 3358 | // For Frames that are set up by stubs, the stub is responsible for setting up |
| 3359 | // the GSCookie. |
| 3360 | // |
| 3361 | // Note that we have to play all these games for the GSCookie as the GSCookie |
| 3362 | // needs to precede the vtable pointer, so that the GSCookie is guaranteed to |
| 3363 | // catch any stack-buffer-overrun corruptions that overwrite the Frame data. |
| 3364 | // |
| 3365 | //----------------------------------------------------------------------------- |
| 3366 | |
| 3367 | class DebuggerEval; |
| 3368 | |
| 3369 | class GCSafeCollection; |
| 3370 | |
| 3371 | template <typename FrameType> |
| 3372 | class FrameWithCookie |
| 3373 | { |
| 3374 | protected: |
| 3375 | |
| 3376 | GSCookie m_gsCookie; |
| 3377 | FrameType m_frame; |
| 3378 | |
| 3379 | public: |
| 3380 | |
| 3381 | // |
| 3382 | // Overload all the required constructors |
| 3383 | // |
| 3384 | |
| 3385 | FrameWithCookie() : |
| 3386 | m_gsCookie(GetProcessGSCookie()), m_frame() { WRAPPER_NO_CONTRACT; } |
| 3387 | |
| 3388 | FrameWithCookie(Thread * pThread) : |
| 3389 | m_gsCookie(GetProcessGSCookie()), m_frame(pThread) { WRAPPER_NO_CONTRACT; } |
| 3390 | |
| 3391 | FrameWithCookie(T_CONTEXT * pContext) : |
| 3392 | m_gsCookie(GetProcessGSCookie()), m_frame(pContext) { WRAPPER_NO_CONTRACT; } |
| 3393 | |
| 3394 | FrameWithCookie(TransitionBlock * pTransitionBlock) : |
| 3395 | m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock) { WRAPPER_NO_CONTRACT; } |
| 3396 | |
| 3397 | FrameWithCookie(TransitionBlock * pTransitionBlock, MethodDesc * pMD) : |
| 3398 | m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pMD) { WRAPPER_NO_CONTRACT; } |
| 3399 | |
| 3400 | FrameWithCookie(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) : |
| 3401 | m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget) { WRAPPER_NO_CONTRACT; } |
| 3402 | |
| 3403 | FrameWithCookie(TransitionBlock * pTransitionBlock, int frameFlags) : |
| 3404 | m_gsCookie(GetProcessGSCookie()), m_frame(pTransitionBlock, frameFlags) { WRAPPER_NO_CONTRACT; } |
| 3405 | |
| 3406 | |
| 3407 | // GCFrame |
| 3408 | FrameWithCookie(Thread * pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) : |
| 3409 | m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; } |
| 3410 | |
| 3411 | FrameWithCookie(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) : |
| 3412 | m_gsCookie(GetProcessGSCookie()), m_frame(pObjRefs, numObjRefs, maybeInterior) { WRAPPER_NO_CONTRACT; } |
| 3413 | |
| 3414 | // GCSafeCollectionFrame |
| 3415 | FrameWithCookie(GCSafeCollection *gcSafeCollection) : |
| 3416 | m_gsCookie(GetProcessGSCookie()), m_frame(gcSafeCollection) { WRAPPER_NO_CONTRACT; } |
| 3417 | |
| 3418 | #ifdef FEATURE_INTERPRETER |
| 3419 | // InterpreterFrame |
| 3420 | FrameWithCookie(Interpreter* interp) : |
| 3421 | m_gsCookie(GetProcessGSCookie()), m_frame(interp) { WRAPPER_NO_CONTRACT; } |
| 3422 | #endif |
| 3423 | |
| 3424 | // HijackFrame |
| 3425 | FrameWithCookie(LPVOID returnAddress, Thread *thread, HijackArgs *args) : |
| 3426 | m_gsCookie(GetProcessGSCookie()), m_frame(returnAddress, thread, args) { WRAPPER_NO_CONTRACT; } |
| 3427 | |
| 3428 | #ifdef DEBUGGING_SUPPORTED |
| 3429 | // FuncEvalFrame |
| 3430 | FrameWithCookie(DebuggerEval *pDebuggerEval, TADDR returnAddress, BOOL showFrame) : |
| 3431 | m_gsCookie(GetProcessGSCookie()), m_frame(pDebuggerEval, returnAddress, showFrame) { WRAPPER_NO_CONTRACT; } |
| 3432 | #endif // DEBUGGING_SUPPORTED |
| 3433 | |
| 3434 | // TailCallFrame |
| 3435 | FrameWithCookie(T_CONTEXT * pContext, Thread *thread) : |
| 3436 | m_gsCookie(GetProcessGSCookie()), m_frame(pContext, thread) { WRAPPER_NO_CONTRACT; } |
| 3437 | |
| 3438 | #ifndef DACCESS_COMPILE |
| 3439 | // GSCookie for HelperMethodFrames is initialized in a common HelperMethodFrame init method |
| 3440 | |
| 3441 | // HelperMethodFrame |
| 3442 | FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs = 0) : |
| 3443 | m_frame(fCallFtnEntry, attribs) { WRAPPER_NO_CONTRACT; } |
| 3444 | |
| 3445 | // HelperMethodFrame_1OBJ |
| 3446 | FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1) : |
| 3447 | m_frame(fCallFtnEntry, attribs, aGCPtr1) { WRAPPER_NO_CONTRACT; } |
| 3448 | |
| 3449 | // HelperMethodFrame_2OBJ |
| 3450 | FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2) : |
| 3451 | m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2) { WRAPPER_NO_CONTRACT; } |
| 3452 | |
| 3453 | // HelperMethodFrame_3OBJ |
| 3454 | FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF * aGCPtr1, OBJECTREF * aGCPtr2, OBJECTREF * aGCPtr3) : |
| 3455 | m_frame(fCallFtnEntry, attribs, aGCPtr1, aGCPtr2, aGCPtr3) { WRAPPER_NO_CONTRACT; } |
| 3456 | |
| 3457 | // HelperMethodFrame_PROTECTOBJ |
| 3458 | FORCEINLINE FrameWithCookie(void* fCallFtnEntry, unsigned attribs, OBJECTREF* pObjRefs, int numObjRefs) : |
| 3459 | m_frame(fCallFtnEntry, attribs, pObjRefs, numObjRefs) { WRAPPER_NO_CONTRACT; } |
| 3460 | |
| 3461 | #endif // DACCESS_COMPILE |
| 3462 | |
| 3463 | // ProtectByRefsFrame |
| 3464 | FrameWithCookie(Thread * pThread, ByRefInfo * pByRefs) : |
| 3465 | m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pByRefs) { WRAPPER_NO_CONTRACT; } |
| 3466 | |
| 3467 | // ProtectValueClassFrame |
| 3468 | FrameWithCookie(Thread * pThread, ValueClassInfo * pValueClasses) : |
| 3469 | m_gsCookie(GetProcessGSCookie()), m_frame(pThread, pValueClasses) { WRAPPER_NO_CONTRACT; } |
| 3470 | |
| 3471 | // ExceptionFilterFrame |
| 3472 | FrameWithCookie(size_t* pShadowSP) : |
| 3473 | m_gsCookie(GetProcessGSCookie()), m_frame(pShadowSP) { WRAPPER_NO_CONTRACT; } |
| 3474 | |
| 3475 | #ifdef _DEBUG |
| 3476 | // AssumeByrefFromJITStack |
| 3477 | FrameWithCookie(OBJECTREF *pObjRef) : |
| 3478 | m_gsCookie(GetProcessGSCookie()), m_frame(pObjRef) { WRAPPER_NO_CONTRACT; } |
| 3479 | |
| 3480 | void SetAddrOfHaveCheckedRestoreState(BOOL* pDoneCheck) |
| 3481 | { |
| 3482 | WRAPPER_NO_CONTRACT; |
| 3483 | m_frame.SetAddrOfHaveCheckedRestoreState(pDoneCheck); |
| 3484 | } |
| 3485 | |
| 3486 | #endif //_DEBUG |
| 3487 | |
| 3488 | // |
| 3489 | // Overload some common Frame methods for easy redirection |
| 3490 | // |
| 3491 | |
| 3492 | void Push() { WRAPPER_NO_CONTRACT; m_frame.Push(); } |
| 3493 | void Pop() { WRAPPER_NO_CONTRACT; m_frame.Pop(); } |
| 3494 | void Push(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Push(pThread); } |
| 3495 | void Pop(Thread * pThread) { WRAPPER_NO_CONTRACT; m_frame.Pop(pThread); } |
| 3496 | PCODE GetReturnAddress() { WRAPPER_NO_CONTRACT; return m_frame.GetReturnAddress(); } |
| 3497 | T_CONTEXT * GetContext() { WRAPPER_NO_CONTRACT; return m_frame.GetContext(); } |
| 3498 | FrameType* operator&() { LIMITED_METHOD_CONTRACT; return &m_frame; } |
| 3499 | LazyMachState * MachineState() { WRAPPER_NO_CONTRACT; return m_frame.MachineState(); } |
| 3500 | Thread * GetThread() { WRAPPER_NO_CONTRACT; return m_frame.GetThread(); } |
| 3501 | BOOL InsureInit(bool initialInit, struct MachState* unwindState) |
| 3502 | { WRAPPER_NO_CONTRACT; return m_frame.InsureInit(initialInit, unwindState); } |
| 3503 | void Poll() { WRAPPER_NO_CONTRACT; m_frame.Poll(); } |
| 3504 | void SetStackPointerPtr(TADDR sp) { WRAPPER_NO_CONTRACT; m_frame.SetStackPointerPtr(sp); } |
| 3505 | void InitAndLink(T_CONTEXT *pContext) { WRAPPER_NO_CONTRACT; m_frame.InitAndLink(pContext); } |
| 3506 | void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior) |
| 3507 | { WRAPPER_NO_CONTRACT; m_frame.Init(pThread, pObjRefs, numObjRefs, maybeInterior); } |
| 3508 | ValueClassInfo ** GetValueClassInfoList() { WRAPPER_NO_CONTRACT; return m_frame.GetValueClassInfoList(); } |
| 3509 | |
| 3510 | #if 0 |
| 3511 | // |
| 3512 | // Access to the underlying Frame |
| 3513 | // You should only need to use this if none of the above overloads work for you |
| 3514 | // Consider adding the required overload to the list above |
| 3515 | // |
| 3516 | |
| 3517 | FrameType& operator->() { LIMITED_METHOD_CONTRACT; return m_frame; } |
| 3518 | #endif |
| 3519 | |
| 3520 | // Since the "&" operator is overloaded, use this function to get to the |
| 3521 | // address of FrameWithCookie, rather than that of FrameWithCookie::m_frame. |
| 3522 | GSCookie * GetGSCookiePtr() { LIMITED_METHOD_CONTRACT; return &m_gsCookie; } |
| 3523 | }; |
| 3524 | |
| 3525 | //------------------------------------------------------------------------ |
| 3526 | // These macros GC-protect OBJECTREF pointers on the EE's behalf. |
| 3527 | // In between these macros, the GC can move but not discard the protected |
| 3528 | // objects. If the GC moves an object, it will update the guarded OBJECTREF's. |
| 3529 | // Typical usage: |
| 3530 | // |
| 3531 | // OBJECTREF or = <some valid objectref>; |
| 3532 | // GCPROTECT_BEGIN(or); |
| 3533 | // |
| 3534 | // ...<do work that can trigger GC>... |
| 3535 | // |
| 3536 | // GCPROTECT_END(); |
| 3537 | // |
| 3538 | // |
| 3539 | // These macros can also protect multiple OBJECTREF's if they're packaged |
| 3540 | // into a structure: |
| 3541 | // |
| 3542 | // struct xx { |
| 3543 | // OBJECTREF o1; |
| 3544 | // OBJECTREF o2; |
| 3545 | // } gc; |
| 3546 | // |
| 3547 | // GCPROTECT_BEGIN(gc); |
| 3548 | // .... |
| 3549 | // GCPROTECT_END(); |
| 3550 | // |
| 3551 | // |
| 3552 | // Notes: |
| 3553 | // |
| 3554 | // - GCPROTECT_BEGININTERIOR() can be used in place of GCPROTECT_BEGIN() |
| 3555 | // to handle the case where one or more of the OBJECTREFs is potentially |
| 3556 | // an interior pointer. This is a rare situation, because boxing would |
| 3557 | // normally prevent us from encountering it. Be aware that the OBJECTREFs |
| 3558 | // we protect are not validated in this situation. |
| 3559 | // |
| 3560 | // - GCPROTECT_ARRAY_BEGIN() can be used when an array of object references |
| 3561 | // is allocated on the stack. The pointer to the first element is passed |
| 3562 | // along with the number of elements in the array. |
| 3563 | // |
| 3564 | // - The argument to GCPROTECT_BEGIN should be an lvalue because it |
| 3565 | // uses "sizeof" to count the OBJECTREF's. |
| 3566 | // |
| 3567 | // - GCPROTECT_BEGIN spiritually violates our normal convention of not passing |
| 3568 | // non-const refernce arguments. Unfortunately, this is necessary in |
| 3569 | // order for the sizeof thing to work. |
| 3570 | // |
| 3571 | // - GCPROTECT_BEGIN does _not_ zero out the OBJECTREF's. You must have |
| 3572 | // valid OBJECTREF's when you invoke this macro. |
| 3573 | // |
| 3574 | // - GCPROTECT_BEGIN begins a new C nesting block. Besides allowing |
| 3575 | // GCPROTECT_BEGIN's to nest, it also has the advantage of causing |
| 3576 | // a compiler error if you forget to code a maching GCPROTECT_END. |
| 3577 | // |
| 3578 | // - If you are GCPROTECTing something, it means you are expecting a GC to occur. |
| 3579 | // So we assert that GC is not forbidden. If you hit this assert, you probably need |
| 3580 | // a HELPER_METHOD_FRAME to protect the region that can cause the GC. |
| 3581 | //------------------------------------------------------------------------ |
| 3582 | |
| 3583 | #ifndef DACCESS_COMPILE |
| 3584 | |
| 3585 | #ifdef _PREFAST_ |
| 3586 | // Suppress prefast warning #6384: Dividing sizeof a pointer by another value |
| 3587 | #pragma warning(disable:6384) |
| 3588 | #endif /*_PREFAST_ */ |
| 3589 | |
| 3590 | #define GCPROTECT_BEGIN(ObjRefStruct) do { \ |
| 3591 | FrameWithCookie<GCFrame> __gcframe( \ |
| 3592 | (OBJECTREF*)&(ObjRefStruct), \ |
| 3593 | sizeof(ObjRefStruct)/sizeof(OBJECTREF), \ |
| 3594 | FALSE); \ |
| 3595 | /* work around unreachable code warning */ \ |
| 3596 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) |
| 3597 | |
| 3598 | #define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \ |
| 3599 | FrameWithCookie<GCFrame> __gcframe( \ |
| 3600 | pThread, \ |
| 3601 | (OBJECTREF*)&(ObjRefStruct), \ |
| 3602 | sizeof(ObjRefStruct)/sizeof(OBJECTREF), \ |
| 3603 | FALSE); \ |
| 3604 | /* work around unreachable code warning */ \ |
| 3605 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) |
| 3606 | |
| 3607 | #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \ |
| 3608 | FrameWithCookie<GCFrame> __gcframe( \ |
| 3609 | (OBJECTREF*)&(ObjRefArray), \ |
| 3610 | cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \ |
| 3611 | FALSE); \ |
| 3612 | /* work around unreachable code warning */ \ |
| 3613 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) |
| 3614 | |
| 3615 | #define GCPROTECT_BEGININTERIOR(ObjRefStruct) do { \ |
| 3616 | FrameWithCookie<GCFrame> __gcframe( \ |
| 3617 | (OBJECTREF*)&(ObjRefStruct), \ |
| 3618 | sizeof(ObjRefStruct)/sizeof(OBJECTREF), \ |
| 3619 | TRUE); \ |
| 3620 | /* work around unreachable code warning */ \ |
| 3621 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) |
| 3622 | |
| 3623 | #define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \ |
| 3624 | FrameWithCookie<GCFrame> __gcframe( \ |
| 3625 | (OBJECTREF*)&(ObjRefArray), \ |
| 3626 | cnt, \ |
| 3627 | TRUE); \ |
| 3628 | /* work around unreachable code warning */ \ |
| 3629 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) |
| 3630 | |
| 3631 | |
| 3632 | #define GCPROTECT_END() \ |
| 3633 | DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \ |
| 3634 | __gcframe.Pop(); } while(0) |
| 3635 | |
| 3636 | |
| 3637 | #else // #ifndef DACCESS_COMPILE |
| 3638 | |
| 3639 | #define GCPROTECT_BEGIN(ObjRefStruct) |
| 3640 | #define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) |
| 3641 | #define GCPROTECT_BEGININTERIOR(ObjRefStruct) |
| 3642 | #define GCPROTECT_END() |
| 3643 | |
| 3644 | #endif // #ifndef DACCESS_COMPILE |
| 3645 | |
| 3646 | |
| 3647 | #define ASSERT_ADDRESS_IN_STACK(address) _ASSERTE (Thread::IsAddressInCurrentStack (address)); |
| 3648 | |
| 3649 | #if defined (_DEBUG) && !defined (DACCESS_COMPILE) |
| 3650 | #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) \ |
| 3651 | /* make sure we are only called inside an FCall */ \ |
| 3652 | if (__me == 0) {}; \ |
| 3653 | /* make sure the address is in stack. If the address is an interior */ \ |
| 3654 | /*pointer points to GC heap, the FCall still needs to protect it explicitly */ \ |
| 3655 | ASSERT_ADDRESS_IN_STACK (__objRef); \ |
| 3656 | do { \ |
| 3657 | FrameWithCookie<AssumeByrefFromJITStack> __dummyAssumeByrefFromJITStack ((__objRef)); \ |
| 3658 | __dummyAssumeByrefFromJITStack.Push (); \ |
| 3659 | /* work around unreachable code warning */ \ |
| 3660 | if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GC_PROTECT) |
| 3661 | |
| 3662 | #define ASSUME_BYREF_FROM_JIT_STACK_END() \ |
| 3663 | DEBUG_ASSURE_NO_RETURN_END(GC_PROTECT) } \ |
| 3664 | __dummyAssumeByrefFromJITStack.Pop(); } while(0) |
| 3665 | #else //defined (_DEBUG) && !defined (DACCESS_COMPILE) |
| 3666 | #define ASSUME_BYREF_FROM_JIT_STACK_BEGIN(__objRef) |
| 3667 | #define ASSUME_BYREF_FROM_JIT_STACK_END() |
| 3668 | #endif //defined (_DEBUG) && !defined (DACCESS_COMPILE) |
| 3669 | |
| 3670 | //------------------------------------------------------------------------ |
| 3671 | |
| 3672 | #if defined(FRAMES_TURNED_FPO_ON) |
| 3673 | #pragma optimize("", on) // Go back to command line default optimizations |
| 3674 | #undef FRAMES_TURNED_FPO_ON |
| 3675 | #undef FPO_ON |
| 3676 | #endif |
| 3677 | |
| 3678 | #endif //__frames_h__ |
| 3679 | |