1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
18 const static size_t MAX_LOCALDESC_ELEMENTS = 8;
20 BYTE ElementType[MAX_LOCALDESC_ELEMENTS];
22 TypeHandle InternalToken; // only valid with ELEMENT_TYPE_INTERNAL
24 // used only for E_T_FNPTR and E_T_ARRAY
29 size_t cbArrayBoundsInfo;
30 BOOL bIsCopyConstructed; // used for E_T_PTR
37 inline LocalDesc(CorElementType elemType)
39 ElementType[0] = static_cast<BYTE>(elemType);
41 bIsCopyConstructed = FALSE;
44 inline LocalDesc(TypeHandle thType)
46 ElementType[0] = ELEMENT_TYPE_INTERNAL;
48 InternalToken = thType;
49 bIsCopyConstructed = FALSE;
52 inline LocalDesc(MethodTable *pMT)
55 ElementType[0] = ELEMENT_TYPE_INTERNAL;
57 InternalToken = TypeHandle(pMT);
58 bIsCopyConstructed = FALSE;
63 LIMITED_METHOD_CONTRACT;
64 ChangeType(ELEMENT_TYPE_BYREF);
69 LIMITED_METHOD_CONTRACT;
70 ChangeType(ELEMENT_TYPE_PINNED);
75 LIMITED_METHOD_CONTRACT;
76 ChangeType(ELEMENT_TYPE_SZARRAY);
79 // makes the LocalDesc semantically equivalent to ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
80 void MakeCopyConstructedPointer()
82 LIMITED_METHOD_CONTRACT;
83 ChangeType(ELEMENT_TYPE_PTR);
84 bIsCopyConstructed = TRUE;
87 void ChangeType(CorElementType elemType)
89 LIMITED_METHOD_CONTRACT;
90 PREFIX_ASSUME((MAX_LOCALDESC_ELEMENTS-1) >= cbType);
92 for (size_t i = cbType; i >= 1; i--)
94 ElementType[i] = ElementType[i-1];
97 ElementType[0] = static_cast<BYTE>(elemType);
111 bool lastElementTypeIsValueType = false;
113 if (ElementType[cbType - 1] == ELEMENT_TYPE_VALUETYPE)
115 lastElementTypeIsValueType = true;
117 else if ((ElementType[cbType - 1] == ELEMENT_TYPE_INTERNAL) &&
118 (InternalToken.IsNativeValueType() ||
119 InternalToken.GetMethodTable()->IsValueType()))
121 lastElementTypeIsValueType = true;
124 if (!lastElementTypeIsValueType)
129 // verify that the prefix element types don't make the type a non-value type
130 // this only works on LocalDescs with the prefixes exposed in the Add* methods above.
131 for (size_t i = 0; i < cbType - 1; i++)
133 if (ElementType[i] == ELEMENT_TYPE_BYREF
134 || ElementType[i] == ELEMENT_TYPE_SZARRAY
135 || ElementType[i] == ELEMENT_TYPE_PTR)
150 DWORD Append(LocalDesc* pLoc);
153 CQuickBytes m_qbSigBuffer;
158 enum Constants { INITIAL_BUFFER_SIZE = 256 };
160 void EnsureEnoughQuickBytes(size_t cbToAppend);
163 //---------------------------------------------------------------------------------------
165 class LocalSigBuilder : protected StubSigBuilder
168 DWORD NewLocal(LocalDesc * pLoc)
175 PRECONDITION(CheckPointer(pLoc));
183 DWORD GetSig(BYTE * pbSig, DWORD cbBuffer);
185 }; // class LocalSigBuilder
187 //---------------------------------------------------------------------------------------
189 class FunctionSigBuilder : protected StubSigBuilder
192 FunctionSigBuilder();
194 DWORD NewArg(LocalDesc * pArg)
203 LIMITED_METHOD_CONTRACT;
207 void SetCallingConv(CorCallingConvention callingConv)
209 LIMITED_METHOD_CONTRACT;
210 m_callingConv = callingConv;
213 CorCallingConvention GetCallingConv()
215 LIMITED_METHOD_CONTRACT;
216 return m_callingConv;
219 void SetSig(PCCOR_SIGNATURE pSig, DWORD cSig);
222 DWORD GetSig(BYTE * pbSig, DWORD cbBuffer);
224 void SetReturnType(LocalDesc* pLoc);
226 CorElementType GetReturnElementType()
228 LIMITED_METHOD_CONTRACT;
230 CONSISTENCY_CHECK(m_qbReturnSig.Size() > 0);
231 return *(CorElementType *)m_qbReturnSig.Ptr();
234 PCCOR_SIGNATURE GetReturnSig()
236 LIMITED_METHOD_CONTRACT;
238 CONSISTENCY_CHECK(m_qbReturnSig.Size() > 0);
239 return (PCCOR_SIGNATURE)m_qbReturnSig.Ptr();
243 CorCallingConvention m_callingConv;
244 CQuickBytes m_qbReturnSig;
245 }; // class FunctionSigBuilder
248 // exercise the resize code
249 #define TOKEN_LOOKUP_MAP_SIZE (8*sizeof(void*))
251 #define TOKEN_LOOKUP_MAP_SIZE (64*sizeof(void*))
254 //---------------------------------------------------------------------------------------
261 STANDARD_VM_CONTRACT;
263 m_qbEntries.AllocThrows(TOKEN_LOOKUP_MAP_SIZE);
264 m_nextAvailableRid = 0;
268 TokenLookupMap(TokenLookupMap* pSrc)
270 STANDARD_VM_CONTRACT;
272 m_nextAvailableRid = pSrc->m_nextAvailableRid;
273 size_t size = pSrc->m_qbEntries.Size();
274 m_qbEntries.AllocThrows(size);
275 memcpy(m_qbEntries.Ptr(), pSrc->m_qbEntries.Ptr(), size);
278 TypeHandle LookupTypeDef(mdToken token)
281 return LookupTokenWorker<mdtTypeDef, MethodTable*>(token);
283 MethodDesc* LookupMethodDef(mdToken token)
286 return LookupTokenWorker<mdtMethodDef, MethodDesc*>(token);
288 FieldDesc* LookupFieldDef(mdToken token)
291 return LookupTokenWorker<mdtFieldDef, FieldDesc*>(token);
294 mdToken GetToken(TypeHandle pMT)
297 return GetTokenWorker<mdtTypeDef, TypeHandle>(pMT);
299 mdToken GetToken(MethodDesc* pMD)
302 return GetTokenWorker<mdtMethodDef, MethodDesc*>(pMD);
304 mdToken GetToken(FieldDesc* pFieldDesc)
307 return GetTokenWorker<mdtFieldDef, FieldDesc*>(pFieldDesc);
311 template<mdToken TokenType, typename HandleType>
312 HandleType LookupTokenWorker(mdToken token)
319 PRECONDITION(RidFromToken(token)-1 < m_nextAvailableRid);
320 PRECONDITION(RidFromToken(token) != 0);
321 PRECONDITION(TypeFromToken(token) == TokenType);
325 return ((HandleType*)m_qbEntries.Ptr())[RidFromToken(token)-1];
328 template<mdToken TokenType, typename HandleType>
329 mdToken GetTokenWorker(HandleType handle)
336 PRECONDITION(handle != NULL);
340 if (m_qbEntries.Size() <= (sizeof(handle) * m_nextAvailableRid))
342 m_qbEntries.ReSizeThrows(2 * m_qbEntries.Size());
345 mdToken token = TokenFromRid(m_nextAvailableRid++, TokenType)+1;
347 ((HandleType*)m_qbEntries.Ptr())[RidFromToken(token)-1] = handle;
352 unsigned int m_nextAvailableRid;
353 CQuickBytesSpecifySize<TOKEN_LOOKUP_MAP_SIZE> m_qbEntries;
356 struct ILStubEHClause
358 enum Kind { kNone, kTypedCatch, kFinally };
361 DWORD dwTryBeginOffset;
363 DWORD dwHandlerBeginOffset;
364 DWORD cbHandlerLength;
371 //---------------------------------------------------------------------------------------
375 friend class ILCodeLabel;
376 friend class ILCodeStream;
380 ILStubLinker(Module* pModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD,
381 BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub = FALSE, BOOL fIsReverseStub = FALSE);
384 void GenerateCode(BYTE* pbBuffer, size_t cbBufferSize);
389 void DeleteCodeLabels();
390 void DeleteCodeStreams();
399 static void PatchInstructionArgument(ILCodeLabel* pLabel, UINT_PTR uNewArg
400 DEBUG_ARG(UINT16 uExpectedInstruction));
403 bool IsInCodeStreamList(ILCodeStream* pcs);
408 void SetHasThis (bool fHasThis);
409 bool HasThis () { LIMITED_METHOD_CONTRACT; return m_fHasThis; }
411 DWORD GetLocalSigSize();
412 DWORD GetLocalSig(BYTE * pbLocalSig, DWORD cbBuffer);
414 DWORD GetStubTargetMethodSigSize();
415 DWORD GetStubTargetMethodSig(BYTE * pbLocalSig, DWORD cbBuffer);
417 void SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig);
419 void GetStubTargetReturnType(LocalDesc * pLoc);
420 void GetStubTargetReturnType(LocalDesc * pLoc, Module * pModule);
422 void GetStubArgType(LocalDesc * pLoc);
423 void GetStubArgType(LocalDesc * pLoc, Module * pModule);
424 void GetStubReturnType(LocalDesc * pLoc);
425 void GetStubReturnType(LocalDesc * pLoc, Module * pModule);
426 CorCallingConvention GetStubTargetCallingConv();
428 CorElementType GetStubTargetReturnElementType() { WRAPPER_NO_CONTRACT; return m_nativeFnSigBuilder.GetReturnElementType(); }
430 static void GetManagedTypeHelper(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE pSig, SigTypeContext *pTypeContext, MethodDesc *pMD);
432 BOOL StubHasVoidReturnType();
434 Stub *Link(LoaderHeap *pHeap, UINT *pcbSize /* = NULL*/, BOOL fMC);
436 size_t Link(UINT* puMaxStack);
439 TokenLookupMap* GetTokenLookupMap() { LIMITED_METHOD_CONTRACT; return &m_tokenMap; }
453 ILCodeStream* NewCodeStream(CodeStreamType codeStreamType);
455 MethodDesc *GetTargetMD() { LIMITED_METHOD_CONTRACT; return m_pMD; }
456 Signature GetStubSignature() { LIMITED_METHOD_CONTRACT; return m_stubSig; }
458 void ClearCodeStreams();
460 void LogILStub(CORJIT_FLAGS jitFlags, SString *pDumpILStubCode = NULL);
462 void LogILStubWorker(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, SString *pDumpILStubCode = NULL);
463 void LogILInstruction(size_t curOffset, bool isLabeled, INT iCurStack, ILInstruction* pInstruction, SString *pDumpILStubCode = NULL);
466 ILCodeStream* m_pCodeStreamList;
468 TokenLookupMap m_tokenMap;
469 LocalSigBuilder m_localSigBuilder;
470 FunctionSigBuilder m_nativeFnSigBuilder;
471 BYTE m_rgbBuffer[sizeof(COR_ILMETHOD_DECODER)];
473 Signature m_stubSig; // managed sig of stub
474 SigTypeContext* m_pTypeContext; // type context for m_stubSig
476 SigPointer m_managedSigPtr;
478 Module* m_pStubSigModule;
479 ILCodeLabel* m_pLabelList;
481 bool FirstPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, UINT* puMaxStack);
482 void SecondPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pCurCodeOffset);
484 BYTE* GenerateCodeWorker(BYTE* pbBuffer, ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode);
486 static ILCodeStream* FindLastCodeStream(ILCodeStream* pList);
490 // the public entrypoints for these methods are in ILCodeStream
492 ILCodeLabel* NewCodeLabel();
493 int GetToken(MethodDesc* pMD);
494 int GetToken(MethodTable* pMT);
495 int GetToken(TypeHandle th);
496 int GetToken(FieldDesc* pFD);
497 DWORD NewLocal(CorElementType typ = ELEMENT_TYPE_I);
498 DWORD NewLocal(LocalDesc loc);
500 DWORD SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg = true);
501 DWORD SetStubTargetArgType(LocalDesc* pLoc = NULL, bool fConsumeStubArg = true); // passing pLoc = NULL means "use stub arg type"
502 void SetStubTargetReturnType(CorElementType typ);
503 void SetStubTargetReturnType(LocalDesc* pLoc);
504 void SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv);
506 bool ReturnOpcodePopsStack()
508 if ((!m_fIsReverseStub && m_StubHasVoidReturnType) || (m_fIsReverseStub && m_StubTargetHasVoidReturnType))
515 void TransformArgForJIT(LocalDesc *pLoc);
517 Module * GetStubSigModule();
518 SigTypeContext *GetStubSigTypeContext();
520 BOOL m_StubHasVoidReturnType;
521 BOOL m_StubTargetHasVoidReturnType;
522 BOOL m_fIsReverseStub;
523 INT m_iTargetStackDelta;
524 DWORD m_cbCurrentCompressedSigLen;
529 // We need this MethodDesc so we can reconstruct the generics
530 // SigTypeContext info, if needed.
532 }; // class ILStubLinker
535 //---------------------------------------------------------------------------------------
539 friend class ILStubLinker;
540 friend class ILCodeStream;
546 size_t GetCodeOffset();
549 void SetCodeOffset(size_t codeOffset);
551 ILCodeLabel* m_pNext;
552 ILStubLinker* m_pOwningStubLinker;
553 ILCodeStream* m_pCodeStreamOfLabel; // this is the ILCodeStream that the index is relative to
554 size_t m_codeOffset; // this is the absolute resolved IL offset after linking
555 UINT m_idxLabeledInstruction; // this is the index within the instruction buffer of the owning ILCodeStream
560 friend class ILStubLinker;
565 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
568 #include "opcode.def"
573 static ILInstrEnum LowerOpcode(ILInstrEnum instr, ILStubLinker::ILInstruction* pInstr);
576 static bool IsSupportedInstruction(ILInstrEnum instr);
579 static bool IsBranchInstruction(ILInstrEnum instr)
581 LIMITED_METHOD_CONTRACT;
582 return ((instr >= CEE_BR) && (instr <= CEE_BLT_UN)) || (instr == CEE_LEAVE);
591 void EmitBEQ (ILCodeLabel* pCodeLabel);
592 void EmitBGE (ILCodeLabel* pCodeLabel);
593 void EmitBGE_UN(ILCodeLabel* pCodeLabel);
594 void EmitBGT (ILCodeLabel* pCodeLabel);
595 void EmitBLE (ILCodeLabel* pCodeLabel);
596 void EmitBLE_UN (ILCodeLabel* pCodeLabel);
597 void EmitBLT (ILCodeLabel* pCodeLabel);
598 void EmitBR (ILCodeLabel* pCodeLabel);
600 void EmitBRFALSE (ILCodeLabel* pCodeLabel);
601 void EmitBRTRUE (ILCodeLabel* pCodeLabel);
602 void EmitCALL (int token, int numInArgs, int numRetArgs);
603 void EmitCALLI (int token, int numInArgs, int numRetArgs);
621 void EmitCONV_OVF_I4();
622 void EmitCONV_T (CorElementType type);
624 void EmitCPOBJ (int token);
626 void EmitENDFINALLY ();
628 void EmitINITOBJ (int token);
629 void EmitJMP (int token);
630 void EmitLDARG (unsigned uArgIdx);
631 void EmitLDARGA (unsigned uArgIdx);
632 void EmitLDC (DWORD_PTR uConst);
633 void EmitLDC_R4 (UINT32 uConst);
634 void EmitLDC_R8 (UINT64 uConst);
635 void EmitLDELEMA (int token);
636 void EmitLDELEM_REF ();
637 void EmitLDFLD (int token);
638 void EmitLDFLDA (int token);
639 void EmitLDFTN (int token);
641 void EmitLDIND_I1 ();
642 void EmitLDIND_I2 ();
643 void EmitLDIND_I4 ();
644 void EmitLDIND_I8 ();
645 void EmitLDIND_R4 ();
646 void EmitLDIND_R8 ();
647 void EmitLDIND_REF ();
648 void EmitLDIND_T (LocalDesc* pType);
649 void EmitLDIND_U1 ();
650 void EmitLDIND_U2 ();
651 void EmitLDIND_U4 ();
653 void EmitLDLOC (DWORD dwLocalNum);
654 void EmitLDLOCA (DWORD dwLocalNum);
656 void EmitLDOBJ (int token);
657 void EmitLDSFLD (int token);
658 void EmitLDSFLDA (int token);
659 void EmitLDTOKEN (int token);
660 void EmitLEAVE (ILCodeLabel* pCodeLabel);
661 void EmitLOCALLOC ();
664 void EmitNEWOBJ (int token, int numInArgs);
665 void EmitNOP (LPCSTR pszNopComment);
669 void EmitSTARG (unsigned uArgIdx);
670 void EmitSTELEM_REF ();
672 void EmitSTIND_I1 ();
673 void EmitSTIND_I2 ();
674 void EmitSTIND_I4 ();
675 void EmitSTIND_I8 ();
676 void EmitSTIND_R4 ();
677 void EmitSTIND_R8 ();
678 void EmitSTIND_REF ();
679 void EmitSTIND_T (LocalDesc* pType);
680 void EmitSTFLD (int token);
681 void EmitSTLOC (DWORD dwLocalNum);
682 void EmitSTOBJ (int token);
683 void EmitSTSFLD (int token);
687 // Overloads to simplify common usage patterns
688 void EmitNEWOBJ (BinderMethodID id, int numInArgs);
689 void EmitCALL (BinderMethodID id, int numInArgs, int numRetArgs);
691 void EmitLabel(ILCodeLabel* pLabel);
692 void EmitLoadThis ();
693 void EmitLoadNullPtr();
694 void EmitArgIteratorCreateAndLoad();
696 ILCodeLabel* NewCodeLabel();
701 // these functions just forward to the owning ILStubLinker
704 int GetToken(MethodDesc* pMD);
705 int GetToken(MethodTable* pMT);
706 int GetToken(TypeHandle th);
707 int GetToken(FieldDesc* pFD);
709 DWORD NewLocal(CorElementType typ = ELEMENT_TYPE_I);
710 DWORD NewLocal(LocalDesc loc);
711 DWORD SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg = true);
712 DWORD SetStubTargetArgType(LocalDesc* pLoc = NULL, bool fConsumeStubArg = true); // passing pLoc = NULL means "use stub arg type"
713 void SetStubTargetReturnType(CorElementType typ);
714 void SetStubTargetReturnType(LocalDesc* pLoc);
721 ILCodeStream(ILStubLinker* pOwner, ILStubLinker::CodeStreamType codeStreamType) :
724 m_pqbILInstructions(NULL),
726 m_codeStreamType(codeStreamType)
740 if (NULL != m_pqbILInstructions)
742 delete m_pqbILInstructions;
743 m_pqbILInstructions = NULL;
747 ILStubLinker::CodeStreamType GetStreamType() { return m_codeStreamType; }
749 LPCSTR GetStreamDescription(ILStubLinker::CodeStreamType streamType);
753 void Emit(ILInstrEnum instr, INT16 iStackDelta, UINT_PTR uArg);
757 INITIAL_NUM_IL_INSTRUCTIONS = 64,
758 INITIAL_IL_INSTRUCTION_BUFFER_SIZE = INITIAL_NUM_IL_INSTRUCTIONS * sizeof(ILStubLinker::ILInstruction),
761 typedef CQuickBytesSpecifySize<INITIAL_IL_INSTRUCTION_BUFFER_SIZE> ILCodeStreamBuffer;
763 ILCodeStream* m_pNextStream;
764 ILStubLinker* m_pOwner;
765 ILCodeStreamBuffer* m_pqbILInstructions;
767 ILStubLinker::CodeStreamType m_codeStreamType; // Type of the ILCodeStream
770 const static UINT32 SPECIAL_VALUE_NAN_64_ON_32 = 0xFFFFFFFF;
774 #define TOKEN_ILSTUB_TARGET_SIG (TokenFromRid(0xFFFFFF, mdtSignature))
776 #endif // __STUBGEN_H__