diff options
author | Fadi Hanna <fadim@microsoft.com> | 2016-05-13 20:35:54 -0700 |
---|---|---|
committer | Fadi Hanna <fadim@microsoft.com> | 2016-05-13 20:35:54 -0700 |
commit | 97b4ff0b438261ba11b357008630076054a6f25d (patch) | |
tree | 320c32b25b556124cb354ab06a86c8f6ae806d98 | |
parent | 5b065284dc57bc3a9eaee9f86b0df258b1d3d7af (diff) | |
download | coreclr-97b4ff0b438261ba11b357008630076054a6f25d.tar.gz coreclr-97b4ff0b438261ba11b357008630076054a6f25d.tar.bz2 coreclr-97b4ff0b438261ba11b357008630076054a6f25d.zip |
Initial implementation of generic dictionary access for R2R. (#4519)
For now, only TypeHandle dictionary entry slots are supported and encoded in a R2R version resilient format (the rest to come soon).
Support is only limited for x64 Windows platforms (rest is still TODO)
The basic idea: each dictionary access is initally a call to a DynamicHelper R2R cell that computes the dictionary signature, and patches the R2R cell address with an assembly stub that performs the dictionary lookup.
-rw-r--r-- | src/inc/corcompile.h | 13 | ||||
-rw-r--r-- | src/inc/corinfo.h | 9 | ||||
-rw-r--r-- | src/inc/readytorun.h | 15 | ||||
-rw-r--r-- | src/inc/readytorunhelpers.h | 12 | ||||
-rw-r--r-- | src/jit/compiler.h | 10 | ||||
-rw-r--r-- | src/jit/importer.cpp | 291 | ||||
-rw-r--r-- | src/vm/amd64/cgenamd64.cpp | 109 | ||||
-rw-r--r-- | src/vm/i386/cgenx86.cpp | 26 | ||||
-rw-r--r-- | src/vm/jitinterface.cpp | 510 | ||||
-rw-r--r-- | src/vm/jitinterface.h | 44 | ||||
-rw-r--r-- | src/vm/prestub.cpp | 121 | ||||
-rw-r--r-- | src/vm/readytoruninfo.h | 3 | ||||
-rw-r--r-- | src/vm/zapsig.cpp | 16 | ||||
-rw-r--r-- | src/zap/zapimage.cpp | 62 | ||||
-rw-r--r-- | src/zap/zapimport.cpp | 69 | ||||
-rw-r--r-- | src/zap/zapimport.h | 5 | ||||
-rw-r--r-- | src/zap/zapinfo.cpp | 118 | ||||
-rw-r--r-- | src/zap/zapinfo.h | 8 | ||||
-rw-r--r-- | src/zap/zapreadytorun.cpp | 38 |
19 files changed, 1029 insertions, 450 deletions
diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h index fd728212bc..0b87b3e253 100644 --- a/src/inc/corcompile.h +++ b/src/inc/corcompile.h @@ -683,11 +683,15 @@ enum CORCOMPILE_GCREFMAP_TOKENS // Tags for fixup blobs enum CORCOMPILE_FIXUP_BLOB_KIND { - ENCODE_NONE = 0, + ENCODE_NONE = 0, - ENCODE_MODULE_OVERRIDE = 0x80, /* When the high bit is set, override of the module immediately follows */ + ENCODE_MODULE_OVERRIDE = 0x80, /* When the high bit is set, override of the module immediately follows */ - ENCODE_TYPE_HANDLE = 0x10, /* Type handle */ + ENCODE_DICTIONARY_LOOKUP_THISOBJ = 0x07, + ENCODE_DICTIONARY_LOOKUP_TYPE = 0x08, + ENCODE_DICTIONARY_LOOKUP_METHOD = 0x09, + + ENCODE_TYPE_HANDLE = 0x10, /* Type handle */ ENCODE_METHOD_HANDLE, /* Method handle */ ENCODE_FIELD_HANDLE, /* Field handle */ @@ -728,7 +732,8 @@ enum CORCOMPILE_FIXUP_BLOB_KIND ENCODE_DELEGATE_CTOR, - ENCODE_MODULE_HANDLE = 0x50, /* Module token */ + + ENCODE_MODULE_HANDLE = 0x50, /* Module token */ ENCODE_STATIC_FIELD_ADDRESS, /* For accessing a static field */ ENCODE_MODULE_ID_FOR_STATICS, /* For accessing static fields */ ENCODE_MODULE_ID_FOR_GENERIC_STATICS, /* For accessing static fields */ diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index bd4a086dea..6ea69bbe87 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -639,7 +639,6 @@ enum CorInfoHelpFunc CORINFO_HELP_READYTORUN_CHKCAST, CORINFO_HELP_READYTORUN_STATIC_BASE, CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, - #if COR_JIT_EE_VERSION > 460 CORINFO_HELP_READYTORUN_GENERIC_HANDLE, CORINFO_HELP_READYTORUN_DELEGATE_CTOR, @@ -2425,10 +2424,10 @@ public: #if COR_JIT_EE_VERSION > 460 virtual bool getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_LOOKUP_KIND * pGenericLookupKind, - CorInfoHelpFunc id, - CORINFO_CONST_LOOKUP * pLookup + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup ) = 0; virtual void getReadyToRunDelegateCtorHelper( diff --git a/src/inc/readytorun.h b/src/inc/readytorun.h index 7a82ec4016..71879cdad4 100644 --- a/src/inc/readytorun.h +++ b/src/inc/readytorun.h @@ -122,6 +122,10 @@ enum ReadyToRunTypeLayoutFlags enum ReadyToRunFixupKind { + READYTORUN_FIXUP_ThisObjDictionaryLookup = 0x07, + READYTORUN_FIXUP_TypeDictionaryLookup = 0x08, + READYTORUN_FIXUP_MethodDictionaryLookup = 0x09, + READYTORUN_FIXUP_TypeHandle = 0x10, READYTORUN_FIXUP_MethodHandle = 0x11, READYTORUN_FIXUP_FieldHandle = 0x12, @@ -226,6 +230,17 @@ enum ReadyToRunHelper READYTORUN_HELPER_Unbox_Nullable = 0x5B, READYTORUN_HELPER_NewMultiDimArr = 0x5C, + // Helpers used with generic handle lookup cases + READYTORUN_HELPER_NewObject = 0x60, + READYTORUN_HELPER_NewArray = 0x61, + READYTORUN_HELPER_CheckCastAny = 0x62, + READYTORUN_HELPER_CheckInstanceAny = 0x63, + READYTORUN_HELPER_GenericGcStaticBase = 0x64, + READYTORUN_HELPER_GenericNonGcStaticBase = 0x65, + READYTORUN_HELPER_GenericGcTlsBase = 0x66, + READYTORUN_HELPER_GenericNonGcTlsBase = 0x67, + READYTORUN_HELPER_VirtualFuncPtr = 0x68, + // Long mul/div/shift ops READYTORUN_HELPER_LMul = 0xC0, READYTORUN_HELPER_LMulOfv = 0xC1, diff --git a/src/inc/readytorunhelpers.h b/src/inc/readytorunhelpers.h index 2dcb1a1a03..c9c429263c 100644 --- a/src/inc/readytorunhelpers.h +++ b/src/inc/readytorunhelpers.h @@ -42,6 +42,18 @@ HELPER(READYTORUN_HELPER_Unbox, CORINFO_HELP_UNBOX, HELPER(READYTORUN_HELPER_Unbox_Nullable, CORINFO_HELP_UNBOX_NULLABLE, ) HELPER(READYTORUN_HELPER_NewMultiDimArr, CORINFO_HELP_NEW_MDARR, ) +HELPER(READYTORUN_HELPER_NewObject, CORINFO_HELP_NEWFAST, ) +HELPER(READYTORUN_HELPER_NewArray, CORINFO_HELP_NEWARR_1_DIRECT, ) +HELPER(READYTORUN_HELPER_CheckCastAny, CORINFO_HELP_CHKCASTANY, ) +HELPER(READYTORUN_HELPER_CheckInstanceAny, CORINFO_HELP_ISINSTANCEOFANY, ) + +HELPER(READYTORUN_HELPER_GenericGcStaticBase, CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericNonGcStaticBase, CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,) + +HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, ) + HELPER(READYTORUN_HELPER_LMul, CORINFO_HELP_LMUL, ) HELPER(READYTORUN_HELPER_LMulOfv, CORINFO_HELP_LMUL_OVF, ) HELPER(READYTORUN_HELPER_ULMulOvf, CORINFO_HELP_ULMUL_OVF, ) diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 32888c1556..88c5965b49 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -2818,12 +2818,13 @@ public: return impTokenToHandle(pResolvedToken, pRuntimeLookup, mustRestoreHandle, TRUE); } - GenTreePtr impLookupToTree(CORINFO_LOOKUP *pLookup, + GenTreePtr impLookupToTree(CORINFO_RESOLVED_TOKEN *pResolvedToken, + CORINFO_LOOKUP *pLookup, unsigned flags, void *compileTimeHandle); - GenTreePtr impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND kind, - CORINFO_RUNTIME_LOOKUP *pLookup, + GenTreePtr impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN *pResolvedToken, + CORINFO_LOOKUP *pLookup, void * compileTimeHandle); GenTreePtr impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP *pLookup, @@ -2833,7 +2834,8 @@ public: GenTreePtr impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN * pResolvedToken, CorInfoHelpFunc helper, var_types type, - GenTreePtr arg = NULL); + GenTreeArgList* arg = NULL, + CORINFO_LOOKUP_KIND * pGenericLookupKind = NULL); GenTreePtr impCastClassOrIsInstToTree(GenTreePtr op1, GenTreePtr op2, diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index b5b7f88b71..e210e6520b 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -1571,10 +1571,13 @@ GenTreePtr Compiler::impTokenToHandle(CORINFO_RESOLVED_TOKEN * pResolve } } - return impLookupToTree(&embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token), embedInfo.compileTimeHandle); + return impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token), embedInfo.compileTimeHandle); } -GenTreePtr Compiler::impLookupToTree(CORINFO_LOOKUP *pLookup, unsigned handleFlags, void *compileTimeHandle) +GenTreePtr Compiler::impLookupToTree(CORINFO_RESOLVED_TOKEN *pResolvedToken, + CORINFO_LOOKUP *pLookup, + unsigned handleFlags, + void *compileTimeHandle) { if (!pLookup->lookupKind.needsRuntimeLookup) { @@ -1604,9 +1607,7 @@ GenTreePtr Compiler::impLookupToTree(CORINFO_LOOKUP *pLookup, unsigned // Need to use dictionary-based access which depends on the typeContext // which is only available at runtime, not at compile-time. - return impRuntimeLookupToTree(pLookup->lookupKind.runtimeLookupKind, - &pLookup->runtimeLookup, - compileTimeHandle); + return impRuntimeLookupToTree(pResolvedToken, pLookup, compileTimeHandle); } } @@ -1627,23 +1628,21 @@ GenTreePtr Compiler::impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP *pL 0, 0, compileTimeHandle); } -GenTreePtr Compiler::impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN * pResolvedToken, - CorInfoHelpFunc helper, - var_types type, - GenTreePtr arg) +GenTreePtr Compiler::impReadyToRunHelperToTree( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CorInfoHelpFunc helper, + var_types type, + GenTreeArgList* args /* =NULL*/, + CORINFO_LOOKUP_KIND * pGenericLookupKind /* =NULL. Only used with generics */) { CORINFO_CONST_LOOKUP lookup; #if COR_JIT_EE_VERSION > 460 - info.compCompHnd->getReadyToRunHelper(pResolvedToken, nullptr, helper, &lookup); + if (!info.compCompHnd->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, helper, &lookup)) + return NULL; #else info.compCompHnd->getReadyToRunHelper(pResolvedToken, helper, &lookup); #endif - GenTreeArgList* args = NULL; - - if (arg != NULL) - args = gtNewArgList(arg); - GenTreePtr op1 = gtNewHelperCallNode(helper, type, GTF_EXCEPT, args); op1->gtCall.gtEntryPoint = lookup; @@ -1682,7 +1681,7 @@ GenTreePtr Compiler::impMethodPointer(CORINFO_RESOLVED_TOKEN * pResolvedToken, C return nullptr; } - op1 = impLookupToTree(&pCallInfo->codePointerLookup, GTF_ICON_FTN_ADDR, pCallInfo->hMethod); + op1 = impLookupToTree(pResolvedToken, &pCallInfo->codePointerLookup, GTF_ICON_FTN_ADDR, pCallInfo->hMethod); break; default: @@ -1712,10 +1711,13 @@ GenTreePtr Compiler::impMethodPointer(CORINFO_RESOLVED_TOKEN * pResolvedToken, C to lookup the handle. */ -GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND kind, - CORINFO_RUNTIME_LOOKUP* pLookup, +GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN *pResolvedToken, + CORINFO_LOOKUP *pLookup, void* compileTimeHandle) { + CORINFO_RUNTIME_LOOKUP_KIND kind = pLookup->lookupKind.runtimeLookupKind; + CORINFO_RUNTIME_LOOKUP* pRuntimeLookup = &pLookup->runtimeLookup; + // This method can only be called from the importer instance of the Compiler. // In other word, it cannot be called by the instance of the Compiler for the inlinee. assert(!compIsForInlining()); @@ -1744,24 +1746,34 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND ctxTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL); // Exact method descriptor as passed in as last arg } +#ifdef FEATURE_READYTORUN_COMPILER + if (opts.IsReadyToRun()) + { + return impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, + TYP_I_IMPL, gtNewArgList(ctxTree), &pLookup->lookupKind); + } +#endif + + // It's available only via the run-time helper function - if (pLookup->indirections == CORINFO_USEHELPER) + if (pRuntimeLookup->indirections == CORINFO_USEHELPER) { - GenTreeArgList* helperArgs = gtNewArgList(ctxTree, gtNewIconEmbHndNode(pLookup->signature, NULL, GTF_ICON_TOKEN_HDL, 0, NULL, compileTimeHandle)); + GenTreeArgList* helperArgs = gtNewArgList(ctxTree, gtNewIconEmbHndNode( + pRuntimeLookup->signature, NULL, GTF_ICON_TOKEN_HDL, 0, NULL, compileTimeHandle)); - return gtNewHelperCallNode(pLookup->helper, TYP_I_IMPL, GTF_EXCEPT, helperArgs); + return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, GTF_EXCEPT, helperArgs); } // Slot pointer GenTreePtr slotPtrTree = ctxTree; - if (pLookup->testForNull) + if (pRuntimeLookup->testForNull) { slotPtrTree = impCloneExpr(ctxTree, &ctxTree, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, NULL DEBUGARG("impRuntimeLookup slot") ); } // Applied repeated indirections - for (WORD i = 0; i < pLookup->indirections; i++) + for (WORD i = 0; i < pRuntimeLookup->indirections; i++) { if (i != 0) { @@ -1769,14 +1781,14 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND slotPtrTree->gtFlags |= GTF_IND_NONFAULTING; slotPtrTree->gtFlags |= GTF_IND_INVARIANT; } - if (pLookup->offsets[i] != 0) - slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, slotPtrTree, gtNewIconNode(pLookup->offsets[i], TYP_I_IMPL)); + if (pRuntimeLookup->offsets[i] != 0) + slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, slotPtrTree, gtNewIconNode(pRuntimeLookup->offsets[i], TYP_I_IMPL)); } // No null test required - if (!pLookup->testForNull) + if (!pRuntimeLookup->testForNull) { - if (pLookup->indirections == 0) + if (pRuntimeLookup->indirections == 0) { return slotPtrTree; } @@ -1784,7 +1796,7 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND slotPtrTree = gtNewOperNode(GT_IND, TYP_I_IMPL, slotPtrTree); slotPtrTree->gtFlags |= GTF_IND_NONFAULTING; - if (!pLookup->testForFixup) + if (!pRuntimeLookup->testForFixup) { return slotPtrTree; } @@ -1811,7 +1823,7 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND return gtNewLclvNode(tmp, TYP_I_IMPL); } - assert(pLookup->indirections != 0); + assert(pRuntimeLookup->indirections != 0); impSpillSideEffects(true, CHECK_SPILL_ALL DEBUGARG("bubbling QMark1")); @@ -1822,8 +1834,9 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RUNTIME_LOOKUP_KIND GenTreePtr handleCopy = impCloneExpr(handle, &handle, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL, NULL DEBUGARG("impRuntimeLookup typehandle") ); // Call to helper - GenTreeArgList* helperArgs = gtNewArgList(ctxTree, gtNewIconEmbHndNode(pLookup->signature, NULL, GTF_ICON_TOKEN_HDL, 0, NULL, compileTimeHandle)); - GenTreePtr helperCall = gtNewHelperCallNode(pLookup->helper, TYP_I_IMPL, GTF_EXCEPT, helperArgs); + GenTreeArgList* helperArgs = gtNewArgList(ctxTree, gtNewIconEmbHndNode( + pRuntimeLookup->signature, NULL, GTF_ICON_TOKEN_HDL, 0, NULL, compileTimeHandle)); + GenTreePtr helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, GTF_EXCEPT, helperArgs); // Check for null and possibly call helper GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, handle, gtNewIconNode(0, TYP_I_IMPL)); @@ -4499,7 +4512,7 @@ GenTreePtr Compiler::impImportLdvirtftn (GenTreePtr thisPtr, } #ifdef FEATURE_READYTORUN_COMPILER - if (opts.IsReadyToRun()) + if (opts.IsReadyToRun() && !pCallInfo->exactContextNeedsRuntimeLookup) { GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, TYP_I_IMPL, GTF_EXCEPT, gtNewArgList(thisPtr)); @@ -4546,14 +4559,6 @@ void Compiler::impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolved GenTreePtr op1, op2 = nullptr; var_types lclTyp; - - if (!opts.IsReadyToRun()) - { - // Ensure that the value class is restored - op2 = impTokenToHandle(pResolvedToken, NULL, TRUE /* mustRestoreHandle */); - if (op2 == NULL) // compDonotInline() - return; - } impSpillSpecialSideEff(); @@ -4562,7 +4567,7 @@ void Compiler::impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolved GenTreePtr exprToBox = impPopStack(operCls).val; CorInfoHelpFunc boxHelper = info.compCompHnd->getBoxHelper(pResolvedToken->hClass); - if (boxHelper == CORINFO_HELP_BOX) + if (boxHelper == CORINFO_HELP_BOX) { // we are doing 'normal' boxing. This means that we can inline the box operation // Box(expr) gets morphed into @@ -4584,13 +4589,29 @@ void Compiler::impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolved impBoxTempInUse = true; #ifdef FEATURE_READYTORUN_COMPILER + bool usingReadyToRunHelper = false; + if (opts.IsReadyToRun()) { op1 = impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_NEW, TYP_REF); + usingReadyToRunHelper = (op1 != NULL); } - else + + if (!usingReadyToRunHelper) #endif { + // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call + // and the newfast call with a single call to a dynamic R2R cell that will: + // 1) Load the context + // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub + // 3) Allocate and return the new object for boxing + // Reason: performance (today, we'll always use the slow helper for the R2R generics case) + + // Ensure that the value class is restored + op2 = impTokenToHandle(pResolvedToken, NULL, TRUE /* mustRestoreHandle */); + if (op2 == NULL) // compDonotInline() + return; + op1 = gtNewHelperCallNode( info.compCompHnd->getNewHelper(pResolvedToken, info.compMethodHnd), TYP_REF, 0, gtNewArgList(op2)); @@ -4654,13 +4675,10 @@ void Compiler::impImportAndPushBox (CORINFO_RESOLVED_TOKEN * pResolved { // Don't optimize, just call the helper and be done with it - if (opts.IsReadyToRun()) - { - // Ensure that the value class is restored - op2 = impTokenToHandle(pResolvedToken, nullptr, TRUE /* mustRestoreHandle */); - if (op2 == nullptr) // compDonotInline() - return; - } + // Ensure that the value class is restored + op2 = impTokenToHandle(pResolvedToken, nullptr, TRUE /* mustRestoreHandle */); + if (op2 == nullptr) // compDonotInline() + return; GenTreeArgList* args = gtNewArgList(op2, impGetStructAddr(exprToBox, operCls, (unsigned)CHECK_SPILL_ALL, true)); op1 = gtNewHelperCallNode(boxHelper, TYP_REF, GTF_EXCEPT, args); @@ -5871,10 +5889,9 @@ var_types Compiler::impImportCall (OPCODE opcode, return callRetTyp; } - GenTreePtr stubAddr = impRuntimeLookupToTree(callInfo->stubLookup.lookupKind.runtimeLookupKind, - &callInfo->stubLookup.runtimeLookup, methHnd); + GenTreePtr stubAddr = impRuntimeLookupToTree(pResolvedToken, &callInfo->stubLookup, methHnd); assert(!compDonotInline()); - + // This is the rough code to set up an indirect stub call assert(stubAddr!= 0); @@ -6035,7 +6052,12 @@ var_types Compiler::impImportCall (OPCODE opcode, assert((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_VARARG); assert((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_NATIVEVARARG); - GenTreePtr fptr = impLookupToTree(&callInfo->codePointerLookup, GTF_ICON_FTN_ADDR, callInfo->hMethod); + GenTreePtr fptr = impLookupToTree( + pResolvedToken, + &callInfo->codePointerLookup, + GTF_ICON_FTN_ADDR, + callInfo->hMethod); + if (compDonotInline()) { return callRetTyp; @@ -6375,21 +6397,23 @@ var_types Compiler::impImportCall (OPCODE opcode, { CORINFO_METHOD_HANDLE exactMethodHandle = (CORINFO_METHOD_HANDLE)((SIZE_T)exactContextHnd & ~CORINFO_CONTEXTFLAGS_MASK); -#ifdef FEATURE_READYTORUN_COMPILER - if (opts.IsReadyToRun()) + if (!exactContextNeedsRuntimeLookup) { - instParam = impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle); - if (instParam == nullptr) +#ifdef FEATURE_READYTORUN_COMPILER + if (opts.IsReadyToRun()) { - return callRetTyp; + instParam = impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle); + if (instParam == nullptr) + { + return callRetTyp; + } } - } - else + else #endif - if (!exactContextNeedsRuntimeLookup) - { - instParam = gtNewIconEmbMethHndNode(exactMethodHandle); - info.compCompHnd->methodMustBeLoadedBeforeCodeIsRun(exactMethodHandle); + { + instParam = gtNewIconEmbMethHndNode(exactMethodHandle); + info.compCompHnd->methodMustBeLoadedBeforeCodeIsRun(exactMethodHandle); + } } else { @@ -6420,27 +6444,29 @@ var_types Compiler::impImportCall (OPCODE opcode, // instParam. instParam = gtNewIconNode(0, TYP_REF); } -#ifdef FEATURE_READYTORUN_COMPILER - else - if (opts.IsReadyToRun()) + + if (!exactContextNeedsRuntimeLookup) { - instParam = impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle); - if (instParam == NULL) +#ifdef FEATURE_READYTORUN_COMPILER + if (opts.IsReadyToRun()) { - return callRetTyp; + instParam = impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle); + if (instParam == NULL) + { + return callRetTyp; + } } - } + else #endif - else - if (!exactContextNeedsRuntimeLookup) - { - instParam = gtNewIconEmbClsHndNode(exactClassHandle); - info.compCompHnd->classMustBeLoadedBeforeCodeIsRun(exactClassHandle); + { + instParam = gtNewIconEmbClsHndNode(exactClassHandle); + info.compCompHnd->classMustBeLoadedBeforeCodeIsRun(exactClassHandle); + } } else { instParam = impParentClassTokenToHandle(pResolvedToken, &runtimeLookup, TRUE /*mustRestoreHandle*/); - if (instParam == NULL) + if (instParam == NULL) { return callRetTyp; } @@ -8289,16 +8315,9 @@ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTr */ GenTreePtr Compiler::impCastClassOrIsInstToTree(GenTreePtr op1, GenTreePtr op2, CORINFO_RESOLVED_TOKEN * pResolvedToken, bool isCastClass) { - bool expandInline; - - assert(op1->TypeGet() == TYP_REF); + bool expandInline; -#ifdef FEATURE_READYTORUN_COMPILER - if (opts.IsReadyToRun()) - { - return impReadyToRunHelperToTree(pResolvedToken, isCastClass ? CORINFO_HELP_READYTORUN_CHKCAST : CORINFO_HELP_READYTORUN_ISINSTANCEOF, TYP_REF, op1); - } -#endif + assert(op1->TypeGet() == TYP_REF); CorInfoHelpFunc helper = info.compCompHnd->getCastingHelper(pResolvedToken, isCastClass); @@ -8556,6 +8575,7 @@ void Compiler::impImportBlockCode(BasicBlock * block) while (codeAddr < codeEndp) { + bool usingReadyToRunHelper = false; CORINFO_RESOLVED_TOKEN resolvedToken; CORINFO_RESOLVED_TOKEN constrainedResolvedToken; CORINFO_CALL_INFO callInfo; @@ -11388,14 +11408,23 @@ DO_LDFTN: if (opts.IsReadyToRun()) { op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEW, TYP_REF); + usingReadyToRunHelper = (op1 != NULL); } - else + + if (!usingReadyToRunHelper) #endif { op1 = impParentClassTokenToHandle(&resolvedToken, NULL, TRUE); if (op1 == NULL) // compDonotInline() return; + // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call + // and the newfast call with a single call to a dynamic R2R cell that will: + // 1) Load the context + // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub + // 3) Allocate and return the new object + // Reason: performance (today, we'll always use the slow helper for the R2R generics case) + op1 = gtNewHelperCallNode( info.compCompHnd->getNewHelper(&resolvedToken, info.compMethodHnd), TYP_REF, 0, gtNewArgList(op1)); @@ -12322,9 +12351,26 @@ FIELD_DONE: #ifdef FEATURE_READYTORUN_COMPILER if (opts.IsReadyToRun()) { - op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEWARR_1, TYP_REF, op2); + op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEWARR_1, TYP_REF, gtNewArgList(op2)); + usingReadyToRunHelper = (op1 != NULL); + + if (!usingReadyToRunHelper) + { + // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call + // and the newarr call with a single call to a dynamic R2R cell that will: + // 1) Load the context + // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub + // 3) Allocate the new array + // Reason: performance (today, we'll always use the slow helper for the R2R generics case) + + // Need to restore array classes before creating array objects on the heap + op1 = impTokenToHandle(&resolvedToken, NULL, TRUE /*mustRestoreHandle*/); + if (op1 == NULL) // compDonotInline() + return; + } } - else + + if (!usingReadyToRunHelper) #endif { args = gtNewArgList(op1, op2); @@ -12399,7 +12445,7 @@ FIELD_DONE: _impResolveToken(CORINFO_TOKENKIND_Casting); JITDUMP(" %08X", resolvedToken.token); - + if (!opts.IsReadyToRun()) { op2 = impTokenToHandle(&resolvedToken, NULL, FALSE); @@ -12416,8 +12462,38 @@ FIELD_DONE: accessAllowedResult = info.compCompHnd->canAccessClass(&resolvedToken, info.compMethodHnd, &calloutHelper); impHandleAccessAllowed(accessAllowedResult, &calloutHelper); - op1 = impPopStack().val; - op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, false); + op1 = impPopStack().val; + +#ifdef FEATURE_READYTORUN_COMPILER + if (opts.IsReadyToRun()) + { + GenTreePtr opLookup = impReadyToRunHelperToTree(&resolvedToken, + CORINFO_HELP_READYTORUN_ISINSTANCEOF, + TYP_REF, + gtNewArgList(op1)); + usingReadyToRunHelper = (opLookup != NULL); + op1 = (usingReadyToRunHelper ? opLookup : op1); + + if (!usingReadyToRunHelper) + { + // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call + // and the isinstanceof_any call with a single call to a dynamic R2R cell that will: + // 1) Load the context + // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub + // 3) Perform the 'is instance' check on the input object + // Reason: performance (today, we'll always use the slow helper for the R2R generics case) + + op2 = impTokenToHandle(&resolvedToken, NULL, FALSE); + if (op2 == NULL) // compDonotInline() + return; + } + } + + if (!usingReadyToRunHelper) +#endif + { + op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, false); + } if (compDonotInline()) { return; @@ -12911,7 +12987,36 @@ FIELD_DONE: // and op2 to contain code that creates the type handle corresponding to typeRef CASTCLASS: - op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, true); +#ifdef FEATURE_READYTORUN_COMPILER + if (opts.IsReadyToRun()) + { + GenTreePtr opLookup = impReadyToRunHelperToTree(&resolvedToken, + CORINFO_HELP_READYTORUN_CHKCAST, + TYP_REF, + gtNewArgList(op1)); + usingReadyToRunHelper = (opLookup != NULL); + op1 = (usingReadyToRunHelper ? opLookup : op1); + + if (!usingReadyToRunHelper) + { + // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call + // and the chkcastany call with a single call to a dynamic R2R cell that will: + // 1) Load the context + // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub + // 3) Check the object on the stack for the type-cast + // Reason: performance (today, we'll always use the slow helper for the R2R generics case) + + op2 = impTokenToHandle(&resolvedToken, NULL, FALSE); + if (op2 == NULL) // compDonotInline() + return; + } + } + + if (!usingReadyToRunHelper) +#endif + { + op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, true); + } if (compDonotInline()) { return; diff --git a/src/vm/amd64/cgenamd64.cpp b/src/vm/amd64/cgenamd64.cpp index a83c166474..e972ae8953 100644 --- a/src/vm/amd64/cgenamd64.cpp +++ b/src/vm/amd64/cgenamd64.cpp @@ -953,9 +953,16 @@ PCODE DynamicHelpers::CreateHelper(LoaderAllocator * pAllocator, TADDR arg, PCOD END_DYNAMIC_HELPER_EMIT(); } -PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +void DynamicHelpers::EmitHelperWithArg(BYTE*& p, LoaderAllocator * pAllocator, TADDR arg, PCODE target) { - BEGIN_DYNAMIC_HELPER_EMIT(15); + CONTRACTL + { + GC_NOTRIGGER; + PRECONDITION(p != NULL && target != NULL); + } + CONTRACTL_END; + + // Move an an argument into the second argument register and jump to a target function. #ifdef UNIX_AMD64_ABI *(UINT16 *)p = 0xBE48; // mov rsi, XXXXXX @@ -969,6 +976,13 @@ PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR ar *p++ = X86_INSTR_JMP_REL32; // jmp rel32 *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, target, NULL, pAllocator); p += 4; +} + +PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +{ + BEGIN_DYNAMIC_HELPER_EMIT(15); + + EmitHelperWithArg(p, pAllocator, arg, target); END_DYNAMIC_HELPER_EMIT(); } @@ -1126,6 +1140,97 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD END_DYNAMIC_HELPER_EMIT(); } +PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup) +{ + STANDARD_VM_CONTRACT; + + // TODO: fix codegen for correct Unix ABI... + + // It's available only via the run-time helper function + if (pLookup->indirections == CORINFO_USEHELPER) + { + BEGIN_DYNAMIC_HELPER_EMIT(15); + + // rcx contains the generic context parameter + // mov rdx,pLookup->signature + // jmp pLookup->helper + EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper)); + + END_DYNAMIC_HELPER_EMIT(); + } + else + { + int indirectionsSize = 0; + for (WORD i = 0; i < pLookup->indirections; i++) + indirectionsSize += (pLookup->offsets[i] >= 0x80 ? 7 : 4); + + int codeSize = indirectionsSize + (pLookup->testForNull ? 30 : 4); + + BEGIN_DYNAMIC_HELPER_EMIT(codeSize); + + if (pLookup->testForNull) + { + // rcx contains the generic context parameter. Save a copy of it in the rax register + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + } + + for (WORD i = 0; i < pLookup->indirections; i++) + { + // mov rcx,qword ptr [rcx+offset] + if (pLookup->offsets[i] >= 0x80) + { + *(UINT32*)p = 0x00898b48; p += 3; + *p = (UINT32)pLookup->offsets[i]; p += 4; + } + else + { + *(UINT32*)p = 0x00498b48; p += 3; + *p++ = (BYTE)pLookup->offsets[i]; + } + } + + // No null test required + if (!pLookup->testForNull) + { + // No fixups needed for R2R + + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + *p++ = 0xC3; // ret + } + else + { + // rcx contains the value of the dictionary slot entry + + _ASSERTE(pLookup->indirections != 0); + + // test rcx,rcx + *(UINT32*)p = 0x00c98548; p += 3; + + // je 'HELPER_CALL' (a jump of 4 bytes) + *(UINT16*)p = 0x0474; p += 2; + + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + *p++ = 0xC3; // ret + + // 'HELPER_CALL' + { + // Put the generic context back into rcx (was previously saved in rax) + // mov rcx,rax + *(UINT32*)p = 0x00c18948; p += 3; + + // mov rdx,pLookup->signature + // jmp pLookup->helper + EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper)); + } + } + + END_DYNAMIC_HELPER_EMIT(); + } +} + #endif // FEATURE_READYTORUN #endif // DACCESS_COMPILE diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp index 7e5c28cae5..343b6ed72b 100644 --- a/src/vm/i386/cgenx86.cpp +++ b/src/vm/i386/cgenx86.cpp @@ -1995,9 +1995,16 @@ PCODE DynamicHelpers::CreateHelper(LoaderAllocator * pAllocator, TADDR arg, PCOD END_DYNAMIC_HELPER_EMIT(); } -PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +void DynamicHelpers::EmitHelperWithArg(BYTE*& p, LoaderAllocator * pAllocator, TADDR arg, PCODE target) { - BEGIN_DYNAMIC_HELPER_EMIT(10); + CONTRACTL + { + GC_NOTRIGGER; + PRECONDITION(p != NULL && target != NULL); + } + CONTRACTL_END; + + // Move an an argument into the second argument register and jump to a target function. *p++ = 0xBA; // mov edx, XXXXXX *(INT32 *)p = (INT32)arg; @@ -2006,6 +2013,13 @@ PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR ar *p++ = X86_INSTR_JMP_REL32; // jmp rel32 *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, target); p += 4; +} + +PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +{ + BEGIN_DYNAMIC_HELPER_EMIT(10); + + EmitHelperWithArg(p, pAllocator, arg, target); END_DYNAMIC_HELPER_EMIT(); } @@ -2139,6 +2153,14 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD END_DYNAMIC_HELPER_EMIT(); } +PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup) +{ + STANDARD_VM_CONTRACT; + + // TODO (NYI) + ThrowHR(E_NOTIMPL); +} + #endif // FEATURE_READYTORUN diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index e94cb0dbf7..4bb55e9e7b 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -1789,116 +1789,86 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, if (!(flags & CORINFO_ACCESS_INLINECHECK)) { - //get the field's type. Grab the class for structs. - pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass); + //get the field's type. Grab the class for structs. + pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass); - MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); - - // - //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent - //of the memberRef and load that one. That should give us the open instantiation. - // - //If the field we found is owned by a generic type, you have to go back to the signature and reload. - //Otherwise we filled in !0. - TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass); - if (pResolvedToken->pTypeSpec != NULL) - { - SigTypeContext typeContext; - SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext); - - SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); - fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext); + MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); - // typeHnd can be a variable type - if (fieldTypeForSecurity.GetMethodTable() == NULL) + // + //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent + //of the memberRef and load that one. That should give us the open instantiation. + // + //If the field we found is owned by a generic type, you have to go back to the signature and reload. + //Otherwise we filled in !0. + TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass); + if (pResolvedToken->pTypeSpec != NULL) { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS); - } - } - - BOOL doAccessCheck = TRUE; - AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks; + SigTypeContext typeContext; + SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext); - DynamicResolver * pAccessContext = NULL; + SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); + fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext); - //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do - //not completely describe the type. - TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable()); - if (IsDynamicScope(pResolvedToken->tokenScope)) - { - doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity, - &accessCheckType, &pAccessContext); - } + // typeHnd can be a variable type + if (fieldTypeForSecurity.GetMethodTable() == NULL) + { + COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS); + } + } - //Now for some link time checks. - //Um... where are the field link demands? + BOOL doAccessCheck = TRUE; + AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks; - pResult->accessAllowed = CORINFO_ACCESS_ALLOWED; + DynamicResolver * pAccessContext = NULL; - if (doAccessCheck) - { - //Well, let's check some visibility at least. - AccessCheckOptions accessCheckOptions(accessCheckType, - pAccessContext, - FALSE, - pField); + //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do + //not completely describe the type. + TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable()); + if (IsDynamicScope(pResolvedToken->tokenScope)) + { + doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity, + &accessCheckType, &pAccessContext); + } - _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL); - StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable()); + //Now for some link time checks. + //Um... where are the field link demands? - BOOL canAccess = ClassLoader::CanAccess( - &accessContext, - fieldTypeForSecurity.GetMethodTable(), - fieldTypeForSecurity.GetAssembly(), - fieldAttribs, - NULL, - (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field. - accessCheckOptions, - FALSE /*checkTargetMethodTransparency*/, - TRUE /*checkTargetTypeTransparency*/); + pResult->accessAllowed = CORINFO_ACCESS_ALLOWED; - if (!canAccess) + if (doAccessCheck) { - //Set up the throw helper - pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL; + //Well, let's check some visibility at least. + AccessCheckOptions accessCheckOptions(accessCheckType, + pAccessContext, + FALSE, + pField); - pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION; - pResult->accessCalloutHelper.numArgs = 2; + _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL); + StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable()); - pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity)); - pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField)); + BOOL canAccess = ClassLoader::CanAccess( + &accessContext, + fieldTypeForSecurity.GetMethodTable(), + fieldTypeForSecurity.GetAssembly(), + fieldAttribs, + NULL, + (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field. + accessCheckOptions, + FALSE /*checkTargetMethodTransparency*/, + TRUE /*checkTargetTypeTransparency*/); - if (IsCompilingForNGen()) + if (!canAccess) { - //see code:CEEInfo::getCallInfo for more information. - if (pCallerForSecurity->ContainsGenericVariables()) - COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc")); - } - } - else - { - CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED; - CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE; + //Set up the throw helper + pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL; - DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed, runtimeChecks); - if (isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK) - { - pResult->accessAllowed = isAccessAllowed; - //Explain the callback to the JIT. - pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_CHECK; - pResult->accessCalloutHelper.numArgs = 3; + pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION; + pResult->accessCalloutHelper.numArgs = 2; pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity)); - - /* REVISIT_TODO Wed 4/8/2009 - * This field handle is not useful on its own. We also need to embed the enclosing class - * handle. - */ pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField)); - pResult->accessCalloutHelper.args[2].Set(runtimeChecks); - if (IsCompilingForNGen()) { //see code:CEEInfo::getCallInfo for more information. @@ -1906,9 +1876,38 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc")); } } - } - } + else + { + CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED; + CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE; + + DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed, runtimeChecks); + if (isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK) + { + pResult->accessAllowed = isAccessAllowed; + //Explain the callback to the JIT. + pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_CHECK; + pResult->accessCalloutHelper.numArgs = 3; + + pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity)); + + /* REVISIT_TODO Wed 4/8/2009 + * This field handle is not useful on its own. We also need to embed the enclosing class + * handle. + */ + pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField)); + + pResult->accessCalloutHelper.args[2].Set(runtimeChecks); + if (IsCompilingForNGen()) + { + //see code:CEEInfo::getCallInfo for more information. + if (pCallerForSecurity->ContainsGenericVariables()) + COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc")); + } + } + } + } } EE_TO_JIT_TRANSITION(); @@ -3057,12 +3056,12 @@ static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr) } void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind, - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, - MethodDesc * pTemplateMD /* for method-based slots */, - CORINFO_LOOKUP *pResultLookup) + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, + MethodDesc * pTemplateMD /* for method-based slots */, + CORINFO_LOOKUP *pResultLookup) { - CONTRACTL { + CONTRACTL{ STANDARD_VM_CHECK; PRECONDITION(CheckPointer(pResultLookup)); } CONTRACTL_END; @@ -3071,6 +3070,38 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr _ASSERTE(!isVerifyOnly()); pResultLookup->lookupKind.needsRuntimeLookup = true; + pResultLookup->lookupKind.runtimeLookupFlags = 0; + +#ifdef FEATURE_READYTORUN_COMPILER + if (IsReadyToRunCompilation()) + { +#if defined(UNIX_AMD64_ABI) || !defined(_TARGET_AMD64_) + // TODO + // Not yet fully enabled on UNIX... need calling convention fixes for the dictionary lookup stub + // generated by cgenamd64.cpp:DynamicHelpers::CreateDictionaryLookupHelper(...) + ThrowHR(E_NOTIMPL); +#endif + + switch (entryKind) + { + case TypeHandleSlot: + pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle; + break; + + case DeclaringTypeHandleSlot: + case MethodDescSlot: + case FieldDescSlot: + case MethodEntrySlot: + case ConstrainedMethodEntrySlot: + case DispatchStubAddrSlot: + ThrowHR(E_NOTIMPL); + + default: + _ASSERTE(!"Unknown dictionary entry kind!"); + IfFailThrow(E_FAIL); + } + } +#endif CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup; pResult->signature = NULL; @@ -3105,80 +3136,24 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr } #endif // FEATURE_NATIVE_IMAGE_GENERATION - // If we've got a method type parameter of any kind then we must look in the method desc arg + DWORD numGenericArgs; + DictionaryLayout* pDictionaryLayout; + LoaderAllocator* pAllocator; + if (pContextMD->RequiresInstMethodDescArg()) { + pAllocator = pContextMD->GetLoaderAllocator(); + numGenericArgs = pContextMD->GetNumGenericMethodArgs(); + pDictionaryLayout = pContextMD->GetDictionaryLayout(); + pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM; pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD; - - if (fInstrument) - goto NoSpecialCase; - - // Special cases: - // (1) Naked method type variable: look up directly in instantiation hanging off runtime md - // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)> - if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr)) - { - SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); - CorElementType type; - IfFailThrow(sigptr.GetElemType(&type)); - if (type == ELEMENT_TYPE_MVAR) - { - pResult->indirections = 2; - pResult->testForNull = 0; -#ifdef FEATURE_PREJIT - pResult->testForFixup = 1; -#else - pResult->testForFixup = 0; -#endif - pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo); - - ULONG data; - IfFailThrow(sigptr.GetData(&data)); - pResult->offsets[1] = sizeof(TypeHandle) * data; - - return; - } - } - else if (entryKind == MethodDescSlot) - { - // It's the context itself (i.e. a recursive call) - if (!pTemplateMD->HasSameMethodDefAs(pContextMD)) - goto NoSpecialCase; - - // Now just check that the instantiation is (!!0, ..., !!(n-1)) - if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec))) - goto NoSpecialCase; - - // Type instantiation has to match too if there is one - if (pContextMT->HasInstantiation()) - { - TypeHandle thTemplate(pResolvedToken->hClass); - - if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT)) - goto NoSpecialCase; - - // This check filters out method instantiation on generic type definition, like G::M<!!0>() - // We may not ever get it here. Filter it out just to be sure... - if (pResolvedToken->pTypeSpec == NULL) - goto NoSpecialCase; - - if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))) - goto NoSpecialCase; - } - - // Just use the method descriptor that was passed in! - pResult->indirections = 0; - pResult->testForNull = 0; - pResult->testForFixup = 0; - - return; - } } - // Otherwise we must just have class type variables else { - _ASSERTE(pContextMT->GetNumGenericArgs() > 0); + pAllocator = pContextMT->GetLoaderAllocator(); + numGenericArgs = pContextMT->GetNumGenericArgs(); + pDictionaryLayout = pContextMT->GetClass()->GetDictionaryLayout(); if (pContextMD->RequiresInstMethodTableArg()) { @@ -3187,53 +3162,122 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS; } // If we've got an object, go through its vtable - else + else { _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis()); pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ; pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS; } + } + + ComputeRuntimeLookupForSharedGenericTokenStatic( + entryKind, + pResolvedToken, + pConstrainedResolvedToken, + pTemplateMD, + pAllocator, + numGenericArgs, + pDictionaryLayout, + (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM ? 0 : pContextMT->GetNumDicts()), + pResultLookup, + TRUE, + fInstrument); +} + +void CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic(DictionaryEntryKind entryKind, + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, + MethodDesc * pTemplateMD /* for method-based slots */, + LoaderAllocator* pAllocator, + DWORD numGenericArgs, + DictionaryLayout* pDictionaryLayout, + DWORD typeDictionaryIndex, + CORINFO_LOOKUP *pResultLookup, + BOOL fEnableTypeHandleLookupOptimization, + BOOL fInstrument) +{ + CONTRACTL{ + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pResultLookup)); + } CONTRACTL_END; - if (fInstrument) - goto NoSpecialCase; + pResultLookup->lookupKind.needsRuntimeLookup = true; - // Special cases: - // (1) Naked class type variable: look up directly in instantiation hanging off vtable - // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr - if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr)) + CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup; + pResult->signature = NULL; + + // Unless we decide otherwise, just do the lookup via a helper function + pResult->indirections = CORINFO_USEHELPER; + + if (fEnableTypeHandleLookupOptimization) + { + MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext); + MethodTable *pContextMT = pContextMD->GetMethodTable(); + + // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup. + // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here. + _ASSERTE(pContextMD->IsSharedByGenericInstantiations()); + + // If we've got a method type parameter of any kind then we must look in the method desc arg + if (pContextMD->RequiresInstMethodDescArg()) { - SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); - CorElementType type; - IfFailThrow(sigptr.GetElemType(&type)); - if (type == ELEMENT_TYPE_VAR) + if (fInstrument) + goto NoSpecialCase; + + // Special cases: + // (1) Naked method type variable: look up directly in instantiation hanging off runtime md + // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)> + if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr)) { - pResult->indirections = 3; - pResult->testForNull = 0; + SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); + CorElementType type; + IfFailThrow(sigptr.GetElemType(&type)); + if (type == ELEMENT_TYPE_MVAR) + { + pResult->indirections = 2; + pResult->testForNull = 0; #ifdef FEATURE_PREJIT - pResult->testForFixup = 1; + pResult->testForFixup = 1; #else - pResult->testForFixup = 0; + pResult->testForFixup = 0; #endif - pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo(); - pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts()-1); - ULONG data; - IfFailThrow(sigptr.GetData(&data)); - pResult->offsets[2] = sizeof(TypeHandle) * data; + pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo); - return; + ULONG data; + IfFailThrow(sigptr.GetData(&data)); + pResult->offsets[1] = sizeof(TypeHandle) * data; + + return; + } } - else if (type == ELEMENT_TYPE_GENERICINST && - (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM)) + else if (entryKind == MethodDescSlot) { - TypeHandle thTemplate(pResolvedToken->hClass); - - if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT)) + // It's the context itself (i.e. a recursive call) + if (!pTemplateMD->HasSameMethodDefAs(pContextMD)) goto NoSpecialCase; - if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))) + // Now just check that the instantiation is (!!0, ..., !!(n-1)) + if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec))) goto NoSpecialCase; - // Just use the vtable pointer itself! + // Type instantiation has to match too if there is one + if (pContextMT->HasInstantiation()) + { + TypeHandle thTemplate(pResolvedToken->hClass); + + if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT)) + goto NoSpecialCase; + + // This check filters out method instantiation on generic type definition, like G::M<!!0>() + // We may not ever get it here. Filter it out just to be sure... + if (pResolvedToken->pTypeSpec == NULL) + goto NoSpecialCase; + + if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))) + goto NoSpecialCase; + } + + // Just use the method descriptor that was passed in! pResult->indirections = 0; pResult->testForNull = 0; pResult->testForFixup = 0; @@ -3241,18 +3285,76 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr return; } } + // Otherwise we must just have class type variables + else + { + _ASSERTE(pContextMT->GetNumGenericArgs() > 0); + + if (fInstrument) + goto NoSpecialCase; + + // Special cases: + // (1) Naked class type variable: look up directly in instantiation hanging off vtable + // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr + if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr)) + { + SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); + CorElementType type; + IfFailThrow(sigptr.GetElemType(&type)); + if (type == ELEMENT_TYPE_VAR) + { + pResult->indirections = 3; + pResult->testForNull = 0; +#ifdef FEATURE_PREJIT + pResult->testForFixup = 1; +#else + pResult->testForFixup = 0; +#endif + pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo(); + pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1); + ULONG data; + IfFailThrow(sigptr.GetData(&data)); + pResult->offsets[2] = sizeof(TypeHandle) * data; + + return; + } + else if (type == ELEMENT_TYPE_GENERICINST && + (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM)) + { + TypeHandle thTemplate(pResolvedToken->hClass); + + if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT)) + goto NoSpecialCase; + + if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))) + goto NoSpecialCase; + + // Just use the vtable pointer itself! + pResult->indirections = 0; + pResult->testForNull = 0; + pResult->testForFixup = 0; + + return; + } + } + } } NoSpecialCase: + // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a + // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs) + if (IsReadyToRunCompilation()) + return; + SigBuilder sigBuilder; sigBuilder.AppendData(entryKind); if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM) { - _ASSERTE(pContextMT->GetNumDicts() > 0); - sigBuilder.AppendData(pContextMT->GetNumDicts() - 1); + _ASSERTE(typeDictionaryIndex > 0); + sigBuilder.AppendData(typeDictionaryIndex - 1); } Module * pModule = (Module *)pResolvedToken->tokenScope; @@ -3427,10 +3529,7 @@ NoSpecialCase: // It's a method dictionary lookup if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM) { - _ASSERTE(pContextMD != NULL); - _ASSERTE(pContextMD->HasMethodInstantiation()); - - if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1)) + if (DictionaryLayout::FindToken(pAllocator, numGenericArgs, pDictionaryLayout, pResult, &sigBuilder, 1)) { pResult->testForNull = 1; pResult->testForFixup = 0; @@ -3443,7 +3542,7 @@ NoSpecialCase: // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ) else { - if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2)) + if (DictionaryLayout::FindToken(pAllocator, numGenericArgs, pDictionaryLayout, pResult, &sigBuilder, 2)) { pResult->testForNull = 1; pResult->testForFixup = 0; @@ -3452,7 +3551,7 @@ NoSpecialCase: pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo(); // Next indirect through the dictionary appropriate to this instantiated type - pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts()-1); + pResult->offsets[1] = sizeof(TypeHandle*) * (typeDictionaryIndex - 1); } } } @@ -5212,6 +5311,12 @@ void CEEInfo::getCallInfo( // For reference types, the constrained type does not affect method resolution DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot; + if (IsReadyToRunCompilation() && pConstrainedResolvedToken != NULL) + { + // READYTORUN: FUTURE: Constrained generic calls + ThrowHR(E_NOTIMPL); + } + ComputeRuntimeLookupForSharedGenericToken(entryKind, pResolvedToken, pConstrainedResolvedToken, @@ -6197,14 +6302,15 @@ CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd) /***********************************************************************/ bool CEEInfo::getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_LOOKUP_KIND * pGenericLookupKind, - CorInfoHelpFunc id, - CORINFO_CONST_LOOKUP * pLookup + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup ) { LIMITED_METHOD_CONTRACT; UNREACHABLE(); // only called during NGen + return false; } /***********************************************************************/ diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h index 0df1884935..08721ae2df 100644 --- a/src/vm/jitinterface.h +++ b/src/vm/jitinterface.h @@ -544,10 +544,10 @@ public: CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls); bool getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_LOOKUP_KIND * pGenericLookupKind, - CorInfoHelpFunc id, - CORINFO_CONST_LOOKUP * pLookup + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup ); void getReadyToRunDelegateCtorHelper( @@ -949,10 +949,10 @@ public: void **ppIndirection); CORINFO_METHOD_HANDLE embedMethodHandle(CORINFO_METHOD_HANDLE handle, void **ppIndirection); - void embedGenericHandle( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - BOOL fEmbedParent, - CORINFO_GENERICHANDLE_RESULT *pResult); + + void embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, + BOOL fEmbedParent, + CORINFO_GENERICHANDLE_RESULT *pResult); CORINFO_LOOKUP_KIND getLocationOfThisType(CORINFO_METHOD_HANDLE context); @@ -1135,6 +1135,26 @@ public: MethodDesc * GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle); + // Prepare the information about how to do a runtime lookup of the handle with shared + // generic variables. + void ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind, + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, + MethodDesc * pTemplateMD /* for method-based slots */, + CORINFO_LOOKUP *pResultLookup); + + static void ComputeRuntimeLookupForSharedGenericTokenStatic(DictionaryEntryKind entryKind, + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, + MethodDesc * pTemplateMD /* for method-based slots */, + LoaderAllocator* pAllocator, + DWORD numGenericArgs, + DictionaryLayout* pDictionaryLayout, + DWORD typeDictionaryIndex, + CORINFO_LOOKUP *pResultLookup, + BOOL fEnableTypeHandleLookupOptimization, + BOOL fInstrument); + protected: // NGen provides its own modifications to EE-JIT interface. From technical reason it cannot simply inherit // from code:CEEInfo class (because it has dependencies on VM that NGen does not want). @@ -1169,14 +1189,6 @@ protected: // The main entrypoints for module activation tracking void ScanToken(Module * pModule, CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD = NULL); void ScanTokenForDynamicScope(CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD = NULL); - - // Prepare the information about how to do a runtime lookup of the handle with shared - // generic variables. - void ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind, - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken /* for ConstrainedMethodEntrySlot */, - MethodDesc * pTemplateMD /* for method-based slots */, - CORINFO_LOOKUP *pResultLookup); }; diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp index a35b421547..1ae7b39ea7 100644 --- a/src/vm/prestub.cpp +++ b/src/vm/prestub.cpp @@ -2314,6 +2314,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR TypeHandle th; MethodDesc * pMD = NULL; FieldDesc * pFD = NULL; + CORINFO_GENERICHANDLE_RESULT embedInfo; switch (kind) { @@ -2327,6 +2328,7 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR case ENCODE_NEW_ARRAY_HELPER: th = ZapSig::DecodeType(pModule, pInfoModule, pBlob); break; + case ENCODE_THREAD_STATIC_BASE_NONGC_HELPER: case ENCODE_THREAD_STATIC_BASE_GC_HELPER: case ENCODE_STATIC_BASE_NONGC_HELPER: @@ -2338,27 +2340,122 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR th.AsMethodTable()->CheckRunClassInitThrowing(); fReliable = true; break; + case ENCODE_FIELD_ADDRESS: pFD = ZapSig::DecodeField(pModule, pInfoModule, pBlob, &th); _ASSERTE(pFD->IsStatic()); goto Statics; + case ENCODE_VIRTUAL_ENTRY: // case ENCODE_VIRTUAL_ENTRY_DEF_TOKEN: // case ENCODE_VIRTUAL_ENTRY_REF_TOKEN: // case ENCODE_VIRTUAL_ENTRY_SLOT: fReliable = true; case ENCODE_DELEGATE_CTOR: - pMD = ZapSig::DecodeMethod(pModule, pInfoModule, pBlob, &th); - if (pMD->RequiresInstArg()) { - pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, - th.AsMethodTable(), - FALSE /* forceBoxedEntryPoint */, - pMD->GetMethodInstantiation(), - FALSE /* allowInstParam */); + pMD = ZapSig::DecodeMethod(pModule, pInfoModule, pBlob, &th); + if (pMD->RequiresInstArg()) + { + pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, + th.AsMethodTable(), + FALSE /* forceBoxedEntryPoint */, + pMD->GetMethodInstantiation(), + FALSE /* allowInstParam */); + } + pMD->EnsureActive(); + } + break; + + case ENCODE_DICTIONARY_LOOKUP_THISOBJ: + case ENCODE_DICTIONARY_LOOKUP_TYPE: + case ENCODE_DICTIONARY_LOOKUP_METHOD: + { + // Generic context is the first argument on the pTransitionBlock (either a methodtable or a methoddesc pointer) + TADDR genericContextPtr = *(TADDR*)(((TADDR)pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters())); + + DWORD numGenericArgs = 0; + MethodTable* pContextMT = NULL; + MethodDesc* pContextMD = NULL; + DictionaryLayout* pDictionaryLayout = NULL; + + if (kind == ENCODE_DICTIONARY_LOOKUP_METHOD) + { + pContextMD = (MethodDesc*)genericContextPtr; + numGenericArgs = pContextMD->GetNumGenericMethodArgs(); + pDictionaryLayout = pContextMD->GetDictionaryLayout(); + embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM; + embedInfo.lookup.runtimeLookup.helper = CORINFO_HELP_RUNTIMEHANDLE_METHOD; + } + else + { + pContextMT = (MethodTable*)genericContextPtr; + + if (kind == ENCODE_DICTIONARY_LOOKUP_THISOBJ) + { + TypeHandle contextTypeHandle = ZapSig::DecodeType(pModule, pInfoModule, pBlob); + + SigPointer p(pBlob); + p.SkipExactlyOne(); + pBlob = p.GetPtr(); + + pContextMT = pContextMT->GetMethodTableMatchingParentClass(contextTypeHandle.AsMethodTable()); + embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ; + } + else + { + embedInfo.lookup.lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM; + } + + numGenericArgs = pContextMT->GetNumGenericArgs(); + pDictionaryLayout = pContextMT->GetClass()->GetDictionaryLayout(); + embedInfo.lookup.runtimeLookup.helper = CORINFO_HELP_RUNTIMEHANDLE_CLASS; + } + + CORINFO_RESOLVED_TOKEN resolvedToken; + INDEBUG(memset(&resolvedToken, 0xCC, sizeof(resolvedToken))); + resolvedToken.tokenType = CORINFO_TOKENKIND_Ldtoken; // Reasonable default value to use that works + resolvedToken.tokenScope = (CORINFO_MODULE_HANDLE)pModule; + resolvedToken.pMethodSpec = resolvedToken.pTypeSpec = NULL; + resolvedToken.cbMethodSpec = resolvedToken.cbTypeSpec = 0; + + DictionaryEntryKind entryKind = EmptySlot; + CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob); + + switch (signatureKind) + { + case ENCODE_TYPE_HANDLE: + { + entryKind = TypeHandleSlot; + resolvedToken.cbTypeSpec = -1; + resolvedToken.pTypeSpec = pBlob; + } + break; + + // TODO: Support for the rest of the dictionary signature kinds + + default: + _ASSERTE(!"Unexpected CORCOMPILE_FIXUP_BLOB_KIND"); + ThrowHR(COR_E_BADIMAGEFORMAT); + } + + CEEInfo::ComputeRuntimeLookupForSharedGenericTokenStatic( + entryKind, + &resolvedToken, + NULL, // pConstrainedResolvedToken for ConstrainedMethodEntrySlot + NULL, // pTemplateMD for method-based slots + pModule->GetLoaderAllocator(), + numGenericArgs, + pDictionaryLayout, + pContextMT == NULL ? 0 : pContextMT->GetNumDicts(), + &embedInfo.lookup, + FALSE, // fEnableTypeHandleLookupOptimization, + FALSE // fInstrument + ); + + _ASSERTE(embedInfo.lookup.lookupKind.needsRuntimeLookup); } - pMD->EnsureActive(); break; + default: _ASSERTE(!"Unexpected CORCOMPILE_FIXUP_BLOB_KIND"); ThrowHR(COR_E_BADIMAGEFORMAT); @@ -2568,6 +2665,14 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR } break; + case ENCODE_DICTIONARY_LOOKUP_THISOBJ: + case ENCODE_DICTIONARY_LOOKUP_TYPE: + case ENCODE_DICTIONARY_LOOKUP_METHOD: + { + pHelper = DynamicHelpers::CreateDictionaryLookupHelper(pModule->GetLoaderAllocator(), &embedInfo.lookup.runtimeLookup); + } + break; + default: UNREACHABLE(); } diff --git a/src/vm/readytoruninfo.h b/src/vm/readytoruninfo.h index f2a7a1ec49..24bdae89b9 100644 --- a/src/vm/readytoruninfo.h +++ b/src/vm/readytoruninfo.h @@ -126,6 +126,8 @@ private: class DynamicHelpers { +private: + static void EmitHelperWithArg(BYTE*& pCode, LoaderAllocator * pAllocator, TADDR arg, PCODE target); public: static PCODE CreateHelper(LoaderAllocator * pAllocator, TADDR arg, PCODE target); static PCODE CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target); @@ -136,6 +138,7 @@ public: static PCODE CreateReturnIndirConst(LoaderAllocator * pAllocator, TADDR arg, INT8 offset); static PCODE CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, PCODE target); static PCODE CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADDR arg, TADDR arg2, PCODE target); + static PCODE CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup); }; #endif // _READYTORUNINFO_H_ diff --git a/src/vm/zapsig.cpp b/src/vm/zapsig.cpp index 7d3b73f0f1..54f6c37db4 100644 --- a/src/vm/zapsig.cpp +++ b/src/vm/zapsig.cpp @@ -992,9 +992,9 @@ MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule, } FieldDesc * ZapSig::DecodeField(Module *pReferencingModule, - Module *pInfoModule, - PCCOR_SIGNATURE pBuffer, - TypeHandle * ppTH /*=NULL*/) + Module *pInfoModule, + PCCOR_SIGNATURE pBuffer, + TypeHandle * ppTH /*=NULL*/) { CONTRACTL { @@ -1201,11 +1201,11 @@ BOOL ZapSig::EncodeMethod( methodFlags &= ~ENCODE_METHOD_SIG_OwnerType; } else - if (!(methodFlags & ENCODE_METHOD_SIG_InstantiatingStub)) - { - if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars) - methodFlags &= ~ENCODE_METHOD_SIG_OwnerType; - } + if (!(methodFlags & ENCODE_METHOD_SIG_InstantiatingStub)) + { + if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars) + methodFlags &= ~ENCODE_METHOD_SIG_OwnerType; + } break; default: diff --git a/src/zap/zapimage.cpp b/src/zap/zapimage.cpp index 3ce7cd6d3c..a435d6a44d 100644 --- a/src/zap/zapimage.cpp +++ b/src/zap/zapimage.cpp @@ -2226,38 +2226,48 @@ ZapImage::CompileStatus ZapImage::TryCompileMethodWorker(CORINFO_METHOD_HANDLE h Exception *ex = GET_EXCEPTION(); HRESULT hrException = ex->GetHR(); - StackSString message; - ex->GetMessage(message); +#ifdef FEATURE_READYTORUN_COMPILER + // NYI features in R2R - Stop crossgen from spitting unnecessary messages to the console + if (IsReadyToRunCompilation() && hrException == E_NOTIMPL) + { + result = NOT_COMPILED; + } + else +#endif + { + StackSString message; + ex->GetMessage(message); - CorZapLogLevel level; + CorZapLogLevel level; -#ifdef CROSSGEN_COMPILE - // Warnings should not go to stderr during crossgen - level = CORZAP_LOGLEVEL_WARNING; -#else - level = CORZAP_LOGLEVEL_ERROR; -#endif + #ifdef CROSSGEN_COMPILE + // Warnings should not go to stderr during crossgen + level = CORZAP_LOGLEVEL_WARNING; + #else + level = CORZAP_LOGLEVEL_ERROR; + #endif - // FileNotFound errors here can be converted into a single error string per ngen compile, and the detailed error is available with verbose logging - if (hrException == COR_E_FILENOTFOUND) - { - StackSString logMessage(W("System.IO.FileNotFoundException: ")); - logMessage.Append(message); - FileNotFoundError(logMessage.GetUnicode()); - level = CORZAP_LOGLEVEL_INFO; - } + // FileNotFound errors here can be converted into a single error string per ngen compile, and the detailed error is available with verbose logging + if (hrException == COR_E_FILENOTFOUND) + { + StackSString logMessage(W("System.IO.FileNotFoundException: ")); + logMessage.Append(message); + FileNotFoundError(logMessage.GetUnicode()); + level = CORZAP_LOGLEVEL_INFO; + } - m_zapper->Print(level, W("%s while compiling method %s\n"), message.GetUnicode(), zapInfo.m_currentMethodName.GetUnicode()); + m_zapper->Print(level, W("%s while compiling method %s\n"), message.GetUnicode(), zapInfo.m_currentMethodName.GetUnicode()); - result = COMPILE_FAILED; - m_zapper->m_failed = TRUE; + result = COMPILE_FAILED; + m_zapper->m_failed = TRUE; - if (m_stats != NULL) - { - if ((m_zapper->m_pOpt->m_compilerFlags & CORJIT_FLG_IL_STUB) == 0) - m_stats->m_failedMethods++; - else - m_stats->m_failedILStubs++; + if (m_stats != NULL) + { + if ((m_zapper->m_pOpt->m_compilerFlags & CORJIT_FLG_IL_STUB) == 0) + m_stats->m_failedMethods++; + else + m_stats->m_failedILStubs++; + } } } EX_END_CATCH(SwallowAllExceptions); diff --git a/src/zap/zapimport.cpp b/src/zap/zapimport.cpp index c0ea82743a..37226fcc41 100644 --- a/src/zap/zapimport.cpp +++ b/src/zap/zapimport.cpp @@ -1697,7 +1697,22 @@ public: CORCOMPILE_FIXUP_BLOB_KIND GetKind() { - return (CORCOMPILE_FIXUP_BLOB_KIND)(int)GetHandle(); + int kind = (int)GetHandle(); + + if ((kind & 1) == 1) + { + return (CORCOMPILE_FIXUP_BLOB_KIND)(kind >> 1); + } + else + { + _ASSERTE( + (GetBlob()->GetSize() > 0) && ( + GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_THISOBJ || + GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_METHOD || + GetBlob()->GetData()[0] == ENCODE_DICTIONARY_LOOKUP_TYPE)); + + return (CORCOMPILE_FIXUP_BLOB_KIND)GetBlob()->GetData()[0]; + } } virtual void EncodeSignature(ZapImportTable * pTable, SigBuilder * pSigBuilder) @@ -1728,6 +1743,9 @@ static ReadyToRunHelper GetDelayLoadHelperForDynamicHelper(CORCOMPILE_FIXUP_BLOB case ENCODE_THREAD_STATIC_BASE_GC_HELPER: case ENCODE_CCTOR_TRIGGER: case ENCODE_FIELD_ADDRESS: + case ENCODE_DICTIONARY_LOOKUP_THISOBJ: + case ENCODE_DICTIONARY_LOOKUP_TYPE: + case ENCODE_DICTIONARY_LOOKUP_METHOD: return READYTORUN_HELPER_DelayLoad_Helper; case ENCODE_CHKCAST_HELPER: @@ -1773,9 +1791,52 @@ void ZapImportSectionSignatures::PlaceDynamicHelperCell(ZapImport * pImport) m_pImage->GetImportTable()->PlaceImportBlob(pCell); } +ZapImport * ZapImportTable::GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pLookup) +{ + _ASSERTE(pLookup->needsRuntimeLookup); + + SigBuilder sigBuilder; + + sigBuilder.AppendData(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE); + + if ((kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) == ENCODE_DICTIONARY_LOOKUP_THISOBJ) + { + CORINFO_CLASS_HANDLE hClassContext = GetJitInfo()->getMethodClass(pResolvedToken->tokenContext); + GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), hClassContext, &sigBuilder, NULL, NULL); + } + + switch (pLookup->runtimeLookupFlags) + { + case READYTORUN_FIXUP_TypeHandle: + { + if (pResolvedToken->pTypeSpec == NULL) + { + _ASSERTE(!"Invalid IL that directly references __Canon"); + ThrowHR(E_NOTIMPL); + } + + sigBuilder.AppendData(ENCODE_TYPE_HANDLE); + if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr) + sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY); + sigBuilder.AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); + } + break; + + // TODO: support for the rest of the dictionary signature kinds + + default: + _ASSERTE(!"Invalid R2R fixup kind!"); + ThrowHR(E_NOTIMPL); + } + + _ASSERTE(((DWORD)pResolvedToken->tokenContext & 1) == 0); + + return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void*)pResolvedToken->tokenContext, &sigBuilder); +} + ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_CLASS_HANDLE handle) { - ZapImport * pImport = GetImport<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)kind, handle); + ZapImport * pImport = GetImport<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), handle); if (!pImport->HasBlob()) { @@ -1805,7 +1866,7 @@ ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), delegateType, &sigBuilder, NULL, NULL); } - return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)kind, &sigBuilder); + return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), &sigBuilder); } ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken) @@ -1815,7 +1876,7 @@ ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind EncodeField((CORCOMPILE_FIXUP_BLOB_KIND)(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE), handle, &sigBuilder, pResolvedToken); - return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)kind, &sigBuilder); + return GetImportForSignature<ZapDynamicHelperCell, ZapNodeType_DynamicHelperCell>((void *)(uintptr_t)((kind << 1) | 1), &sigBuilder); } class ZapIndirectHelperThunk : public ZapImport diff --git a/src/zap/zapimport.h b/src/zap/zapimport.h index 9aa5e95f27..1c6ec03c45 100644 --- a/src/zap/zapimport.h +++ b/src/zap/zapimport.h @@ -432,10 +432,11 @@ public: ZapImport * GetExternalMethodCell(CORINFO_METHOD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken); ZapImport * GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_CLASS_HANDLE handle); - ZapImport * GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_CLASS_HANDLE delegateType = NULL); + ZapImport * GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_METHOD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_CLASS_HANDLE delegateType = NULL); ZapImport * GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_FIELD_HANDLE handle, CORINFO_RESOLVED_TOKEN * pResolvedToken); + ZapImport * GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_LOOKUP_KIND * pLookup); + #ifdef FEATURE_READYTORUN_COMPILER ZapNode * GetPlacedIndirectHelperThunk(ReadyToRunHelper helperNum, PVOID pArg = NULL, ZapNode * pCell = NULL); ZapNode * GetIndirectHelperThunk(ReadyToRunHelper helperNum, PVOID pArg = NULL); diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index 79abbf7bc1..20b532fd07 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -1549,7 +1549,7 @@ CORINFO_METHOD_HANDLE ZapInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle, if (IsReadyToRunCompilation()) { - _ASSERTE(!"embedMethodHandle"); + // READYTORUN FUTURE: Handle this case correctly ThrowHR(E_NOTIMPL); } @@ -1597,7 +1597,8 @@ ZapInfo::embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, if (pResult->lookup.lookupKind.needsRuntimeLookup) { - embedGenericSignature(&pResult->lookup); + if (!IsReadyToRunCompilation()) + embedGenericSignature(&pResult->lookup); if (pResult->handleType == CORINFO_HANDLETYPE_METHOD) { @@ -1681,7 +1682,7 @@ void ZapInfo::embedGenericSignature(CORINFO_LOOKUP * pLookup) if (IsReadyToRunCompilation()) { - m_zapper->Warning(W("ReadyToRun: embedGenericSignature not yet supported\n")); + UNREACHABLE_MSG("We should never get here for the ReadyToRun compilation."); ThrowHR(E_NOTIMPL); } @@ -2138,7 +2139,8 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, { if (pResult->stubLookup.lookupKind.needsRuntimeLookup) { - embedGenericSignature(&pResult->stubLookup); + if (!IsReadyToRunCompilation()) + embedGenericSignature(&pResult->stubLookup); return; } @@ -2171,7 +2173,8 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, case CORINFO_CALL_CODE_POINTER: _ASSERTE(pResult->codePointerLookup.lookupKind.needsRuntimeLookup); - embedGenericSignature(&pResult->codePointerLookup); + if (!IsReadyToRunCompilation()) + embedGenericSignature(&pResult->codePointerLookup); // There is no easy way to detect method referenced via generic lookups in generated code. // Report this method reference unconditionally. @@ -2212,23 +2215,15 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, case CORINFO_VIRTUALCALL_LDVIRTFTN: #ifdef FEATURE_READYTORUN_COMPILER - if (IsReadyToRunCompilation()) + if (IsReadyToRunCompilation() && !pResult->exactContextNeedsRuntimeLookup) { - if ((pResult->classFlags & CORINFO_FLG_SHAREDINST) != 0 || - (pResult->methodFlags & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } - DWORD fAtypicalCallsite = (flags & CORINFO_CALLINFO_ATYPICAL_CALLSITE) ? CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE : 0; ZapImport * pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_VIRTUAL_ENTRY | fAtypicalCallsite), pResult->hMethod, pResolvedToken); - pResult->codePointerLookup.constLookup.accessType = IAT_PVALUE; - pResult->codePointerLookup.constLookup.addr = pImport; + pResult->codePointerLookup.constLookup.accessType = IAT_PVALUE; + pResult->codePointerLookup.constLookup.addr = pImport; _ASSERTE(!pResult->sig.hasTypeArg()); } @@ -2248,9 +2243,10 @@ void ZapInfo::getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, { if (pResult->exactContextNeedsRuntimeLookup) { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup not yet supported\n")); - ThrowHR(E_NOTIMPL); + // Nothing to do... The generic handle lookup gets embedded in to the codegen + // during the jitting of the call. + // (Note: The generic lookup in R2R is performed by a call to a helper at runtime, not by + // codegen emitted at crossgen time) } else { @@ -3006,9 +3002,18 @@ void ZapInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, break; case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER: - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Shared generic static field access not yet supported\n")); - ThrowHR(E_NOTIMPL); + { + // Nothing to do... The generic handle lookup gets embedded in to the codegen + // during the jitting of the field lookup. + // (Note: The generic lookup in R2R is performed by a call to a helper at runtime, not by + // codegen emitted at crossgen time) + // TODO: replace the call to the generic lookup helper and the call to the static helper function + // with a single call to a R2R cell that performs: + // 1) Generic handle lookup + // 2) Computes the statics base address + // 3) Generates a stub for subsequent lookups that includes dictionary access + // (For perf reasons) + } break; case CORINFO_FIELD_STATIC_ADDRESS: // field at given address @@ -3354,6 +3359,9 @@ unsigned ZapInfo::getClassNumInstanceFields(CORINFO_CLASS_HANDLE cls) CorInfoHelpFunc ZapInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle) { + if (IsReadyToRunCompilation()) + return CORINFO_HELP_NEWFAST; + classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass); return m_pEEJitInfo->getNewHelper(pResolvedToken, callerHandle); } @@ -3385,20 +3393,24 @@ CorInfoHelpFunc ZapInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE cls) CorInfoHelpFunc ZapInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing) { + if (IsReadyToRunCompilation()) + return (fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY); + return m_pEEJitInfo->getCastingHelper(pResolvedToken, fThrowing); } CorInfoHelpFunc ZapInfo::getNewArrHelper(CORINFO_CLASS_HANDLE arrayCls) { + if (IsReadyToRunCompilation()) + return CORINFO_HELP_NEWARR_1_DIRECT; + return m_pEEJitInfo->getNewArrHelper(arrayCls); } -bool ZapInfo::getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_LOOKUP_KIND * pGenericLookupKind, - CorInfoHelpFunc id, - CORINFO_CONST_LOOKUP * pLookup - ) +bool ZapInfo::getReadyToRunHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup) { #ifdef FEATURE_READYTORUN_COMPILER _ASSERTE(IsReadyToRunCompilation()); @@ -3412,55 +3424,35 @@ bool ZapInfo::getReadyToRunHelper( { case CORINFO_HELP_READYTORUN_NEW: if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } + return false; // Requires runtime lookup. pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_NEW_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; case CORINFO_HELP_READYTORUN_NEWARR_1: if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } + return false; // Requires runtime lookup. pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_NEW_ARRAY_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; case CORINFO_HELP_READYTORUN_ISINSTANCEOF: if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } + return false; // Requires runtime lookup. pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_ISINSTANCEOF_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; case CORINFO_HELP_READYTORUN_CHKCAST: if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } + return false; // Requires runtime lookup. pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_CHKCAST_HELPER | fAtypicalCallsite), pResolvedToken->hClass); break; case CORINFO_HELP_READYTORUN_STATIC_BASE: if ((getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_SHAREDINST) != 0) - { - // READYTORUN: FUTURE: Generics - m_zapper->Warning(W("ReadyToRun: Generic dictionary lookup required\n")); - ThrowHR(E_NOTIMPL); - } + return false; // Requires runtime lookup. if (m_pImage->GetCompileInfo()->IsInCurrentVersionBubble(m_pEEJitInfo->getClassModule(pResolvedToken->hClass))) { pImport = m_pImage->GetImportTable()->GetDynamicHelperCell( @@ -3474,6 +3466,26 @@ bool ZapInfo::getReadyToRunHelper( } break; + case CORINFO_HELP_READYTORUN_GENERIC_HANDLE: + _ASSERTE(pGenericLookupKind != NULL && pGenericLookupKind->needsRuntimeLookup); + if (pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM) + { + pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell( + (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_METHOD | fAtypicalCallsite), pResolvedToken, pGenericLookupKind); + } + else if (pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_THISOBJ) + { + pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell( + (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_THISOBJ | fAtypicalCallsite), pResolvedToken, pGenericLookupKind); + } + else + { + _ASSERTE(pGenericLookupKind->runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM); + pImport = m_pImage->GetImportTable()->GetDictionaryLookupCell( + (CORCOMPILE_FIXUP_BLOB_KIND)(ENCODE_DICTIONARY_LOOKUP_TYPE | fAtypicalCallsite), pResolvedToken, pGenericLookupKind); + } + break; + default: _ASSERTE(false); ThrowHR(E_NOTIMPL); diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h index 059917acfb..d2a29b7a59 100644 --- a/src/zap/zapinfo.h +++ b/src/zap/zapinfo.h @@ -547,10 +547,10 @@ public: CorInfoHelpFunc getUnBoxHelper(CORINFO_CLASS_HANDLE cls); bool getReadyToRunHelper( - CORINFO_RESOLVED_TOKEN * pResolvedToken, - CORINFO_LOOKUP_KIND * pGenericLookupKind, - CorInfoHelpFunc id, - CORINFO_CONST_LOOKUP * pLookup + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup ); void getReadyToRunDelegateCtorHelper( diff --git a/src/zap/zapreadytorun.cpp b/src/zap/zapreadytorun.cpp index 06ba5f6ab7..7a9a802c76 100644 --- a/src/zap/zapreadytorun.cpp +++ b/src/zap/zapreadytorun.cpp @@ -470,6 +470,10 @@ static_assert_no_msg((int)READYTORUN_FIELD_SIG_OwnerType == (int)ENC // // READYTORUN_FIXUP // +static_assert_no_msg((int)READYTORUN_FIXUP_ThisObjDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_THISOBJ); +static_assert_no_msg((int)READYTORUN_FIXUP_TypeDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_TYPE); +static_assert_no_msg((int)READYTORUN_FIXUP_MethodDictionaryLookup == (int)ENCODE_DICTIONARY_LOOKUP_METHOD); + static_assert_no_msg((int)READYTORUN_FIXUP_TypeHandle == (int)ENCODE_TYPE_HANDLE); static_assert_no_msg((int)READYTORUN_FIXUP_MethodHandle == (int)ENCODE_METHOD_HANDLE); static_assert_no_msg((int)READYTORUN_FIXUP_FieldHandle == (int)ENCODE_FIELD_HANDLE); @@ -486,30 +490,30 @@ static_assert_no_msg((int)READYTORUN_FIXUP_VirtualEntry_Slot == (int)ENC static_assert_no_msg((int)READYTORUN_FIXUP_Helper == (int)ENCODE_READYTORUN_HELPER); static_assert_no_msg((int)READYTORUN_FIXUP_StringHandle == (int)ENCODE_STRING_HANDLE); -static_assert_no_msg((int)READYTORUN_FIXUP_NewObject == (int)ENCODE_NEW_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_NewArray == (int)ENCODE_NEW_ARRAY_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_NewObject == (int)ENCODE_NEW_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_NewArray == (int)ENCODE_NEW_ARRAY_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_IsInstanceOf == (int)ENCODE_ISINSTANCEOF_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_ChkCast == (int)ENCODE_CHKCAST_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_IsInstanceOf == (int)ENCODE_ISINSTANCEOF_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_ChkCast == (int)ENCODE_CHKCAST_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_FieldAddress == (int)ENCODE_FIELD_ADDRESS); -static_assert_no_msg((int)READYTORUN_FIXUP_CctorTrigger == (int)ENCODE_CCTOR_TRIGGER); +static_assert_no_msg((int)READYTORUN_FIXUP_FieldAddress == (int)ENCODE_FIELD_ADDRESS); +static_assert_no_msg((int)READYTORUN_FIXUP_CctorTrigger == (int)ENCODE_CCTOR_TRIGGER); -static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseNonGC == (int)ENCODE_STATIC_BASE_NONGC_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseGC == (int)ENCODE_STATIC_BASE_GC_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseNonGC == (int)ENCODE_THREAD_STATIC_BASE_NONGC_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseGC == (int)ENCODE_THREAD_STATIC_BASE_GC_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseNonGC == (int)ENCODE_STATIC_BASE_NONGC_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_StaticBaseGC == (int)ENCODE_STATIC_BASE_GC_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseNonGC == (int)ENCODE_THREAD_STATIC_BASE_NONGC_HELPER); +static_assert_no_msg((int)READYTORUN_FIXUP_ThreadStaticBaseGC == (int)ENCODE_THREAD_STATIC_BASE_GC_HELPER); -static_assert_no_msg((int)READYTORUN_FIXUP_FieldBaseOffset == (int)ENCODE_FIELD_BASE_OFFSET); -static_assert_no_msg((int)READYTORUN_FIXUP_FieldOffset == (int)ENCODE_FIELD_OFFSET); +static_assert_no_msg((int)READYTORUN_FIXUP_FieldBaseOffset == (int)ENCODE_FIELD_BASE_OFFSET); +static_assert_no_msg((int)READYTORUN_FIXUP_FieldOffset == (int)ENCODE_FIELD_OFFSET); -static_assert_no_msg((int)READYTORUN_FIXUP_TypeDictionary == (int)ENCODE_TYPE_DICTIONARY); -static_assert_no_msg((int)READYTORUN_FIXUP_MethodDictionary == (int)ENCODE_METHOD_DICTIONARY); +static_assert_no_msg((int)READYTORUN_FIXUP_TypeDictionary == (int)ENCODE_TYPE_DICTIONARY); +static_assert_no_msg((int)READYTORUN_FIXUP_MethodDictionary == (int)ENCODE_METHOD_DICTIONARY); -static_assert_no_msg((int)READYTORUN_FIXUP_Check_TypeLayout == (int)ENCODE_CHECK_TYPE_LAYOUT); -static_assert_no_msg((int)READYTORUN_FIXUP_Check_FieldOffset == (int)ENCODE_CHECK_FIELD_OFFSET); +static_assert_no_msg((int)READYTORUN_FIXUP_Check_TypeLayout == (int)ENCODE_CHECK_TYPE_LAYOUT); +static_assert_no_msg((int)READYTORUN_FIXUP_Check_FieldOffset == (int)ENCODE_CHECK_FIELD_OFFSET); -static_assert_no_msg((int)READYTORUN_FIXUP_DelegateCtor == (int)ENCODE_DELEGATE_CTOR); +static_assert_no_msg((int)READYTORUN_FIXUP_DelegateCtor == (int)ENCODE_DELEGATE_CTOR); // // READYTORUN_EXCEPTION |