diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index b2ea69924dbdc6..9b3a3a809a26f8 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -1736,6 +1736,7 @@ int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn) size_t data = !direct ? (size_t)indirect | INTERP_INDIRECT_HELPER_TAG : (size_t)direct; + assert(data); return GetDataItemIndex((void*)data); } @@ -3710,6 +3711,45 @@ int InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) break; } + case CEE_LDTOKEN: + { + AddIns(INTOP_LDTOKEN); + + CORINFO_RESOLVED_TOKEN resolvedToken; + ResolveToken(getU4LittleEndian(m_ip + 1), CORINFO_TOKENKIND_Ldtoken, &resolvedToken); + + CORINFO_CLASS_HANDLE clsHnd = m_compHnd->getTokenTypeAsHandle(&resolvedToken); + PushStackType(StackTypeVT, clsHnd); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + + // see jit/importer.cpp CEE_LDTOKEN + CorInfoHelpFunc helper; + if (resolvedToken.hClass) + { + helper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hClass); + } + else if (resolvedToken.hMethod) + { + helper = CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hMethod); + } + else if (resolvedToken.hField) + { + helper = CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD; + m_pLastNewIns->data[0] = GetDataItemIndex(resolvedToken.hField); + } + else + { + helper = CORINFO_HELP_FAIL_FAST; + assert(!"Token not resolved or resolved to unexpected type"); + } + + m_pLastNewIns->data[1] = GetDataItemIndexForHelperFtn(helper); + m_ip += 5; + break; + } + default: assert(0); break; diff --git a/src/coreclr/interpreter/interpretershared.h b/src/coreclr/interpreter/interpretershared.h index f4a93666f2906c..14b25f71c2c82f 100644 --- a/src/coreclr/interpreter/interpretershared.h +++ b/src/coreclr/interpreter/interpretershared.h @@ -16,6 +16,9 @@ struct InterpMethod { +#if DEBUG + InterpMethod *self; +#endif CORINFO_METHOD_HANDLE methodHnd; int32_t allocaSize; void** pDataItems; @@ -23,11 +26,23 @@ struct InterpMethod InterpMethod(CORINFO_METHOD_HANDLE methodHnd, int32_t allocaSize, void** pDataItems, bool initLocals) { +#if DEBUG + this->self = this; +#endif this->methodHnd = methodHnd; this->allocaSize = allocaSize; this->pDataItems = pDataItems; this->initLocals = initLocals; } + + bool CheckIntegrity() + { +#if DEBUG + return this->self == this; +#else + return true; +#endif + } }; #endif diff --git a/src/coreclr/interpreter/intops.def b/src/coreclr/interpreter/intops.def index 15cbdb336d8998..8f1a45f8611ae0 100644 --- a/src/coreclr/interpreter/intops.def +++ b/src/coreclr/interpreter/intops.def @@ -42,6 +42,8 @@ OPDEF(INTOP_STELEM_I8, "stelem.i8", 4, 0, 3, InterpOpNoArgs) OPDEF(INTOP_STELEM_R4, "stelem.r4", 4, 0, 3, InterpOpNoArgs) OPDEF(INTOP_STELEM_R8, "stelem.r8", 4, 0, 3, InterpOpNoArgs) +OPDEF(INTOP_LDTOKEN, "ldtoken", 4, 1, 0, InterpOpTwoInts) // [token data item] [conversion helper func] + OPDEF(INTOP_MOV_I4_I1, "mov.i4.i1", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_MOV_I4_U1, "mov.i4.u1", 3, 1, 1, InterpOpNoArgs) OPDEF(INTOP_MOV_I4_I2, "mov.i4.i2", 3, 1, 1, InterpOpNoArgs) diff --git a/src/coreclr/vm/callstubgenerator.cpp b/src/coreclr/vm/callstubgenerator.cpp index 2394c5bacea3f1..30a70af7ace201 100644 --- a/src/coreclr/vm/callstubgenerator.cpp +++ b/src/coreclr/vm/callstubgenerator.cpp @@ -47,7 +47,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_RCX_RDX, // 01 (PCODE)Load_RCX_RDX_R8, // 02 (PCODE)Load_RCX_RDX_R8_R9, // 03 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_RDX, // 11 (PCODE)Load_RDX_R8, // 12 (PCODE)Load_RDX_R8_R9, // 13 @@ -75,7 +75,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_XMM0_XMM1, // 01 (PCODE)Load_XMM0_XMM1_XMM2, // 02 (PCODE)Load_XMM0_XMM1_XMM2_XMM3, // 03 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_XMM1, // 11 (PCODE)Load_XMM1_XMM2, // 12 (PCODE)Load_XMM1_XMM2_XMM3, // 13 @@ -121,7 +121,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_RDI_RSI_RDX_RCX, // 03 (PCODE)Load_RDI_RSI_RDX_RCX_R8, // 04 (PCODE)Load_RDI_RSI_RDX_RCX_R8_R9, // 05 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_RSI, // 11 (PCODE)Load_RSI_RDX, // 12 (PCODE)Load_RSI_RDX_RCX, // 13 @@ -200,7 +200,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5, // 05 (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5_XMM6, // 06 (PCODE)Load_XMM0_XMM1_XMM2_XMM3_XMM4_XMM5_XMM6_XMM7,// 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_XMM1, // 11 (PCODE)Load_XMM1_XMM2, // 12 (PCODE)Load_XMM1_XMM2_XMM3, // 13 @@ -321,7 +321,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_X0_X1_X2_X3_X4_X5, // 05 (PCODE)Load_X0_X1_X2_X3_X4_X5_X6, // 06 (PCODE)Load_X0_X1_X2_X3_X4_X5_X6_X7, // 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_X1, // 11 (PCODE)Load_X1_X2, // 12 (PCODE)Load_X1_X2_X3, // 13 @@ -338,7 +338,7 @@ PCODE GPRegsRoutines[] = (PCODE)Load_X2_X3_X4_X5_X6, // 26 (PCODE)Load_X2_X3_X4_X5_X6_X7, // 27 (PCODE)0, // 30 - (PCODE)0, // 31 + (PCODE)0, // 31 (PCODE)0, // 32 (PCODE)Load_X3, // 33 (PCODE)Load_X3_X4, // 34 @@ -438,7 +438,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_D0_D1_D2_D3_D4_D5, // 05 (PCODE)Load_D0_D1_D2_D3_D4_D5_D6, // 06 (PCODE)Load_D0_D1_D2_D3_D4_D5_D6_D7, // 07 - (PCODE)0, // 10 + (PCODE)0, // 10 (PCODE)Load_D1, // 11 (PCODE)Load_D1_D2, // 12 (PCODE)Load_D1_D2_D3, // 13 @@ -455,7 +455,7 @@ PCODE FPRegsRoutines[] = (PCODE)Load_D2_D3_D4_D5_D6, // 26 (PCODE)Load_D2_D3_D4_D5_D6_D7, // 27 (PCODE)0, // 30 - (PCODE)0, // 31 + (PCODE)0, // 31 (PCODE)0, // 32 (PCODE)Load_D3, // 33 (PCODE)Load_D3_D4, // 34 @@ -590,7 +590,7 @@ CallStubHeader *CallStubGenerator::GenerateCallStub(MethodDesc *pMD, AllocMemTra ArgLocDesc argLocDesc; argIt.GetArgLoc(ofs, &argLocDesc); -#ifdef UNIX_AMD64_ABI +#ifdef UNIX_AMD64_ABI if (argIt.GetArgLocDescForStructInRegs() != NULL) { TypeHandle argTypeHandle; @@ -604,33 +604,43 @@ CallStubHeader *CallStubGenerator::GenerateCallStub(MethodDesc *pMD, AllocMemTra { ArgLocDesc argLocDescEightByte = {}; SystemVClassificationType eightByteType = pEEClass->GetEightByteClassification(i); - if (eightByteType == SystemVClassificationTypeInteger) - { - if (argLocDesc.m_cGenReg != 0) - { - argLocDescEightByte.m_cGenReg = 1; - argLocDescEightByte.m_idxGenReg = argLocDesc.m_idxGenReg++; - } - else - { - argLocDescEightByte.m_byteStackSize = 8; - argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; - argLocDesc.m_byteStackIndex += 8; - } - } - else if (eightByteType == SystemVClassificationTypeSSE) + switch (eightByteType) { - if (argLocDesc.m_cFloatReg != 0) + case SystemVClassificationTypeInteger: + case SystemVClassificationTypeIntegerReference: + case SystemVClassificationTypeIntegerByRef: { - argLocDescEightByte.m_cFloatReg = 1; - argLocDescEightByte.m_idxFloatReg = argLocDesc.m_idxFloatReg++; + if (argLocDesc.m_cGenReg != 0) + { + argLocDescEightByte.m_cGenReg = 1; + argLocDescEightByte.m_idxGenReg = argLocDesc.m_idxGenReg++; + } + else + { + argLocDescEightByte.m_byteStackSize = 8; + argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; + argLocDesc.m_byteStackIndex += 8; + } + break; } - else + case SystemVClassificationTypeSSE: { - argLocDescEightByte.m_byteStackSize = 8; - argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; - argLocDesc.m_byteStackIndex += 8; + if (argLocDesc.m_cFloatReg != 0) + { + argLocDescEightByte.m_cFloatReg = 1; + argLocDescEightByte.m_idxFloatReg = argLocDesc.m_idxFloatReg++; + } + else + { + argLocDescEightByte.m_byteStackSize = 8; + argLocDescEightByte.m_byteStackIndex = argLocDesc.m_byteStackIndex; + argLocDesc.m_byteStackIndex += 8; + } + break; } + default: + assert(!"Unhandled systemv classification for argument in GenerateCallStub"); + break; } ProcessArgument(argIt, argLocDescEightByte, pRoutines); } @@ -878,7 +888,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe } if (argLocDesc.m_cGenReg != 0) - { + { if (m_r1 == NoRange) // No active range yet { // Start a new range @@ -907,7 +917,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe // Start a new range m_x1 = argLocDesc.m_idxFloatReg; m_x2 = m_x1 + argLocDesc.m_cFloatReg - 1; - } + } else if (argLocDesc.m_idxFloatReg == m_x2 + 1) { // Extend an existing range @@ -929,7 +939,7 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe // Start a new range m_s1 = argLocDesc.m_byteStackIndex; m_s2 = m_s1 + argLocDesc.m_byteStackSize - 1; - } + } else if ((argLocDesc.m_byteStackIndex == m_s2 + 1) && (argLocDesc.m_byteStackSize >= 8)) { // Extend an existing range, but only if the argument is at least pointer size large. @@ -987,4 +997,4 @@ void CallStubGenerator::ProcessArgument(ArgIterator& argIt, ArgLocDesc& argLocDe #endif // UNIX_AMD64_ABI } -#endif // FEATURE_INTERPRETER \ No newline at end of file +#endif // FEATURE_INTERPRETER diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 0bfbe460275879..15d91a4cf5398c 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -91,6 +91,8 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr int8_t *stack; InterpMethod *pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); + pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); stack = pFrame->pStack; @@ -1172,6 +1174,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr // Set execution state for the new frame pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); stack = pFrame->pStack; ip = pFrame->startIp + sizeof(InterpMethod*) / sizeof(int32_t); pThreadContext->pStackPointer = stack + pMethod->allocaSize; @@ -1423,6 +1426,21 @@ do { \ STELEM(double, double); break; } + case INTOP_LDTOKEN: + { + int dreg = ip[1]; + void *nativeHandle = pMethod->pDataItems[ip[2]]; + size_t helperDirectOrIndirect = (size_t)pMethod->pDataItems[ip[3]]; + HELPER_FTN_PP helper = nullptr; + if (helperDirectOrIndirect & INTERP_INDIRECT_HELPER_TAG) + helper = *(HELPER_FTN_PP *)(helperDirectOrIndirect & ~INTERP_INDIRECT_HELPER_TAG); + else + helper = (HELPER_FTN_PP)helperDirectOrIndirect; + void *managedHandle = helper(nativeHandle); + LOCAL_VAR(dreg, void*) = managedHandle; + ip += 4; + break; + } case INTOP_FAILFAST: assert(0); break; @@ -1456,6 +1474,7 @@ do { \ stack = pFrame->pStack; pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; goto MAIN_LOOP; } @@ -1472,6 +1491,7 @@ do { \ ip = pFrame->ip; stack = pFrame->pStack; pMethod = *(InterpMethod**)pFrame->startIp; + assert(pMethod->CheckIntegrity()); pFrame->ip = NULL; pThreadContext->pStackPointer = pFrame->pStack + pMethod->allocaSize; diff --git a/src/tests/JIT/interpreter/Interpreter.cs b/src/tests/JIT/interpreter/Interpreter.cs index 866102e9f2e480..a78df5ef49b14e 100644 --- a/src/tests/JIT/interpreter/Interpreter.cs +++ b/src/tests/JIT/interpreter/Interpreter.cs @@ -419,6 +419,13 @@ public static void RunInterpreterTests() if (!TestSizeof()) Environment.FailFast(null); + if (!TestLdtoken()) + Environment.FailFast(null); + /* + if (!TestMdArray()) + Environment.FailFast(null); + */ + System.GC.Collect(); } @@ -959,4 +966,31 @@ public static unsafe bool TestSizeof() return false; return true; } + + public static int LdtokenField = 7; + + public static bool TestLdtoken() + { + Type t = typeof(int); + int i = 42; + if (!ReferenceEquals(t, i.GetType())) + return false; + // These generate field and method ldtoken opcodes, but the test fails because we are missing castclass and possibly also generics + /* + System.Linq.Expressions.Expression> f = () => LdtokenField; + System.Linq.Expressions.Expression a = () => TestLdtoken(); + */ + return true; + } + + public static bool TestMdArray() + { + // FIXME: This generates roughly: + // newobj int[,].ctor + // ldtoken int[,] + // call System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray + // The newobj currently fails because int[,].ctor isn't a real method, the interp needs to use getCallInfo to determine how to invoke it + int[,] a = {{1, 2}, {3, 4}}; + return a[0, 1] == 2; + } }