[RISC-V] Initial patch to fix RISCV64 interpreter (#94548)
[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 #elif defined(TARGET_RISCV64)
233         void DescribeProlog(UINT cIntRegArgs, UINT cVecRegArgs, UINT cbStackFrame);
234         UINT GetSavedRegArgsOffset();
235         UINT GetStackFrameSize();
236 #endif
237
238         //===========================================================================
239         // Unwind information
240
241         // Records location of preserved or parameter register
242         VOID UnwindSavedReg (UCHAR reg, ULONG SPRelativeOffset);
243         VOID UnwindPushedReg (UCHAR reg);
244
245         // Records "sub rsp, xxx"
246         VOID UnwindAllocStack (SHORT FrameSizeIncrement);
247
248         // Records frame pointer register
249         VOID UnwindSetFramePointer (UCHAR reg);
250
251         // In DEBUG, emits a call to m_pUnwindInfoCheckLabel (via
252         // EmitUnwindInfoCheckWorker).  Code at that label will call to a
253         // helper that will attempt to RtlVirtualUnwind through the stub.  The
254         // helper will preserve ALL registers.
255         VOID EmitUnwindInfoCheck();
256
257 #if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
258 protected:
259
260         // Injects a call to the given label.
261         virtual VOID EmitUnwindInfoCheckWorker (CodeLabel *pCheckLabel) { _ASSERTE(!"override me"); }
262
263         // Emits a call to a helper that will attempt to RtlVirtualUnwind
264         // through the stub.  The helper will preserve ALL registers.
265         virtual VOID EmitUnwindInfoCheckSubfunction() { _ASSERTE(!"override me"); }
266 #endif
267
268 public:
269
270         //---------------------------------------------------------------
271         // Generate the actual stub. The returned stub has a refcount of 1.
272         // No other methods (other than the destructor) should be called
273         // after calling Link().
274         //
275         // Throws exception on failure.
276         //---------------------------------------------------------------
277         Stub *Link(LoaderHeap *heap, DWORD flags = 0);
278
279     private:
280         CodeElement   *m_pCodeElements;     // stored in *reverse* order
281         CodeLabel     *m_pFirstCodeLabel;   // linked list of CodeLabels
282         LabelRef      *m_pFirstLabelRef;    // linked list of references
283         CodeLabel     *m_pPatchLabel;       // label of stub patch offset
284                                             // currently just for multicast
285                                             // frames.
286         PTR_MethodDesc m_pTargetMethod;     // Used for instantiating stubs.
287         SHORT         m_stackSize;          // count of pushes/pops
288         CQuickHeap    m_quickHeap;          // throwaway heap for
289                                             //   labels, and
290                                             //   internals.
291         BOOL          m_fDataOnly;          // the stub contains only data - does not need FlushInstructionCache
292
293 #ifdef TARGET_ARM
294 protected:
295         BOOL            m_fProlog;              // True if DescribeProlog has been called
296         UINT            m_cCalleeSavedRegs;     // Count of callee saved registers (0 == none, 1 == r4, 2 ==
297                                                 // r4-r5 etc. up to 8 == r4-r11)
298         UINT            m_cbStackFrame;         // Count of bytes in the stack frame (excl of saved regs)
299         BOOL            m_fPushArgRegs;         // If true, r0-r3 are saved before callee saved regs
300 #endif // TARGET_ARM
301
302 #ifdef TARGET_ARM64
303 protected:
304         BOOL            m_fProlog;              // True if DescribeProlog has been called
305         UINT            m_cIntRegArgs;          // Count of int register arguments (x0 - x7)
306         UINT            m_cVecRegArgs;          // Count of FP register arguments (v0 - v7)
307         UINT            m_cCalleeSavedRegs;     // Count of callee saved registers (x19 - x28)
308         UINT            m_cbStackSpace;         // Additional stack space for return buffer and stack alignment
309 #endif // TARGET_ARM64
310
311 #ifdef TARGET_RISCV64
312 protected:
313         BOOL            m_fProlog;              // True if DescribeProlog has been called
314         UINT            m_cIntRegArgs;          // Count of int register arguments (x10 - x17)
315         UINT            m_cFpRegArgs;           // Count of FP register arguments (f10 - f17)
316         UINT            m_cbStackSpace;         // Additional stack space for return buffer and stack alignment
317 #endif // TARGET_RISCV64
318
319 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
320
321 #ifdef _DEBUG
322         CodeLabel     *m_pUnwindInfoCheckLabel;  // subfunction to call to unwind info check helper.
323                                                  // On AMD64, the prologue is restricted to 256
324                                                  // bytes, so this reduces the size of the injected
325                                                  // code from 14 to 5 bytes.
326 #endif
327
328 #ifdef TARGET_AMD64
329         IntermediateUnwindInfo *m_pUnwindInfoList;
330         UINT          m_nUnwindSlots;       // number of slots to allocate at end, == UNWIND_INFO::CountOfCodes
331         BOOL          m_fHaveFramePointer;  // indicates stack operations no longer need to be recorded
332
333         //
334         // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
335         //
336         UINT UnwindInfoSize(UINT codeSize)
337         {
338             if (m_nUnwindSlots == 0) return 0;
339
340             return sizeof(T_RUNTIME_FUNCTION) + offsetof(UNWIND_INFO, UnwindCode) + m_nUnwindSlots * sizeof(UNWIND_CODE);
341         }
342 #endif // TARGET_AMD64
343
344 #ifdef TARGET_ARM
345 #define MAX_UNWIND_CODE_WORDS 5  /* maximum number of 32-bit words to store unwind codes */
346         // Cache information about the stack frame set up in the prolog and use it in the generation of the
347         // epilog.
348 private:
349         // Reserve fixed size block that's big enough to fit any unwind info we can have
350         static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
351
352         //
353         // Returns total UnwindInfoSize, including RUNTIME_FUNCTION entry
354         //
355         UINT UnwindInfoSize(UINT codeSize)
356         {
357             if (!m_fProlog) return 0;
358
359             return c_nUnwindInfoSize;
360         }
361 #endif // TARGET_ARM
362
363 #ifdef TARGET_ARM64
364 #define MAX_UNWIND_CODE_WORDS 5  /* maximum number of 32-bit words to store unwind codes */
365
366 private:
367         // Reserve fixed size block that's big enough to fit any unwind info we can have
368         static const int c_nUnwindInfoSize = sizeof(T_RUNTIME_FUNCTION) + sizeof(DWORD) + MAX_UNWIND_CODE_WORDS *4;
369         UINT UnwindInfoSize(UINT codeSize)
370         {
371             if (!m_fProlog) return 0;
372
373             return c_nUnwindInfoSize;
374         }
375
376 #endif // TARGET_ARM64
377
378 #endif // STUBLINKER_GENERATES_UNWIND_INFO
379
380         CodeRun *AppendNewEmptyCodeRun();
381
382
383         // Returns pointer to last CodeElement or NULL.
384         CodeElement *GetLastCodeElement()
385         {
386             LIMITED_METHOD_CONTRACT;
387             return m_pCodeElements;
388         }
389
390         // Appends a new CodeElement.
391         VOID AppendCodeElement(CodeElement *pCodeElement);
392
393
394         // Calculates the size of the stub code that is allocate
395         // immediately after the stub object. Returns the
396         // total size. GlobalSize contains the size without
397         // that data part.
398         virtual int CalculateSize(int* globalsize);
399
400         // Writes out the code element into memory following the
401         // stub object.
402         bool EmitStub(Stub* pStub, int globalsize, int totalSize, LoaderHeap* pHeap);
403
404         CodeRun *GetLastCodeRunIfAny();
405
406         bool EmitUnwindInfo(Stub* pStubRX, Stub* pStubRW, int globalsize, LoaderHeap* pHeap);
407
408 #if defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
409         UNWIND_CODE *AllocUnwindInfo (UCHAR Op, UCHAR nExtraSlots = 0);
410 #endif // defined(TARGET_AMD64) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
411 };
412
413 //************************************************************************
414 // CodeLabel
415 //************************************************************************
416 struct CodeLabel
417 {
418     // Link pointer for StubLink's list of labels
419     CodeLabel       *m_next;
420
421     // if FALSE, label refers to some code within the same stub
422     // if TRUE, label refers to some externally supplied address.
423     BOOL             m_fExternal;
424
425     // if TRUE, means we want the actual address of the label and
426     // not an offset to it
427     BOOL             m_fAbsolute;
428
429     union {
430
431         // Internal
432         struct {
433             // Indicates the position of the label, expressed
434             // as an offset into a CodeRun.
435             CodeRun         *m_pCodeRun;
436             UINT             m_localOffset;
437
438         } i;
439
440
441         // External
442         struct {
443             LPVOID           m_pExternalAddress;
444         } e;
445     };
446 };
447
448 enum NewStubFlags
449 {
450     NEWSTUB_FL_NONE                 = 0x00000000,
451     NEWSTUB_FL_INSTANTIATING_METHOD = 0x00000001,
452     NEWSTUB_FL_MULTICAST            = 0x00000002,
453     NEWSTUB_FL_EXTERNAL             = 0x00000004,
454     NEWSTUB_FL_LOADERHEAP           = 0x00000008,
455     NEWSTUB_FL_THUNK                = 0x00000010
456 };
457
458
459 //-------------------------------------------------------------------------
460 // An executable stub. These can only be created by the StubLinker().
461 // Each stub has a reference count (which is maintained in a thread-safe
462 // manner.) When the ref-count goes to zero, the stub automatically
463 // cleans itself up.
464 //-------------------------------------------------------------------------
465 typedef DPTR(class Stub) PTR_Stub;
466 typedef DPTR(PTR_Stub) PTR_PTR_Stub;
467 class Stub
468 {
469     friend class CheckDuplicatedStructLayouts;
470     friend class CheckAsmOffsets;
471
472     protected:
473     enum
474     {
475         MULTICAST_DELEGATE_BIT  = 0x80000000,
476         EXTERNAL_ENTRY_BIT      = 0x40000000,
477         LOADER_HEAP_BIT         = 0x20000000,
478         INSTANTIATING_STUB_BIT  = 0x10000000,
479         UNWIND_INFO_BIT         = 0x08000000,
480         THUNK_BIT               = 0x04000000,
481
482         CODEBYTES_MASK          = THUNK_BIT - 1,
483         MAX_CODEBYTES           = CODEBYTES_MASK + 1,
484     };
485     static_assert_no_msg(CODEBYTES_MASK < THUNK_BIT);
486
487     public:
488         //-------------------------------------------------------------------
489         // Inc the refcount.
490         //-------------------------------------------------------------------
491         VOID IncRef();
492
493         //-------------------------------------------------------------------
494         // Dec the refcount.
495         // Returns true if the count went to zero and the stub was deleted
496         //-------------------------------------------------------------------
497         BOOL DecRef();
498
499         //-------------------------------------------------------------------
500         // Used for throwing out unused stubs from stub caches. This
501         // method cannot be 100% accurate due to race conditions. This
502         // is ok because stub cache management is robust in the face
503         // of missed or premature cleanups.
504         //-------------------------------------------------------------------
505         BOOL HeuristicLooksOrphaned()
506         {
507             LIMITED_METHOD_CONTRACT;
508             _ASSERTE(m_signature == kUsedStub);
509             return (m_refcount == 1);
510         }
511
512         //-------------------------------------------------------------------
513         // Used by the debugger to help step through stubs
514         //-------------------------------------------------------------------
515         BOOL IsMulticastDelegate()
516         {
517             LIMITED_METHOD_CONTRACT;
518             return (m_numCodeBytesAndFlags & MULTICAST_DELEGATE_BIT) != 0;
519         }
520
521         //-------------------------------------------------------------------
522         // Used by the debugger to help step through stubs
523         //-------------------------------------------------------------------
524         BOOL IsInstantiatingStub()
525         {
526             LIMITED_METHOD_CONTRACT;
527             return (m_numCodeBytesAndFlags & INSTANTIATING_STUB_BIT) != 0;
528         }
529
530         //-------------------------------------------------------------------
531         // Used by the debugger to help step through stubs
532         //-------------------------------------------------------------------
533         BOOL IsManagedThunk()
534         {
535             LIMITED_METHOD_CONTRACT;
536             return (m_numCodeBytesAndFlags & THUNK_BIT) != 0;
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         void SetPatchOffset(USHORT offset)
545         {
546             LIMITED_METHOD_CONTRACT;
547             _ASSERTE(!IsInstantiatingStub());
548             m_data.PatchOffset = offset;
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         USHORT GetPatchOffset()
557         {
558             LIMITED_METHOD_CONTRACT;
559             _ASSERTE(!IsInstantiatingStub());
560             return m_data.PatchOffset;
561         }
562
563         //-------------------------------------------------------------------
564         // For stubs which execute user code, a patch offset needs to be set
565         // to tell the debugger how far into the stub code the debugger has
566         // to step until the frame is set up.
567         //-------------------------------------------------------------------
568         TADDR GetPatchAddress()
569         {
570             LIMITED_METHOD_CONTRACT;
571             _ASSERTE(!IsInstantiatingStub());
572             return dac_cast<TADDR>(GetEntryPointInternal()) + GetPatchOffset();
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         void SetInstantiatedMethodDesc(PTR_MethodDesc pMD)
581         {
582             LIMITED_METHOD_CONTRACT;
583             _ASSERTE(IsInstantiatingStub());
584             m_data.InstantiatedMethod = pMD;
585         }
586
587         //-------------------------------------------------------------------
588         // For instantiating methods, the target MethodDesc needs to be set
589         // to tell the debugger where to step through the instantiating method
590         // stub.
591         //-------------------------------------------------------------------
592         PTR_MethodDesc GetInstantiatedMethodDesc()
593         {
594             LIMITED_METHOD_CONTRACT;
595             _ASSERTE(IsInstantiatingStub());
596             return m_data.InstantiatedMethod;
597         }
598
599         //-------------------------------------------------------------------
600         // Unwind information.
601         //-------------------------------------------------------------------
602
603 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
604
605         BOOL HasUnwindInfo()
606         {
607             LIMITED_METHOD_CONTRACT;
608             return (m_numCodeBytesAndFlags & UNWIND_INFO_BIT) != 0;
609         }
610
611         StubUnwindInfoHeaderSuffix *GetUnwindInfoHeaderSuffix()
612         {
613             CONTRACTL
614             {
615                 NOTHROW;
616                 GC_NOTRIGGER;
617                 FORBID_FAULT;
618             }
619             CONTRACTL_END
620
621             _ASSERTE(HasUnwindInfo());
622
623             TADDR info = dac_cast<TADDR>(this);
624
625             return PTR_StubUnwindInfoHeaderSuffix
626                 (info - sizeof(StubUnwindInfoHeaderSuffix));
627         }
628
629         StubUnwindInfoHeader *GetUnwindInfoHeader()
630         {
631             CONTRACTL
632             {
633                 NOTHROW;
634                 GC_NOTRIGGER;
635                 FORBID_FAULT;
636             }
637             CONTRACTL_END
638
639             _ASSERTE(HasUnwindInfo());
640
641             StubUnwindInfoHeaderSuffix *pSuffix = GetUnwindInfoHeaderSuffix();
642
643             TADDR suffixEnd = dac_cast<TADDR>(pSuffix) + sizeof(*pSuffix);
644
645             return PTR_StubUnwindInfoHeader(suffixEnd -
646                                             StubUnwindInfoHeader::ComputeAlignedSize(pSuffix->nUnwindInfoSize));
647         }
648
649 #endif // STUBLINKER_GENERATES_UNWIND_INFO
650
651         //-------------------------------------------------------------------
652         // Returns pointer to the start of the allocation containing this Stub.
653         //-------------------------------------------------------------------
654         TADDR GetAllocationBase();
655
656         //-------------------------------------------------------------------
657         // Return executable entrypoint after checking the ref count.
658         //-------------------------------------------------------------------
659         PCODE GetEntryPoint()
660         {
661             WRAPPER_NO_CONTRACT;
662             SUPPORTS_DAC;
663
664             _ASSERTE(m_signature == kUsedStub);
665             _ASSERTE(m_refcount > 0);
666
667             TADDR pEntryPoint = dac_cast<TADDR>(GetEntryPointInternal());
668
669 #ifdef TARGET_ARM
670
671 #ifndef THUMB_CODE
672 #define THUMB_CODE 1
673 #endif
674
675             pEntryPoint |= THUMB_CODE;
676 #endif
677
678             return pEntryPoint;
679         }
680
681         UINT GetNumCodeBytes()
682         {
683             WRAPPER_NO_CONTRACT;
684             SUPPORTS_DAC;
685
686             return (m_numCodeBytesAndFlags & CODEBYTES_MASK);
687         }
688
689         //-------------------------------------------------------------------
690         // Return start of the stub blob
691         //-------------------------------------------------------------------
692         PTR_CBYTE GetBlob()
693         {
694             WRAPPER_NO_CONTRACT;
695             SUPPORTS_DAC;
696
697             _ASSERTE(m_signature == kUsedStub);
698             _ASSERTE(m_refcount > 0);
699
700             return GetEntryPointInternal();
701         }
702
703         //-------------------------------------------------------------------
704         // Return the Stub as in GetEntryPoint and size of the stub+code in bytes
705         //   WARNING: Depending on the stub kind this may be just Stub size as
706         //            not all stubs have the info about the code size.
707         //            It's the caller responsibility to determine that
708         //-------------------------------------------------------------------
709         static Stub* RecoverStubAndSize(PCODE pEntryPoint, DWORD *pSize)
710         {
711             CONTRACT(Stub*)
712             {
713                 NOTHROW;
714                 GC_NOTRIGGER;
715                 MODE_ANY;
716
717                 PRECONDITION(pEntryPoint && pSize);
718             }
719             CONTRACT_END;
720
721             Stub *pStub = Stub::RecoverStub(pEntryPoint);
722             *pSize = sizeof(Stub) + pStub->GetNumCodeBytes();
723             RETURN pStub;
724         }
725
726         HRESULT CloneStub(BYTE *pBuffer, DWORD dwBufferSize)
727         {
728             LIMITED_METHOD_CONTRACT;
729             if ((pBuffer == NULL) ||
730                 (dwBufferSize < (sizeof(*this) + GetNumCodeBytes())))
731             {
732                 return E_INVALIDARG;
733             }
734
735             memcpyNoGCRefs(pBuffer, this, sizeof(*this) + GetNumCodeBytes());
736             reinterpret_cast<Stub *>(pBuffer)->m_refcount = 1;
737
738             return S_OK;
739         }
740
741         //-------------------------------------------------------------------
742         // Reverse GetEntryPoint.
743         //-------------------------------------------------------------------
744         static Stub* RecoverStub(PCODE pEntryPoint)
745         {
746             STATIC_CONTRACT_NOTHROW;
747             STATIC_CONTRACT_GC_NOTRIGGER;
748
749             TADDR pStubData = PCODEToPINSTR(pEntryPoint);
750
751             Stub *pStub = PTR_Stub(pStubData - sizeof(*pStub));
752
753 #if !defined(DACCESS_COMPILE)
754             _ASSERTE(pStub->m_signature == kUsedStub);
755             _ASSERTE(pStub->GetEntryPoint() == pEntryPoint);
756 #elif defined(_DEBUG)
757             // If this isn't really a stub we don't want
758             // to continue with it.
759             // TODO: This should be removed once IsStub
760             // can adverstise whether it's safe to call
761             // further StubManager methods.
762             if (pStub->m_signature != kUsedStub ||
763                 pStub->GetEntryPoint() != pEntryPoint)
764             {
765                 DacError(E_INVALIDARG);
766             }
767 #endif
768             return pStub;
769         }
770
771         //-------------------------------------------------------------------
772         // Returns TRUE if entry point is not inside the Stub allocation.
773         //-------------------------------------------------------------------
774         BOOL HasExternalEntryPoint() const
775         {
776             LIMITED_METHOD_CONTRACT;
777
778             return (m_numCodeBytesAndFlags & EXTERNAL_ENTRY_BIT) != 0;
779         }
780
781         //-------------------------------------------------------------------
782         // This creates stubs.
783         //-------------------------------------------------------------------
784         static Stub* NewStub(LoaderHeap *pLoaderHeap, UINT numCodeBytes,
785                              DWORD flags = NEWSTUB_FL_NONE
786 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
787                              , UINT nUnwindInfoSize = 0
788 #endif
789                              );
790
791         static Stub* NewStub(PTR_VOID pCode, DWORD flags = NEWSTUB_FL_NONE);
792         static Stub* NewStub(PCODE pCode, DWORD flags = NEWSTUB_FL_NONE)
793         {
794             return NewStub((PTR_VOID)pCode, flags);
795         }
796
797         //-------------------------------------------------------------------
798         // One-time init
799         //-------------------------------------------------------------------
800         static void Init();
801
802     protected:
803         // fMC: Set to true if the stub is a multicast delegate, false otherwise
804         void SetupStub(int numCodeBytes, DWORD flags
805 #ifdef STUBLINKER_GENERATES_UNWIND_INFO
806                        , UINT nUnwindInfoSlots
807 #endif
808                        );
809         void DeleteStub();
810
811         //-------------------------------------------------------------------
812         // Return executable entrypoint without checking the ref count.
813         //-------------------------------------------------------------------
814         inline PTR_CBYTE GetEntryPointInternal()
815         {
816             LIMITED_METHOD_CONTRACT;
817             SUPPORTS_DAC;
818
819             _ASSERTE(m_signature == kUsedStub);
820
821
822             if (HasExternalEntryPoint())
823             {
824                 return dac_cast<PTR_BYTE>(*dac_cast<PTR_PCODE>(dac_cast<TADDR>(this) + sizeof(*this)));
825             }
826             else
827             {
828                 // StubLink always puts the entrypoint first.
829                 return dac_cast<PTR_CBYTE>(this) + sizeof(*this);
830             }
831         }
832
833         UINT32 m_refcount;
834         UINT32 m_numCodeBytesAndFlags;
835         union
836         {
837             USHORT          PatchOffset;
838             PTR_MethodDesc  InstantiatedMethod;
839         } m_data;
840
841 #ifdef _DEBUG
842         enum {
843             kUsedStub  = 0x42555453,     // 'STUB'
844             kFreedStub = 0x46555453,     // 'STUF'
845         };
846
847         UINT32  m_signature;
848 #ifdef HOST_64BIT
849         //README ALIGNMENT: Enusure code after the Stub struct align to 16-bytes.
850         UINT32  m_pad_code_bytes1;
851         UINT32  m_pad_code_bytes2;
852         UINT32  m_pad_code_bytes3;
853 #endif // HOST_64BIT
854 #endif // _DEBUG
855
856         Stub() = delete; // Stubs are created by NewStub(), not "new".
857 };
858
859 //-------------------------------------------------------------------------
860 // Each platform encodes the "branch" instruction in a different
861 // way. We use objects derived from InstructionFormat to abstract this
862 // information away. InstructionFormats don't contain any variable data
863 // so they should be allocated statically.
864 //
865 // Note that StubLinker does not create or define any InstructionFormats.
866 // The client does.
867 //
868 // The following example shows how to define a InstructionFormat for the
869 // X86 jump near instruction which takes on two forms:
870 //
871 //   EB xx        jmp  rel8    ;; SHORT JMP (signed 8-bit offset)
872 //   E9 xxxxxxxx  jmp  rel32   ;; NEAR JMP (signed 32-bit offset)
873 //
874 // InstructionFormat's provide StubLinker the following information:
875 //
876 //   RRT.m_allowedSizes
877 //
878 //     What are the possible sizes that the reference can
879 //     take? The X86 jump can take either an 8-bit or 32-bit offset
880 //     so this value is set to (k8|k32). StubLinker will try to
881 //     use the smallest size possible.
882 //
883 //
884 //   RRT.m_fTreatSizesAsSigned
885 //     Sign-extend or zero-extend smallsizes offsets to the platform
886 //     code pointer size? For x86, this field is set to TRUE (rel8
887 //     is considered signed.)
888 //
889 //
890 //   UINT RRT.GetSizeOfInstruction(refsize, variationCode)
891 //     Returns the total size of the instruction in bytes for a given
892 //     refsize. For this example:
893 //
894 //          if (refsize==k8) return 2;
895 //          if (refsize==k32) return 5;
896 //
897 //
898 //   UINT RRT.GetSizeOfData(refsize, variationCode)
899 //     Returns the total size of the separate data area (if any) that the
900 //     instruction needs in bytes for a given refsize. For this example
901 //     on the SH3
902 //          if (refsize==k32) return 4; else return 0;
903 //
904 //   The default implem of this returns 0, so CPUs that don't have need
905 //   for a separate constant area don't have to worry about it.
906 //
907 //
908 //   BOOL CanReach(refsize, variationcode, fExternal, offset)
909 //     Returns whether the instruction with the given variationcode &
910 //     refsize can reach the given offset. In the case of External
911 //     calls, fExternal is set and offset is the target address. In this case an
912 //     implementation should return TRUE only if refsize is big enough to fit a
913 //     full machine-sized pointer to anywhere in the address space.
914 //
915 //
916 //   VOID RRT.EmitInstruction(UINT     refsize,
917 //                            __int64  fixedUpReference,
918 //                            BYTE    *pOutBuffer,
919 //                            UINT     variationCode,
920 //                            BYTE    *pDataBuffer)
921 //
922 //     Given a chosen size (refsize) and the final offset value
923 //     computed by StubLink (fixedUpReference), write out the
924 //     instruction into the provided buffer (guaranteed to be
925 //     big enough provided you told the truth with GetSizeOfInstruction()).
926 //     If needed (e.g. on SH3) a data buffer is also passed in for
927 //     storage of constants.
928 //
929 //     For x86 jmp near:
930 //
931 //          if (refsize==k8) {
932 //              pOutBuffer[0] = 0xeb;
933 //              pOutBuffer[1] = (__int8)fixedUpReference;
934 //          } else if (refsize == k32) {
935 //              pOutBuffer[0] = 0xe9;
936 //              *((__int32*)(1+pOutBuffer)) = (__int32)fixedUpReference;
937 //          } else {
938 //              CRASH("Bad input.");
939 //          }
940 //
941 // VOID RRT.GetHotSpotOffset(UINT refsize, UINT variationCode)
942 //
943 //     The reference offset is always relative to some IP: this
944 //     method tells StubLinker where that IP is relative to the
945 //     start of the instruction. For X86, the offset is always
946 //     relative to the start of the *following* instruction so
947 //     the correct implementation is:
948 //
949 //          return GetSizeOfInstruction(refsize, variationCode);
950 //
951 //     Actually, InstructionFormat() provides a default implementation of this
952 //     method that does exactly this so X86 need not override this at all.
953 //
954 //
955 // The extra "variationCode" argument is an __int32 that StubLinker receives
956 // from EmitLabelRef() and passes uninterpreted to each RRT method.
957 // This allows one RRT to handle a family of related instructions,
958 // for example, the family of conditional jumps on the X86.
959 //
960 //-------------------------------------------------------------------------
961 class InstructionFormat
962 {
963     private:
964         enum
965         {
966         // if you want to add a size, insert it in-order (e.g. a 18-bit size would
967         // go between k16 and k32) and shift all the higher values up. All values
968         // must be a power of 2 since the get ORed together.
969
970             _k8,
971 #ifdef INSTRFMT_K9
972             _k9,
973 #endif
974 #ifdef INSTRFMT_K13
975             _k13,
976 #endif
977             _k16,
978 #ifdef INSTRFMT_K24
979             _k24,
980 #endif
981 #ifdef INSTRFMT_K26
982             _k26,
983 #endif
984             _k32,
985 #ifdef INSTRFMT_K64SMALL
986             _k64Small,
987 #endif
988 #ifdef INSTRFMT_K64
989             _k64,
990 #endif
991             _kAllowAlways,
992         };
993
994     public:
995
996         enum
997         {
998             k8          = (1 << _k8),
999 #ifdef INSTRFMT_K9
1000             k9          = (1 << _k9),
1001 #endif
1002 #ifdef INSTRFMT_K13
1003             k13         = (1 << _k13),
1004 #endif
1005             k16         = (1 << _k16),
1006 #ifdef INSTRFMT_K24
1007             k24         = (1 << _k24),
1008 #endif
1009 #ifdef INSTRFMT_K26
1010             k26         = (1 << _k26),
1011 #endif
1012             k32         = (1 << _k32),
1013 #ifdef INSTRFMT_K64SMALL
1014             k64Small    = (1 << _k64Small),
1015 #endif
1016 #ifdef INSTRFMT_K64
1017             k64         = (1 << _k64),
1018 #endif
1019             kAllowAlways= (1 << _kAllowAlways),
1020             kMax = kAllowAlways,
1021         };
1022
1023         const UINT m_allowedSizes;         // OR mask using above "k" values
1024         InstructionFormat(UINT allowedSizes) : m_allowedSizes(allowedSizes)
1025         {
1026             LIMITED_METHOD_CONTRACT;
1027         }
1028
1029         virtual UINT GetSizeOfInstruction(UINT refsize, UINT variationCode) = 0;
1030         virtual VOID EmitInstruction(UINT refsize, __int64 fixedUpReference, BYTE *pCodeBufferRX, BYTE *pCodeBufferRW, UINT variationCode, BYTE *pDataBuffer) = 0;
1031         virtual UINT GetHotSpotOffset(UINT refsize, UINT variationCode)
1032         {
1033             WRAPPER_NO_CONTRACT;
1034             // Default implementation: the offset is added to the
1035             // start of the following instruction.
1036             return GetSizeOfInstruction(refsize, variationCode);
1037         }
1038
1039         virtual UINT GetSizeOfData(UINT refsize, UINT variationCode)
1040         {
1041             LIMITED_METHOD_CONTRACT;
1042             // Default implementation: 0 extra bytes needed (most CPUs)
1043             return 0;
1044         }
1045
1046         virtual BOOL CanReach(UINT refsize, UINT variationCode, BOOL fExternal, INT_PTR offset)
1047         {
1048             LIMITED_METHOD_CONTRACT;
1049
1050             if (fExternal) {
1051                 // For external, we don't have enough info to predict
1052                 // the offset yet so we only accept if the offset size
1053                 // is at least as large as the native pointer size.
1054                 switch(refsize) {
1055                     case InstructionFormat::k8: // intentional fallthru
1056                     case InstructionFormat::k16: // intentional fallthru
1057 #ifdef INSTRFMT_K24
1058                     case InstructionFormat::k24: // intentional fallthru
1059 #endif
1060 #ifdef INSTRFMT_K26
1061                     case InstructionFormat::k26: // intentional fallthru
1062 #endif
1063                         return FALSE;           // no 8 or 16-bit platforms
1064
1065                     case InstructionFormat::k32:
1066                         return sizeof(LPVOID) <= 4;
1067 #ifdef INSTRFMT_K64
1068                     case InstructionFormat::k64:
1069                         return sizeof(LPVOID) <= 8;
1070 #endif
1071                     case InstructionFormat::kAllowAlways:
1072                         return TRUE;
1073
1074                     default:
1075                         _ASSERTE(0);
1076                         return FALSE;
1077                 }
1078             } else {
1079                 switch(refsize)
1080                 {
1081                     case InstructionFormat::k8:
1082                         return FitsInI1(offset);
1083
1084                     case InstructionFormat::k16:
1085                         return FitsInI2(offset);
1086
1087 #ifdef INSTRFMT_K24
1088                     case InstructionFormat::k24:
1089                         return FitsInI2(offset>>8);
1090 #endif
1091
1092 #ifdef INSTRFMT_K26
1093                     case InstructionFormat::k26:
1094                         return FitsInI2(offset>>10);
1095 #endif
1096                     case InstructionFormat::k32:
1097                         return FitsInI4(offset);
1098 #ifdef INSTRFMT_K64
1099                     case InstructionFormat::k64:
1100                         // intentional fallthru
1101 #endif
1102                     case InstructionFormat::kAllowAlways:
1103                         return TRUE;
1104                     default:
1105                         _ASSERTE(0);
1106                         return FALSE;
1107
1108                 }
1109             }
1110         }
1111 };
1112
1113
1114
1115
1116
1117 //-------------------------------------------------------------------------
1118 // This stub cache associates stubs with an integer key.  For some clients,
1119 // this might represent the size of the argument stack in some cpu-specific
1120 // units (for the x86, the size is expressed in DWORDS.)  For other clients,
1121 // this might take into account the style of stub (e.g. whether it returns
1122 // an object reference or not).
1123 //-------------------------------------------------------------------------
1124 class ArgBasedStubCache
1125 {
1126     public:
1127        ArgBasedStubCache(UINT fixedSize = NUMFIXEDSLOTS);
1128        ~ArgBasedStubCache();
1129
1130        //-----------------------------------------------------------------
1131        // Retrieves the stub associated with the given key.
1132        //-----------------------------------------------------------------
1133        Stub *GetStub(UINT_PTR key);
1134
1135        //-----------------------------------------------------------------
1136        // Tries to associate the stub with the given key.
1137        // It may fail because another thread might swoop in and
1138        // do the association before you do. Thus, you must use the
1139        // return value stub rather than the pStub.
1140        //-----------------------------------------------------------------
1141        Stub* AttemptToSetStub(UINT_PTR key, Stub *pStub);
1142
1143
1144        // Suggestions for number of slots
1145        enum {
1146  #ifdef _DEBUG
1147              NUMFIXEDSLOTS = 3,
1148  #else
1149              NUMFIXEDSLOTS = 16,
1150  #endif
1151        };
1152
1153 #ifdef _DEBUG
1154        VOID Dump();  //Diagnostic dump
1155 #endif
1156
1157     private:
1158
1159        // How many low-numbered keys have direct access?
1160        UINT      m_numFixedSlots;
1161
1162        // For 'm_numFixedSlots' low-numbered keys, we store them in an array.
1163        Stub    **m_aStub;
1164
1165
1166        struct SlotEntry
1167        {
1168            Stub             *m_pStub;
1169            UINT_PTR         m_key;
1170            SlotEntry        *m_pNext;
1171        };
1172
1173        // High-numbered keys are stored in a sparse linked list.
1174        SlotEntry            *m_pSlotEntries;
1175
1176
1177        Crst                  m_crst;
1178 };
1179
1180
1181 #define CPUSTUBLINKER StubLinkerCPU
1182
1183 class NDirectStubLinker;
1184 class CPUSTUBLINKER;
1185
1186 #endif // __stublink_h__