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.
14 #include "jitinterface.h"
15 #include "ilstubcache.h"
16 #include "sigbuilder.h"
18 #include "formattype.h"
19 #include "typestring.h"
25 // ....[.....\xxxxx]..0... -> ....[xxxxx]..0...
28 void DumpIL_RemoveFullPath(SString &strTokenFormatting)
31 if (strTokenFormatting.IsEmpty())
34 SString::Iterator begin = strTokenFormatting.Begin();
35 SString::Iterator end = strTokenFormatting.End();
36 SString::Iterator leftBracket = strTokenFormatting.Begin();
38 // Find the first '[' in the string.
39 while ((leftBracket != end) && (*leftBracket != W('[')))
44 if (leftBracket != end)
46 SString::Iterator lastSlash = strTokenFormatting.End() - 1;
48 // Find the last '\\' in the string.
49 while ((lastSlash != leftBracket) && (*lastSlash != W('\\')))
54 if (leftBracket != lastSlash)
56 strTokenFormatting.Delete(leftBracket + 1, lastSlash - leftBracket);
61 void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTokenFormatting, const SString &strStubTargetSig)
63 void* pvLookupRetVal = (void*)POISONC;
64 _ASSERTE(strTokenFormatting.IsEmpty());
68 if (TypeFromToken(token) == mdtMethodDef)
70 MethodDesc* pMD = pTokenMap->LookupMethodDef(token);
72 CONSISTENCY_CHECK(CheckPointer(pMD));
74 pMD->GetFullMethodInfo(strTokenFormatting);
76 else if (TypeFromToken(token) == mdtTypeDef)
78 TypeHandle typeHnd = pTokenMap->LookupTypeDef(token);
79 pvLookupRetVal = typeHnd.AsPtr();
80 CONSISTENCY_CHECK(!typeHnd.IsNull());
83 MethodTable *pMT = NULL;
84 if (typeHnd.IsTypeDesc())
86 TypeDesc *pTypeDesc = typeHnd.AsTypeDesc();
87 pMT = pTypeDesc->GetMethodTable();
91 pMT = typeHnd.AsMethodTable();
94 // AppendType handles NULL correctly
95 TypeString::AppendType(typeName, TypeHandle(pMT));
97 if (pMT && typeHnd.IsNativeValueType())
98 typeName.Append(W("_NativeValueType"));
99 strTokenFormatting.Set(typeName);
101 else if (TypeFromToken(token) == mdtFieldDef)
103 FieldDesc* pFD = pTokenMap->LookupFieldDef(token);
104 pvLookupRetVal = pFD;
105 CONSISTENCY_CHECK(CheckPointer(pFD));
108 TypeString::AppendType(typeName, TypeHandle(pFD->GetApproxEnclosingMethodTable()));
110 SString strFieldName(SString::Utf8, pFD->GetName());
111 strTokenFormatting.Printf(W("%s::%s"), typeName.GetUnicode(), strFieldName.GetUnicode());
113 else if (TypeFromToken(token) == mdtModule)
115 // Do nothing, because strTokenFormatting is already empty.
117 else if (TypeFromToken(token) == mdtSignature)
119 CONSISTENCY_CHECK(token == TOKEN_ILSTUB_TARGET_SIG);
120 strTokenFormatting.Set(strStubTargetSig);
124 strTokenFormatting.Printf(W("%d"), token);
126 DumpIL_RemoveFullPath(strTokenFormatting);
130 strTokenFormatting.Printf(W("%d"), token);
132 EX_END_CATCH(SwallowAllExceptions)
135 void ILCodeStream::Emit(ILInstrEnum instr, INT16 iStackDelta, UINT_PTR uArg)
137 STANDARD_VM_CONTRACT;
139 UINT idxCurInstr = 0;
140 ILStubLinker::ILInstruction* pInstrBuffer = NULL;
142 if (NULL == m_pqbILInstructions)
144 m_pqbILInstructions = new ILCodeStreamBuffer();
147 idxCurInstr = m_uCurInstrIdx;
150 m_pqbILInstructions->ReSizeThrows(m_uCurInstrIdx * sizeof(ILStubLinker::ILInstruction));
152 pInstrBuffer = (ILStubLinker::ILInstruction*)m_pqbILInstructions->Ptr();
154 pInstrBuffer[idxCurInstr].uInstruction = static_cast<UINT16>(instr);
155 pInstrBuffer[idxCurInstr].iStackDelta = iStackDelta;
156 pInstrBuffer[idxCurInstr].uArg = uArg;
159 ILCodeLabel* ILStubLinker::NewCodeLabel()
161 STANDARD_VM_CONTRACT;
163 ILCodeLabel* pCodeLabel = new ILCodeLabel();
165 pCodeLabel->m_pNext = m_pLabelList;
166 pCodeLabel->m_pOwningStubLinker = this;
167 pCodeLabel->m_pCodeStreamOfLabel = NULL;
168 pCodeLabel->m_idxLabeledInstruction = -1;
170 m_pLabelList = pCodeLabel;
175 void ILCodeStream::EmitLabel(ILCodeLabel* pCodeLabel)
180 PRECONDITION_MSG(m_pOwner == pCodeLabel->m_pOwningStubLinker, "you can only use a code label in the ILStubLinker that created it!");
184 pCodeLabel->m_pCodeStreamOfLabel = this;
185 pCodeLabel->m_idxLabeledInstruction = m_uCurInstrIdx;
187 Emit(CEE_CODE_LABEL, 0, (UINT_PTR)pCodeLabel);
190 static const BYTE s_rgbOpcodeSizes[] =
193 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
197 #define ShortInlineVar 1
198 #define ShortInlineI 1
201 #define ShortInlineR 4
203 #define InlineMethod 4
205 #define ShortInlineBrTarget 1
206 #define InlineBrTarget 4
207 #define InlineSwitch -1
209 #define InlineString 4
210 #define InlineField 4
214 #include "opcode.def"
218 #undef ShortInlineVar
226 #undef ShortInlineBrTarget
227 #undef InlineBrTarget
243 static const ILOpcode s_rgOpcodes[] =
246 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
248 #include "opcode.def"
253 ILCodeStream::ILInstrEnum ILCodeStream::LowerOpcode(ILInstrEnum instr, ILStubLinker::ILInstruction* pInstr)
258 PRECONDITION(instr == (ILInstrEnum)pInstr->uInstruction);
263 // NOTE: we do not lower branches to their smallest form because that
264 // would introduce extra passes at link time, which isn't really
265 // worth the savings in IL code size.
268 UINT_PTR uConst = pInstr->uArg;
274 if (uConst == (UINT_PTR)-1)
276 instr = CEE_LDC_I4_M1;
281 instr = (ILInstrEnum)((UINT_PTR)CEE_LDC_I4_0 + uConst);
284 if (FitsInI1(uConst))
286 instr = CEE_LDC_I4_S;
289 if (FitsInI4(uConst))
300 instr = (ILInstrEnum)((UINT_PTR)CEE_LDARG_0 + uConst);
309 instr = (ILInstrEnum)((UINT_PTR)CEE_LDLOC_0 + uConst);
318 instr = (ILInstrEnum)((UINT_PTR)CEE_STLOC_0 + uConst);
323 if (FitsInI1(uConst))
325 static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARG - (UINT_PTR)CEE_LDARG_S);
326 static_assert_no_msg(((UINT_PTR)CEE_LDARG - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARG_S);
327 static_assert_no_msg(((UINT_PTR)CEE_LDLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOC_S);
328 static_assert_no_msg(((UINT_PTR)CEE_STLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_STLOC_S);
330 instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
339 if (FitsInI1(uConst))
341 static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARGA - (UINT_PTR)CEE_LDARGA_S);
342 static_assert_no_msg(((UINT_PTR)CEE_LDARGA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARGA_S);
343 static_assert_no_msg(((UINT_PTR)CEE_STARG - c_uMakeShortDelta) == (UINT_PTR)CEE_STARG_S);
344 static_assert_no_msg(((UINT_PTR)CEE_LDLOCA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOCA_S);
346 instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
355 pInstr->uInstruction = static_cast<UINT16>(instr);
359 void ILStubLinker::PatchInstructionArgument(ILCodeLabel* pLabel, UINT_PTR uNewArg
360 DEBUG_ARG(UINT16 uExpectedInstruction))
362 LIMITED_METHOD_CONTRACT;
364 UINT idx = pLabel->m_idxLabeledInstruction;
365 ILCodeStream* pLabelCodeStream = pLabel->m_pCodeStreamOfLabel;
366 ILInstruction* pLabelInstrBuffer = (ILInstruction*)pLabelCodeStream->m_pqbILInstructions->Ptr();
368 CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == ILCodeStream::CEE_CODE_LABEL);
369 CONSISTENCY_CHECK(pLabelInstrBuffer[idx].iStackDelta == 0);
373 CONSISTENCY_CHECK(idx < pLabelCodeStream->m_uCurInstrIdx);
374 CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == uExpectedInstruction);
376 pLabelInstrBuffer[idx].uArg = uNewArg;
379 ILCodeLabel::ILCodeLabel()
382 m_pOwningStubLinker = NULL;
383 m_pCodeStreamOfLabel = NULL;
385 m_idxLabeledInstruction = -1;
388 ILCodeLabel::~ILCodeLabel()
392 size_t ILCodeLabel::GetCodeOffset()
394 LIMITED_METHOD_CONTRACT;
396 CONSISTENCY_CHECK(m_codeOffset != (size_t)-1);
401 void ILCodeLabel::SetCodeOffset(size_t codeOffset)
403 LIMITED_METHOD_CONTRACT;
405 CONSISTENCY_CHECK((m_codeOffset == (size_t)-1) && (codeOffset != (size_t)-1));
406 m_codeOffset = codeOffset;
409 static const LPCSTR s_rgOpcodeNames[] =
411 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
413 #include "opcode.def"
420 static const BYTE s_rgbOpcodeArgType[] =
423 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
425 #include "opcode.def"
431 //---------------------------------------------------------------------------------------
434 ILStubLinker::LogILInstruction(
438 ILInstruction * pInstruction,
439 SString * pDumpILStubCode)
441 STANDARD_VM_CONTRACT;
449 strLabel.Printf(W("IL_%04x:"), curOffset);
453 strLabel.Set(W(" "));
461 ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstruction->uInstruction;
462 size_t cbOpcodeName = strlen(s_rgOpcodeNames[instr]);
463 SString strOpcodeName;
464 strOpcodeName.SetUTF8(s_rgOpcodeNames[instr]);
465 // Set the width of the opcode to 15.
466 strOpcode.Set(W(" "));
467 strOpcode.Replace(strOpcode.Begin(), (COUNT_T)cbOpcodeName, strOpcodeName);
473 static const size_t c_cchPreallocateArgument = 512;
475 strArgument.Preallocate(c_cchPreallocateArgument);
477 static const size_t c_cchPreallocateTokenName = 1024;
478 SString strTokenName;
479 strTokenName.Preallocate(c_cchPreallocateTokenName);
481 if (ILCodeStream::IsBranchInstruction(instr))
483 size_t branchDistance = (size_t)pInstruction->uArg;
484 size_t targetOffset = curOffset + s_rgbOpcodeSizes[instr] + branchDistance;
485 strArgument.Printf(W("IL_%04x"), targetOffset);
487 else if ((ILCodeStream::ILInstrEnum)CEE_NOP == instr)
489 SString strInstruction;
490 strInstruction.Printf("%s", (char *)pInstruction->uArg);
491 strInstruction.ConvertToUnicode(strArgument);
495 switch (s_rgbOpcodeArgType[instr])
503 strArgument.Printf(W("0x%x"), pInstruction->uArg);
507 strArgument.Printf(W("0x%p"), (void *)pInstruction->uArg);
517 // No token value when we dump IL for ETW
518 if (pDumpILStubCode == NULL)
519 strArgument.Printf(W("0x%08x"), pInstruction->uArg);
521 LPUTF8 pszFormattedStubTargetSig = NULL;
522 CQuickBytes qbTargetSig;
524 if (TOKEN_ILSTUB_TARGET_SIG == pInstruction->uArg)
526 PCCOR_SIGNATURE pTargetSig;
528 CQuickBytes qbTempTargetSig;
530 IMDInternalImport * pIMDI = MscorlibBinder::GetModule()->GetMDImport();
532 cTargetSig = GetStubTargetMethodSigSize();
533 pTargetSig = (PCCOR_SIGNATURE)qbTempTargetSig.AllocThrows(cTargetSig);
535 GetStubTargetMethodSig((BYTE*)pTargetSig, cTargetSig);
536 PrettyPrintSig(pTargetSig, cTargetSig, "", &qbTargetSig, pIMDI, NULL);
538 pszFormattedStubTargetSig = (LPUTF8)qbTargetSig.Ptr();
541 // Dump to szTokenNameBuffer if logging, otherwise dump to szArgumentBuffer to avoid an extra space because we are omitting the token
542 _ASSERTE(FitsIn<mdToken>(pInstruction->uArg));
543 SString strFormattedStubTargetSig;
544 strFormattedStubTargetSig.SetUTF8(pszFormattedStubTargetSig);
545 if (pDumpILStubCode == NULL)
546 DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strTokenName, strFormattedStubTargetSig);
548 DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strArgument, strFormattedStubTargetSig);
559 pDumpILStubCode->AppendPrintf(W("%s /*(%2d)*/ %s %s %s\n"), strLabel.GetUnicode(), iCurStack, strOpcode.GetUnicode(),
560 strArgument.GetUnicode(), strTokenName.GetUnicode());
564 StackScratchBuffer strLabelBuffer;
565 StackScratchBuffer strOpcodeBuffer;
566 StackScratchBuffer strArgumentBuffer;
567 StackScratchBuffer strTokenNameBuffer;
568 LOG((LF_STUBS, LL_INFO1000, "%s (%2d) %s %s %s\n", strLabel.GetUTF8(strLabelBuffer), iCurStack, \
569 strOpcode.GetUTF8(strOpcodeBuffer), strArgument.GetUTF8(strArgumentBuffer), strTokenName.GetUTF8(strTokenNameBuffer)));
571 } // ILStubLinker::LogILInstruction
573 //---------------------------------------------------------------------------------------
576 ILStubLinker::LogILStubWorker(
577 ILInstruction * pInstrBuffer,
581 SString * pDumpILStubCode)
586 PRECONDITION(CheckPointer(pcbCode));
587 PRECONDITION(CheckPointer(piCurStack));
588 PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
592 bool isLabeled = false;
594 for (UINT i = 0; i < numInstr; i++)
596 ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
597 CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
599 if (instr == ILCodeStream::CEE_CODE_LABEL)
605 LogILInstruction(*pcbCode, isLabeled, *piCurStack, &pInstrBuffer[i], pDumpILStubCode);
609 // calculate the code size
611 PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
612 *pcbCode += s_rgbOpcodeSizes[instr];
615 // calculate curstack
617 *piCurStack += pInstrBuffer[i].iStackDelta;
620 // Be sure to log any trailing label that has no associated instruction.
625 pDumpILStubCode->AppendPrintf(W("IL_%04x:\n"), *pcbCode);
629 LOG((LF_STUBS, LL_INFO1000, "IL_%04x:\n", *pcbCode));
634 static void LogJitFlags(DWORD facility, DWORD level, CORJIT_FLAGS jitFlags)
642 LOG((facility, level, "jitFlags:\n"));
644 #define LOG_FLAG(name) \
645 if (jitFlags.IsSet(name)) \
647 LOG((facility, level, " " #name "\n")); \
648 jitFlags.Clear(name); \
651 // these are all we care about at the moment
652 LOG_FLAG(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB);
653 LOG_FLAG(CORJIT_FLAGS::CORJIT_FLAG_PUBLISH_SECRET_PARAM);
657 if (!jitFlags.IsEmpty())
659 LOG((facility, level, "UNKNOWN FLAGS also set\n"));
663 void ILStubLinker::LogILStub(CORJIT_FLAGS jitFlags, SString *pDumpILStubCode)
668 PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
672 ILCodeStream* pCurrentStream = m_pCodeStreamList;
676 if (pDumpILStubCode == NULL)
677 LogJitFlags(LF_STUBS, LL_INFO1000, jitFlags);
679 while (pCurrentStream)
681 if (pCurrentStream->m_pqbILInstructions)
684 pDumpILStubCode->AppendPrintf("// %s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
686 LOG((LF_STUBS, LL_INFO1000, "%s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType())));
688 ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
689 LogILStubWorker(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, pDumpILStubCode);
692 pDumpILStubCode->AppendPrintf("// } %s \n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
694 LOG((LF_STUBS, LL_INFO1000, "}\n"));
697 pCurrentStream = pCurrentStream->m_pNextStream;
701 bool ILStubLinker::FirstPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, UINT* puMaxStack)
706 PRECONDITION(CheckPointer(puMaxStack));
710 bool fStackUnderflow = false;
712 for (UINT i = 0; i < numInstr; i++)
714 ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
715 CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
718 // down-size instructions
720 instr = ILCodeStream::LowerOpcode(instr, &pInstrBuffer[i]);
723 // fill in code label offsets
725 if (instr == ILCodeStream::CEE_CODE_LABEL)
727 ILCodeLabel* pLabel = (ILCodeLabel*)(pInstrBuffer[i].uArg);
728 pLabel->SetCodeOffset(*pcbCode);
732 // calculate the code size
734 PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
735 *pcbCode += s_rgbOpcodeSizes[instr];
738 // calculate maxstack
740 *piCurStack += pInstrBuffer[i].iStackDelta;
741 if (*piCurStack > (INT)*puMaxStack)
743 *puMaxStack = *piCurStack;
748 fStackUnderflow = true;
753 return fStackUnderflow;
756 void ILStubLinker::SecondPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pCurCodeOffset)
761 PRECONDITION(CheckPointer(pCurCodeOffset));
765 for (UINT i = 0; i < numInstr; i++)
767 ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
768 CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
769 *pCurCodeOffset += s_rgbOpcodeSizes[instr];
771 if (ILCodeStream::IsBranchInstruction(instr))
773 ILCodeLabel* pLabel = (ILCodeLabel*) pInstrBuffer[i].uArg;
775 CONSISTENCY_CHECK(this == pLabel->m_pOwningStubLinker);
776 CONSISTENCY_CHECK(IsInCodeStreamList(pLabel->m_pCodeStreamOfLabel));
778 pInstrBuffer[i].uArg = pLabel->GetCodeOffset() - *pCurCodeOffset;
783 size_t ILStubLinker::Link(UINT* puMaxStack)
788 PRECONDITION(CheckPointer(puMaxStack));
793 // Pass1: calculate code size, lower instructions to smallest form,
794 // fill in branch target offsets, and calculate maxstack
797 ILCodeStream* pCurrentStream = m_pCodeStreamList;
801 DEBUG_STMT(bool fStackUnderflow = false);
803 while (pCurrentStream)
805 if (pCurrentStream->m_pqbILInstructions)
807 ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
808 INDEBUG( fStackUnderflow = ) FirstPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, &uMaxStack);
811 pCurrentStream = pCurrentStream->m_pNextStream;
815 // Pass2: go back and patch the branch instructions
818 pCurrentStream = m_pCodeStreamList;
819 size_t curCodeOffset = 0;
821 while (pCurrentStream)
823 if (pCurrentStream->m_pqbILInstructions)
825 ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
826 SecondPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &curCodeOffset);
829 pCurrentStream = pCurrentStream->m_pNextStream;
835 LogILStub(CORJIT_FLAGS());
836 CONSISTENCY_CHECK_MSG(false, "IL stack underflow! -- see logging output");
840 *puMaxStack = uMaxStack;
846 static const PCSTR s_rgOpNames[] =
849 #define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
851 #include "opcode.def"
859 BYTE* ILStubLinker::GenerateCodeWorker(BYTE* pbBuffer, ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode)
864 PRECONDITION(CheckPointer(pcbCode));
868 for (UINT i = 0; i < numInstr; i++)
870 ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
871 CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
874 // copy the IL instructions from the various linkers into the given buffer
876 if (instr != ILCodeStream::CEE_CODE_LABEL)
878 const ILOpcode* pOpcode = &s_rgOpcodes[instr];
880 PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
881 int opSize = s_rgbOpcodeSizes[instr];
882 bool twoByteOp = (pOpcode->byte1 != 0xFF);
883 int argSize = opSize - (twoByteOp ? 2 : 1);
887 *pbBuffer++ = pOpcode->byte1;
890 *pbBuffer++ = pOpcode->byte2;
898 *pbBuffer = (BYTE)pInstrBuffer[i].uArg;
902 SET_UNALIGNED_VAL16(pbBuffer, pInstrBuffer[i].uArg);
906 SET_UNALIGNED_VAL32(pbBuffer, pInstrBuffer[i].uArg);
911 UINT64 uVal = pInstrBuffer[i].uArg;
912 #ifndef _WIN64 // We don't have room on 32-bit platforms to store the CLR_NAN_64 value, so
913 // we use a special value to represent CLR_NAN_64 and then recreate it here.
914 if ((instr == ILCodeStream::CEE_LDC_R8) && (((UINT32)uVal) == ILCodeStream::SPECIAL_VALUE_NAN_64_ON_32))
917 SET_UNALIGNED_VAL64(pbBuffer, uVal);
922 UNREACHABLE_MSG("unexpected il opcode argument size");
933 void ILStubLinker::GenerateCode(BYTE* pbBuffer, size_t cbBufferSize)
935 STANDARD_VM_CONTRACT;
937 ILCodeStream* pCurrentStream = m_pCodeStreamList;
940 while (pCurrentStream)
942 if (pCurrentStream->m_pqbILInstructions)
944 ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
945 pbBuffer = GenerateCodeWorker(pbBuffer, pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode);
948 pCurrentStream = pCurrentStream->m_pNextStream;
951 CONSISTENCY_CHECK(cbCode <= cbBufferSize);
956 bool ILStubLinker::IsInCodeStreamList(ILCodeStream* pcs)
958 LIMITED_METHOD_CONTRACT;
960 ILCodeStream* pCurrentStream = m_pCodeStreamList;
961 while (pCurrentStream)
963 if (pcs == pCurrentStream)
968 pCurrentStream = pCurrentStream->m_pNextStream;
975 bool ILCodeStream::IsSupportedInstruction(ILInstrEnum instr)
977 LIMITED_METHOD_CONTRACT;
979 CONSISTENCY_CHECK_MSG(instr != CEE_SWITCH, "CEE_SWITCH is not supported currently due to InlineSwitch in s_rgbOpcodeSizes");
980 CONSISTENCY_CHECK_MSG(((instr >= CEE_BR_S) && (instr <= CEE_BLT_UN_S)) || (CEE_LEAVE), "we only use long-form branch opcodes");
985 LPCSTR ILCodeStream::GetStreamDescription(ILStubLinker::CodeStreamType streamType)
987 LIMITED_METHOD_CONTRACT;
989 static LPCSTR lpszDescriptions[] = {
1001 size_t len = sizeof(lpszDescriptions)/sizeof(LPCSTR);
1002 _ASSERT(streamType >= 0 && (size_t)streamType < len);
1005 return lpszDescriptions[streamType];
1008 void ILCodeStream::EmitADD()
1010 WRAPPER_NO_CONTRACT;
1011 Emit(CEE_ADD, -1, 0);
1013 void ILCodeStream::EmitADD_OVF()
1015 WRAPPER_NO_CONTRACT;
1016 Emit(CEE_ADD_OVF, -1, 0);
1018 void ILCodeStream::EmitAND()
1020 WRAPPER_NO_CONTRACT;
1021 Emit(CEE_AND, -1, 0);
1023 void ILCodeStream::EmitARGLIST()
1025 WRAPPER_NO_CONTRACT;
1026 Emit(CEE_ARGLIST, 1, 0);
1029 void ILCodeStream::EmitBEQ(ILCodeLabel* pCodeLabel)
1031 WRAPPER_NO_CONTRACT;
1032 Emit(CEE_BEQ, -2, (UINT_PTR)pCodeLabel);
1035 void ILCodeStream::EmitBGE(ILCodeLabel* pCodeLabel)
1037 WRAPPER_NO_CONTRACT;
1038 Emit(CEE_BGE, -2, (UINT_PTR)pCodeLabel);
1041 void ILCodeStream::EmitBGE_UN(ILCodeLabel* pCodeLabel)
1043 WRAPPER_NO_CONTRACT;
1044 Emit(CEE_BGE_UN, -2, (UINT_PTR)pCodeLabel);
1047 void ILCodeStream::EmitBGT(ILCodeLabel* pCodeLabel)
1049 WRAPPER_NO_CONTRACT;
1050 Emit(CEE_BGT, -2, (UINT_PTR)pCodeLabel);
1052 void ILCodeStream::EmitBLE(ILCodeLabel* pCodeLabel)
1054 WRAPPER_NO_CONTRACT;
1055 Emit(CEE_BLE, -2, (UINT_PTR)pCodeLabel);
1057 void ILCodeStream::EmitBLE_UN(ILCodeLabel* pCodeLabel)
1059 WRAPPER_NO_CONTRACT;
1060 Emit(CEE_BLE_UN, -2, (UINT_PTR)pCodeLabel);
1062 void ILCodeStream::EmitBLT(ILCodeLabel* pCodeLabel)
1064 WRAPPER_NO_CONTRACT;
1065 Emit(CEE_BLT, -2, (UINT_PTR)pCodeLabel);
1067 void ILCodeStream::EmitBR(ILCodeLabel* pCodeLabel)
1069 WRAPPER_NO_CONTRACT;
1070 Emit(CEE_BR, 0, (UINT_PTR)pCodeLabel);
1072 void ILCodeStream::EmitBREAK()
1074 WRAPPER_NO_CONTRACT;
1075 Emit(CEE_BREAK, 0, 0);
1077 void ILCodeStream::EmitBRFALSE(ILCodeLabel* pCodeLabel)
1079 WRAPPER_NO_CONTRACT;
1080 Emit(CEE_BRFALSE, -1, (UINT_PTR)pCodeLabel);
1082 void ILCodeStream::EmitBRTRUE(ILCodeLabel* pCodeLabel)
1084 WRAPPER_NO_CONTRACT;
1085 Emit(CEE_BRTRUE, -1, (UINT_PTR)pCodeLabel);
1087 void ILCodeStream::EmitCALL(int token, int numInArgs, int numRetArgs)
1089 WRAPPER_NO_CONTRACT;
1090 Emit(CEE_CALL, (INT16)(numRetArgs - numInArgs), token);
1092 void ILCodeStream::EmitCALLI(int token, int numInArgs, int numRetArgs)
1094 WRAPPER_NO_CONTRACT;
1095 Emit(CEE_CALLI, (INT16)(numRetArgs - numInArgs - 1), token);
1097 void ILCodeStream::EmitCEQ ()
1099 WRAPPER_NO_CONTRACT;
1100 Emit(CEE_CEQ, -1, 0);
1102 void ILCodeStream::EmitCGT()
1104 WRAPPER_NO_CONTRACT;
1105 Emit(CEE_CGT, -1, 0);
1107 void ILCodeStream::EmitCGT_UN()
1109 WRAPPER_NO_CONTRACT;
1110 Emit(CEE_CGT_UN, -1, 0);
1112 void ILCodeStream::EmitCLT()
1114 WRAPPER_NO_CONTRACT;
1115 Emit(CEE_CLT, -1, 0);
1117 void ILCodeStream::EmitCLT_UN()
1119 WRAPPER_NO_CONTRACT;
1120 Emit(CEE_CLT_UN, -1, 0);
1122 void ILCodeStream::EmitCONV_I()
1124 WRAPPER_NO_CONTRACT;
1125 Emit(CEE_CONV_I, 0, 0);
1127 void ILCodeStream::EmitCONV_I1()
1129 WRAPPER_NO_CONTRACT;
1130 Emit(CEE_CONV_I1, 0, 0);
1132 void ILCodeStream::EmitCONV_I2()
1134 WRAPPER_NO_CONTRACT;
1135 Emit(CEE_CONV_I2, 0, 0);
1137 void ILCodeStream::EmitCONV_I4()
1139 WRAPPER_NO_CONTRACT;
1140 Emit(CEE_CONV_I4, 0, 0);
1142 void ILCodeStream::EmitCONV_I8()
1144 WRAPPER_NO_CONTRACT;
1145 Emit(CEE_CONV_I8, 0, 0);
1147 void ILCodeStream::EmitCONV_U()
1149 WRAPPER_NO_CONTRACT;
1150 Emit(CEE_CONV_U, 0, 0);
1152 void ILCodeStream::EmitCONV_U1()
1154 WRAPPER_NO_CONTRACT;
1155 Emit(CEE_CONV_U1, 0, 0);
1157 void ILCodeStream::EmitCONV_U2()
1159 WRAPPER_NO_CONTRACT;
1160 Emit(CEE_CONV_U2, 0, 0);
1162 void ILCodeStream::EmitCONV_U4()
1164 WRAPPER_NO_CONTRACT;
1165 Emit(CEE_CONV_U4, 0, 0);
1167 void ILCodeStream::EmitCONV_U8()
1169 WRAPPER_NO_CONTRACT;
1170 Emit(CEE_CONV_U8, 0, 0);
1172 void ILCodeStream::EmitCONV_R4()
1174 WRAPPER_NO_CONTRACT;
1175 Emit(CEE_CONV_R4, 0, 0);
1177 void ILCodeStream::EmitCONV_R8()
1179 WRAPPER_NO_CONTRACT;
1180 Emit(CEE_CONV_R8, 0, 0);
1182 void ILCodeStream::EmitCONV_OVF_I4()
1184 WRAPPER_NO_CONTRACT;
1185 Emit(CEE_CONV_OVF_I4, 0, 0);
1187 void ILCodeStream::EmitCONV_T(CorElementType t)
1189 STANDARD_VM_CONTRACT;
1193 case ELEMENT_TYPE_U1:
1196 case ELEMENT_TYPE_I1:
1199 case ELEMENT_TYPE_U2:
1202 case ELEMENT_TYPE_I2:
1205 case ELEMENT_TYPE_U4:
1208 case ELEMENT_TYPE_I4:
1211 case ELEMENT_TYPE_U8:
1214 case ELEMENT_TYPE_I8:
1217 case ELEMENT_TYPE_R4:
1220 case ELEMENT_TYPE_R8:
1223 case ELEMENT_TYPE_I:
1226 case ELEMENT_TYPE_U:
1230 _ASSERTE(!"Invalid type for conversion");
1234 void ILCodeStream::EmitCPBLK()
1236 WRAPPER_NO_CONTRACT;
1237 Emit(CEE_CPBLK, -3, 0);
1239 void ILCodeStream::EmitCPOBJ(int token)
1241 WRAPPER_NO_CONTRACT;
1242 Emit(CEE_CPOBJ, -2, token);
1244 void ILCodeStream::EmitDUP ()
1246 WRAPPER_NO_CONTRACT;
1247 Emit(CEE_DUP, 1, 0);
1249 void ILCodeStream::EmitENDFINALLY()
1251 WRAPPER_NO_CONTRACT;
1252 Emit(CEE_ENDFINALLY, 0, 0);
1254 void ILCodeStream::EmitINITBLK()
1256 WRAPPER_NO_CONTRACT;
1257 Emit(CEE_INITBLK, -3, 0);
1259 void ILCodeStream::EmitINITOBJ(int token)
1261 WRAPPER_NO_CONTRACT;
1262 Emit(CEE_INITOBJ, -1, token);
1264 void ILCodeStream::EmitJMP(int token)
1266 WRAPPER_NO_CONTRACT;
1267 Emit(CEE_JMP, 0, token);
1269 void ILCodeStream::EmitLDARG (unsigned uArgIdx)
1271 WRAPPER_NO_CONTRACT;
1273 if (m_pOwner->m_fHasThis)
1277 Emit(CEE_LDARG, 1, uArgIdx);
1279 void ILCodeStream::EmitLDARGA (unsigned uArgIdx)
1281 WRAPPER_NO_CONTRACT;
1282 if (m_pOwner->m_fHasThis)
1286 Emit(CEE_LDARGA, 1, uArgIdx);
1288 void ILCodeStream::EmitLDC(DWORD_PTR uConst)
1290 WRAPPER_NO_CONTRACT;
1299 void ILCodeStream::EmitLDC_R4(UINT32 uConst)
1301 WRAPPER_NO_CONTRACT;
1302 Emit(CEE_LDC_R4, 1, uConst);
1304 void ILCodeStream::EmitLDC_R8(UINT64 uConst)
1306 STANDARD_VM_CONTRACT;
1307 #ifndef _WIN64 // We don't have room on 32-bit platforms to stor the CLR_NAN_64 value, so
1308 // we use a special value to represent CLR_NAN_64 and then recreate it later.
1309 CONSISTENCY_CHECK(((UINT32)uConst) != SPECIAL_VALUE_NAN_64_ON_32);
1310 if (uConst == CLR_NAN_64)
1311 uConst = SPECIAL_VALUE_NAN_64_ON_32;
1313 CONSISTENCY_CHECK(FitsInU4(uConst));
1315 Emit(CEE_LDC_R8, 1, (UINT_PTR)uConst);
1317 void ILCodeStream::EmitLDELEMA(int token)
1319 WRAPPER_NO_CONTRACT;
1320 Emit(CEE_LDELEMA, -1, token);
1322 void ILCodeStream::EmitLDELEM_REF()
1324 WRAPPER_NO_CONTRACT;
1325 Emit(CEE_LDELEM_REF, -1, 0);
1327 void ILCodeStream::EmitLDFLD(int token)
1329 WRAPPER_NO_CONTRACT;
1330 Emit(CEE_LDFLD, 0, token);
1332 void ILCodeStream::EmitLDFLDA(int token)
1334 WRAPPER_NO_CONTRACT;
1335 Emit(CEE_LDFLDA, 0, token);
1337 void ILCodeStream::EmitLDFTN(int token)
1339 WRAPPER_NO_CONTRACT;
1340 Emit(CEE_LDFTN, 1, token);
1342 void ILCodeStream::EmitLDIND_I()
1344 WRAPPER_NO_CONTRACT;
1345 Emit(CEE_LDIND_I, 0, 0);
1347 void ILCodeStream::EmitLDIND_I1()
1349 WRAPPER_NO_CONTRACT;
1350 Emit(CEE_LDIND_I1, 0, 0);
1352 void ILCodeStream::EmitLDIND_I2()
1354 WRAPPER_NO_CONTRACT;
1355 Emit(CEE_LDIND_I2, 0, 0);
1357 void ILCodeStream::EmitLDIND_I4()
1359 WRAPPER_NO_CONTRACT;
1360 Emit(CEE_LDIND_I4, 0, 0);
1362 void ILCodeStream::EmitLDIND_I8()
1364 WRAPPER_NO_CONTRACT;
1365 Emit(CEE_LDIND_I8, 0, 0);
1367 void ILCodeStream::EmitLDIND_R4()
1369 WRAPPER_NO_CONTRACT;
1370 Emit(CEE_LDIND_R4, 0, 0);
1372 void ILCodeStream::EmitLDIND_R8()
1374 WRAPPER_NO_CONTRACT;
1375 Emit(CEE_LDIND_R8, 0, 0);
1377 void ILCodeStream::EmitLDIND_REF()
1379 WRAPPER_NO_CONTRACT;
1380 Emit(CEE_LDIND_REF, 0, 0);
1382 void ILCodeStream::EmitLDIND_T(LocalDesc* pType)
1386 PRECONDITION(pType->cbType >= 1);
1390 CorElementType elementType = ELEMENT_TYPE_END;
1392 bool onlyFoundModifiers = true;
1393 for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
1395 elementType = (CorElementType)pType->ElementType[i];
1396 onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
1400 switch (elementType)
1402 case ELEMENT_TYPE_I1: EmitLDIND_I1(); break;
1403 case ELEMENT_TYPE_BOOLEAN: // fall through
1404 case ELEMENT_TYPE_U1: EmitLDIND_U1(); break;
1405 case ELEMENT_TYPE_I2: EmitLDIND_I2(); break;
1406 case ELEMENT_TYPE_CHAR: // fall through
1407 case ELEMENT_TYPE_U2: EmitLDIND_U2(); break;
1408 case ELEMENT_TYPE_I4: EmitLDIND_I4(); break;
1409 case ELEMENT_TYPE_U4: EmitLDIND_U4(); break;
1410 case ELEMENT_TYPE_I8: EmitLDIND_I8(); break;
1411 case ELEMENT_TYPE_U8: EmitLDIND_I8(); break;
1412 case ELEMENT_TYPE_R4: EmitLDIND_R4(); break;
1413 case ELEMENT_TYPE_R8: EmitLDIND_R8(); break;
1414 case ELEMENT_TYPE_PTR: // same as ELEMENT_TYPE_I
1415 case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
1416 case ELEMENT_TYPE_I: EmitLDIND_I(); break;
1417 case ELEMENT_TYPE_U: EmitLDIND_I(); break;
1418 case ELEMENT_TYPE_STRING: // fall through
1419 case ELEMENT_TYPE_CLASS: // fall through
1420 case ELEMENT_TYPE_ARRAY:
1421 case ELEMENT_TYPE_SZARRAY:
1422 case ELEMENT_TYPE_OBJECT: EmitLDIND_REF(); break;
1424 case ELEMENT_TYPE_INTERNAL:
1426 CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1432 UNREACHABLE_MSG("unexpected type passed to EmitLDIND_T");
1436 void ILCodeStream::EmitLDIND_U1()
1438 WRAPPER_NO_CONTRACT;
1439 Emit(CEE_LDIND_U1, 0, 0);
1441 void ILCodeStream::EmitLDIND_U2()
1443 WRAPPER_NO_CONTRACT;
1444 Emit(CEE_LDIND_U2, 0, 0);
1446 void ILCodeStream::EmitLDIND_U4()
1448 WRAPPER_NO_CONTRACT;
1449 Emit(CEE_LDIND_U4, 0, 0);
1451 void ILCodeStream::EmitLDLEN()
1453 WRAPPER_NO_CONTRACT;
1454 Emit(CEE_LDLEN, 0, 0);
1456 void ILCodeStream::EmitLDLOC (DWORD dwLocalNum)
1458 STANDARD_VM_CONTRACT;
1459 CONSISTENCY_CHECK(dwLocalNum != (DWORD)-1);
1460 CONSISTENCY_CHECK(dwLocalNum != (WORD)-1);
1461 Emit(CEE_LDLOC, 1, dwLocalNum);
1463 void ILCodeStream::EmitLDLOCA (DWORD dwLocalNum)
1465 WRAPPER_NO_CONTRACT;
1466 Emit(CEE_LDLOCA, 1, dwLocalNum);
1468 void ILCodeStream::EmitLDNULL()
1470 WRAPPER_NO_CONTRACT;
1471 Emit(CEE_LDNULL, 1, 0);
1473 void ILCodeStream::EmitLDOBJ (int token)
1475 WRAPPER_NO_CONTRACT;
1476 Emit(CEE_LDOBJ, 0, token);
1478 void ILCodeStream::EmitLDSFLD(int token)
1480 WRAPPER_NO_CONTRACT;
1481 Emit(CEE_LDSFLD, 1, token);
1483 void ILCodeStream::EmitLDSFLDA(int token)
1485 WRAPPER_NO_CONTRACT;
1486 Emit(CEE_LDSFLDA, 1, token);
1488 void ILCodeStream::EmitLDTOKEN(int token)
1490 WRAPPER_NO_CONTRACT;
1491 Emit(CEE_LDTOKEN, 1, token);
1493 void ILCodeStream::EmitLEAVE(ILCodeLabel* pCodeLabel)
1495 WRAPPER_NO_CONTRACT;
1496 Emit(CEE_LEAVE, 0, (UINT_PTR)pCodeLabel);
1498 void ILCodeStream::EmitLOCALLOC()
1500 WRAPPER_NO_CONTRACT;
1501 Emit(CEE_LOCALLOC, 0, 0);
1503 void ILCodeStream::EmitMUL()
1505 WRAPPER_NO_CONTRACT;
1506 Emit(CEE_MUL, -1, 0);
1508 void ILCodeStream::EmitMUL_OVF()
1510 WRAPPER_NO_CONTRACT;
1511 Emit(CEE_MUL_OVF, -1, 0);
1513 void ILCodeStream::EmitNEWOBJ(int token, int numInArgs)
1515 WRAPPER_NO_CONTRACT;
1516 Emit(CEE_NEWOBJ, (INT16)(1 - numInArgs), token);
1519 void ILCodeStream::EmitNOP(LPCSTR pszNopComment)
1521 WRAPPER_NO_CONTRACT;
1522 Emit(CEE_NOP, 0, (UINT_PTR)pszNopComment);
1525 void ILCodeStream::EmitPOP()
1527 WRAPPER_NO_CONTRACT;
1528 Emit(CEE_POP, -1, 0);
1530 void ILCodeStream::EmitRET()
1532 WRAPPER_NO_CONTRACT;
1533 INT16 iStackDelta = m_pOwner->ReturnOpcodePopsStack() ? -1 : 0;
1534 Emit(CEE_RET, iStackDelta, 0);
1536 void ILCodeStream::EmitSHR_UN()
1538 WRAPPER_NO_CONTRACT;
1539 Emit(CEE_SHR_UN, -1, 0);
1541 void ILCodeStream::EmitSTARG(unsigned uArgIdx)
1543 WRAPPER_NO_CONTRACT;
1544 Emit(CEE_STARG, -1, uArgIdx);
1546 void ILCodeStream::EmitSTELEM_REF()
1548 WRAPPER_NO_CONTRACT;
1549 Emit(CEE_STELEM_REF, -3, 0);
1551 void ILCodeStream::EmitSTIND_I()
1553 WRAPPER_NO_CONTRACT;
1554 Emit(CEE_STIND_I, -2, 0);
1556 void ILCodeStream::EmitSTIND_I1()
1558 WRAPPER_NO_CONTRACT;
1559 Emit(CEE_STIND_I1, -2, 0);
1561 void ILCodeStream::EmitSTIND_I2()
1563 WRAPPER_NO_CONTRACT;
1564 Emit(CEE_STIND_I2, -2, 0);
1566 void ILCodeStream::EmitSTIND_I4()
1568 WRAPPER_NO_CONTRACT;
1569 Emit(CEE_STIND_I4, -2, 0);
1571 void ILCodeStream::EmitSTIND_I8()
1573 WRAPPER_NO_CONTRACT;
1574 Emit(CEE_STIND_I8, -2, 0);
1576 void ILCodeStream::EmitSTIND_R4()
1578 WRAPPER_NO_CONTRACT;
1579 Emit(CEE_STIND_R4, -2, 0);
1581 void ILCodeStream::EmitSTIND_R8()
1583 WRAPPER_NO_CONTRACT;
1584 Emit(CEE_STIND_R8, -2, 0);
1586 void ILCodeStream::EmitSTIND_REF()
1588 WRAPPER_NO_CONTRACT;
1589 Emit(CEE_STIND_REF, -2, 0);
1591 void ILCodeStream::EmitSTIND_T(LocalDesc* pType)
1595 PRECONDITION(pType->cbType >= 1);
1599 CorElementType elementType = ELEMENT_TYPE_END;
1601 bool onlyFoundModifiers = true;
1602 for(size_t i = 0; i < pType->cbType && onlyFoundModifiers; i++)
1604 elementType = (CorElementType)pType->ElementType[i];
1605 onlyFoundModifiers = (elementType == ELEMENT_TYPE_PINNED);
1607 switch (pType->ElementType[0])
1609 case ELEMENT_TYPE_I1: EmitSTIND_I1(); break;
1610 case ELEMENT_TYPE_BOOLEAN: // fall through
1611 case ELEMENT_TYPE_U1: EmitSTIND_I1(); break;
1612 case ELEMENT_TYPE_I2: EmitSTIND_I2(); break;
1613 case ELEMENT_TYPE_CHAR: // fall through
1614 case ELEMENT_TYPE_U2: EmitSTIND_I2(); break;
1615 case ELEMENT_TYPE_I4: EmitSTIND_I4(); break;
1616 case ELEMENT_TYPE_U4: EmitSTIND_I4(); break;
1617 case ELEMENT_TYPE_I8: EmitSTIND_I8(); break;
1618 case ELEMENT_TYPE_U8: EmitSTIND_I8(); break;
1619 case ELEMENT_TYPE_R4: EmitSTIND_R4(); break;
1620 case ELEMENT_TYPE_R8: EmitSTIND_R8(); break;
1621 case ELEMENT_TYPE_PTR: // same as ELEMENT_TYPE_I
1622 case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
1623 case ELEMENT_TYPE_I: EmitSTIND_I(); break;
1624 case ELEMENT_TYPE_U: EmitSTIND_I(); break;
1625 case ELEMENT_TYPE_STRING: // fall through
1626 case ELEMENT_TYPE_CLASS: // fall through
1627 case ELEMENT_TYPE_ARRAY:
1628 case ELEMENT_TYPE_SZARRAY:
1629 case ELEMENT_TYPE_OBJECT: EmitSTIND_REF(); break;
1631 case ELEMENT_TYPE_INTERNAL:
1633 CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
1639 UNREACHABLE_MSG("unexpected type passed to EmitSTIND_T");
1643 void ILCodeStream::EmitSTFLD(int token)
1645 WRAPPER_NO_CONTRACT;
1646 Emit(CEE_STFLD, -2, token);
1648 void ILCodeStream::EmitSTLOC(DWORD dwLocalNum)
1650 WRAPPER_NO_CONTRACT;
1651 Emit(CEE_STLOC, -1, dwLocalNum);
1653 void ILCodeStream::EmitSTOBJ(int token)
1655 WRAPPER_NO_CONTRACT;
1656 Emit(CEE_STOBJ, -2, token);
1658 void ILCodeStream::EmitSTSFLD(int token)
1660 WRAPPER_NO_CONTRACT;
1661 Emit(CEE_STSFLD, -1, token);
1663 void ILCodeStream::EmitSUB()
1665 WRAPPER_NO_CONTRACT;
1666 Emit(CEE_SUB, -1, 0);
1668 void ILCodeStream::EmitTHROW()
1670 WRAPPER_NO_CONTRACT;
1671 Emit(CEE_THROW, -1, 0);
1675 void ILCodeStream::EmitNEWOBJ(BinderMethodID id, int numInArgs)
1677 STANDARD_VM_CONTRACT;
1678 EmitNEWOBJ(GetToken(MscorlibBinder::GetMethod(id)), numInArgs);
1681 void ILCodeStream::EmitCALL(BinderMethodID id, int numInArgs, int numRetArgs)
1683 STANDARD_VM_CONTRACT;
1684 EmitCALL(GetToken(MscorlibBinder::GetMethod(id)), numInArgs, numRetArgs);
1687 void ILStubLinker::SetHasThis (bool fHasThis)
1689 LIMITED_METHOD_CONTRACT;
1690 m_fHasThis = fHasThis;
1693 void ILCodeStream::EmitLoadThis ()
1695 WRAPPER_NO_CONTRACT;
1696 _ASSERTE(m_pOwner->m_fHasThis);
1697 // OK, this is ugly, but we add 1 to all LDARGs when
1698 // m_fHasThis is true, so we compensate for that here
1699 // so that we don't have to have a special method to
1701 EmitLDARG((unsigned)-1);
1704 void ILCodeStream::EmitLoadNullPtr()
1706 WRAPPER_NO_CONTRACT;
1708 // This is the correct way to load unmanaged zero pointer. EmitLDC(0) alone works
1709 // fine in most cases but may lead to wrong code being generated on 64-bit if the
1710 // flow graph is complex.
1715 void ILCodeStream::EmitArgIteratorCreateAndLoad()
1717 STANDARD_VM_CONTRACT;
1720 // we insert the ArgIterator in the same spot that the VASigCookie will go for sanity
1722 LocalDesc aiLoc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
1725 aiLocNum = NewLocal(aiLoc);
1727 EmitLDLOCA(aiLocNum);
1731 EmitCALL(METHOD__ARG_ITERATOR__CTOR2, 2, 0);
1733 aiLoc.ElementType[0] = ELEMENT_TYPE_BYREF;
1734 aiLoc.ElementType[1] = ELEMENT_TYPE_INTERNAL;
1736 aiLoc.InternalToken = MscorlibBinder::GetClass(CLASS__ARG_ITERATOR);
1738 SetStubTargetArgType(&aiLoc, false);
1741 DWORD ILStubLinker::NewLocal(CorElementType typ)
1746 INJECT_FAULT(COMPlusThrowOM());
1750 LocalDesc locDesc(typ);
1751 return NewLocal(locDesc);
1754 StubSigBuilder::StubSigBuilder() :
1758 STANDARD_VM_CONTRACT;
1760 m_pbSigCursor = (BYTE*) m_qbSigBuffer.AllocThrows(INITIAL_BUFFER_SIZE);
1763 void StubSigBuilder::EnsureEnoughQuickBytes(size_t cbToAppend)
1765 STANDARD_VM_CONTRACT;
1767 SIZE_T cbBuffer = m_qbSigBuffer.Size();
1768 if ((m_cbSig + cbToAppend) >= cbBuffer)
1770 m_qbSigBuffer.ReSizeThrows(2 * cbBuffer);
1771 m_pbSigCursor = ((BYTE*)m_qbSigBuffer.Ptr()) + m_cbSig;
1775 DWORD StubSigBuilder::Append(LocalDesc* pLoc)
1780 INJECT_FAULT(COMPlusThrowOM());
1781 PRECONDITION(CheckPointer(pLoc));
1785 EnsureEnoughQuickBytes(pLoc->cbType + sizeof(TypeHandle));
1787 memcpyNoGCRefs(m_pbSigCursor, pLoc->ElementType, pLoc->cbType);
1788 m_pbSigCursor += pLoc->cbType;
1789 m_cbSig += pLoc->cbType;
1793 while (i < pLoc->cbType)
1795 CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
1796 && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1798 switch (pLoc->ElementType[i])
1800 case ELEMENT_TYPE_INTERNAL:
1801 SET_UNALIGNED_PTR(m_pbSigCursor, (UINT_PTR)pLoc->InternalToken.AsPtr());
1802 m_pbSigCursor += sizeof(TypeHandle);
1803 m_cbSig += sizeof(TypeHandle);
1806 case ELEMENT_TYPE_FNPTR:
1808 SigPointer ptr(pLoc->pSig);
1810 SigBuilder sigBuilder;
1811 ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1814 PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1816 EnsureEnoughQuickBytes(cbFnPtrSig);
1818 memcpyNoGCRefs(m_pbSigCursor, pFnPtrSig, cbFnPtrSig);
1820 m_pbSigCursor += cbFnPtrSig;
1821 m_cbSig += cbFnPtrSig;
1832 if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1834 EnsureEnoughQuickBytes(pLoc->cbArrayBoundsInfo);
1836 memcpyNoGCRefs(m_pbSigCursor, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1837 m_pbSigCursor += pLoc->cbArrayBoundsInfo;
1838 m_cbSig += pLoc->cbArrayBoundsInfo;
1841 _ASSERTE(m_cbSig <= m_qbSigBuffer.Size()); // we corrupted our buffer resizing if this assert fires
1846 //---------------------------------------------------------------------------------------
1849 LocalSigBuilder::GetSigSize()
1851 STANDARD_VM_CONTRACT;
1854 UINT32 cbEncoded = CorSigCompressData(m_nItems, temp);
1856 S_UINT32 cbSigSize =
1857 S_UINT32(1) + // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
1858 S_UINT32(cbEncoded) + // encoded number of locals
1859 S_UINT32(m_cbSig) + // types
1860 S_UINT32(1); // ELEMENT_TYPE_END
1861 if (cbSigSize.IsOverflow())
1863 IfFailThrow(COR_E_OVERFLOW);
1865 return cbSigSize.Value();
1868 //---------------------------------------------------------------------------------------
1871 LocalSigBuilder::GetSig(
1875 STANDARD_VM_CONTRACT;
1877 size_t cb = CorSigCompressData(m_nItems, temp);
1879 _ASSERTE((1 + cb + m_cbSig + 1) == GetSigSize());
1881 if ((1 + cb + m_cbSig + 1) <= cbBuffer)
1883 pbLocalSig[0] = IMAGE_CEE_CS_CALLCONV_LOCAL_SIG;
1884 memcpyNoGCRefs(&pbLocalSig[1], temp, cb);
1885 memcpyNoGCRefs(&pbLocalSig[1 + cb], m_qbSigBuffer.Ptr(), m_cbSig);
1886 pbLocalSig[1 + cb + m_cbSig] = ELEMENT_TYPE_END;
1887 return (DWORD)(1 + cb + m_cbSig + 1);
1895 FunctionSigBuilder::FunctionSigBuilder() :
1896 m_callingConv(IMAGE_CEE_CS_CALLCONV_DEFAULT)
1898 STANDARD_VM_CONTRACT;
1899 m_qbReturnSig.ReSizeThrows(1);
1900 *(CorElementType *)m_qbReturnSig.Ptr() = ELEMENT_TYPE_VOID;
1904 void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc)
1909 PRECONDITION(pLoc->cbType > 0);
1913 m_qbReturnSig.ReSizeThrows(pLoc->cbType);
1914 memcpyNoGCRefs(m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType);
1918 while (i < pLoc->cbType)
1920 CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
1921 && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
1923 switch (pLoc->ElementType[i])
1925 case ELEMENT_TYPE_INTERNAL:
1926 m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + sizeof(TypeHandle));
1927 SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - + sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr());
1930 case ELEMENT_TYPE_FNPTR:
1932 SigPointer ptr(pLoc->pSig);
1934 SigBuilder sigBuilder;
1935 ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
1938 PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
1940 m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + cbFnPtrSig);
1942 memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - cbFnPtrSig, pFnPtrSig, cbFnPtrSig);
1953 if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
1955 SIZE_T size = m_qbReturnSig.Size();
1956 m_qbReturnSig.ReSizeThrows(size + pLoc->cbArrayBoundsInfo);
1957 memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + size, pLoc->pSig, pLoc->cbArrayBoundsInfo);
1961 void FunctionSigBuilder::SetSig(PCCOR_SIGNATURE pSig, DWORD cSig)
1963 STANDARD_VM_CONTRACT;
1965 // parse the incoming signature
1966 SigPointer sigPtr(pSig, cSig);
1968 // 1) calling convention
1970 IfFailThrow(sigPtr.GetCallingConvInfo(&callConv));
1971 SetCallingConv((CorCallingConvention)callConv);
1973 // 2) number of parameters
1974 IfFailThrow(sigPtr.GetData(&m_nItems));
1977 PCCOR_SIGNATURE ptr = sigPtr.GetPtr();
1978 IfFailThrow(sigPtr.SkipExactlyOne());
1980 size_t retSigLength = sigPtr.GetPtr() - ptr;
1982 m_qbReturnSig.ReSizeThrows(retSigLength);
1983 memcpyNoGCRefs(m_qbReturnSig.Ptr(), ptr, retSigLength);
1988 size_t cbSigLen = (cSig - (sigPtr.GetPtr() - pSig));
1990 m_pbSigCursor = (BYTE *)m_qbSigBuffer.Ptr();
1991 EnsureEnoughQuickBytes(cbSigLen);
1993 memcpyNoGCRefs(m_pbSigCursor, sigPtr.GetPtr(), cbSigLen);
1996 m_pbSigCursor += cbSigLen;
1999 //---------------------------------------------------------------------------------------
2002 FunctionSigBuilder::GetSigSize()
2004 STANDARD_VM_CONTRACT;
2007 DWORD cbEncodedLen = CorSigCompressData(m_nItems, temp);
2008 SIZE_T cbEncodedRetType = m_qbReturnSig.Size();
2010 CONSISTENCY_CHECK(cbEncodedRetType > 0);
2012 S_UINT32 cbSigSize =
2013 S_UINT32(1) + // calling convention
2014 S_UINT32(cbEncodedLen) + // encoded number of args
2015 S_UINT32(cbEncodedRetType) + // encoded return type
2016 S_UINT32(m_cbSig) + // types
2017 S_UINT32(1); // ELEMENT_TYPE_END
2018 if (cbSigSize.IsOverflow())
2020 IfFailThrow(COR_E_OVERFLOW);
2022 return cbSigSize.Value();
2025 //---------------------------------------------------------------------------------------
2028 FunctionSigBuilder::GetSig(
2032 STANDARD_VM_CONTRACT;
2034 size_t cbEncodedLen = CorSigCompressData(m_nItems, tempLen);
2035 size_t cbEncodedRetType = m_qbReturnSig.Size();
2037 CONSISTENCY_CHECK(cbEncodedRetType > 0);
2039 _ASSERTE((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) == GetSigSize());
2041 if ((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) <= cbBuffer)
2043 BYTE* pbCursor = pbLocalSig;
2044 *pbCursor = static_cast<BYTE>(m_callingConv);
2047 memcpyNoGCRefs(pbCursor, tempLen, cbEncodedLen);
2048 pbCursor += cbEncodedLen;
2050 memcpyNoGCRefs(pbCursor, m_qbReturnSig.Ptr(), m_qbReturnSig.Size());
2051 pbCursor += m_qbReturnSig.Size();
2053 memcpyNoGCRefs(pbCursor, m_qbSigBuffer.Ptr(), m_cbSig);
2054 pbCursor += m_cbSig;
2055 pbCursor[0] = ELEMENT_TYPE_END;
2056 return (DWORD)(1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1);
2064 DWORD ILStubLinker::NewLocal(LocalDesc loc)
2066 WRAPPER_NO_CONTRACT;
2068 return m_localSigBuilder.NewLocal(&loc);
2071 //---------------------------------------------------------------------------------------
2074 ILStubLinker::GetLocalSigSize()
2076 LIMITED_METHOD_CONTRACT;
2078 return m_localSigBuilder.GetSigSize();
2081 //---------------------------------------------------------------------------------------
2084 ILStubLinker::GetLocalSig(
2088 STANDARD_VM_CONTRACT;
2090 DWORD dwRet = m_localSigBuilder.GetSig(pbLocalSig, cbBuffer);
2094 //---------------------------------------------------------------------------------------
2097 ILStubLinker::GetStubTargetMethodSigSize()
2099 STANDARD_VM_CONTRACT;
2101 return m_nativeFnSigBuilder.GetSigSize();
2104 //---------------------------------------------------------------------------------------
2107 ILStubLinker::GetStubTargetMethodSig(
2111 LIMITED_METHOD_CONTRACT;
2113 DWORD dwRet = m_nativeFnSigBuilder.GetSig(pbSig, cbSig);
2117 void ILStubLinker::SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
2119 STANDARD_VM_CONTRACT;
2121 m_nativeFnSigBuilder.SetSig(pSig, cSig);
2124 static BOOL SigHasVoidReturnType(const Signature &signature)
2133 SigPointer ptr = signature.CreateSigPointer();
2136 IfFailThrow(ptr.GetCallingConvInfo(&data));
2137 // Skip number of type arguments
2138 if (data & IMAGE_CEE_CS_CALLCONV_GENERIC)
2140 IfFailThrow(ptr.GetData(NULL));
2143 // skip number of args
2144 IfFailThrow(ptr.GetData(NULL));
2146 CorElementType retType;
2147 IfFailThrow(ptr.PeekElemType(&retType));
2149 return (ELEMENT_TYPE_VOID == retType);
2153 ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD,
2154 BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub, BOOL fIsReverseStub) :
2155 m_pCodeStreamList(NULL),
2156 m_stubSig(signature),
2157 m_pTypeContext(pTypeContext),
2159 m_pStubSigModule(pStubSigModule),
2161 m_StubHasVoidReturnType(FALSE),
2162 m_fIsReverseStub(fIsReverseStub),
2163 m_iTargetStackDelta(0),
2164 m_cbCurrentCompressedSigLen(1),
2173 INJECT_FAULT(COMPlusThrowOM());
2177 m_managedSigPtr = signature.CreateSigPointer();
2178 if (!signature.IsEmpty())
2180 // Until told otherwise, assume that the stub has the same return type as the signature.
2181 m_StubHasVoidReturnType = SigHasVoidReturnType(signature);
2182 m_StubTargetHasVoidReturnType = m_StubHasVoidReturnType;
2185 // Get the stub's calling convention. Set m_fHasThis to match
2186 // IMAGE_CEE_CS_CALLCONV_HASTHIS.
2189 ULONG uStubCallingConvInfo;
2190 IfFailThrow(m_managedSigPtr.GetCallingConvInfo(&uStubCallingConvInfo));
2198 // If target calling convention was specified, use it instead.
2199 // Otherwise, derive one based on the stub's signature.
2202 ULONG uCallingConvInfo = uStubCallingConvInfo;
2204 ULONG uCallingConv = (uCallingConvInfo & IMAGE_CEE_CS_CALLCONV_MASK);
2205 ULONG uNativeCallingConv;
2207 if (IMAGE_CEE_CS_CALLCONV_VARARG == uCallingConv)
2210 // If we have a PInvoke stub that has a VARARG calling convention
2211 // we will transition to a NATIVEVARARG calling convention for the
2212 // target call. The JIT64 knows about this calling convention,
2213 // basically it is the same as the managed vararg calling convention
2214 // except without a VASigCookie.
2216 // If our stub is not a PInvoke stub and has a vararg calling convention,
2217 // we are most likely going to have to forward those variable arguments
2218 // on to our call target. Unfortunately, callsites to varargs methods
2219 // in IL always have full signatures (that's where the VASigCookie comes
2220 // from). But we don't have that in this case, so we play some tricks and
2221 // pass an ArgIterator down to an assembly routine that pulls out the
2222 // variable arguments and puts them in the right spot before forwarding
2223 // to the stub target.
2225 // The net result is that we don't want to set the native calling
2226 // convention to be vararg for non-PInvoke stubs, so we just use
2227 // the default callconv.
2229 if (!fIsNDirectStub)
2230 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2232 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG;
2236 uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
2239 if (fTargetHasThis && !fIsNDirectStub)
2241 // ndirect native sig never has a 'this' pointer
2242 uNativeCallingConv |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
2247 m_iTargetStackDelta--;
2250 m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv);
2252 if (uStubCallingConvInfo & IMAGE_CEE_CS_CALLCONV_GENERIC)
2253 IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of type parameters
2255 IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of parameters
2256 IfFailThrow(m_managedSigPtr.SkipExactlyOne()); // skip return type
2260 ILStubLinker::~ILStubLinker()
2270 DeleteCodeStreams();
2273 void ILStubLinker::DeleteCodeLabels()
2284 // walk the list of labels and free each one
2286 ILCodeLabel* pCurrent = m_pLabelList;
2289 ILCodeLabel* pDeleteMe = pCurrent;
2290 pCurrent = pCurrent->m_pNext;
2293 m_pLabelList = NULL;
2296 void ILStubLinker::DeleteCodeStreams()
2306 ILCodeStream* pCurrent = m_pCodeStreamList;
2309 ILCodeStream* pDeleteMe = pCurrent;
2310 pCurrent = pCurrent->m_pNextStream;
2313 m_pCodeStreamList = NULL;
2316 void ILStubLinker::ClearCodeStreams()
2326 ILCodeStream* pCurrent = m_pCodeStreamList;
2329 pCurrent->ClearCode();
2330 pCurrent = pCurrent->m_pNextStream;
2334 void ILStubLinker::GetStubReturnType(LocalDesc* pLoc)
2336 WRAPPER_NO_CONTRACT;
2338 GetStubReturnType(pLoc, m_pStubSigModule);
2341 void ILStubLinker::GetStubReturnType(LocalDesc* pLoc, Module* pModule)
2343 STANDARD_VM_CONTRACT;
2344 SigPointer ptr = m_stubSig.CreateSigPointer();
2349 IfFailThrow(ptr.GetCallingConvInfo(&uCallingConv));
2351 if (uCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2352 IfFailThrow(ptr.GetData((ULONG*)&nTypeArgs));
2354 IfFailThrow(ptr.GetData((ULONG*)&nArgs));
2356 GetManagedTypeHelper(pLoc, pModule, ptr.GetPtr(), m_pTypeContext, m_pMD);
2359 CorCallingConvention ILStubLinker::GetStubTargetCallingConv()
2361 LIMITED_METHOD_CONTRACT;
2362 return m_nativeFnSigBuilder.GetCallingConv();
2365 void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc)
2367 STANDARD_VM_CONTRACT;
2368 // Turn everything into blittable primitives. The reason this method is needed are
2369 // byrefs which are OK only when they ref stack data or are pinned. This condition
2370 // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid
2372 switch (pLoc->ElementType[0])
2375 case ELEMENT_TYPE_VOID:
2376 case ELEMENT_TYPE_BOOLEAN:
2377 case ELEMENT_TYPE_CHAR:
2378 case ELEMENT_TYPE_I1:
2379 case ELEMENT_TYPE_U1:
2380 case ELEMENT_TYPE_I2:
2381 case ELEMENT_TYPE_U2:
2382 case ELEMENT_TYPE_I4:
2383 case ELEMENT_TYPE_U4:
2384 case ELEMENT_TYPE_I8:
2385 case ELEMENT_TYPE_U8:
2386 case ELEMENT_TYPE_R4:
2387 case ELEMENT_TYPE_R8:
2388 case ELEMENT_TYPE_I:
2389 case ELEMENT_TYPE_U:
2391 // no transformation needed
2395 case ELEMENT_TYPE_VALUETYPE:
2397 _ASSERTE(!"Should have been replaced by a native value type!");
2401 case ELEMENT_TYPE_PTR:
2404 if (pLoc->bIsCopyConstructed)
2406 // The only pointers that we don't transform to ELEMENT_TYPE_I are those that are
2407 // ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
2408 // in the original signature. This convention is understood by the UM thunk compiler
2409 // (code:UMThunkMarshInfo.CompileNExportThunk) which will generate different thunk code.
2410 // Such parameters come from unmanaged by value but must enter the IL stub by reference
2411 // because we are not supposed to make a copy.
2414 #endif // _TARGET_X86_
2416 pLoc->ElementType[0] = ELEMENT_TYPE_I;
2422 case ELEMENT_TYPE_INTERNAL:
2424 // JIT will handle structures
2425 if (pLoc->InternalToken.IsValueType())
2427 _ASSERTE(pLoc->InternalToken.IsBlittable());
2430 // intentional fall-thru
2433 // pointers, byrefs, strings, arrays, other ref types -> ELEMENT_TYPE_I
2436 pLoc->ElementType[0] = ELEMENT_TYPE_I;
2443 Module *ILStubLinker::GetStubSigModule()
2445 LIMITED_METHOD_CONTRACT;
2446 return m_pStubSigModule;
2449 SigTypeContext *ILStubLinker::GetStubSigTypeContext()
2451 LIMITED_METHOD_CONTRACT;
2452 return m_pTypeContext;
2455 void ILStubLinker::SetStubTargetReturnType(CorElementType typ)
2457 WRAPPER_NO_CONTRACT;
2459 LocalDesc locDesc(typ);
2460 SetStubTargetReturnType(&locDesc);
2463 void ILStubLinker::SetStubTargetReturnType(LocalDesc* pLoc)
2468 WRAPPER(GC_NOTRIGGER);
2470 PRECONDITION(CheckPointer(pLoc, NULL_NOT_OK));
2474 TransformArgForJIT(pLoc);
2476 m_nativeFnSigBuilder.SetReturnType(pLoc);
2478 // Update check for if a stub has a void return type based on the provided return type.
2479 m_StubTargetHasVoidReturnType = ((1 == pLoc->cbType) && (ELEMENT_TYPE_VOID == pLoc->ElementType[0])) ? TRUE : FALSE;
2480 if (!m_StubTargetHasVoidReturnType)
2482 m_iTargetStackDelta++;
2487 DWORD ILStubLinker::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg /*= true*/)
2489 STANDARD_VM_CONTRACT;
2491 LocalDesc locDesc(typ);
2492 return SetStubTargetArgType(&locDesc, fConsumeStubArg);
2495 void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv)
2497 LIMITED_METHOD_CONTRACT;
2498 m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv);
2501 static size_t GetManagedTypeForMDArray(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext)
2507 PRECONDITION(CheckPointer(pLoc));
2508 PRECONDITION(CheckPointer(pModule));
2509 PRECONDITION(CheckPointer(psigManagedArg));
2510 PRECONDITION(*psigManagedArg == ELEMENT_TYPE_ARRAY);
2518 // copy ELEMENT_TYPE_ARRAY
2520 pLoc->ElementType[cbDest] = *psigManagedArg;
2524 ptr.SetSig(psigManagedArg);
2526 IfFailThrow(ptr.SkipCustomModifiers());
2528 psigManagedArg = ptr.GetPtr();
2533 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2535 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2543 PCCOR_SIGNATURE psigNextManagedArg;
2545 // find the start of the next argument
2546 ptr.SetSig(psigManagedArg - 1); // -1 to back up to E_T_ARRAY;
2547 IfFailThrow(ptr.SkipExactlyOne());
2549 psigNextManagedArg = ptr.GetPtr();
2551 // find the start of the array bounds information
2552 ptr.SetSig(psigManagedArg);
2553 IfFailThrow(ptr.SkipExactlyOne());
2555 psigManagedArg = ptr.GetPtr(); // point to the array bounds info
2556 cbType = psigNextManagedArg - psigManagedArg;
2558 pLoc->pSig = psigManagedArg; // point to the array bounds info
2559 pLoc->cbArrayBoundsInfo = cbType; // size of array bounds info
2560 pLoc->cbType = cbDest;
2567 void ILStubLinker::GetManagedTypeHelper(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext, MethodDesc *pMD)
2573 PRECONDITION(CheckPointer(pLoc));
2574 PRECONDITION(CheckPointer(pModule));
2575 PRECONDITION(CheckPointer(psigManagedArg));
2579 SigPointer ptr(psigManagedArg);
2580 CorElementType eType;
2581 LOG((LF_STUBS, LL_INFO10000, "GetManagedTypeHelper on type at %p\n", psigManagedArg));
2583 IfFailThrow(ptr.PeekElemType(&eType));
2587 while (eType == ELEMENT_TYPE_PTR ||
2588 eType == ELEMENT_TYPE_BYREF ||
2589 eType == ELEMENT_TYPE_SZARRAY)
2591 pLoc->ElementType[cbDest] = static_cast<BYTE>(eType);
2594 if (cbDest >= LocalDesc::MAX_LOCALDESC_ELEMENTS)
2596 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2599 IfFailThrow(ptr.GetElemType(NULL));
2600 IfFailThrow(ptr.PeekElemType(&eType));
2603 SigPointer ptr2(ptr);
2604 IfFailThrow(ptr2.SkipCustomModifiers());
2605 psigManagedArg = ptr2.GetPtr();
2609 case ELEMENT_TYPE_VAR:
2610 case ELEMENT_TYPE_MVAR:
2612 IfFailThrow(ptr.GetElemType(NULL)); // skip ET
2614 IfFailThrowBF(ptr.GetData(&varNum), BFA_BAD_COMPLUS_SIG, pModule);
2616 DWORD varCount = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst.GetNumArgs() :
2617 pTypeContext->m_methodInst.GetNumArgs());
2618 THROW_BAD_FORMAT_MAYBE(varNum < varCount, BFA_BAD_COMPLUS_SIG, pModule);
2620 pLoc->InternalToken = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst[varNum] :
2621 pTypeContext->m_methodInst[varNum]);
2623 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2628 case ELEMENT_TYPE_CLASS:
2629 case ELEMENT_TYPE_VALUETYPE:
2630 case ELEMENT_TYPE_INTERNAL:
2632 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2634 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2639 case ELEMENT_TYPE_GENERICINST:
2641 pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
2643 pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
2648 case ELEMENT_TYPE_FNPTR:
2649 // save off a pointer to the managed sig
2650 // we'll convert it in bulk when we store it
2651 // in the generated sig
2652 pLoc->pSigModule = pModule;
2653 pLoc->pSig = psigManagedArg+1;
2655 pLoc->ElementType[cbDest] = ELEMENT_TYPE_FNPTR;
2659 case ELEMENT_TYPE_ARRAY:
2660 cbDest = GetManagedTypeForMDArray(pLoc, pModule, psigManagedArg, pTypeContext);
2666 PCCOR_SIGNATURE psigNextManagedArg;
2668 IfFailThrow(ptr.SkipExactlyOne());
2670 psigNextManagedArg = ptr.GetPtr();
2671 cbType = psigNextManagedArg - psigManagedArg;
2674 if (!ClrSafeInt<size_t>::addition(cbDest, cbType, cbNewDest) ||
2675 cbNewDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2677 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2680 memcpyNoGCRefs(&pLoc->ElementType[cbDest], psigManagedArg, cbType);
2686 if (cbDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
2688 COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
2691 pLoc->cbType = cbDest;
2694 void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc)
2699 PRECONDITION(CheckPointer(pLoc));
2703 GetStubTargetReturnType(pLoc, m_pStubSigModule);
2706 void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc, Module* pModule)
2711 PRECONDITION(CheckPointer(pLoc));
2712 PRECONDITION(CheckPointer(pModule));
2716 GetManagedTypeHelper(pLoc, pModule, m_nativeFnSigBuilder.GetReturnSig(), m_pTypeContext, NULL);
2719 void ILStubLinker::GetStubArgType(LocalDesc* pLoc)
2725 PRECONDITION(CheckPointer(pLoc));
2729 GetStubArgType(pLoc, m_pStubSigModule);
2732 void ILStubLinker::GetStubArgType(LocalDesc* pLoc, Module* pModule)
2738 PRECONDITION(CheckPointer(pLoc));
2739 PRECONDITION(CheckPointer(pModule));
2743 GetManagedTypeHelper(pLoc, pModule, m_managedSigPtr.GetPtr(), m_pTypeContext, m_pMD);
2746 //---------------------------------------------------------------------------------------
2749 ILStubLinker::SetStubTargetArgType(
2750 LocalDesc * pLoc, // = NULL
2751 bool fConsumeStubArg) // = true
2753 STANDARD_VM_CONTRACT;
2757 if (fConsumeStubArg)
2759 _ASSERTE(m_pStubSigModule);
2764 GetStubArgType(pLoc, m_pStubSigModule);
2767 IfFailThrow(m_managedSigPtr.SkipExactlyOne());
2770 TransformArgForJIT(pLoc);
2772 DWORD dwArgNum = m_nativeFnSigBuilder.NewArg(pLoc);
2773 m_iTargetStackDelta--;
2776 } // ILStubLinker::SetStubTargetArgType
2778 //---------------------------------------------------------------------------------------
2780 int ILStubLinker::GetToken(MethodDesc* pMD)
2782 STANDARD_VM_CONTRACT;
2783 return m_tokenMap.GetToken(pMD);
2786 int ILStubLinker::GetToken(MethodTable* pMT)
2788 STANDARD_VM_CONTRACT;
2789 return m_tokenMap.GetToken(TypeHandle(pMT));
2792 int ILStubLinker::GetToken(TypeHandle th)
2794 STANDARD_VM_CONTRACT;
2795 return m_tokenMap.GetToken(th);
2798 int ILStubLinker::GetToken(FieldDesc* pFD)
2800 STANDARD_VM_CONTRACT;
2801 return m_tokenMap.GetToken(pFD);
2805 BOOL ILStubLinker::StubHasVoidReturnType()
2807 LIMITED_METHOD_CONTRACT;
2808 return m_StubHasVoidReturnType;
2811 void ILStubLinker::ClearCode()
2826 ILCodeStream* ILStubLinker::FindLastCodeStream(ILCodeStream* pList)
2828 LIMITED_METHOD_CONTRACT;
2835 while (NULL != pList->m_pNextStream)
2837 pList = pList->m_pNextStream;
2843 ILCodeStream* ILStubLinker::NewCodeStream(CodeStreamType codeStreamType)
2845 STANDARD_VM_CONTRACT;
2847 NewHolder<ILCodeStream> pNewCodeStream = new ILCodeStream(this, codeStreamType);
2849 if (NULL == m_pCodeStreamList)
2851 m_pCodeStreamList = pNewCodeStream;
2855 ILCodeStream* pTail = FindLastCodeStream(m_pCodeStreamList);
2856 CONSISTENCY_CHECK(NULL == pTail->m_pNextStream);
2857 pTail->m_pNextStream = pNewCodeStream;
2860 pNewCodeStream.SuppressRelease();
2861 return pNewCodeStream;
2864 int ILCodeStream::GetToken(MethodDesc* pMD)
2866 STANDARD_VM_CONTRACT;
2867 return m_pOwner->GetToken(pMD);
2869 int ILCodeStream::GetToken(MethodTable* pMT)
2871 STANDARD_VM_CONTRACT;
2872 return m_pOwner->GetToken(pMT);
2874 int ILCodeStream::GetToken(TypeHandle th)
2876 STANDARD_VM_CONTRACT;
2877 return m_pOwner->GetToken(th);
2879 int ILCodeStream::GetToken(FieldDesc* pFD)
2881 STANDARD_VM_CONTRACT;
2882 return m_pOwner->GetToken(pFD);
2885 DWORD ILCodeStream::NewLocal(CorElementType typ)
2887 STANDARD_VM_CONTRACT;
2888 return m_pOwner->NewLocal(typ);
2890 DWORD ILCodeStream::NewLocal(LocalDesc loc)
2892 WRAPPER_NO_CONTRACT;
2893 return m_pOwner->NewLocal(loc);
2895 DWORD ILCodeStream::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg)
2897 STANDARD_VM_CONTRACT;
2898 return m_pOwner->SetStubTargetArgType(typ, fConsumeStubArg);
2900 DWORD ILCodeStream::SetStubTargetArgType(LocalDesc* pLoc, bool fConsumeStubArg)
2902 STANDARD_VM_CONTRACT;
2903 return m_pOwner->SetStubTargetArgType(pLoc, fConsumeStubArg);
2905 void ILCodeStream::SetStubTargetReturnType(CorElementType typ)
2907 STANDARD_VM_CONTRACT;
2908 m_pOwner->SetStubTargetReturnType(typ);
2910 void ILCodeStream::SetStubTargetReturnType(LocalDesc* pLoc)
2912 STANDARD_VM_CONTRACT;
2913 m_pOwner->SetStubTargetReturnType(pLoc);
2915 ILCodeLabel* ILCodeStream::NewCodeLabel()
2917 STANDARD_VM_CONTRACT;
2918 return m_pOwner->NewCodeLabel();
2920 void ILCodeStream::ClearCode()
2922 LIMITED_METHOD_CONTRACT;