diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 4cee79fd1e30f3..851580db7fafb8 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -1645,6 +1645,11 @@ static void FreeInterpreterStackMap(void *key, void *value, void *userdata) delete (InterpreterStackMap *)value; } +static void InterpreterCompilerBreak() +{ + assert(!"InterpreterCompilerBreak reached"); +} + InterpCompiler::InterpCompiler(COMP_HANDLE compHnd, CORINFO_METHOD_INFO* methodInfo) : m_stackmapsByClass(FreeInterpreterStackMap) @@ -1689,6 +1694,13 @@ InterpMethod* InterpCompiler::CompileMethod() printf("Interpreter compile method %s\n", m_methodName.GetUnderlyingArray()); } #endif +#ifdef DEBUG + if (InterpConfig.InterpBreak().contains(m_compHnd, m_methodInfo->ftn, m_classHnd, &m_methodInfo->args)) + { + InterpreterCompilerBreak(); + } +#endif + m_isSynchronized = m_compHnd->getMethodAttribs(m_methodHnd) & CORINFO_FLG_SYNCH; if (m_isSynchronized) { @@ -3679,6 +3691,90 @@ void InterpCompiler::EmitCalli(bool isTailCall, void* calliCookie, int callIFunc m_pLastNewIns->SetSVars2(CALL_ARGS_SVAR, callIFunctionPointerVar); } +void InterpCompiler::EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken) +{ + CORINFO_HELPER_DESC calloutHelper; + CorInfoIsAccessAllowedResult accessAllowed = + m_compHnd->canAccessClass(pResolvedToken, m_methodHnd, &calloutHelper); + + // Inject call to callsite callout helper + EmitCallsiteCallout(accessAllowed, &calloutHelper); +} + +void InterpCompiler::EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc) +{ + if (accessAllowed == CORINFO_ACCESS_ILLEGAL) + { + int32_t svars[CORINFO_ACCESS_ALLOWED_MAX_ARGS]; + + for (unsigned i = 0; i < calloutDesc->numArgs; i++) + { + void *value = NULL; + void *pValue = NULL; + + switch (calloutDesc->args[i].argType) + { + case CORINFO_HELPER_ARG_TYPE_Class: + value = (void*)m_compHnd->embedClassHandle(calloutDesc->args[i].classHandle, &pValue); + break; + case CORINFO_HELPER_ARG_TYPE_Method: + value = (void*)m_compHnd->embedMethodHandle(calloutDesc->args[i].methodHandle, &pValue); + break; + default: + NO_WAY("Callsite callout with unsupported arg type"); + } + + if (value == NULL) + { + if (pValue == NULL) + { + NO_WAY("Callsite callout with unsupported arg type"); + } + + AddIns(INTOP_LDPTR); + m_pLastNewIns->data[0] = GetDataItemIndex(pValue); + PushInterpType(InterpTypeI, nullptr); + int tempVar = m_pStackPointer[-1].var; + m_pLastNewIns->SetDVar(tempVar); + + // Now we generate an LDIND_I to get the actual value out of the ref + AddIns(INTOP_LDIND_I); + m_pLastNewIns->data[0] = 0; + m_pLastNewIns->SetSVar(tempVar); + m_pStackPointer--; + PushInterpType(InterpTypeI, NULL); + m_pLastNewIns->SetDVar(m_pStackPointer[-1].var); + m_pStackPointer--; + svars[i] = m_pStackPointer[0].var; + } + else + { + AddIns(INTOP_LDPTR); + m_pLastNewIns->data[0] = GetDataItemIndex(value); + PushInterpType(InterpTypeI, nullptr); + svars[i] = m_pStackPointer[-1].var; + m_pLastNewIns->SetDVar(svars[i]); + m_pStackPointer--; + } + } + if (calloutDesc->numArgs == 2) + { + AddIns(INTOP_CALL_HELPER_V_SS); + m_pLastNewIns->SetSVars2(svars[0], svars[1]); + } + else if (calloutDesc->numArgs == 3) + { + AddIns(INTOP_CALL_HELPER_V_SSS); + m_pLastNewIns->SetSVars3(svars[0], svars[1], svars[2]); + } + else + { + NO_WAY("Callsite callout with unsupported number of args"); + } + m_pLastNewIns->data[0] = GetDataForHelperFtn(calloutDesc->helperNum); + } +} + void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli) { uint32_t token = getU4LittleEndian(m_ip + 1); @@ -3761,6 +3857,10 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re flags = (CORINFO_CALLINFO_FLAGS)(flags | CORINFO_CALLINFO_CALLVIRT); m_compHnd->getCallInfo(&resolvedCallToken, pConstrainedToken, m_methodInfo->ftn, flags, &callInfo); + + // Inject call to callsite callout helper + EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper); + if (callInfo.methodFlags & CORINFO_FLG_INTRINSIC) { NamedIntrinsic ni = GetNamedIntrinsic(m_compHnd, m_methodHnd, callInfo.hMethod); @@ -6293,6 +6393,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_ADDRESS, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC); if (isStatic) @@ -6324,6 +6427,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + CorInfoType fieldType = fieldInfo.fieldType; bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC); InterpType interpFieldType = GetInterpType(fieldType); @@ -6384,6 +6490,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + CorInfoType fieldType = fieldInfo.fieldType; bool isStatic = !!(fieldInfo.fieldFlags & CORINFO_FLG_FIELD_STATIC); InterpType interpFieldType = GetInterpType(fieldType); @@ -6418,6 +6527,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_ADDRESS, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + EmitStaticFieldAddress(&fieldInfo, &resolvedToken); m_ip += 5; @@ -6431,6 +6543,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + CorInfoType fieldType = fieldInfo.fieldType; InterpType interpFieldType = GetInterpType(fieldType); @@ -6454,6 +6569,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) ResolveToken(token, CORINFO_TOKENKIND_Field, &resolvedToken); m_compHnd->getFieldInfo(&resolvedToken, m_methodHnd, CORINFO_ACCESS_GET, &fieldInfo); + // Inject call to callsite callout helper + EmitCallsiteCallout(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper); + CorInfoType fieldType = fieldInfo.fieldType; InterpType interpFieldType = GetInterpType(fieldType); @@ -6584,6 +6702,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CORINFO_RESOLVED_TOKEN resolvedToken; ResolveToken(token, CORINFO_TOKENKIND_Class, &resolvedToken); + + EmitCanAccessCallout(&resolvedToken); + CORINFO_GENERICHANDLE_RESULT embedInfo; m_compHnd->embedGenericHandle(&resolvedToken, true, m_methodInfo->ftn, &embedInfo); assert(embedInfo.compileTimeHandle != NULL); @@ -6834,6 +6955,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) NO_WAY("Currently do not support LDFTN of Parameterized functions"); } + // Inject call to callsite callout helper + EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper); + m_pStackPointer--; int thisVar = m_pStackPointer[0].var; @@ -6864,6 +6988,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) NO_WAY("Currently do not support LDFTN of Parameterized functions"); } + // Inject call to callsite callout helper + EmitCallsiteCallout(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper); + DO_LDFTN: if (callInfo.kind == CORINFO_CALL) { @@ -6961,6 +7088,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CHECK_STACK(1); CORINFO_RESOLVED_TOKEN resolvedToken; ResolveToken(token, CORINFO_TOKENKIND_Box, &resolvedToken); + + EmitCanAccessCallout(&resolvedToken); + if (m_compHnd->isValueClass(resolvedToken.hClass)) { CORINFO_GENERICHANDLE_RESULT embedInfo; @@ -6980,6 +7110,9 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CHECK_STACK(1); CORINFO_RESOLVED_TOKEN resolvedToken; ResolveToken(token, CORINFO_TOKENKIND_Class, &resolvedToken); + + EmitCanAccessCallout(&resolvedToken); + CORINFO_GENERICHANDLE_RESULT embedInfo; m_compHnd->embedGenericHandle(&resolvedToken, false, m_methodInfo->ftn, &embedInfo); DeclarePointerIsClass((CORINFO_CLASS_HANDLE)embedInfo.compileTimeHandle); @@ -7067,6 +7200,8 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CORINFO_RESOLVED_TOKEN resolvedToken; ResolveToken(token, CORINFO_TOKENKIND_Newarr, &resolvedToken); + EmitCanAccessCallout(&resolvedToken); + CORINFO_CLASS_HANDLE arrayClsHnd = resolvedToken.hClass; CorInfoHelpFunc helpFunc = m_compHnd->getNewArrHelper(arrayClsHnd); DeclarePointerIsClass(arrayClsHnd); @@ -7465,6 +7600,8 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) CORINFO_RESOLVED_TOKEN resolvedToken; ResolveToken(getU4LittleEndian(m_ip + 1), CORINFO_TOKENKIND_Casting, &resolvedToken); + EmitCanAccessCallout(&resolvedToken); + CorInfoHelpFunc castingHelper = m_compHnd->getCastingHelper(&resolvedToken, *m_ip == CEE_CASTCLASS /* throwing */); CORINFO_GENERICHANDLE_RESULT embedInfo; diff --git a/src/coreclr/interpreter/compiler.h b/src/coreclr/interpreter/compiler.h index db4d667b789fd7..a926243a90f28c 100644 --- a/src/coreclr/interpreter/compiler.h +++ b/src/coreclr/interpreter/compiler.h @@ -746,6 +746,8 @@ class InterpCompiler void EmitBox(StackInfo* pStackInfo, const CORINFO_GENERICHANDLE_RESULT &boxType, bool argByRef); void EmitLeave(int32_t ilOffset, int32_t target); void EmitPushSyncObject(); + void EmitCallsiteCallout(CorInfoIsAccessAllowedResult accessAllowed, CORINFO_HELPER_DESC* calloutDesc); + void EmitCanAccessCallout(CORINFO_RESOLVED_TOKEN *pResolvedToken); // Var Offset allocator TArray *m_pActiveCalls; diff --git a/src/coreclr/interpreter/inc/intops.def b/src/coreclr/interpreter/inc/intops.def index d5729f43dbb60c..1ba3e9cee29ddf 100644 --- a/src/coreclr/interpreter/inc/intops.def +++ b/src/coreclr/interpreter/inc/intops.def @@ -403,6 +403,10 @@ OPDEF(INTOP_CALL_HELPER_V_AGS, "call.helper.v.ags", 6, 1, 2, InterpOpGenericHelp // Call a helper function with a signature of void helper(SVar1, AddrOfSVar2) OPDEF(INTOP_CALL_HELPER_V_SA, "call.helper.v.sa", 4, 0, 2, InterpOpHelperFtnNoArgs) +// Call a helper function with a signature of void helper(Pointer,Pointer,Pointer) +OPDEF(INTOP_CALL_HELPER_V_SS, "call.helper.v.ss", 4, 0, 2, InterpOpHelperFtnNoArgs) +OPDEF(INTOP_CALL_HELPER_V_SSS, "call.helper.v.sss", 5, 0, 3, InterpOpHelperFtnNoArgs) + OPDEF(INTOP_GENERICLOOKUP, "generic", 4, 1, 1, InterpOpGenericLookup) OPDEF(INTOP_CALL_FINALLY, "call.finally", 2, 0, 0, InterpOpBranch) diff --git a/src/coreclr/interpreter/interpconfigvalues.h b/src/coreclr/interpreter/interpconfigvalues.h index 2e729dedd4af69..df245abaf7f4e5 100644 --- a/src/coreclr/interpreter/interpconfigvalues.h +++ b/src/coreclr/interpreter/interpconfigvalues.h @@ -22,6 +22,7 @@ RELEASE_CONFIG_METHODSET(Interpreter, "Interpreter") CONFIG_METHODSET(InterpHaltOnCall, "InterpHaltOnCall"); // Assert in the compiler when compiling a call to these method(s) CONFIG_METHODSET(InterpHalt, "InterpHalt"); +CONFIG_METHODSET(InterpBreak, "InterpBreak"); // Break into the debugger when compiling this method CONFIG_METHODSET(InterpDump, "InterpDump"); CONFIG_INTEGER(InterpList, "InterpList", 0); // List the methods which are compiled by the interpreter JIT RELEASE_CONFIG_INTEGER(InterpMode, "InterpMode", 0); // Interpreter mode, one of the following: diff --git a/src/coreclr/vm/interpexec.cpp b/src/coreclr/vm/interpexec.cpp index 2bb77033da0b6d..d6cc958f06341e 100644 --- a/src/coreclr/vm/interpexec.cpp +++ b/src/coreclr/vm/interpexec.cpp @@ -2333,6 +2333,59 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr ip += 4; break; } + case INTOP_CALL_HELPER_V_SS: + { + void* helperArg1 = LOCAL_VAR(ip[1], void*); + void* helperArg2 = LOCAL_VAR(ip[2], void*); + MethodDesc *pILTargetMethod = NULL; + HELPER_FTN_V_PP helperFtn = GetPossiblyIndirectHelper(pMethod, ip[3], &pILTargetMethod); + if (pILTargetMethod != NULL) + { + returnOffset = pMethod->allocaSize; + callArgsOffset = pMethod->allocaSize; + + // Pass arguments to the target method + LOCAL_VAR(callArgsOffset, void*) = helperArg1; + LOCAL_VAR(callArgsOffset + INTERP_STACK_SLOT_SIZE, void*) = helperArg2; + + targetMethod = pILTargetMethod; + ip += 4; + goto CALL_INTERP_METHOD; + } + + _ASSERTE(helperFtn != NULL); + helperFtn(helperArg1, helperArg2); + ip += 4; + break; + } + + case INTOP_CALL_HELPER_V_SSS: + { + void* helperArg1 = LOCAL_VAR(ip[1], void*); + void* helperArg2 = LOCAL_VAR(ip[2], void*); + void* helperArg3 = LOCAL_VAR(ip[3], void*); + MethodDesc *pILTargetMethod = NULL; + HELPER_FTN_V_PPP helperFtn = GetPossiblyIndirectHelper(pMethod, ip[4], &pILTargetMethod); + if (pILTargetMethod != NULL) + { + returnOffset = pMethod->allocaSize; + callArgsOffset = pMethod->allocaSize; + + // Pass arguments to the target method + LOCAL_VAR(callArgsOffset, void*) = helperArg1; + LOCAL_VAR(callArgsOffset + INTERP_STACK_SLOT_SIZE, void*) = helperArg2; + LOCAL_VAR(callArgsOffset + 2 * INTERP_STACK_SLOT_SIZE, void*) = helperArg3; + + targetMethod = pILTargetMethod; + ip += 5; + goto CALL_INTERP_METHOD; + } + + _ASSERTE(helperFtn != NULL); + helperFtn(helperArg1, helperArg2, helperArg3); + ip += 5; + break; + } case INTOP_CALLVIRT_TAIL: case INTOP_CALLVIRT: