summaryrefslogtreecommitdiff
path: root/src/vm/stubgen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/stubgen.cpp')
-rw-r--r--src/vm/stubgen.cpp2907
1 files changed, 2907 insertions, 0 deletions
diff --git a/src/vm/stubgen.cpp b/src/vm/stubgen.cpp
new file mode 100644
index 0000000000..fffa52a366
--- /dev/null
+++ b/src/vm/stubgen.cpp
@@ -0,0 +1,2907 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: StubGen.cpp
+//
+
+//
+
+
+#include "common.h"
+
+#include "stubgen.h"
+#include "jitinterface.h"
+#include "ilstubcache.h"
+#include "sigbuilder.h"
+
+#include "formattype.h"
+#include "typestring.h"
+
+
+#include "field.h"
+
+//
+// ....[.....\xxxxx]..0... -> ....[xxxxx]..0...
+// ^ ^ ^
+
+void DumpIL_RemoveFullPath(SString &strTokenFormatting)
+{
+ STANDARD_VM_CONTRACT;
+ if (strTokenFormatting.IsEmpty())
+ return;
+
+ SString::Iterator begin = strTokenFormatting.Begin();
+ SString::Iterator end = strTokenFormatting.End();
+ SString::Iterator leftBracket = strTokenFormatting.Begin();
+
+ // Find the first '[' in the string.
+ while ((leftBracket != end) && (*leftBracket != W('[')))
+ {
+ ++leftBracket;
+ }
+
+ if (leftBracket != end)
+ {
+ SString::Iterator lastSlash = strTokenFormatting.End() - 1;
+
+ // Find the last '\\' in the string.
+ while ((lastSlash != leftBracket) && (*lastSlash != W('\\')))
+ {
+ --lastSlash;
+ }
+
+ if (leftBracket != lastSlash)
+ {
+ strTokenFormatting.Delete(leftBracket + 1, lastSlash - leftBracket);
+ }
+ }
+}
+
+void DumpIL_FormatToken(TokenLookupMap* pTokenMap, mdToken token, SString &strTokenFormatting, const SString &strStubTargetSig)
+{
+ void* pvLookupRetVal = (void*)POISONC;
+ _ASSERTE(strTokenFormatting.IsEmpty());
+
+ EX_TRY
+ {
+ if (TypeFromToken(token) == mdtMethodDef)
+ {
+ MethodDesc* pMD = pTokenMap->LookupMethodDef(token);
+ pvLookupRetVal = pMD;
+ CONSISTENCY_CHECK(CheckPointer(pMD));
+
+ pMD->GetFullMethodInfo(strTokenFormatting);
+ }
+ else if (TypeFromToken(token) == mdtTypeDef)
+ {
+ TypeHandle typeHnd = pTokenMap->LookupTypeDef(token);
+ pvLookupRetVal = typeHnd.AsPtr();
+ CONSISTENCY_CHECK(!typeHnd.IsNull());
+
+ SString typeName;
+ MethodTable *pMT = NULL;
+ if (typeHnd.IsTypeDesc())
+ {
+ TypeDesc *pTypeDesc = typeHnd.AsTypeDesc();
+ pMT = pTypeDesc->GetMethodTable();
+ }
+ else
+ {
+ pMT = typeHnd.AsMethodTable();
+ }
+
+ // AppendType handles NULL correctly
+ TypeString::AppendType(typeName, TypeHandle(pMT));
+
+ if (pMT && typeHnd.IsNativeValueType())
+ typeName.Append(W("_NativeValueType"));
+ strTokenFormatting.Set(typeName);
+ }
+ else if (TypeFromToken(token) == mdtFieldDef)
+ {
+ FieldDesc* pFD = pTokenMap->LookupFieldDef(token);
+ pvLookupRetVal = pFD;
+ CONSISTENCY_CHECK(CheckPointer(pFD));
+
+ SString typeName;
+ TypeString::AppendType(typeName, TypeHandle(pFD->GetApproxEnclosingMethodTable()));
+
+ SString strFieldName(SString::Utf8, pFD->GetName());
+ strTokenFormatting.Printf(W("%s::%s"), typeName.GetUnicode(), strFieldName.GetUnicode());
+ }
+ else if (TypeFromToken(token) == mdtModule)
+ {
+ // Do nothing, because strTokenFormatting is already empty.
+ }
+ else if (TypeFromToken(token) == mdtSignature)
+ {
+ CONSISTENCY_CHECK(token == TOKEN_ILSTUB_TARGET_SIG);
+ strTokenFormatting.Set(strStubTargetSig);
+ }
+ else
+ {
+ strTokenFormatting.Printf(W("%d"), token);
+ }
+ DumpIL_RemoveFullPath(strTokenFormatting);
+ }
+ EX_CATCH
+ {
+ strTokenFormatting.Printf(W("%d"), token);
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+}
+
+void ILCodeStream::Emit(ILInstrEnum instr, INT16 iStackDelta, UINT_PTR uArg)
+{
+ STANDARD_VM_CONTRACT;
+
+ UINT idxCurInstr = 0;
+ ILStubLinker::ILInstruction* pInstrBuffer = NULL;
+
+ if (NULL == m_pqbILInstructions)
+ {
+ m_pqbILInstructions = new ILCodeStreamBuffer();
+ }
+
+ idxCurInstr = m_uCurInstrIdx;
+
+ m_uCurInstrIdx++;
+ m_pqbILInstructions->ReSizeThrows(m_uCurInstrIdx * sizeof(ILStubLinker::ILInstruction));
+
+ pInstrBuffer = (ILStubLinker::ILInstruction*)m_pqbILInstructions->Ptr();
+
+ pInstrBuffer[idxCurInstr].uInstruction = static_cast<UINT16>(instr);
+ pInstrBuffer[idxCurInstr].iStackDelta = iStackDelta;
+ pInstrBuffer[idxCurInstr].uArg = uArg;
+}
+
+ILCodeLabel* ILStubLinker::NewCodeLabel()
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeLabel* pCodeLabel = new ILCodeLabel();
+
+ pCodeLabel->m_pNext = m_pLabelList;
+ pCodeLabel->m_pOwningStubLinker = this;
+ pCodeLabel->m_pCodeStreamOfLabel = NULL;
+ pCodeLabel->m_idxLabeledInstruction = -1;
+
+ m_pLabelList = pCodeLabel;
+
+ return pCodeLabel;
+}
+
+void ILCodeStream::EmitLabel(ILCodeLabel* pCodeLabel)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION_MSG(m_pOwner == pCodeLabel->m_pOwningStubLinker, "you can only use a code label in the ILStubLinker that created it!");
+ }
+ CONTRACTL_END;
+
+ pCodeLabel->m_pCodeStreamOfLabel = this;
+ pCodeLabel->m_idxLabeledInstruction = m_uCurInstrIdx;
+
+ Emit(CEE_CODE_LABEL, 0, (UINT_PTR)pCodeLabel);
+}
+
+static const BYTE s_rgbOpcodeSizes[] =
+{
+
+#define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
+ ((l) + (oprType)),
+
+#define InlineNone 0
+#define ShortInlineVar 1
+#define ShortInlineI 1
+#define InlineI 4
+#define InlineI8 8
+#define ShortInlineR 4
+#define InlineR 8
+#define InlineMethod 4
+#define InlineSig 4
+#define ShortInlineBrTarget 1
+#define InlineBrTarget 4
+#define InlineSwitch -1
+#define InlineType 4
+#define InlineString 4
+#define InlineField 4
+#define InlineTok 4
+#define InlineVar 2
+
+#include "opcode.def"
+
+#undef OPDEF
+#undef InlineNone
+#undef ShortInlineVar
+#undef ShortInlineI
+#undef InlineI
+#undef InlineI8
+#undef ShortInlineR
+#undef InlineR
+#undef InlineMethod
+#undef InlineSig
+#undef ShortInlineBrTarget
+#undef InlineBrTarget
+#undef InlineSwitch
+#undef InlineType
+#undef InlineString
+#undef InlineField
+#undef InlineTok
+#undef InlineVar
+
+};
+
+struct ILOpcode
+{
+ BYTE byte1;
+ BYTE byte2;
+};
+
+static const ILOpcode s_rgOpcodes[] =
+{
+
+#define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
+ { (s1), (s2) },
+#include "opcode.def"
+#undef OPDEF
+
+};
+
+ILCodeStream::ILInstrEnum ILCodeStream::LowerOpcode(ILInstrEnum instr, ILStubLinker::ILInstruction* pInstr)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(instr == (ILInstrEnum)pInstr->uInstruction);
+ }
+ CONTRACTL_END;
+
+ //
+ // NOTE: we do not lower branches to their smallest form because that
+ // would introduce extra passes at link time, which isn't really
+ // worth the savings in IL code size.
+ //
+
+ UINT_PTR uConst = pInstr->uArg;
+
+ switch (instr)
+ {
+ case CEE_LDC_I8:
+ {
+ if (uConst == (UINT_PTR)-1)
+ {
+ instr = CEE_LDC_I4_M1;
+ }
+ else
+ if (uConst < 9)
+ {
+ instr = (ILInstrEnum)((UINT_PTR)CEE_LDC_I4_0 + uConst);
+ }
+ else
+ if (FitsInI1(uConst))
+ {
+ instr = CEE_LDC_I4_S;
+ }
+ else
+ if (FitsInI4(uConst))
+ {
+ instr = CEE_LDC_I4;
+ }
+ break;
+ }
+
+ case CEE_LDARG:
+ {
+ if (uConst <= 3)
+ {
+ instr = (ILInstrEnum)((UINT_PTR)CEE_LDARG_0 + uConst);
+ break;
+ }
+ goto lShortForm;
+ }
+ case CEE_LDLOC:
+ {
+ if (uConst <= 3)
+ {
+ instr = (ILInstrEnum)((UINT_PTR)CEE_LDLOC_0 + uConst);
+ break;
+ }
+ goto lShortForm;
+ }
+ case CEE_STLOC:
+ {
+ if (uConst <= 3)
+ {
+ instr = (ILInstrEnum)((UINT_PTR)CEE_STLOC_0 + uConst);
+ break;
+ }
+
+lShortForm:
+ if (FitsInI1(uConst))
+ {
+ static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARG - (UINT_PTR)CEE_LDARG_S);
+ static_assert_no_msg(((UINT_PTR)CEE_LDARG - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARG_S);
+ static_assert_no_msg(((UINT_PTR)CEE_LDLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOC_S);
+ static_assert_no_msg(((UINT_PTR)CEE_STLOC - c_uMakeShortDelta) == (UINT_PTR)CEE_STLOC_S);
+
+ instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
+ }
+ break;
+ }
+
+ case CEE_LDARGA:
+ case CEE_STARG:
+ case CEE_LDLOCA:
+ {
+ if (FitsInI1(uConst))
+ {
+ static const UINT_PTR c_uMakeShortDelta = ((UINT_PTR)CEE_LDARGA - (UINT_PTR)CEE_LDARGA_S);
+ static_assert_no_msg(((UINT_PTR)CEE_LDARGA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDARGA_S);
+ static_assert_no_msg(((UINT_PTR)CEE_STARG - c_uMakeShortDelta) == (UINT_PTR)CEE_STARG_S);
+ static_assert_no_msg(((UINT_PTR)CEE_LDLOCA - c_uMakeShortDelta) == (UINT_PTR)CEE_LDLOCA_S);
+
+ instr = (ILInstrEnum)((UINT_PTR)instr - c_uMakeShortDelta);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ pInstr->uInstruction = static_cast<UINT16>(instr);
+ return instr;
+}
+
+void ILStubLinker::PatchInstructionArgument(ILCodeLabel* pLabel, UINT_PTR uNewArg
+ DEBUG_ARG(UINT16 uExpectedInstruction))
+{
+ LIMITED_METHOD_CONTRACT;
+
+ UINT idx = pLabel->m_idxLabeledInstruction;
+ ILCodeStream* pLabelCodeStream = pLabel->m_pCodeStreamOfLabel;
+ ILInstruction* pLabelInstrBuffer = (ILInstruction*)pLabelCodeStream->m_pqbILInstructions->Ptr();
+
+ CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == ILCodeStream::CEE_CODE_LABEL);
+ CONSISTENCY_CHECK(pLabelInstrBuffer[idx].iStackDelta == 0);
+
+ idx++;
+
+ CONSISTENCY_CHECK(idx < pLabelCodeStream->m_uCurInstrIdx);
+ CONSISTENCY_CHECK(pLabelInstrBuffer[idx].uInstruction == uExpectedInstruction);
+
+ pLabelInstrBuffer[idx].uArg = uNewArg;
+}
+
+ILCodeLabel::ILCodeLabel()
+{
+ m_pNext = NULL;
+ m_pOwningStubLinker = NULL;
+ m_pCodeStreamOfLabel = NULL;
+ m_codeOffset = -1;
+ m_idxLabeledInstruction = -1;
+}
+
+ILCodeLabel::~ILCodeLabel()
+{
+}
+
+size_t ILCodeLabel::GetCodeOffset()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ CONSISTENCY_CHECK(m_codeOffset != (size_t)-1);
+ return m_codeOffset;
+}
+
+
+void ILCodeLabel::SetCodeOffset(size_t codeOffset)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ CONSISTENCY_CHECK((m_codeOffset == (size_t)-1) && (codeOffset != (size_t)-1));
+ m_codeOffset = codeOffset;
+}
+
+static const LPCSTR s_rgOpcodeNames[] =
+{
+#define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
+ string,
+#include "opcode.def"
+#undef OPDEF
+
+};
+
+#include "openum.h"
+
+static const BYTE s_rgbOpcodeArgType[] =
+{
+
+#define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
+ oprType,
+#include "opcode.def"
+#undef OPDEF
+
+};
+
+
+//---------------------------------------------------------------------------------------
+//
+void
+ILStubLinker::LogILInstruction(
+ size_t curOffset,
+ bool isLabeled,
+ INT iCurStack,
+ ILInstruction * pInstruction,
+ SString * pDumpILStubCode)
+{
+ STANDARD_VM_CONTRACT;
+ //
+ // format label
+ //
+ SString strLabel;
+
+ if (isLabeled)
+ {
+ strLabel.Printf(W("IL_%04x:"), curOffset);
+ }
+ else
+ {
+ strLabel.Set(W(" "));
+ }
+
+ //
+ // format opcode
+ //
+ SString strOpcode;
+
+ ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstruction->uInstruction;
+ size_t cbOpcodeName = strlen(s_rgOpcodeNames[instr]);
+ SString strOpcodeName;
+ strOpcodeName.SetUTF8(s_rgOpcodeNames[instr]);
+ // Set the width of the opcode to 15.
+ strOpcode.Set(W(" "));
+ strOpcode.Replace(strOpcode.Begin(), (COUNT_T)cbOpcodeName, strOpcodeName);
+
+ //
+ // format argument
+ //
+
+ static const size_t c_cchPreallocateArgument = 512;
+ SString strArgument;
+ strArgument.Preallocate(c_cchPreallocateArgument);
+
+ static const size_t c_cchPreallocateTokenName = 1024;
+ SString strTokenName;
+ strTokenName.Preallocate(c_cchPreallocateTokenName);
+
+ if (ILCodeStream::IsBranchInstruction(instr))
+ {
+ size_t branchDistance = (size_t)pInstruction->uArg;
+ size_t targetOffset = curOffset + s_rgbOpcodeSizes[instr] + branchDistance;
+ strArgument.Printf(W("IL_%04x"), targetOffset);
+ }
+ else if ((ILCodeStream::ILInstrEnum)CEE_NOP == instr)
+ {
+ SString strInstruction;
+ strInstruction.Printf("%s", (char *)pInstruction->uArg);
+ strInstruction.ConvertToUnicode(strArgument);
+ }
+ else
+ {
+ switch (s_rgbOpcodeArgType[instr])
+ {
+ case InlineNone:
+ break;
+
+ case ShortInlineVar:
+ case ShortInlineI:
+ case InlineI:
+ strArgument.Printf(W("0x%x"), pInstruction->uArg);
+ break;
+
+ case InlineI8:
+ strArgument.Printf(W("0x%p"), (void *)pInstruction->uArg);
+ break;
+
+ case InlineMethod:
+ case InlineField:
+ case InlineType:
+ case InlineString:
+ case InlineSig:
+ case InlineRVA:
+ case InlineTok:
+ // No token value when we dump IL for ETW
+ if (pDumpILStubCode == NULL)
+ strArgument.Printf(W("0x%08x"), pInstruction->uArg);
+
+ LPUTF8 pszFormattedStubTargetSig = NULL;
+ CQuickBytes qbTargetSig;
+
+ if (TOKEN_ILSTUB_TARGET_SIG == pInstruction->uArg)
+ {
+ PCCOR_SIGNATURE pTargetSig;
+ ULONG cTargetSig;
+ CQuickBytes qbTempTargetSig;
+
+ IMDInternalImport * pIMDI = MscorlibBinder::GetModule()->GetMDImport();
+
+ cTargetSig = GetStubTargetMethodSigSize();
+ pTargetSig = (PCCOR_SIGNATURE)qbTempTargetSig.AllocThrows(cTargetSig);
+
+ GetStubTargetMethodSig((BYTE*)pTargetSig, cTargetSig);
+ PrettyPrintSig(pTargetSig, cTargetSig, "", &qbTargetSig, pIMDI, NULL);
+
+ pszFormattedStubTargetSig = (LPUTF8)qbTargetSig.Ptr();
+ }
+
+ // Dump to szTokenNameBuffer if logging, otherwise dump to szArgumentBuffer to avoid an extra space because we are omitting the token
+ _ASSERTE(FitsIn<mdToken>(pInstruction->uArg));
+ SString strFormattedStubTargetSig;
+ strFormattedStubTargetSig.SetUTF8(pszFormattedStubTargetSig);
+ if (pDumpILStubCode == NULL)
+ DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strTokenName, strFormattedStubTargetSig);
+ else
+ DumpIL_FormatToken(&m_tokenMap, static_cast<mdToken>(pInstruction->uArg), strArgument, strFormattedStubTargetSig);
+
+ break;
+ }
+ }
+
+ //
+ // log it!
+ //
+ if (pDumpILStubCode)
+ {
+ pDumpILStubCode->AppendPrintf(W("%s /*(%2d)*/ %s %s %s\n"), strLabel.GetUnicode(), iCurStack, strOpcode.GetUnicode(),
+ strArgument.GetUnicode(), strTokenName.GetUnicode());
+ }
+ else
+ {
+ StackScratchBuffer strLabelBuffer;
+ StackScratchBuffer strOpcodeBuffer;
+ StackScratchBuffer strArgumentBuffer;
+ StackScratchBuffer strTokenNameBuffer;
+ LOG((LF_STUBS, LL_INFO1000, "%s (%2d) %s %s %s\n", strLabel.GetUTF8(strLabelBuffer), iCurStack, \
+ strOpcode.GetUTF8(strOpcodeBuffer), strArgument.GetUTF8(strArgumentBuffer), strTokenName.GetUTF8(strTokenNameBuffer)));
+ }
+} // ILStubLinker::LogILInstruction
+
+//---------------------------------------------------------------------------------------
+//
+void
+ILStubLinker::LogILStubWorker(
+ ILInstruction * pInstrBuffer,
+ UINT numInstr,
+ size_t * pcbCode,
+ INT * piCurStack,
+ SString * pDumpILStubCode)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pcbCode));
+ PRECONDITION(CheckPointer(piCurStack));
+ PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ bool isLabeled = false;
+
+ for (UINT i = 0; i < numInstr; i++)
+ {
+ ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
+ CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
+
+ if (instr == ILCodeStream::CEE_CODE_LABEL)
+ {
+ isLabeled = true;
+ continue;
+ }
+
+ LogILInstruction(*pcbCode, isLabeled, *piCurStack, &pInstrBuffer[i], pDumpILStubCode);
+ isLabeled = false;
+
+ //
+ // calculate the code size
+ //
+ PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
+ *pcbCode += s_rgbOpcodeSizes[instr];
+
+ //
+ // calculate curstack
+ //
+ *piCurStack += pInstrBuffer[i].iStackDelta;
+ }
+
+ // Be sure to log any trailing label that has no associated instruction.
+ if (isLabeled)
+ {
+ if (pDumpILStubCode)
+ {
+ pDumpILStubCode->AppendPrintf(W("IL_%04x:\n"), *pcbCode);
+ }
+ else
+ {
+ LOG((LF_STUBS, LL_INFO1000, "IL_%04x:\n", *pcbCode));
+ }
+ }
+}
+
+static inline void LogOneFlag(DWORD flags, DWORD flag, LPCSTR str, DWORD facility, DWORD level)
+{
+ if (flags & flag)
+ {
+ LOG((facility, level, str));
+ }
+}
+
+static void LogJitFlags(DWORD facility, DWORD level, DWORD dwJitFlags)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ }
+ CONTRACTL_END;
+
+ LOG((facility, level, "dwJitFlags: 0x%08x\n", dwJitFlags));
+
+#define LOG_FLAG(name) LogOneFlag(dwJitFlags, name, " " #name "\n", facility, level);
+
+ // these are all we care about at the moment
+ LOG_FLAG(CORJIT_FLG_IL_STUB);
+ LOG_FLAG(CORJIT_FLG_PUBLISH_SECRET_PARAM);
+
+#undef LOG_FLAGS
+
+ DWORD dwKnownMask =
+ CORJIT_FLG_IL_STUB |
+ CORJIT_FLG_PUBLISH_SECRET_PARAM |
+ NULL;
+
+ DWORD dwUnknownFlags = dwJitFlags & ~dwKnownMask;
+ if (0 != dwUnknownFlags)
+ {
+ LOG((facility, level, "UNKNOWN FLAGS: 0x%08x\n", dwUnknownFlags));
+ }
+}
+
+void ILStubLinker::LogILStub(DWORD dwJitFlags, SString *pDumpILStubCode)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pDumpILStubCode, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pCurrentStream = m_pCodeStreamList;
+ size_t cbCode = 0;
+ INT iCurStack = 0;
+
+ if (pDumpILStubCode == NULL)
+ LogJitFlags(LF_STUBS, LL_INFO1000, dwJitFlags);
+
+ while (pCurrentStream)
+ {
+ if (pCurrentStream->m_pqbILInstructions)
+ {
+ if (pDumpILStubCode)
+ pDumpILStubCode->AppendPrintf("// %s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
+ else
+ LOG((LF_STUBS, LL_INFO1000, "%s {\n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType())));
+
+ ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
+ LogILStubWorker(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, pDumpILStubCode);
+
+ if (pDumpILStubCode)
+ pDumpILStubCode->AppendPrintf("// } %s \n", pCurrentStream->GetStreamDescription(pCurrentStream->GetStreamType()));
+ else
+ LOG((LF_STUBS, LL_INFO1000, "}\n"));
+ }
+
+ pCurrentStream = pCurrentStream->m_pNextStream;
+ }
+}
+
+bool ILStubLinker::FirstPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode, INT* piCurStack, UINT* puMaxStack)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(puMaxStack));
+ }
+ CONTRACTL_END;
+
+ bool fStackUnderflow = false;
+
+ for (UINT i = 0; i < numInstr; i++)
+ {
+ ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
+ CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
+
+ //
+ // down-size instructions
+ //
+ instr = ILCodeStream::LowerOpcode(instr, &pInstrBuffer[i]);
+
+ //
+ // fill in code label offsets
+ //
+ if (instr == ILCodeStream::CEE_CODE_LABEL)
+ {
+ ILCodeLabel* pLabel = (ILCodeLabel*)(pInstrBuffer[i].uArg);
+ pLabel->SetCodeOffset(*pcbCode);
+ }
+
+ //
+ // calculate the code size
+ //
+ PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
+ *pcbCode += s_rgbOpcodeSizes[instr];
+
+ //
+ // calculate maxstack
+ //
+ *piCurStack += pInstrBuffer[i].iStackDelta;
+ if (*piCurStack > (INT)*puMaxStack)
+ {
+ *puMaxStack = *piCurStack;
+ }
+#ifdef _DEBUG
+ if (*piCurStack < 0)
+ {
+ fStackUnderflow = true;
+ }
+#endif // _DEBUG
+ }
+
+ return fStackUnderflow;
+}
+
+void ILStubLinker::SecondPassLink(ILInstruction* pInstrBuffer, UINT numInstr, size_t* pCurCodeOffset)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pCurCodeOffset));
+ }
+ CONTRACTL_END;
+
+ for (UINT i = 0; i < numInstr; i++)
+ {
+ ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
+ CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
+ *pCurCodeOffset += s_rgbOpcodeSizes[instr];
+
+ if (ILCodeStream::IsBranchInstruction(instr))
+ {
+ ILCodeLabel* pLabel = (ILCodeLabel*) pInstrBuffer[i].uArg;
+
+ CONSISTENCY_CHECK(this == pLabel->m_pOwningStubLinker);
+ CONSISTENCY_CHECK(IsInCodeStreamList(pLabel->m_pCodeStreamOfLabel));
+
+ pInstrBuffer[i].uArg = pLabel->GetCodeOffset() - *pCurCodeOffset;
+ }
+ }
+}
+
+size_t ILStubLinker::Link(UINT* puMaxStack)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(puMaxStack));
+ }
+ CONTRACTL_END;
+
+ //
+ // Pass1: calculate code size, lower instructions to smallest form,
+ // fill in branch target offsets, and calculate maxstack
+ //
+
+ ILCodeStream* pCurrentStream = m_pCodeStreamList;
+ size_t cbCode = 0;
+ INT iCurStack = 0;
+ UINT uMaxStack = 0;
+ DEBUG_STMT(bool fStackUnderflow = false);
+
+ while (pCurrentStream)
+ {
+ if (pCurrentStream->m_pqbILInstructions)
+ {
+ ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
+ INDEBUG( fStackUnderflow = ) FirstPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode, &iCurStack, &uMaxStack);
+ }
+
+ pCurrentStream = pCurrentStream->m_pNextStream;
+ }
+
+ //
+ // Pass2: go back and patch the branch instructions
+ //
+
+ pCurrentStream = m_pCodeStreamList;
+ size_t curCodeOffset = 0;
+
+ while (pCurrentStream)
+ {
+ if (pCurrentStream->m_pqbILInstructions)
+ {
+ ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
+ SecondPassLink(pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &curCodeOffset);
+ }
+
+ pCurrentStream = pCurrentStream->m_pNextStream;
+ }
+
+#ifdef _DEBUG
+ if (fStackUnderflow)
+ {
+ LogILStub(NULL);
+ CONSISTENCY_CHECK_MSG(false, "IL stack underflow! -- see logging output");
+ }
+#endif // _DEBUG
+
+ *puMaxStack = uMaxStack;
+ return cbCode;
+}
+
+#ifdef _DEBUG
+
+static const PCSTR s_rgOpNames[] =
+{
+
+#define OPDEF(name,string,pop,push,oprType,opcType,l,s1,s2,ctrl) \
+ #name,
+#include "opcode.def"
+#undef OPDEF
+
+};
+
+
+#endif // _DEBUG
+
+BYTE* ILStubLinker::GenerateCodeWorker(BYTE* pbBuffer, ILInstruction* pInstrBuffer, UINT numInstr, size_t* pcbCode)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pcbCode));
+ }
+ CONTRACTL_END;
+
+ for (UINT i = 0; i < numInstr; i++)
+ {
+ ILCodeStream::ILInstrEnum instr = (ILCodeStream::ILInstrEnum)pInstrBuffer[i].uInstruction;
+ CONSISTENCY_CHECK(ILCodeStream::IsSupportedInstruction(instr));
+
+ //
+ // copy the IL instructions from the various linkers into the given buffer
+ //
+ if (instr != ILCodeStream::CEE_CODE_LABEL)
+ {
+ const ILOpcode* pOpcode = &s_rgOpcodes[instr];
+
+ PREFIX_ASSUME((size_t)instr < sizeof(s_rgbOpcodeSizes));
+ int opSize = s_rgbOpcodeSizes[instr];
+ bool twoByteOp = (pOpcode->byte1 != 0xFF);
+ int argSize = opSize - (twoByteOp ? 2 : 1);
+
+ if (twoByteOp)
+ {
+ *pbBuffer++ = pOpcode->byte1;
+ }
+
+ *pbBuffer++ = pOpcode->byte2;
+
+ switch (argSize)
+ {
+ case 0:
+ break;
+
+ case 1:
+ *pbBuffer = (BYTE)pInstrBuffer[i].uArg;
+ break;
+
+ case 2:
+ SET_UNALIGNED_VAL16(pbBuffer, pInstrBuffer[i].uArg);
+ break;
+
+ case 4:
+ SET_UNALIGNED_VAL32(pbBuffer, pInstrBuffer[i].uArg);
+ break;
+
+ case 8:
+ {
+ UINT64 uVal = pInstrBuffer[i].uArg;
+#ifndef _WIN64 // We don't have room on 32-bit platforms to store the CLR_NAN_64 value, so
+ // we use a special value to represent CLR_NAN_64 and then recreate it here.
+ if ((instr == ILCodeStream::CEE_LDC_R8) && (((UINT32)uVal) == ILCodeStream::SPECIAL_VALUE_NAN_64_ON_32))
+ uVal = CLR_NAN_64;
+#endif // _WIN64
+ SET_UNALIGNED_VAL64(pbBuffer, uVal);
+ }
+ break;
+
+ default:
+ UNREACHABLE_MSG("unexpected il opcode argument size");
+ }
+
+ pbBuffer += argSize;
+ *pcbCode += opSize;
+ }
+ }
+
+ return pbBuffer;
+}
+
+void ILStubLinker::GenerateCode(BYTE* pbBuffer, size_t cbBufferSize)
+{
+ STANDARD_VM_CONTRACT;
+
+ ILCodeStream* pCurrentStream = m_pCodeStreamList;
+ size_t cbCode = 0;
+
+ while (pCurrentStream)
+ {
+ if (pCurrentStream->m_pqbILInstructions)
+ {
+ ILInstruction* pInstrBuffer = (ILInstruction*)pCurrentStream->m_pqbILInstructions->Ptr();
+ pbBuffer = GenerateCodeWorker(pbBuffer, pInstrBuffer, pCurrentStream->m_uCurInstrIdx, &cbCode);
+ }
+
+ pCurrentStream = pCurrentStream->m_pNextStream;
+ }
+
+ CONSISTENCY_CHECK(cbCode <= cbBufferSize);
+}
+
+
+#ifdef _DEBUG
+bool ILStubLinker::IsInCodeStreamList(ILCodeStream* pcs)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ ILCodeStream* pCurrentStream = m_pCodeStreamList;
+ while (pCurrentStream)
+ {
+ if (pcs == pCurrentStream)
+ {
+ return true;
+ }
+
+ pCurrentStream = pCurrentStream->m_pNextStream;
+ }
+
+ return false;
+}
+
+// static
+bool ILCodeStream::IsSupportedInstruction(ILInstrEnum instr)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ CONSISTENCY_CHECK_MSG(instr != CEE_SWITCH, "CEE_SWITCH is not supported currently due to InlineSwitch in s_rgbOpcodeSizes");
+ CONSISTENCY_CHECK_MSG(((instr >= CEE_BR_S) && (instr <= CEE_BLT_UN_S)) || (CEE_LEAVE), "we only use long-form branch opcodes");
+ return true;
+}
+#endif // _DEBUG
+
+LPCSTR ILCodeStream::GetStreamDescription(ILStubLinker::CodeStreamType streamType)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ static LPCSTR lpszDescriptions[] = {
+ "Initialize",
+ "Marshal",
+ "CallMethod",
+ "UnmarshalReturn",
+ "Unmarshal",
+ "ExceptionCleanup",
+ "Cleanup",
+ "ExceptionHandler",
+ };
+
+#ifdef _DEBUG
+ size_t len = sizeof(lpszDescriptions)/sizeof(LPCSTR);
+ _ASSERT(streamType >= 0 && (size_t)streamType < len);
+#endif // _DEBUG
+
+ return lpszDescriptions[streamType];
+}
+
+void ILCodeStream::EmitADD()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_ADD, -1, 0);
+}
+void ILCodeStream::EmitADD_OVF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_ADD_OVF, -1, 0);
+}
+void ILCodeStream::EmitAND()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_AND, -1, 0);
+}
+void ILCodeStream::EmitARGLIST()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_ARGLIST, 1, 0);
+}
+
+void ILCodeStream::EmitBEQ(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BEQ, -2, (UINT_PTR)pCodeLabel);
+}
+
+void ILCodeStream::EmitBGE(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BGE, -2, (UINT_PTR)pCodeLabel);
+}
+
+void ILCodeStream::EmitBGE_UN(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BGE_UN, -2, (UINT_PTR)pCodeLabel);
+}
+
+void ILCodeStream::EmitBGT(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BGT, -2, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBLE(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BLE, -2, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBLE_UN(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BLE_UN, -2, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBLT(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BLT, -2, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBR(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BR, 0, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBREAK()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BREAK, 0, 0);
+}
+void ILCodeStream::EmitBRFALSE(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BRFALSE, -1, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitBRTRUE(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_BRTRUE, -1, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitCALL(int token, int numInArgs, int numRetArgs)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CALL, (INT16)(numRetArgs - numInArgs), token);
+}
+void ILCodeStream::EmitCALLI(int token, int numInArgs, int numRetArgs)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CALLI, (INT16)(numRetArgs - numInArgs - 1), token);
+}
+void ILCodeStream::EmitCEQ ()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CEQ, -1, 0);
+}
+void ILCodeStream::EmitCGT()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CGT, -1, 0);
+}
+void ILCodeStream::EmitCGT_UN()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CGT_UN, -1, 0);
+}
+void ILCodeStream::EmitCLT()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CLT, -1, 0);
+}
+void ILCodeStream::EmitCLT_UN()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CLT_UN, -1, 0);
+}
+void ILCodeStream::EmitCONV_I()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_I, 0, 0);
+}
+void ILCodeStream::EmitCONV_I1()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_I1, 0, 0);
+}
+void ILCodeStream::EmitCONV_I2()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_I2, 0, 0);
+}
+void ILCodeStream::EmitCONV_I4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_I4, 0, 0);
+}
+void ILCodeStream::EmitCONV_I8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_I8, 0, 0);
+}
+void ILCodeStream::EmitCONV_U()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_U, 0, 0);
+}
+void ILCodeStream::EmitCONV_U1()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_U1, 0, 0);
+}
+void ILCodeStream::EmitCONV_U2()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_U2, 0, 0);
+}
+void ILCodeStream::EmitCONV_U4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_U4, 0, 0);
+}
+void ILCodeStream::EmitCONV_U8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_U8, 0, 0);
+}
+void ILCodeStream::EmitCONV_R4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_R4, 0, 0);
+}
+void ILCodeStream::EmitCONV_R8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_R8, 0, 0);
+}
+void ILCodeStream::EmitCONV_OVF_I4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CONV_OVF_I4, 0, 0);
+}
+void ILCodeStream::EmitCONV_T(CorElementType t)
+{
+ STANDARD_VM_CONTRACT;
+
+ switch (t)
+ {
+ case ELEMENT_TYPE_U1:
+ EmitCONV_U1();
+ break;
+ case ELEMENT_TYPE_I1:
+ EmitCONV_I1();
+ break;
+ case ELEMENT_TYPE_U2:
+ EmitCONV_U2();
+ break;
+ case ELEMENT_TYPE_I2:
+ EmitCONV_I2();
+ break;
+ case ELEMENT_TYPE_U4:
+ EmitCONV_U4();
+ break;
+ case ELEMENT_TYPE_I4:
+ EmitCONV_I4();
+ break;
+ case ELEMENT_TYPE_U8:
+ EmitCONV_U8();
+ break;
+ case ELEMENT_TYPE_I8:
+ EmitCONV_I8();
+ break;
+ case ELEMENT_TYPE_R4:
+ EmitCONV_R4();
+ break;
+ case ELEMENT_TYPE_R8:
+ EmitCONV_R8();
+ break;
+ case ELEMENT_TYPE_I:
+ EmitCONV_I();
+ break;
+ case ELEMENT_TYPE_U:
+ EmitCONV_U();
+ break;
+ default:
+ _ASSERTE(!"Invalid type for conversion");
+ break;
+ }
+}
+void ILCodeStream::EmitCPBLK()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CPBLK, -3, 0);
+}
+void ILCodeStream::EmitCPOBJ(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_CPOBJ, -2, token);
+}
+void ILCodeStream::EmitDUP ()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_DUP, 1, 0);
+}
+void ILCodeStream::EmitENDFINALLY()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_ENDFINALLY, 0, 0);
+}
+void ILCodeStream::EmitINITBLK()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_INITBLK, -3, 0);
+}
+void ILCodeStream::EmitINITOBJ(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_INITOBJ, -1, token);
+}
+void ILCodeStream::EmitJMP(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_JMP, 0, token);
+}
+void ILCodeStream::EmitLDARG (unsigned uArgIdx)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (m_pOwner->m_fHasThis)
+ {
+ uArgIdx++;
+ }
+ Emit(CEE_LDARG, 1, uArgIdx);
+}
+void ILCodeStream::EmitLDARGA (unsigned uArgIdx)
+{
+ WRAPPER_NO_CONTRACT;
+ if (m_pOwner->m_fHasThis)
+ {
+ uArgIdx++;
+ }
+ Emit(CEE_LDARGA, 1, uArgIdx);
+}
+void ILCodeStream::EmitLDC(DWORD_PTR uConst)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(
+#ifdef _WIN64
+ CEE_LDC_I8
+#else
+ CEE_LDC_I4
+#endif
+ , 1, uConst);
+}
+void ILCodeStream::EmitLDC_R4(UINT32 uConst)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDC_R4, 1, uConst);
+}
+void ILCodeStream::EmitLDC_R8(UINT64 uConst)
+{
+ STANDARD_VM_CONTRACT;
+#ifndef _WIN64 // We don't have room on 32-bit platforms to stor the CLR_NAN_64 value, so
+ // we use a special value to represent CLR_NAN_64 and then recreate it later.
+ CONSISTENCY_CHECK(((UINT32)uConst) != SPECIAL_VALUE_NAN_64_ON_32);
+ if (uConst == CLR_NAN_64)
+ uConst = SPECIAL_VALUE_NAN_64_ON_32;
+ else
+ CONSISTENCY_CHECK(FitsInU4(uConst));
+#endif // _WIN64
+ Emit(CEE_LDC_R8, 1, (UINT_PTR)uConst);
+}
+void ILCodeStream::EmitLDELEM_REF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDELEM_REF, -1, 0);
+}
+void ILCodeStream::EmitLDFLD(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDFLD, 0, token);
+}
+void ILCodeStream::EmitLDFLDA(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDFLDA, 0, token);
+}
+void ILCodeStream::EmitLDFTN(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDFTN, 1, token);
+}
+void ILCodeStream::EmitLDIND_I()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_I, 0, 0);
+}
+void ILCodeStream::EmitLDIND_I1()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_I1, 0, 0);
+}
+void ILCodeStream::EmitLDIND_I2()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_I2, 0, 0);
+}
+void ILCodeStream::EmitLDIND_I4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_I4, 0, 0);
+}
+void ILCodeStream::EmitLDIND_I8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_I8, 0, 0);
+}
+void ILCodeStream::EmitLDIND_R4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_R4, 0, 0);
+}
+void ILCodeStream::EmitLDIND_R8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_R8, 0, 0);
+}
+void ILCodeStream::EmitLDIND_REF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_REF, 0, 0);
+}
+void ILCodeStream::EmitLDIND_T(LocalDesc* pType)
+{
+ CONTRACTL
+ {
+ PRECONDITION(pType->cbType == 1);
+ }
+ CONTRACTL_END;
+
+ switch (pType->ElementType[0])
+ {
+ case ELEMENT_TYPE_I1: EmitLDIND_I1(); break;
+ case ELEMENT_TYPE_BOOLEAN: // fall through
+ case ELEMENT_TYPE_U1: EmitLDIND_U1(); break;
+ case ELEMENT_TYPE_I2: EmitLDIND_I2(); break;
+ case ELEMENT_TYPE_CHAR: // fall through
+ case ELEMENT_TYPE_U2: EmitLDIND_U2(); break;
+ case ELEMENT_TYPE_I4: EmitLDIND_I4(); break;
+ case ELEMENT_TYPE_U4: EmitLDIND_U4(); break;
+ case ELEMENT_TYPE_I8: EmitLDIND_I8(); break;
+ case ELEMENT_TYPE_U8: EmitLDIND_I8(); break;
+ case ELEMENT_TYPE_R4: EmitLDIND_R4(); break;
+ case ELEMENT_TYPE_R8: EmitLDIND_R8(); break;
+ case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
+ case ELEMENT_TYPE_I: EmitLDIND_I(); break;
+ case ELEMENT_TYPE_U: EmitLDIND_I(); break;
+ case ELEMENT_TYPE_STRING: // fall through
+ case ELEMENT_TYPE_CLASS: // fall through
+ case ELEMENT_TYPE_ARRAY:
+ case ELEMENT_TYPE_SZARRAY:
+ case ELEMENT_TYPE_OBJECT: EmitLDIND_REF(); break;
+
+ case ELEMENT_TYPE_INTERNAL:
+ {
+ CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
+ EmitLDIND_REF();
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("unexpected type passed to EmitLDIND_T");
+ break;
+ }
+}
+void ILCodeStream::EmitLDIND_U1()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_U1, 0, 0);
+}
+void ILCodeStream::EmitLDIND_U2()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_U2, 0, 0);
+}
+void ILCodeStream::EmitLDIND_U4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDIND_U4, 0, 0);
+}
+void ILCodeStream::EmitLDLEN()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDLEN, 0, 0);
+}
+void ILCodeStream::EmitLDLOC (DWORD dwLocalNum)
+{
+ STANDARD_VM_CONTRACT;
+ CONSISTENCY_CHECK(dwLocalNum != (DWORD)-1);
+ CONSISTENCY_CHECK(dwLocalNum != (WORD)-1);
+ Emit(CEE_LDLOC, 1, dwLocalNum);
+}
+void ILCodeStream::EmitLDLOCA (DWORD dwLocalNum)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDLOCA, 1, dwLocalNum);
+}
+void ILCodeStream::EmitLDNULL()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDNULL, 1, 0);
+}
+void ILCodeStream::EmitLDOBJ (int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDOBJ, 0, token);
+}
+void ILCodeStream::EmitLDSFLD(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDSFLD, 1, token);
+}
+void ILCodeStream::EmitLDSFLDA(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDSFLDA, 1, token);
+}
+void ILCodeStream::EmitLDTOKEN(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LDTOKEN, 1, token);
+}
+void ILCodeStream::EmitLEAVE(ILCodeLabel* pCodeLabel)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LEAVE, 0, (UINT_PTR)pCodeLabel);
+}
+void ILCodeStream::EmitLOCALLOC()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_LOCALLOC, 0, 0);
+}
+void ILCodeStream::EmitMUL()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_MUL, -1, 0);
+}
+void ILCodeStream::EmitMUL_OVF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_MUL_OVF, -1, 0);
+}
+void ILCodeStream::EmitNEWOBJ(int token, int numInArgs)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_NEWOBJ, (INT16)(1 - numInArgs), token);
+}
+
+void ILCodeStream::EmitNOP(LPCSTR pszNopComment)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_NOP, 0, (UINT_PTR)pszNopComment);
+}
+
+void ILCodeStream::EmitPOP()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_POP, -1, 0);
+}
+void ILCodeStream::EmitRET()
+{
+ WRAPPER_NO_CONTRACT;
+ INT16 iStackDelta = m_pOwner->m_StubHasVoidReturnType ? 0 : -1;
+ Emit(CEE_RET, iStackDelta, 0);
+}
+void ILCodeStream::EmitSHR_UN()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_SHR_UN, -1, 0);
+}
+void ILCodeStream::EmitSTARG(unsigned uArgIdx)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STARG, -1, uArgIdx);
+}
+void ILCodeStream::EmitSTELEM_REF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STELEM_REF, -3, 0);
+}
+void ILCodeStream::EmitSTIND_I()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_I, -2, 0);
+}
+void ILCodeStream::EmitSTIND_I1()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_I1, -2, 0);
+}
+void ILCodeStream::EmitSTIND_I2()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_I2, -2, 0);
+}
+void ILCodeStream::EmitSTIND_I4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_I4, -2, 0);
+}
+void ILCodeStream::EmitSTIND_I8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_I8, -2, 0);
+}
+void ILCodeStream::EmitSTIND_R4()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_R4, -2, 0);
+}
+void ILCodeStream::EmitSTIND_R8()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_R8, -2, 0);
+}
+void ILCodeStream::EmitSTIND_REF()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STIND_REF, -2, 0);
+}
+void ILCodeStream::EmitSTIND_T(LocalDesc* pType)
+{
+ CONTRACTL
+ {
+ PRECONDITION(pType->cbType == 1);
+ }
+ CONTRACTL_END;
+
+ switch (pType->ElementType[0])
+ {
+ case ELEMENT_TYPE_I1: EmitSTIND_I1(); break;
+ case ELEMENT_TYPE_BOOLEAN: // fall through
+ case ELEMENT_TYPE_U1: EmitSTIND_I1(); break;
+ case ELEMENT_TYPE_I2: EmitSTIND_I2(); break;
+ case ELEMENT_TYPE_CHAR: // fall through
+ case ELEMENT_TYPE_U2: EmitSTIND_I2(); break;
+ case ELEMENT_TYPE_I4: EmitSTIND_I4(); break;
+ case ELEMENT_TYPE_U4: EmitSTIND_I4(); break;
+ case ELEMENT_TYPE_I8: EmitSTIND_I8(); break;
+ case ELEMENT_TYPE_U8: EmitSTIND_I8(); break;
+ case ELEMENT_TYPE_R4: EmitSTIND_R4(); break;
+ case ELEMENT_TYPE_R8: EmitSTIND_R8(); break;
+ case ELEMENT_TYPE_FNPTR: // same as ELEMENT_TYPE_I
+ case ELEMENT_TYPE_I: EmitSTIND_I(); break;
+ case ELEMENT_TYPE_U: EmitSTIND_I(); break;
+ case ELEMENT_TYPE_STRING: // fall through
+ case ELEMENT_TYPE_CLASS: // fall through
+ case ELEMENT_TYPE_ARRAY:
+ case ELEMENT_TYPE_SZARRAY:
+ case ELEMENT_TYPE_OBJECT: EmitSTIND_REF(); break;
+
+ case ELEMENT_TYPE_INTERNAL:
+ {
+ CONSISTENCY_CHECK_MSG(!(pType->InternalToken.GetMethodTable()->IsValueType()), "don't know how to handle value types here");
+ EmitSTIND_REF();
+ break;
+ }
+
+ default:
+ UNREACHABLE_MSG("unexpected type passed to EmitSTIND_T");
+ break;
+ }
+}
+void ILCodeStream::EmitSTFLD(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STFLD, -2, token);
+}
+void ILCodeStream::EmitSTLOC(DWORD dwLocalNum)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STLOC, -1, dwLocalNum);
+}
+void ILCodeStream::EmitSTOBJ(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STOBJ, -2, token);
+}
+void ILCodeStream::EmitSTSFLD(int token)
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_STSFLD, -1, token);
+}
+void ILCodeStream::EmitSUB()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_SUB, -1, 0);
+}
+void ILCodeStream::EmitTHROW()
+{
+ WRAPPER_NO_CONTRACT;
+ Emit(CEE_THROW, -1, 0);
+}
+
+
+void ILCodeStream::EmitNEWOBJ(BinderMethodID id, int numInArgs)
+{
+ STANDARD_VM_CONTRACT;
+ EmitNEWOBJ(GetToken(MscorlibBinder::GetMethod(id)), numInArgs);
+}
+
+void ILCodeStream::EmitCALL(BinderMethodID id, int numInArgs, int numRetArgs)
+{
+ STANDARD_VM_CONTRACT;
+ EmitCALL(GetToken(MscorlibBinder::GetMethod(id)), numInArgs, numRetArgs);
+}
+
+
+
+
+
+
+void ILStubLinker::SetHasThis (bool fHasThis)
+{
+ LIMITED_METHOD_CONTRACT;
+ m_fHasThis = fHasThis;
+}
+
+void ILCodeStream::EmitLoadThis ()
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(m_pOwner->m_fHasThis);
+ // OK, this is ugly, but we add 1 to all LDARGs when
+ // m_fHasThis is true, so we compensate for that here
+ // so that we don't have to have a special method to
+ // load arguments.
+ EmitLDARG((unsigned)-1);
+}
+
+void ILCodeStream::EmitLoadNullPtr()
+{
+ WRAPPER_NO_CONTRACT;
+
+ // This is the correct way to load unmanaged zero pointer. EmitLDC(0) alone works
+ // fine in most cases but may lead to wrong code being generated on 64-bit if the
+ // flow graph is complex.
+ EmitLDC(0);
+ EmitCONV_I();
+}
+
+void ILCodeStream::EmitArgIteratorCreateAndLoad()
+{
+ STANDARD_VM_CONTRACT;
+
+ //
+ // we insert the ArgIterator in the same spot that the VASigCookie will go for sanity
+ //
+ LocalDesc aiLoc(MscorlibBinder::GetClass(CLASS__ARG_ITERATOR));
+ int aiLocNum;
+
+ aiLocNum = NewLocal(aiLoc);
+
+ EmitLDLOCA(aiLocNum);
+ EmitDUP();
+ EmitARGLIST();
+ EmitLoadNullPtr();
+ EmitCALL(METHOD__ARG_ITERATOR__CTOR2, 2, 0);
+
+ aiLoc.ElementType[0] = ELEMENT_TYPE_BYREF;
+ aiLoc.ElementType[1] = ELEMENT_TYPE_INTERNAL;
+ aiLoc.cbType = 2;
+ aiLoc.InternalToken = MscorlibBinder::GetClass(CLASS__ARG_ITERATOR);
+
+ SetStubTargetArgType(&aiLoc, false);
+}
+
+DWORD ILStubLinker::NewLocal(CorElementType typ)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ INJECT_FAULT(COMPlusThrowOM());
+ }
+ CONTRACTL_END;
+
+ LocalDesc locDesc(typ);
+ return NewLocal(locDesc);
+}
+
+StubSigBuilder::StubSigBuilder() :
+ m_nItems(0),
+ m_cbSig(0)
+{
+ STANDARD_VM_CONTRACT;
+
+ m_pbSigCursor = (BYTE*) m_qbSigBuffer.AllocThrows(INITIAL_BUFFER_SIZE);
+}
+
+void StubSigBuilder::EnsureEnoughQuickBytes(size_t cbToAppend)
+{
+ STANDARD_VM_CONTRACT;
+
+ SIZE_T cbBuffer = m_qbSigBuffer.Size();
+ if ((m_cbSig + cbToAppend) >= cbBuffer)
+ {
+ m_qbSigBuffer.ReSizeThrows(2 * cbBuffer);
+ m_pbSigCursor = ((BYTE*)m_qbSigBuffer.Ptr()) + m_cbSig;
+ }
+}
+
+DWORD StubSigBuilder::Append(LocalDesc* pLoc)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pLoc));
+ }
+ CONTRACTL_END;
+
+ EnsureEnoughQuickBytes(pLoc->cbType + sizeof(TypeHandle));
+
+ memcpyNoGCRefs(m_pbSigCursor, pLoc->ElementType, pLoc->cbType);
+ m_pbSigCursor += pLoc->cbType;
+ m_cbSig += pLoc->cbType;
+
+ size_t i = 0;
+
+ while (i < pLoc->cbType)
+ {
+ CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
+ && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
+
+ switch (pLoc->ElementType[i])
+ {
+ case ELEMENT_TYPE_INTERNAL:
+ SET_UNALIGNED_PTR(m_pbSigCursor, (UINT_PTR)pLoc->InternalToken.AsPtr());
+ m_pbSigCursor += sizeof(TypeHandle);
+ m_cbSig += sizeof(TypeHandle);
+ break;
+
+ case ELEMENT_TYPE_FNPTR:
+ {
+ SigPointer ptr(pLoc->pSig);
+
+ SigBuilder sigBuilder;
+ ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
+
+ DWORD cbFnPtrSig;
+ PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
+
+ EnsureEnoughQuickBytes(cbFnPtrSig);
+
+ memcpyNoGCRefs(m_pbSigCursor, pFnPtrSig, cbFnPtrSig);
+
+ m_pbSigCursor += cbFnPtrSig;
+ m_cbSig += cbFnPtrSig;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ i++;
+ }
+
+ if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
+ {
+ EnsureEnoughQuickBytes(pLoc->cbArrayBoundsInfo);
+
+ memcpyNoGCRefs(m_pbSigCursor, pLoc->pSig, pLoc->cbArrayBoundsInfo);
+ m_pbSigCursor += pLoc->cbArrayBoundsInfo;
+ m_cbSig += pLoc->cbArrayBoundsInfo;
+ }
+
+ _ASSERTE(m_cbSig <= m_qbSigBuffer.Size()); // we corrupted our buffer resizing if this assert fires
+
+ return m_nItems++;
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+LocalSigBuilder::GetSigSize()
+{
+ STANDARD_VM_CONTRACT;
+
+ BYTE temp[4];
+ UINT32 cbEncoded = CorSigCompressData(m_nItems, temp);
+
+ S_UINT32 cbSigSize =
+ S_UINT32(1) + // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
+ S_UINT32(cbEncoded) + // encoded number of locals
+ S_UINT32(m_cbSig) + // types
+ S_UINT32(1); // ELEMENT_TYPE_END
+ if (cbSigSize.IsOverflow())
+ {
+ IfFailThrow(COR_E_OVERFLOW);
+ }
+ return cbSigSize.Value();
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+LocalSigBuilder::GetSig(
+ BYTE * pbLocalSig,
+ DWORD cbBuffer)
+{
+ STANDARD_VM_CONTRACT;
+ BYTE temp[4];
+ size_t cb = CorSigCompressData(m_nItems, temp);
+
+ _ASSERTE((1 + cb + m_cbSig + 1) == GetSigSize());
+
+ if ((1 + cb + m_cbSig + 1) <= cbBuffer)
+ {
+ pbLocalSig[0] = IMAGE_CEE_CS_CALLCONV_LOCAL_SIG;
+ memcpyNoGCRefs(&pbLocalSig[1], temp, cb);
+ memcpyNoGCRefs(&pbLocalSig[1 + cb], m_qbSigBuffer.Ptr(), m_cbSig);
+ pbLocalSig[1 + cb + m_cbSig] = ELEMENT_TYPE_END;
+ return (DWORD)(1 + cb + m_cbSig + 1);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+FunctionSigBuilder::FunctionSigBuilder() :
+ m_callingConv(IMAGE_CEE_CS_CALLCONV_DEFAULT)
+{
+ STANDARD_VM_CONTRACT;
+ m_qbReturnSig.ReSizeThrows(1);
+ *(CorElementType *)m_qbReturnSig.Ptr() = ELEMENT_TYPE_VOID;
+}
+
+
+void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(pLoc->cbType > 0);
+ }
+ CONTRACTL_END;
+
+ m_qbReturnSig.ReSizeThrows(pLoc->cbType);
+ memcpyNoGCRefs(m_qbReturnSig.Ptr(), pLoc->ElementType, pLoc->cbType);
+
+ size_t i = 0;
+
+ while (i < pLoc->cbType)
+ {
+ CONSISTENCY_CHECK( ELEMENT_TYPE_CLASS != pLoc->ElementType[i]
+ && ELEMENT_TYPE_VALUETYPE != pLoc->ElementType[i]);
+
+ switch (pLoc->ElementType[i])
+ {
+ case ELEMENT_TYPE_INTERNAL:
+ m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + sizeof(TypeHandle));
+ SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - + sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr());
+ break;
+
+ case ELEMENT_TYPE_FNPTR:
+ {
+ SigPointer ptr(pLoc->pSig);
+
+ SigBuilder sigBuilder;
+ ptr.ConvertToInternalSignature(pLoc->pSigModule, NULL, &sigBuilder);
+
+ DWORD cbFnPtrSig;
+ PVOID pFnPtrSig = sigBuilder.GetSignature(&cbFnPtrSig);
+
+ m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + cbFnPtrSig);
+
+ memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - cbFnPtrSig, pFnPtrSig, cbFnPtrSig);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ i++;
+ }
+
+ if (pLoc->ElementType[0] == ELEMENT_TYPE_ARRAY)
+ {
+ SIZE_T size = m_qbReturnSig.Size();
+ m_qbReturnSig.ReSizeThrows(size + pLoc->cbArrayBoundsInfo);
+ memcpyNoGCRefs((BYTE *)m_qbReturnSig.Ptr() + size, pLoc->pSig, pLoc->cbArrayBoundsInfo);
+ }
+}
+
+void FunctionSigBuilder::SetSig(PCCOR_SIGNATURE pSig, DWORD cSig)
+{
+ STANDARD_VM_CONTRACT;
+
+ // parse the incoming signature
+ SigPointer sigPtr(pSig, cSig);
+
+ // 1) calling convention
+ ULONG callConv;
+ IfFailThrow(sigPtr.GetCallingConvInfo(&callConv));
+ SetCallingConv((CorCallingConvention)callConv);
+
+ // 2) number of parameters
+ IfFailThrow(sigPtr.GetData(&m_nItems));
+
+ // 3) return type
+ PCCOR_SIGNATURE ptr = sigPtr.GetPtr();
+ IfFailThrow(sigPtr.SkipExactlyOne());
+
+ size_t retSigLength = sigPtr.GetPtr() - ptr;
+
+ m_qbReturnSig.ReSizeThrows(retSigLength);
+ memcpyNoGCRefs(m_qbReturnSig.Ptr(), ptr, retSigLength);
+
+ // 4) parameters
+ m_cbSig = 0;
+
+ size_t cbSigLen = (cSig - (sigPtr.GetPtr() - pSig));
+
+ m_pbSigCursor = (BYTE *)m_qbSigBuffer.Ptr();
+ EnsureEnoughQuickBytes(cbSigLen);
+
+ memcpyNoGCRefs(m_pbSigCursor, sigPtr.GetPtr(), cbSigLen);
+
+ m_cbSig = cbSigLen;
+ m_pbSigCursor += cbSigLen;
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+FunctionSigBuilder::GetSigSize()
+{
+ STANDARD_VM_CONTRACT;
+
+ BYTE temp[4];
+ DWORD cbEncodedLen = CorSigCompressData(m_nItems, temp);
+ SIZE_T cbEncodedRetType = m_qbReturnSig.Size();
+
+ CONSISTENCY_CHECK(cbEncodedRetType > 0);
+
+ S_UINT32 cbSigSize =
+ S_UINT32(1) + // calling convention
+ S_UINT32(cbEncodedLen) + // encoded number of args
+ S_UINT32(cbEncodedRetType) + // encoded return type
+ S_UINT32(m_cbSig) + // types
+ S_UINT32(1); // ELEMENT_TYPE_END
+ if (cbSigSize.IsOverflow())
+ {
+ IfFailThrow(COR_E_OVERFLOW);
+ }
+ return cbSigSize.Value();
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+FunctionSigBuilder::GetSig(
+ BYTE * pbLocalSig,
+ DWORD cbBuffer)
+{
+ STANDARD_VM_CONTRACT;
+ BYTE tempLen[4];
+ size_t cbEncodedLen = CorSigCompressData(m_nItems, tempLen);
+ size_t cbEncodedRetType = m_qbReturnSig.Size();
+
+ CONSISTENCY_CHECK(cbEncodedRetType > 0);
+
+ _ASSERTE((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) == GetSigSize());
+
+ if ((1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1) <= cbBuffer)
+ {
+ BYTE* pbCursor = pbLocalSig;
+ *pbCursor = static_cast<BYTE>(m_callingConv);
+ pbCursor++;
+
+ memcpyNoGCRefs(pbCursor, tempLen, cbEncodedLen);
+ pbCursor += cbEncodedLen;
+
+ memcpyNoGCRefs(pbCursor, m_qbReturnSig.Ptr(), m_qbReturnSig.Size());
+ pbCursor += m_qbReturnSig.Size();
+
+ memcpyNoGCRefs(pbCursor, m_qbSigBuffer.Ptr(), m_cbSig);
+ pbCursor += m_cbSig;
+ pbCursor[0] = ELEMENT_TYPE_END;
+ return (DWORD)(1 + cbEncodedLen + cbEncodedRetType + m_cbSig + 1);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+DWORD ILStubLinker::NewLocal(LocalDesc loc)
+{
+ WRAPPER_NO_CONTRACT;
+
+ return m_localSigBuilder.NewLocal(&loc);
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+ILStubLinker::GetLocalSigSize()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_localSigBuilder.GetSigSize();
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+ILStubLinker::GetLocalSig(
+ BYTE * pbLocalSig,
+ DWORD cbBuffer)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwRet = m_localSigBuilder.GetSig(pbLocalSig, cbBuffer);
+ return dwRet;
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+ILStubLinker::GetStubTargetMethodSigSize()
+{
+ STANDARD_VM_CONTRACT;
+
+ return m_nativeFnSigBuilder.GetSigSize();
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+ILStubLinker::GetStubTargetMethodSig(
+ BYTE * pbSig,
+ DWORD cbSig)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ DWORD dwRet = m_nativeFnSigBuilder.GetSig(pbSig, cbSig);
+ return dwRet;
+}
+
+void ILStubLinker::SetStubTargetMethodSig(PCCOR_SIGNATURE pSig, DWORD cSig)
+{
+ STANDARD_VM_CONTRACT;
+
+ m_nativeFnSigBuilder.SetSig(pSig, cSig);
+}
+
+static BOOL SigHasVoidReturnType(const Signature &signature)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END
+
+ SigPointer ptr = signature.CreateSigPointer();
+
+ ULONG data;
+ IfFailThrow(ptr.GetCallingConvInfo(&data));
+ // Skip number of type arguments
+ if (data & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ {
+ IfFailThrow(ptr.GetData(NULL));
+ }
+
+ // skip number of args
+ IfFailThrow(ptr.GetData(NULL));
+
+ CorElementType retType;
+ IfFailThrow(ptr.PeekElemType(&retType));
+
+ return (ELEMENT_TYPE_VOID == retType);
+}
+
+
+ILStubLinker::ILStubLinker(Module* pStubSigModule, const Signature &signature, SigTypeContext *pTypeContext, MethodDesc *pMD,
+ BOOL fTargetHasThis, BOOL fStubHasThis, BOOL fIsNDirectStub) :
+ m_pCodeStreamList(NULL),
+ m_stubSig(signature),
+ m_pTypeContext(pTypeContext),
+ m_pCode(NULL),
+ m_pStubSigModule(pStubSigModule),
+ m_pLabelList(NULL),
+ m_StubHasVoidReturnType(0),
+ m_iTargetStackDelta(0),
+ m_cbCurrentCompressedSigLen(1),
+ m_nLocals(0),
+ m_fHasThis(false),
+ m_pMD(pMD)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ INJECT_FAULT(COMPlusThrowOM());
+ }
+ CONTRACTL_END
+
+ m_managedSigPtr = signature.CreateSigPointer();
+ if (!signature.IsEmpty())
+ {
+ m_StubHasVoidReturnType = SigHasVoidReturnType(signature);
+
+ //
+ // Get the stub's calling convention. Set m_fHasThis to match
+ // IMAGE_CEE_CS_CALLCONV_HASTHIS.
+ //
+
+ ULONG uStubCallingConvInfo;
+ IfFailThrow(m_managedSigPtr.GetCallingConvInfo(&uStubCallingConvInfo));
+
+ if (fStubHasThis)
+ {
+ m_fHasThis = true;
+ }
+
+ //
+ // If target calling convention was specified, use it instead.
+ // Otherwise, derive one based on the stub's signature.
+ //
+
+ ULONG uCallingConvInfo = uStubCallingConvInfo;
+
+ ULONG uCallingConv = (uCallingConvInfo & IMAGE_CEE_CS_CALLCONV_MASK);
+ ULONG uNativeCallingConv;
+
+ if (IMAGE_CEE_CS_CALLCONV_VARARG == uCallingConv)
+ {
+ //
+ // If we have a PInvoke stub that has a VARARG calling convention
+ // we will transition to a NATIVEVARARG calling convention for the
+ // target call. The JIT64 knows about this calling convention,
+ // basically it is the same as the managed vararg calling convention
+ // except without a VASigCookie.
+ //
+ // If our stub is not a PInvoke stub and has a vararg calling convention,
+ // we are most likely going to have to forward those variable arguments
+ // on to our call target. Unfortunately, callsites to varargs methods
+ // in IL always have full signatures (that's where the VASigCookie comes
+ // from). But we don't have that in this case, so we play some tricks and
+ // pass an ArgIterator down to an assembly routine that pulls out the
+ // variable arguments and puts them in the right spot before forwarding
+ // to the stub target.
+ //
+ // The net result is that we don't want to set the native calling
+ // convention to be vararg for non-PInvoke stubs, so we just use
+ // the default callconv.
+ //
+ if (!fIsNDirectStub)
+ uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
+ else
+ uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG;
+ }
+ else
+ {
+ uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_DEFAULT;
+ }
+
+ if (fTargetHasThis && !fIsNDirectStub)
+ {
+ // ndirect native sig never has a 'this' pointer
+ uNativeCallingConv |= IMAGE_CEE_CS_CALLCONV_HASTHIS;
+ }
+
+ if (fTargetHasThis)
+ {
+ m_iTargetStackDelta--;
+ }
+
+ m_nativeFnSigBuilder.SetCallingConv((CorCallingConvention)uNativeCallingConv);
+
+ if (uStubCallingConvInfo & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of type parameters
+
+ IfFailThrow(m_managedSigPtr.GetData(NULL)); // skip number of parameters
+ IfFailThrow(m_managedSigPtr.SkipExactlyOne()); // skip return type
+ }
+}
+
+ILStubLinker::~ILStubLinker()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ DeleteCodeLabels();
+ DeleteCodeStreams();
+}
+
+void ILStubLinker::DeleteCodeLabels()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ MODE_ANY;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ //
+ // walk the list of labels and free each one
+ //
+ ILCodeLabel* pCurrent = m_pLabelList;
+ while (pCurrent)
+ {
+ ILCodeLabel* pDeleteMe = pCurrent;
+ pCurrent = pCurrent->m_pNext;
+ delete pDeleteMe;
+ }
+ m_pLabelList = NULL;
+}
+
+void ILStubLinker::DeleteCodeStreams()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ MODE_ANY;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pCurrent = m_pCodeStreamList;
+ while (pCurrent)
+ {
+ ILCodeStream* pDeleteMe = pCurrent;
+ pCurrent = pCurrent->m_pNextStream;
+ delete pDeleteMe;
+ }
+ m_pCodeStreamList = NULL;
+}
+
+void ILStubLinker::ClearCodeStreams()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ MODE_ANY;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ ILCodeStream* pCurrent = m_pCodeStreamList;
+ while (pCurrent)
+ {
+ pCurrent->ClearCode();
+ pCurrent = pCurrent->m_pNextStream;
+ }
+}
+
+void ILStubLinker::GetStubReturnType(LocalDesc* pLoc)
+{
+ WRAPPER_NO_CONTRACT;
+
+ GetStubReturnType(pLoc, m_pStubSigModule);
+}
+
+void ILStubLinker::GetStubReturnType(LocalDesc* pLoc, Module* pModule)
+{
+ STANDARD_VM_CONTRACT;
+ SigPointer ptr = m_stubSig.CreateSigPointer();
+ ULONG uCallingConv;
+ int nTypeArgs = 0;
+ int nArgs;
+
+ IfFailThrow(ptr.GetCallingConvInfo(&uCallingConv));
+
+ if (uCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
+ IfFailThrow(ptr.GetData((ULONG*)&nTypeArgs));
+
+ IfFailThrow(ptr.GetData((ULONG*)&nArgs));
+
+ GetManagedTypeHelper(pLoc, pModule, ptr.GetPtr(), m_pTypeContext, m_pMD);
+}
+
+CorCallingConvention ILStubLinker::GetStubTargetCallingConv()
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_nativeFnSigBuilder.GetCallingConv();
+}
+
+void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc)
+{
+ STANDARD_VM_CONTRACT;
+ // Turn everything into blittable primitives. The reason this method is needed are
+ // byrefs which are OK only when they ref stack data or are pinned. This condition
+ // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid
+ // of them here.
+ switch (pLoc->ElementType[0])
+ {
+ // primitives
+ case ELEMENT_TYPE_VOID:
+ case ELEMENT_TYPE_BOOLEAN:
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_R4:
+ case ELEMENT_TYPE_R8:
+ case ELEMENT_TYPE_I:
+ case ELEMENT_TYPE_U:
+ {
+ // no transformation needed
+ break;
+ }
+
+ case ELEMENT_TYPE_VALUETYPE:
+ {
+ _ASSERTE(!"Should have been replaced by a native value type!");
+ break;
+ }
+
+ case ELEMENT_TYPE_PTR:
+ {
+#ifdef _TARGET_X86_
+ if (pLoc->bIsCopyConstructed)
+ {
+ // The only pointers that we don't transform to ELEMENT_TYPE_I are those that are
+ // ET_TYPE_CMOD_REQD<IsCopyConstructed>/ET_TYPE_CMOD_REQD<NeedsCopyConstructorModifier>
+ // in the original signature. This convention is understood by the UM thunk compiler
+ // (code:UMThunkMarshInfo.CompileNExportThunk) which will generate different thunk code.
+ // Such parameters come from unmanaged by value but must enter the IL stub by reference
+ // because we are not supposed to make a copy.
+ }
+ else
+#endif // _TARGET_X86_
+ {
+ pLoc->ElementType[0] = ELEMENT_TYPE_I;
+ pLoc->cbType = 1;
+ }
+ break;
+ }
+
+ case ELEMENT_TYPE_INTERNAL:
+ {
+ // JIT will handle structures
+ if (pLoc->InternalToken.IsValueType())
+ {
+ _ASSERTE(pLoc->InternalToken.IsBlittable());
+ break;
+ }
+ // intentional fall-thru
+ }
+
+ // pointers, byrefs, strings, arrays, other ref types -> ELEMENT_TYPE_I
+ default:
+ {
+ pLoc->ElementType[0] = ELEMENT_TYPE_I;
+ pLoc->cbType = 1;
+ break;
+ }
+ }
+}
+
+Module *ILStubLinker::GetStubSigModule()
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_pStubSigModule;
+}
+
+SigTypeContext *ILStubLinker::GetStubSigTypeContext()
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_pTypeContext;
+}
+
+void ILStubLinker::SetStubTargetReturnType(CorElementType typ)
+{
+ WRAPPER_NO_CONTRACT;
+
+ LocalDesc locDesc(typ);
+ SetStubTargetReturnType(&locDesc);
+}
+
+void ILStubLinker::SetStubTargetReturnType(LocalDesc* pLoc)
+{
+ CONTRACTL
+ {
+ WRAPPER(NOTHROW);
+ WRAPPER(GC_NOTRIGGER);
+ WRAPPER(MODE_ANY);
+ PRECONDITION(CheckPointer(pLoc, NULL_NOT_OK));
+ }
+ CONTRACTL_END;
+
+ TransformArgForJIT(pLoc);
+
+ m_nativeFnSigBuilder.SetReturnType(pLoc);
+
+ if ((1 != pLoc->cbType) || (ELEMENT_TYPE_VOID != pLoc->ElementType[0]))
+ {
+ m_iTargetStackDelta++;
+ }
+}
+
+DWORD ILStubLinker::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg /*= true*/)
+{
+ STANDARD_VM_CONTRACT;
+
+ LocalDesc locDesc(typ);
+ return SetStubTargetArgType(&locDesc, fConsumeStubArg);
+}
+
+void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv)
+{
+ LIMITED_METHOD_CONTRACT;
+ m_nativeFnSigBuilder.SetCallingConv(uNativeCallingConv);
+}
+
+static size_t GetManagedTypeForMDArray(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+
+ PRECONDITION(CheckPointer(pLoc));
+ PRECONDITION(CheckPointer(pModule));
+ PRECONDITION(CheckPointer(psigManagedArg));
+ PRECONDITION(*psigManagedArg == ELEMENT_TYPE_ARRAY);
+ }
+ CONTRACTL_END;
+
+ SigPointer ptr;
+ size_t cbDest = 0;
+
+ //
+ // copy ELEMENT_TYPE_ARRAY
+ //
+ pLoc->ElementType[cbDest] = *psigManagedArg;
+ psigManagedArg++;
+ cbDest++;
+
+ ptr.SetSig(psigManagedArg);
+
+ IfFailThrow(ptr.SkipCustomModifiers());
+
+ psigManagedArg = ptr.GetPtr();
+
+ //
+ // get array type
+ //
+ pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
+
+ pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
+ cbDest++;
+
+ //
+ // get array bounds
+ //
+
+ size_t cbType;
+ PCCOR_SIGNATURE psigNextManagedArg;
+
+ // find the start of the next argument
+ ptr.SetSig(psigManagedArg - 1); // -1 to back up to E_T_ARRAY;
+ IfFailThrow(ptr.SkipExactlyOne());
+
+ psigNextManagedArg = ptr.GetPtr();
+
+ // find the start of the array bounds information
+ ptr.SetSig(psigManagedArg);
+ IfFailThrow(ptr.SkipExactlyOne());
+
+ psigManagedArg = ptr.GetPtr(); // point to the array bounds info
+ cbType = psigNextManagedArg - psigManagedArg;
+
+ pLoc->pSig = psigManagedArg; // point to the array bounds info
+ pLoc->cbArrayBoundsInfo = cbType; // size of array bounds info
+ pLoc->cbType = cbDest;
+
+ return cbDest;
+}
+
+
+// static
+void ILStubLinker::GetManagedTypeHelper(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext, MethodDesc *pMD)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+
+ PRECONDITION(CheckPointer(pLoc));
+ PRECONDITION(CheckPointer(pModule));
+ PRECONDITION(CheckPointer(psigManagedArg));
+ }
+ CONTRACTL_END;
+
+ SigPointer ptr(psigManagedArg);
+ CorElementType eType;
+ LOG((LF_STUBS, LL_INFO10000, "GetManagedTypeHelper on type at %p\n", psigManagedArg));
+
+ IfFailThrow(ptr.PeekElemType(&eType));
+
+ size_t cbDest = 0;
+
+ while (eType == ELEMENT_TYPE_PTR ||
+ eType == ELEMENT_TYPE_BYREF ||
+ eType == ELEMENT_TYPE_SZARRAY)
+ {
+ pLoc->ElementType[cbDest] = static_cast<BYTE>(eType);
+ cbDest++;
+
+ if (cbDest >= LocalDesc::MAX_LOCALDESC_ELEMENTS)
+ {
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
+ }
+
+ IfFailThrow(ptr.GetElemType(NULL));
+ IfFailThrow(ptr.PeekElemType(&eType));
+ }
+
+ SigPointer ptr2(ptr);
+ IfFailThrow(ptr2.SkipCustomModifiers());
+ psigManagedArg = ptr2.GetPtr();
+
+ switch (eType)
+ {
+ case ELEMENT_TYPE_VAR:
+ case ELEMENT_TYPE_MVAR:
+ {
+ IfFailThrow(ptr.GetElemType(NULL)); // skip ET
+ ULONG varNum;
+ IfFailThrowBF(ptr.GetData(&varNum), BFA_BAD_COMPLUS_SIG, pModule);
+
+ DWORD varCount = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst.GetNumArgs() :
+ pTypeContext->m_methodInst.GetNumArgs());
+ THROW_BAD_FORMAT_MAYBE(varNum < varCount, BFA_BAD_COMPLUS_SIG, pModule);
+
+ pLoc->InternalToken = (eType == ELEMENT_TYPE_VAR ? pTypeContext->m_classInst[varNum] :
+ pTypeContext->m_methodInst[varNum]);
+
+ pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
+ cbDest++;
+ break;
+ }
+
+ case ELEMENT_TYPE_CLASS:
+ case ELEMENT_TYPE_VALUETYPE:
+ case ELEMENT_TYPE_INTERNAL:
+ {
+ pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
+
+ pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
+ cbDest++;
+ break;
+ }
+
+ case ELEMENT_TYPE_GENERICINST:
+ {
+ pLoc->InternalToken = ptr.GetTypeHandleThrowing(pModule, pTypeContext);
+
+ pLoc->ElementType[cbDest] = ELEMENT_TYPE_INTERNAL;
+ cbDest++;
+ break;
+ }
+
+ case ELEMENT_TYPE_FNPTR:
+ // save off a pointer to the managed sig
+ // we'll convert it in bulk when we store it
+ // in the generated sig
+ pLoc->pSigModule = pModule;
+ pLoc->pSig = psigManagedArg+1;
+
+ pLoc->ElementType[cbDest] = ELEMENT_TYPE_FNPTR;
+ cbDest++;
+ break;
+
+ case ELEMENT_TYPE_ARRAY:
+ cbDest = GetManagedTypeForMDArray(pLoc, pModule, psigManagedArg, pTypeContext);
+ break;
+
+ default:
+ {
+ size_t cbType;
+ PCCOR_SIGNATURE psigNextManagedArg;
+
+ IfFailThrow(ptr.SkipExactlyOne());
+
+ psigNextManagedArg = ptr.GetPtr();
+ cbType = psigNextManagedArg - psigManagedArg;
+
+ size_t cbNewDest;
+ if (!ClrSafeInt<size_t>::addition(cbDest, cbType, cbNewDest) ||
+ cbNewDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
+ {
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
+ }
+
+ memcpyNoGCRefs(&pLoc->ElementType[cbDest], psigManagedArg, cbType);
+ cbDest = cbNewDest;
+ break;
+ }
+ }
+
+ if (cbDest > LocalDesc::MAX_LOCALDESC_ELEMENTS)
+ {
+ COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
+ }
+
+ pLoc->cbType = cbDest;
+}
+
+void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pLoc));
+ }
+ CONTRACTL_END;
+
+ GetStubTargetReturnType(pLoc, m_pStubSigModule);
+}
+
+void ILStubLinker::GetStubTargetReturnType(LocalDesc* pLoc, Module* pModule)
+{
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pLoc));
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ GetManagedTypeHelper(pLoc, pModule, m_nativeFnSigBuilder.GetReturnSig(), m_pTypeContext, NULL);
+}
+
+void ILStubLinker::GetStubArgType(LocalDesc* pLoc)
+{
+
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pLoc));
+ }
+ CONTRACTL_END;
+
+ GetStubArgType(pLoc, m_pStubSigModule);
+}
+
+void ILStubLinker::GetStubArgType(LocalDesc* pLoc, Module* pModule)
+{
+
+ CONTRACTL
+ {
+ STANDARD_VM_CHECK;
+ PRECONDITION(CheckPointer(pLoc));
+ PRECONDITION(CheckPointer(pModule));
+ }
+ CONTRACTL_END;
+
+ GetManagedTypeHelper(pLoc, pModule, m_managedSigPtr.GetPtr(), m_pTypeContext, m_pMD);
+}
+
+//---------------------------------------------------------------------------------------
+//
+DWORD
+ILStubLinker::SetStubTargetArgType(
+ LocalDesc * pLoc, // = NULL
+ bool fConsumeStubArg) // = true
+{
+ STANDARD_VM_CONTRACT;
+
+ LocalDesc locDesc;
+
+ if (fConsumeStubArg)
+ {
+ _ASSERTE(m_pStubSigModule);
+
+ if (pLoc == NULL)
+ {
+ pLoc = &locDesc;
+ GetStubArgType(pLoc, m_pStubSigModule);
+ }
+
+ IfFailThrow(m_managedSigPtr.SkipExactlyOne());
+ }
+
+ TransformArgForJIT(pLoc);
+
+ DWORD dwArgNum = m_nativeFnSigBuilder.NewArg(pLoc);
+ m_iTargetStackDelta--;
+
+ return dwArgNum;
+} // ILStubLinker::SetStubTargetArgType
+
+//---------------------------------------------------------------------------------------
+//
+int ILStubLinker::GetToken(MethodDesc* pMD)
+{
+ STANDARD_VM_CONTRACT;
+ return m_tokenMap.GetToken(pMD);
+}
+
+int ILStubLinker::GetToken(MethodTable* pMT)
+{
+ STANDARD_VM_CONTRACT;
+ return m_tokenMap.GetToken(TypeHandle(pMT));
+}
+
+int ILStubLinker::GetToken(TypeHandle th)
+{
+ STANDARD_VM_CONTRACT;
+ return m_tokenMap.GetToken(th);
+}
+
+int ILStubLinker::GetToken(FieldDesc* pFD)
+{
+ STANDARD_VM_CONTRACT;
+ return m_tokenMap.GetToken(pFD);
+}
+
+
+BOOL ILStubLinker::StubHasVoidReturnType()
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_StubHasVoidReturnType;
+}
+
+void ILStubLinker::ClearCode()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ MODE_ANY;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ DeleteCodeLabels();
+ ClearCodeStreams();
+}
+
+// static
+ILCodeStream* ILStubLinker::FindLastCodeStream(ILCodeStream* pList)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ if (NULL == pList)
+ {
+ return NULL;
+ }
+
+ while (NULL != pList->m_pNextStream)
+ {
+ pList = pList->m_pNextStream;
+ }
+
+ return pList;
+}
+
+ILCodeStream* ILStubLinker::NewCodeStream(CodeStreamType codeStreamType)
+{
+ STANDARD_VM_CONTRACT;
+
+ NewHolder<ILCodeStream> pNewCodeStream = new ILCodeStream(this, codeStreamType);
+
+ if (NULL == m_pCodeStreamList)
+ {
+ m_pCodeStreamList = pNewCodeStream;
+ }
+ else
+ {
+ ILCodeStream* pTail = FindLastCodeStream(m_pCodeStreamList);
+ CONSISTENCY_CHECK(NULL == pTail->m_pNextStream);
+ pTail->m_pNextStream = pNewCodeStream;
+ }
+
+ pNewCodeStream.SuppressRelease();
+ return pNewCodeStream;
+}
+
+int ILCodeStream::GetToken(MethodDesc* pMD)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->GetToken(pMD);
+}
+int ILCodeStream::GetToken(MethodTable* pMT)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->GetToken(pMT);
+}
+int ILCodeStream::GetToken(TypeHandle th)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->GetToken(th);
+}
+int ILCodeStream::GetToken(FieldDesc* pFD)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->GetToken(pFD);
+}
+
+DWORD ILCodeStream::NewLocal(CorElementType typ)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->NewLocal(typ);
+}
+DWORD ILCodeStream::NewLocal(LocalDesc loc)
+{
+ WRAPPER_NO_CONTRACT;
+ return m_pOwner->NewLocal(loc);
+}
+DWORD ILCodeStream::SetStubTargetArgType(CorElementType typ, bool fConsumeStubArg)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->SetStubTargetArgType(typ, fConsumeStubArg);
+}
+DWORD ILCodeStream::SetStubTargetArgType(LocalDesc* pLoc, bool fConsumeStubArg)
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->SetStubTargetArgType(pLoc, fConsumeStubArg);
+}
+void ILCodeStream::SetStubTargetReturnType(CorElementType typ)
+{
+ STANDARD_VM_CONTRACT;
+ m_pOwner->SetStubTargetReturnType(typ);
+}
+void ILCodeStream::SetStubTargetReturnType(LocalDesc* pLoc)
+{
+ STANDARD_VM_CONTRACT;
+ m_pOwner->SetStubTargetReturnType(pLoc);
+}
+ILCodeLabel* ILCodeStream::NewCodeLabel()
+{
+ STANDARD_VM_CONTRACT;
+ return m_pOwner->NewCodeLabel();
+}
+void ILCodeStream::ClearCode()
+{
+ LIMITED_METHOD_CONTRACT;
+ m_uCurInstrIdx = 0;
+}