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 | |