bd926001ae71934986ce3d2fcfafe651cd0927d7
[platform/upstream/dotnet/runtime.git] / src / coreclr / vm / stublink.h
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
4 // STUBLINK.H
5 //
6
7 //
8 // A StubLinker object provides a way to link several location-independent
9 // code sources into one executable stub, resolving references,
10 // and choosing the shortest possible instruction size. The StubLinker
11 // abstracts out the notion of a "reference" so it is completely CPU
12 // independent. This StubLinker is intended not only to create method
13 // stubs but to create the PCode-marshaling stubs for Native/Direct.
14 //
15 // A StubLinker's typical life-cycle is:
16 //
17 //   1. Create a new StubLinker (it accumulates state for the stub being
18 //      generated.)
19 //   2. Emit code bytes and references (requiring fixups) into the StubLinker.
20 //   3. Call the Link() method to produce the final stub.
21 //   4. Destroy the StubLinker.
22 //
23 // StubLinkers are not multithread-aware: they're intended to be
24 // used entirely on a single thread. Also, StubLinker's report errors
25 // using COMPlusThrow. StubLinker's do have a destructor: to prevent
26 // C++ object unwinding from clashing with COMPlusThrow,
27 // you must use COMPLUSCATCH to ensure the StubLinker's cleanup in the
28 // event of an exception: the following code would do it:
29 //
30 //  StubLinker stublink;
31 //  Inner();
32 //
33 //
34 //  // Have to separate into inner function because VC++ forbids
35 //  // mixing __try & local objects in the same function.
36 //  void Inner() {
37 //      COMPLUSTRY {
38 //          ... do stuff ...
39 //          pLinker->Link();
40 //      } COMPLUSCATCH {
41 //      }
42 //  }
43 //
44
45
46 // This file should only be included via the platform-specific cgencpu.h.
47
48 #include "cgensys.h"
49
50 #ifndef __stublink_h__
51 #define __stublink_h__
52
53 #include "crst.h"
54 #include "util.hpp"
55 #include "eecontract.h"
56
57 //-------------------------------------------------------------------------
58 // Forward refs
59 //-------------------------------------------------------------------------
60 class  InstructionFormat;
61 class  Stub;
62 class  CheckDuplicatedStructLayouts;
63 class  CodeBasedStubCache;
64 struct  CodeLabel;
65
66 struct CodeRun;
67 struct LabelRef;
68 struct CodeElement;
69 struct IntermediateUnwindInfo;
70
71 #if !defined(TARGET_X86) && !defined(TARGET_UNIX)
72 #define STUBLINKER_GENERATES_UNWIND_INFO
73 #endif // !TARGET_X86 && !TARGET_UNIX
74
75
76 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
77
78 typedef DPTR(struct StubUnwindInfoHeaderSuffix) PTR_StubUnwindInfoHeaderSuffix;
79 struct StubUnwindInfoHeaderSuffix
80 {
81     UCHAR nUnwindInfoSize;  // Size of unwind info in bytes
82 };
83
84 // Variable-sized struct that precedes a Stub when the stub requires unwind
85 // information.  Followed by a StubUnwindInfoHeaderSuffix.
86 typedef DPTR(struct StubUnwindInfoHeader) PTR_StubUnwindInfoHeader;
87 struct StubUnwindInfoHeader
88 {
89     PTR_StubUnwindInfoHeader pNext;
90     T_RUNTIME_FUNCTION FunctionEntry;
91     UNWIND_INFO UnwindInfo;  // variable length
92
93     // Computes the size needed for this variable-sized struct.
94     static SIZE_T ComputeAlignedSize(UINT nUnwindInfoSize);
95
96     void Init ();
97
98     bool IsRegistered ();
99 };
100
101 // List of stub address ranges, in increasing address order.
102 struct StubUnwindInfoHeapSegment
103 {
104     PBYTE pbBaseAddress;
105     SIZE_T cbSegment;
106     StubUnwindInfoHeader *pUnwindHeaderList;
107     StubUnwindInfoHeapSegment *pNext;
108
109 #ifdef HOST_64BIT
110     class UnwindInfoTable* pUnwindInfoTable;       // Used to publish unwind info to ETW stack crawler
111 #endif
112 };
113
114 VOID UnregisterUnwindInfoInLoaderHeap (UnlockedLoaderHeap *pHeap);
115
116 #endif // STUBLINKER_GENERATES_UNWIND_INFO
117
118
119 //-------------------------------------------------------------------------
120 // A non-multithreaded object that fixes up and emits one executable stub.
121 //-------------------------------------------------------------------------
122 class StubLinker
123 {
124     public:
125         //---------------------------------------------------------------
126         // Construction
127         //---------------------------------------------------------------
128         StubLinker();
129
130
131         //---------------------------------------------------------------
132         // Create a new undefined label. Label must be assigned to a code
133         // location using EmitLabel() prior to final linking.
134         // Throws exception on failure.
135         //---------------------------------------------------------------
136         CodeLabel* NewCodeLabel();
137
138         //---------------------------------------------------------------
139         // Create a new undefined label for which we want the absolute
140         // address, not offset. Label must be assigned to a code
141         // location using EmitLabel() prior to final linking.
142         // Throws exception on failure.
143         //---------------------------------------------------------------
144         CodeLabel* NewAbsoluteCodeLabel();
145
146         //---------------------------------------------------------------
147         // Combines NewCodeLabel() and EmitLabel() for convenience.
148         // Throws exception on failure.
149         //---------------------------------------------------------------
150         CodeLabel* EmitNewCodeLabel();
151
152
153         //---------------------------------------------------------------
154         // Returns final location of label as an offset from the start
155         // of the stub. Can only be called after linkage.
156         //---------------------------------------------------------------
157         UINT32 GetLabelOffset(CodeLabel *pLabel);
158
159         //---------------------------------------------------------------
160         // Append code bytes.
161         //---------------------------------------------------------------
162         VOID EmitBytes(const BYTE *pBytes, UINT numBytes);
163         VOID Emit8 (unsigned __int8  u8);
164         VOID Emit16(unsigned __int16 u16);
165         VOID Emit32(unsigned __int32 u32);
166         VOID Emit64(unsigned __int64 u64);
167         VOID EmitPtr(const VOID *pval);
168
169         //---------------------------------------------------------------
170         // Append an instruction containing a reference to a label.
171         //
172         //      target             - the label being referenced.
173         //      instructionFormat  - a platform-specific InstructionFormat object
174         //                           that gives properties about the reference.
175         //      variationCode      - uninterpreted data passed to the pInstructionFormat methods.
176         //---------------------------------------------------------------
177         VOID EmitLabelRef(CodeLabel* target, const InstructionFormat & instructionFormat, UINT variationCode);
178
179
180         //---------------------------------------------------------------
181         // Sets the label to point to the current "instruction pointer"
182         // It is invalid to call EmitLabel() twice on
183         // the same label.
184         //---------------------------------------------------------------
185         VOID EmitLabel(CodeLabel* pCodeLabel);
186
187         //---------------------------------------------------------------
188         // Emits the patch label for the stub.
189         // Throws exception on failure.
190         //---------------------------------------------------------------
191         void EmitPatchLabel();
192
193         //---------------------------------------------------------------
194         // Create a new label to an external address.
195         // Throws exception on failure.
196         //---------------------------------------------------------------
197         CodeLabel* NewExternalCodeLabel(LPVOID pExternalAddress);
198         CodeLabel* NewExternalCodeLabel(PCODE pExternalAddress)
199         {
200             return NewExternalCodeLabel((LPVOID)pExternalAddress);
201         }
202
203         //---------------------------------------------------------------
204         // Set the target method for Instantiating stubs.
205         //---------------------------------------------------------------
206         void SetTargetMethod(PTR_MethodDesc pMD);
207
208         //---------------------------------------------------------------
209         // Push and Pop can be used to keep track of stack growth.
210         // These should be adjusted by opcodes written to the stream.
211         //
212         // Note that popping & pushing stack size as opcodes are emitted
213         // is naive & may not be accurate in many cases,
214         // so complex stubs may have to manually adjust the stack size.
215         // However it should work for the vast majority of cases we care
216         // about.
217         //---------------------------------------------------------------
218         void Push(UINT size);
219         void Pop(UINT size);
220
221         INT GetStackSize() { LIMITED_METHOD_CONTRACT; return m_stackSize; }
222         void SetStackSize(SHORT size) { LIMITED_METHOD_CONTRACT; m_stackSize = size; }
223
224         void SetDataOnly(BOOL fDataOnly = TRUE) { LIMITED_METHOD_CONTRACT; m_fDataOnly = fDataOnly; }
225
226 #ifdef TARGET_ARM
227         void DescribeProlog(UINT cCalleeSavedRegs, UINT cbStackFrame, BOOL fPushArgRegs);
228 #elif defined(TARGET_ARM64)
229         void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cCalleeSavedRegs, UINT cbStackFrame);
230         UINT GetSavedRegArgsOffset();
231         UINT GetStackFrameSize();
232 #endif
233
234         //===========================================================================
235         // Unwind information
236
237         // Records location of preserved or parameter register
238         VOID UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset);
239         VOID UnwindPushedReg (UCHAR reg);
240
241         // Records "sub rsp, xxx"
242         VOID UnwindAllocStack (SHORT FrameSizeIncrement);
243
244         // Records frame pointer register
245         VOID UnwindSetFramePointer (UCHAR reg);
246
247         // In DEBUG, emits a call to m_pUnwindInfoCheckLabel (via
248         // EmitUnwindInfoCheckWorker).  Code at that label will call to a
249         // helper that will attempt to RtlVirtualUnwind through the stub.  The
250         // helper will preserve ALL registers.
251         VOID EmitUnwindInfoCheck();
252
253 #if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
254 protected:
255
256         // Injects a call to the given label.
257         virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) { _ASSERTE(!"override me"); }
258
259         // Emits a call to a helper that will attempt to RtlVirtualUnwind
260         // through the stub.  The helper will preserve ALL registers.
261         virtual VOID EmitUnwindInfoCheckSubfunction() { _ASSERTE(!"override me"); }
262 #endif
263
264 public:
265
266         //---------------------------------------------------------------
267         // Generate the actual stub. The returned stub has a refcount of 1.
268         // No other methods (other than the destructor) should be called
269         // after calling Link().
270         //
271         // Throws exception on failure.
272         //---------------------------------------------------------------
273         Stub *Link(LoaderHeap *heap, DWORD flags = 0);
274
275     private:
276         CodeElement   *m_pCodeElements;     // stored in *reverse* order
277         CodeLabel     *m_pFirstCodeLabel;   // linked list of CodeLabels
278         LabelRef      *m_pFirstLabelRef;    // linked list of references
279         CodeLabel     *m_pPatchLabel;       // label of stub patch offset
280                                             // currently just for multicast
281                                             // frames.
282         PTR_MethodDesc m_pTargetMethod;     // Used for instantiating stubs.
283         SHORT         m_stackSize;          // count of pushes/pops
284         CQuickHeap    m_quickHeap;          // throwaway heap for
285                                             //   labels, and
286                                             //   internals.
287         BOOL          m_fDataOnly;          // the stub contains only data - does not need FlushInstructionCache
288
289 #ifdef TARGET_ARM
290 protected:
291         BOOL            m_fProlog;              // True if DescribeProlog has been called
292         UINT            m_cCalleeSavedRegs;     // Count of callee saved registers (0 == none, 1 == r4, 2 ==
293                                                 // r4-r5 etc. up to 8 == r4-r11)
294         UINT            m_cbStackFrame;         // Count of bytes in the stack frame (excl of saved regs)
295         BOOL            m_fPushArgRegs;         // If true, r0-r3 are saved before callee saved regs
296 #endif // TARGET_ARM
297
298 #ifdef TARGET_ARM64
299 protected:
300         BOOL            m_fProlog;              // True if DescribeProlog has been called
301         UINT            m_cIntRegArgs;          // Count of int register arguments (x0 - x7)
302         UINT            m_cVecRegArgs;          // Count of FP register arguments (v0 - v7)
303         UINT            m_cCalleeSavedRegs;     // Count of callee saved registers (x19 - x28)
304         UINT            m_cbStackSpace;         // Additional stack space for return buffer and stack alignment
305 #endif // TARGET_ARM64
306
307 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
308
309 #ifdef _DEBUG
310         CodeLabel     *m_pUnwindInfoCheckLabel;  // subfunction to call to unwind info check helper.
311                                                  // On AMD64, the prologue is restricted to 256
312                                                  // bytes, so this reduces the size of the injected
313                                                  // code from 14 to 5 bytes.
314 #endif
315
316 #ifdef TARGET_AMD64
317         IntermediateUnwindInfo *m_pUnwindInfoList;
318         UINT          m_nUnwindSlots;       // number of slots to allocate at end, == UNWIND_INFO::CountOfCodes
319         BOOL          m_fHaveFramePointer;  // indicates stack operations no longer need to be recorded
320
321         //
322         // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
323         //
324         UINT UnwindInfoSize(UINT codeSize)
325         {
326             if (m_nUnwindSlots == 0) return 0;
327
328             return sizeof(T_RUNTIME_FUNCTION) + offsetof(UNWIND_INFO, UnwindCode) + m_nUnwindSlots * sizeof(UNWIND_CODE);
329         }
330 #endif // TARGET_AMD64
331
332 #ifdef TARGET_ARM
333 #define MAX_UNWIND_CODE_WORDS 5  /* maximum number of 32-bit words to store unwind codes */
334         // Cache information about the stack frame set up in the prolog and use it in the generation of the
335         // epilog.
336 private:
337         // Reserve fixed size block that's big enough to fit any unwind info we can have
338         static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
339
340         //
341         // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
342         //
343         UINT UnwindInfoSize(UINT codeSize)
344         {
345             if (!m_fProlog) return 0;
346
347             return c_nUnwindInfoSize;
348         }
349 #endif // TARGET_ARM
350
351 #ifdef TARGET_ARM64
352 #define MAX_UNWIND_CODE_WORDS 5  /* maximum number of 32-bit words to store unwind codes */
353
354 private:
355         // Reserve fixed size block that's big enough to fit any unwind info we can have
356         static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
357         UINT UnwindInfoSize(UINT codeSize)
358         {
359             if (!m_fProlog) return 0;
360
361             return c_nUnwindInfoSize;
362         }
363
364 #endif // TARGET_ARM64
365
366 #endif // STUBLINKER_GENERATES_UNWIND_INFO
367
368         CodeRun *AppendNewEmptyCodeRun();
369
370
371         // Returns pointer to last CodeElement or NULL.
372         CodeElement *GetLastCodeElement()
373         {
374             LIMITED_METHOD_CONTRACT;
375             return m_pCodeElements;
376         }
377
378         // Appends a new CodeElement.
379         VOID AppendCodeElement(CodeElement *pCodeElement);
380
381
382         // Calculates the size of the stub code that is allocate
383         // immediately after the stub object. Returns the
384         // total size. GlobalSize contains the size without
385         // that data part.
386         virtual int CalculateSize(int* globalsize);
387
388         // Writes out the code element into memory following the
389         // stub object.
390         bool EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap);
391
392         CodeRun *GetLastCodeRunIfAny();
393
394         bool EmitUnwindInfo(Stub* pStubRX, Stub* pStubRW, int globalsize, LoaderHeap* pHeap);
395
396 #if defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
397         UNWIND_CODE *AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots = 0);
398 #endif // defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
399 };
400
401 //************************************************************************
402 // CodeLabel
403 //************************************************************************
404 struct CodeLabel
405 {
406     // Link pointer for StubLink's list of labels
407     CodeLabel       *m_next;
408
409     // if FALSE, label refers to some code within the same stub
410     // if TRUE, label refers to some externally supplied address.
411     BOOL             m_fExternal;
412
413     // if TRUE, means we want the actual address of the label and
414     // not an offset to it
415     BOOL             m_fAbsolute;
416
417     union {
418
419         // Internal
420         struct {
421             // Indicates the position of the label, expressed
422             // as an offset into a CodeRun.
423             CodeRun         *m_pCodeRun;
424             UINT             m_localOffset;
425
426         } i;
427
428
429         // External
430         struct {
431             LPVOID           m_pExternalAddress;
432         } e;
433     };
434 };
435
436 enum NewStubFlags
437 {
438     NEWSTUB_FL_NONE                 = 0x00000000,
439     NEWSTUB_FL_INSTANTIATING_METHOD = 0x00000001,
440     NEWSTUB_FL_MULTICAST            = 0x00000002,
441     NEWSTUB_FL_EXTERNAL             = 0x00000004,
442     NEWSTUB_FL_LOADERHEAP           = 0x00000008,
443     NEWSTUB_FL_THUNK                = 0x00000010
444 };
445
446
447 //-------------------------------------------------------------------------
448 // An executable stub. These can only be created by the StubLinker().
449 // Each stub has a reference count (which is maintained in a thread-safe
450 // manner.) When the ref-count goes to zero, the stub automatically
451 // cleans itself up.
452 //-------------------------------------------------------------------------
453 typedef DPTR(class Stub) PTR_Stub;
454 typedef DPTR(PTR_Stub) PTR_PTR_Stub;
455 class Stub
456 {
457     friend class CheckDuplicatedStructLayouts;
458     friend class CheckAsmOffsets;
459
460     protected:
461     enum
462     {
463         MULTICAST_DELEGATE_BIT  = 0x80000000,
464         EXTERNAL_ENTRY_BIT      = 0x40000000,
465         LOADER_HEAP_BIT         = 0x20000000,
466         INSTANTIATING_STUB_BIT  = 0x10000000,
467         UNWIND_INFO_BIT         = 0x08000000,
468         THUNK_BIT               = 0x04000000,
469
470         CODEBYTES_MASK          = THUNK_BIT - 1,
471         MAX_CODEBYTES           = CODEBYTES_MASK + 1,
472     };
473     static_assert_no_msg(CODEBYTES_MASK < THUNK_BIT);
474
475     public:
476         //-------------------------------------------------------------------
477         // Inc the refcount.
478         //-------------------------------------------------------------------
479         VOID IncRef();
480
481         //-------------------------------------------------------------------
482         // Dec the refcount.
483         // Returns true if the count went to zero and the stub was deleted
484         //-------------------------------------------------------------------
485         BOOL DecRef();
486
487         //-------------------------------------------------------------------
488         // Used for throwing out unused stubs from stub caches. This
489         // method cannot be 100% accurate due to race conditions. This
490         // is ok because stub cache management is robust in the face
491         // of missed or premature cleanups.
492         //-------------------------------------------------------------------
493         BOOL HeuristicLooksOrphaned()
494         {
495             LIMITED_METHOD_CONTRACT;
496             _ASSERTE(m_signature == kUsedStub);
497             return (m_refcount == 1);
498         }
499
500         //-------------------------------------------------------------------
501         // Used by the debugger to help step through stubs
502         //-------------------------------------------------------------------
503         BOOL IsMulticastDelegate()
504         {
505             LIMITED_METHOD_CONTRACT;
506             return (m_numCodeBytesAndFlags & MULTICAST_DELEGATE_BIT) != 0;
507         }
508
509         //-------------------------------------------------------------------
510         // Used by the debugger to help step through stubs
511         //-------------------------------------------------------------------
512         BOOL IsInstantiatingStub()
513         {
514             LIMITED_METHOD_CONTRACT;
515             return (m_numCodeBytesAndFlags & INSTANTIATING_STUB_BIT) != 0;
516         }
517
518         //-------------------------------------------------------------------
519         // Used by the debugger to help step through stubs
520         //-------------------------------------------------------------------
521         BOOL IsManagedThunk()
522         {
523             LIMITED_METHOD_CONTRACT;
524             return (m_numCodeBytesAndFlags & THUNK_BIT) != 0;
525         }
526
527         //-------------------------------------------------------------------
528         // For stubs which execute user code, a patch offset needs to be set
529         // to tell the debugger how far into the stub code the debugger has
530         // to step until the frame is set up.
531         //-------------------------------------------------------------------
532         void SetPatchOffset(USHORT offset)
533         {
534             LIMITED_METHOD_CONTRACT;
535             _ASSERTE(!IsInstantiatingStub());
536             m_data.PatchOffset = offset;
537         }
538
539         //-------------------------------------------------------------------
540         // For stubs which execute user code, a patch offset needs to be set
541         // to tell the debugger how far into the stub code the debugger has
542         // to step until the frame is set up.
543         //-------------------------------------------------------------------
544         USHORT GetPatchOffset()
545         {
546             LIMITED_METHOD_CONTRACT;
547             _ASSERTE(!IsInstantiatingStub());
548             return m_data.PatchOffset;
549         }
550
551         //-------------------------------------------------------------------
552         // For stubs which execute user code, a patch offset needs to be set
553         // to tell the debugger how far into the stub code the debugger has
554         // to step until the frame is set up.
555         //-------------------------------------------------------------------
556         TADDR GetPatchAddress()
557         {
558             LIMITED_METHOD_CONTRACT;
559             _ASSERTE(!IsInstantiatingStub());
560             return dac_cast<TADDR>(GetEntryPointInternal()) + GetPatchOffset();
561         }
562
563         //-------------------------------------------------------------------
564         // For instantiating methods, the target MethodDesc needs to be set
565         // to tell the debugger where to step through the instantiating method
566         // stub.
567         //-------------------------------------------------------------------
568         void SetInstantiatedMethodDesc(PTR_MethodDesc pMD)
569         {
570             LIMITED_METHOD_CONTRACT;
571             _ASSERTE(IsInstantiatingStub());
572             m_data.InstantiatedMethod = pMD;
573         }
574
575         //-------------------------------------------------------------------
576         // For instantiating methods, the target MethodDesc needs to be set
577         // to tell the debugger where to step through the instantiating method
578         // stub.
579         //-------------------------------------------------------------------
580         PTR_MethodDesc GetInstantiatedMethodDesc()
581         {
582             LIMITED_METHOD_CONTRACT;
583             _ASSERTE(IsInstantiatingStub());
584             return m_data.InstantiatedMethod;
585         }
586
587         //-------------------------------------------------------------------
588         // Unwind information.
589         //-------------------------------------------------------------------
590
591 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
592
593         BOOL HasUnwindInfo()
594         {
595             LIMITED_METHOD_CONTRACT;
596             return (m_numCodeBytesAndFlags & UNWIND_INFO_BIT) != 0;
597         }
598
599         StubUnwindInfoHeaderSuffix *GetUnwindInfoHeaderSuffix()
600         {
601             CONTRACTL
602             {
603                 NOTHROW;
604                 GC_NOTRIGGER;
605                 FORBID_FAULT;
606             }
607             CONTRACTL_END
608
609             _ASSERTE(HasUnwindInfo());
610
611             TADDR info = dac_cast<TADDR>(this);
612
613             return PTR_StubUnwindInfoHeaderSuffix
614                 (info - sizeof(StubUnwindInfoHeaderSuffix));
615         }
616
617         StubUnwindInfoHeader *GetUnwindInfoHeader()
618         {
619             CONTRACTL
620             {
621                 NOTHROW;
622                 GC_NOTRIGGER;
623                 FORBID_FAULT;
624             }
625             CONTRACTL_END
626
627             _ASSERTE(HasUnwindInfo());
628
629             StubUnwindInfoHeaderSuffix *pSuffix = GetUnwindInfoHeaderSuffix();
630
631             TADDR suffixEnd = dac_cast<TADDR>(pSuffix) + sizeof(*pSuffix);
632
633             return PTR_StubUnwindInfoHeader(suffixEnd -
634                                             StubUnwindInfoHeader::ComputeAlignedSize(pSuffix->nUnwindInfoSize));
635         }
636
637 #endif // STUBLINKER_GENERATES_UNWIND_INFO
638
639         //-------------------------------------------------------------------
640         // Returns pointer to the start of the allocation containing this Stub.
641         //-------------------------------------------------------------------
642         TADDR GetAllocationBase();
643
644         //-------------------------------------------------------------------
645         // Return executable entrypoint after checking the ref count.
646         //-------------------------------------------------------------------
647         PCODE GetEntryPoint()
648         {
649             WRAPPER_NO_CONTRACT;
650             SUPPORTS_DAC;
651
652             _ASSERTE(m_signature == kUsedStub);
653             _ASSERTE(m_refcount > 0);
654
655             TADDR pEntryPoint = dac_cast<TADDR>(GetEntryPointInternal());
656
657 #ifdef TARGET_ARM
658
659 #ifndef THUMB_CODE
660 #define THUMB_CODE 1
661 #endif
662
663             pEntryPoint |= THUMB_CODE;
664 #endif
665
666             return pEntryPoint;
667         }
668
669         UINT GetNumCodeBytes()
670         {
671             WRAPPER_NO_CONTRACT;
672             SUPPORTS_DAC;
673
674             return (m_numCodeBytesAndFlags & CODEBYTES_MASK);
675         }
676
677         //-------------------------------------------------------------------
678         // Return start of the stub blob
679         //-------------------------------------------------------------------
680         PTR_CBYTE GetBlob()
681         {
682             WRAPPER_NO_CONTRACT;
683             SUPPORTS_DAC;
684
685             _ASSERTE(m_signature == kUsedStub);
686             _ASSERTE(m_refcount > 0);
687
688             return GetEntryPointInternal();
689         }
690
691         //-------------------------------------------------------------------
692         // Return the Stub as in GetEntryPoint and size of the stub+code in bytes
693         //   WARNING: Depending on the stub kind this may be just Stub size as
694         //            not all stubs have the info about the code size.
695         //            It's the caller responsibility to determine that
696         //-------------------------------------------------------------------
697         static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize)
698         {
699             CONTRACT(Stub*)
700             {
701                 NOTHROW;
702                 GC_NOTRIGGER;
703                 MODE_ANY;
704
705                 PRECONDITION(pEntryPoint && pSize);
706             }
707             CONTRACT_END;
708
709             Stub *pStub = Stub::RecoverStub(pEntryPoint);
710             *pSize = sizeof(Stub) + pStub->GetNumCodeBytes();
711             RETURN pStub;
712         }
713
714         HRESULT CloneStub(BYTE *pBuffer, DWORD dwBufferSize)
715         {
716             LIMITED_METHOD_CONTRACT;
717             if ((pBuffer == NULL) ||
718                 (dwBufferSize < (sizeof(*this) + GetNumCodeBytes())))
719             {
720                 return E_INVALIDARG;
721             }
722
723             memcpyNoGCRefs(pBuffer, this, sizeof(*this) + GetNumCodeBytes());
724             reinterpret_cast<Stub *>(pBuffer)->m_refcount = 1;
725
726             return S_OK;
727         }
728
729         //-------------------------------------------------------------------
730         // Reverse GetEntryPoint.
731         //-------------------------------------------------------------------
732         static Stub* RecoverStub(PCODE pEntryPoint)
733         {
734             STATIC_CONTRACT_NOTHROW;
735             STATIC_CONTRACT_GC_NOTRIGGER;
736
737             TADDR pStubData = PCODEToPINSTR(pEntryPoint);
738
739             Stub *pStub = PTR_Stub(pStubData - sizeof(*pStub));
740
741 #if !defined(DACCESS_COMPILE)
742             _ASSERTE(pStub->m_signature == kUsedStub);
743             _ASSERTE(pStub->GetEntryPoint() == pEntryPoint);
744 #elif defined(_DEBUG)
745             // If this isn't really a stub we don't want
746             // to continue with it.
747             // TODO: This should be removed once IsStub
748             // can adverstise whether it's safe to call
749             // further StubManager methods.
750             if (pStub->m_signature != kUsedStub ||
751                 pStub->GetEntryPoint() != pEntryPoint)
752             {
753                 DacError(E_INVALIDARG);
754             }
755 #endif
756             return pStub;
757         }
758
759         //-------------------------------------------------------------------
760         // Returns TRUE if entry point is not inside the Stub allocation.
761         //-------------------------------------------------------------------
762         BOOL HasExternalEntryPoint() const
763         {
764             LIMITED_METHOD_CONTRACT;
765
766             return (m_numCodeBytesAndFlags & EXTERNAL_ENTRY_BIT) != 0;
767         }
768
769         //-------------------------------------------------------------------
770         // This creates stubs.
771         //-------------------------------------------------------------------
772         static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes,
773                              DWORD flags = NEWSTUB_FL_NONE
774 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
775                              , UINT nUnwindInfoSize = 0
776 #endif
777                              );
778
779         static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE);
780         static Stub* NewStub(PCODE pCode, DWORD flags = NEWSTUB_FL_NONE)
781         {
782             return NewStub((PTR_VOID)pCode, flags);
783         }
784
785         //-------------------------------------------------------------------
786         // One-time init
787         //-------------------------------------------------------------------
788         static void Init();
789
790     protected:
791         // fMC: Set to true if the stub is a multicast delegate, false otherwise
792         void SetupStub(int numCodeBytes, DWORD flags
793 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
794                        , UINT nUnwindInfoSlots
795 #endif
796                        );
797         void DeleteStub();
798
799         //-------------------------------------------------------------------
800         // Return executable entrypoint without checking the ref count.
801         //-------------------------------------------------------------------
802         inline PTR_CBYTE GetEntryPointInternal()
803         {
804             LIMITED_METHOD_CONTRACT;
805             SUPPORTS_DAC;
806
807             _ASSERTE(m_signature == kUsedStub);
808
809
810             if (HasExternalEntryPoint())
811             {
812                 return dac_cast<PTR_BYTE>(*dac_cast<PTR_PCODE>(dac_cast<TADDR>(this) + sizeof(*this)));
813             }
814             else
815             {
816                 // StubLink always puts the entrypoint first.
817                 return dac_cast<PTR_CBYTE>(this) + sizeof(*this);
818             }
819         }
820
821         UINT32 m_refcount;
822         UINT32 m_numCodeBytesAndFlags;
823         union
824         {
825             USHORT          PatchOffset;
826             PTR_MethodDesc  InstantiatedMethod;
827         } m_data;
828
829 #ifdef _DEBUG
830         enum {
831             kUsedStub  = 0x42555453,     // 'STUB'
832             kFreedStub = 0x46555453,     // 'STUF'
833         };
834
835         UINT32  m_signature;
836 #ifdef HOST_64BIT
837         //README ALIGNMENT: Enusure code after the Stub struct align to 16-bytes.
838         UINT32  m_pad_code_bytes1;
839         UINT32  m_pad_code_bytes2;
840         UINT32  m_pad_code_bytes3;
841 #endif // HOST_64BIT
842 #endif // _DEBUG
843
844         Stub() = delete; // Stubs are created by NewStub(), not "new".
845 };
846
847 //-------------------------------------------------------------------------
848 // Each platform encodes the "branch" instruction in a different
849 // way. We use objects derived from InstructionFormat to abstract this
850 // information away. InstructionFormats don't contain any variable data
851 // so they should be allocated statically.
852 //
853 // Note that StubLinker does not create or define any InstructionFormats.
854 // The client does.
855 //
856 // The following example shows how to define a InstructionFormat for the
857 // X86 jump near instruction which takes on two forms:
858 //
859 //   EB xx        jmp  rel8    ;; SHORT JMP (signed 8-bit offset)
860 //   E9 xxxxxxxx  jmp  rel32   ;; NEAR JMP (signed 32-bit offset)
861 //
862 // InstructionFormat's provide StubLinker the following information:
863 //
864 //   RRT.m_allowedSizes
865 //
866 //     What are the possible sizes that the reference can
867 //     take? The X86 jump can take either an 8-bit or 32-bit offset
868 //     so this value is set to (k8|k32). StubLinker will try to
869 //     use the smallest size possible.
870 //
871 //
872 //   RRT.m_fTreatSizesAsSigned
873 //     Sign-extend or zero-extend smallsizes offsets to the platform
874 //     code pointer size? For x86, this field is set to TRUE (rel8
875 //     is considered signed.)
876 //
877 //
878 //   UINT RRT.GetSizeOfInstruction(refsize, variationCode)
879 //     Returns the total size of the instruction in bytes for a given
880 //     refsize. For this example:
881 //
882 //          if (refsize==k8) return 2;
883 //          if (refsize==k32) return 5;
884 //
885 //
886 //   UINT RRT.GetSizeOfData(refsize, variationCode)
887 //     Returns the total size of the separate data area (if any) that the
888 //     instruction needs in bytes for a given refsize. For this example
889 //     on the SH3
890 //          if (refsize==k32) return 4; else return 0;
891 //
892 //   The default implem of this returns 0, so CPUs that don't have need
893 //   for a separate constant area don't have to worry about it.
894 //
895 //
896 //   BOOL CanReach(refsize, variationcode, fExternal, offset)
897 //     Returns whether the instruction with the given variationcode &
898 //     refsize can reach the given offset. In the case of External
899 //     calls, fExternal is set and offset is the target address. In this case an
900 //     implementation should return TRUE only if refsize is big enough to fit a
901 //     full machine-sized pointer to anywhere in the address space.
902 //
903 //
904 //   VOID RRT.EmitInstruction(UINT     refsize,
905 //                            __int64  fixedUpReference,
906 //                            BYTE    *pOutBuffer,
907 //                            UINT     variationCode,
908 //                            BYTE    *pDataBuffer)
909 //
910 //     Given a chosen size (refsize) and the final offset value
911 //     computed by StubLink (fixedUpReference), write out the
912 //     instruction into the provided buffer (guaranteed to be
913 //     big enough provided you told the truth with GetSizeOfInstruction()).
914 //     If needed (e.g. on SH3) a data buffer is also passed in for
915 //     storage of constants.
916 //
917 //     For x86 jmp near:
918 //
919 //          if (refsize==k8) {
920 //              pOutBuffer[0] = 0xeb;
921 //              pOutBuffer[1] = (__int8)fixedUpReference;
922 //          } else if (refsize == k32) {
923 //              pOutBuffer[0] = 0xe9;
924 //              *((__int32*)(1+pOutBuffer)) = (__int32)fixedUpReference;
925 //          } else {
926 //              CRASH("Bad input.");
927 //          }
928 //
929 // VOID RRT.GetHotSpotOffset(UINT refsize, UINT variationCode)
930 //
931 //     The reference offset is always relative to some IP: this
932 //     method tells StubLinker where that IP is relative to the
933 //     start of the instruction. For X86, the offset is always
934 //     relative to the start of the *following* instruction so
935 //     the correct implementation is:
936 //
937 //          return GetSizeOfInstruction(refsize, variationCode);
938 //
939 //     Actually, InstructionFormat() provides a default implementation of this
940 //     method that does exactly this so X86 need not override this at all.
941 //
942 //
943 // The extra "variationCode" argument is an __int32 that StubLinker receives
944 // from EmitLabelRef() and passes uninterpreted to each RRT method.
945 // This allows one RRT to handle a family of related instructions,
946 // for example, the family of conditional jumps on the X86.
947 //
948 //-------------------------------------------------------------------------
949 class InstructionFormat
950 {
951     private:
952         enum
953         {
954         // if you want to add a size, insert it in-order (e.g. a 18-bit size would
955         // go between k16 and k32) and shift all the higher values up. All values
956         // must be a power of 2 since the get ORed together.
957
958             _k8,
959 #ifdef INSTRFMT_K9
960             _k9,
961 #endif
962 #ifdef INSTRFMT_K13
963             _k13,
964 #endif
965             _k16,
966 #ifdef INSTRFMT_K24
967             _k24,
968 #endif
969 #ifdef INSTRFMT_K26
970             _k26,
971 #endif
972             _k32,
973 #ifdef INSTRFMT_K64SMALL
974             _k64Small,
975 #endif
976 #ifdef INSTRFMT_K64
977             _k64,
978 #endif
979             _kAllowAlways,
980         };
981
982     public:
983
984         enum
985         {
986             k8          = (1 << _k8),
987 #ifdef INSTRFMT_K9
988             k9          = (1 << _k9),
989 #endif
990 #ifdef INSTRFMT_K13
991             k13         = (1 << _k13),
992 #endif
993             k16         = (1 << _k16),
994 #ifdef INSTRFMT_K24
995             k24         = (1 << _k24),
996 #endif
997 #ifdef INSTRFMT_K26
998             k26         = (1 << _k26),
999 #endif
1000             k32         = (1 << _k32),
1001 #ifdef INSTRFMT_K64SMALL
1002             k64Small    = (1 << _k64Small),
1003 #endif
1004 #ifdef INSTRFMT_K64
1005             k64         = (1 << _k64),
1006 #endif
1007             kAllowAlways= (1 << _kAllowAlways),
1008             kMax = kAllowAlways,
1009         };
1010
1011         const UINT m_allowedSizes;         // OR mask using above "k" values
1012         InstructionFormat(UINT allowedSizes) : m_allowedSizes(allowedSizes)
1013         {
1014             LIMITED_METHOD_CONTRACT;
1015         }
1016
1017         virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) = 0;
1018         virtual VOID EmitInstruction(UINT refsize, __int64 fixedUpReference, BYTE *pCodeBufferRX, BYTE *pCodeBufferRW, UINT variationCode, BYTE *pDataBuffer) = 0;
1019         virtual UINT GetHotSpotOffset(UINT refsize, UINT variationCode)
1020         {
1021             WRAPPER_NO_CONTRACT;
1022             // Default implementation: the offset is added to the
1023             // start of the following instruction.
1024             return GetSizeOfInstruction(refsize, variationCode);
1025         }
1026
1027         virtual UINT GetSizeOfData(UINT refsize, UINT variationCode)
1028         {
1029             LIMITED_METHOD_CONTRACT;
1030             // Default implementation: 0 extra bytes needed (most CPUs)
1031             return 0;
1032         }
1033
1034         virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset)
1035         {
1036             LIMITED_METHOD_CONTRACT;
1037
1038             if (fExternal) {
1039                 // For external, we don't have enough info to predict
1040                 // the offset yet so we only accept if the offset size
1041                 // is at least as large as the native pointer size.
1042                 switch(refsize) {
1043                     case InstructionFormat::k8: // intentional fallthru
1044                     case InstructionFormat::k16: // intentional fallthru
1045 #ifdef INSTRFMT_K24
1046                     case InstructionFormat::k24: // intentional fallthru
1047 #endif
1048 #ifdef INSTRFMT_K26
1049                     case InstructionFormat::k26: // intentional fallthru
1050 #endif
1051                         return FALSE;           // no 8 or 16-bit platforms
1052
1053                     case InstructionFormat::k32:
1054                         return sizeof(LPVOID) <= 4;
1055 #ifdef INSTRFMT_K64
1056                     case InstructionFormat::k64:
1057                         return sizeof(LPVOID) <= 8;
1058 #endif
1059                     case InstructionFormat::kAllowAlways:
1060                         return TRUE;
1061
1062                     default:
1063                         _ASSERTE(0);
1064                         return FALSE;
1065                 }
1066             } else {
1067                 switch(refsize)
1068                 {
1069                     case InstructionFormat::k8:
1070                         return FitsInI1(offset);
1071
1072                     case InstructionFormat::k16:
1073                         return FitsInI2(offset);
1074
1075 #ifdef INSTRFMT_K24
1076                     case InstructionFormat::k24:
1077                         return FitsInI2(offset>>8);
1078 #endif
1079
1080 #ifdef INSTRFMT_K26
1081                     case InstructionFormat::k26:
1082                         return FitsInI2(offset>>10);
1083 #endif
1084                     case InstructionFormat::k32:
1085                         return FitsInI4(offset);
1086 #ifdef INSTRFMT_K64
1087                     case InstructionFormat::k64:
1088                         // intentional fallthru
1089 #endif
1090                     case InstructionFormat::kAllowAlways:
1091                         return TRUE;
1092                     default:
1093                         _ASSERTE(0);
1094                         return FALSE;
1095
1096                 }
1097             }
1098         }
1099 };
1100
1101
1102
1103
1104
1105 //-------------------------------------------------------------------------
1106 // This stub cache associates stubs with an integer key.  For some clients,
1107 // this might represent the size of the argument stack in some cpu-specific
1108 // units (for the x86, the size is expressed in DWORDS.)  For other clients,
1109 // this might take into account the style of stub (e.g. whether it returns
1110 // an object reference or not).
1111 //-------------------------------------------------------------------------
1112 class ArgBasedStubCache
1113 {
1114     public:
1115        ArgBasedStubCache(UINT fixedSize = NUMFIXEDSLOTS);
1116        ~ArgBasedStubCache();
1117
1118        //-----------------------------------------------------------------
1119        // Retrieves the stub associated with the given key.
1120        //-----------------------------------------------------------------
1121        Stub *GetStub(UINT_PTR key);
1122
1123        //-----------------------------------------------------------------
1124        // Tries to associate the stub with the given key.
1125        // It may fail because another thread might swoop in and
1126        // do the association before you do. Thus, you must use the
1127        // return value stub rather than the pStub.
1128        //-----------------------------------------------------------------
1129        Stub* AttemptToSetStub(UINT_PTR key, Stub *pStub);
1130
1131
1132        // Suggestions for number of slots
1133        enum {
1134  #ifdef _DEBUG
1135              NUMFIXEDSLOTS = 3,
1136  #else
1137              NUMFIXEDSLOTS = 16,
1138  #endif
1139        };
1140
1141 #ifdef _DEBUG
1142        VOID Dump();  //Diagnostic dump
1143 #endif
1144
1145     private:
1146
1147        // How many low-numbered keys have direct access?
1148        UINT      m_numFixedSlots;
1149
1150        // For 'm_numFixedSlots' low-numbered keys, we store them in an array.
1151        Stub    **m_aStub;
1152
1153
1154        struct SlotEntry
1155        {
1156            Stub             *m_pStub;
1157            UINT_PTR         m_key;
1158            SlotEntry        *m_pNext;
1159        };
1160
1161        // High-numbered keys are stored in a sparse linked list.
1162        SlotEntry            *m_pSlotEntries;
1163
1164
1165        Crst                  m_crst;
1166 };
1167
1168
1169 #define CPUSTUBLINKER StubLinkerCPU
1170
1171 class NDirectStubLinker;
1172 class CPUSTUBLINKER;
1173
1174 #endif // __stublink_h__