summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFadi Hanna <fadim@microsoft.com>2016-05-13 20:35:54 -0700
committerFadi Hanna <fadim@microsoft.com>2016-05-13 20:35:54 -0700
commit97b4ff0b438261ba11b357008630076054a6f25d (patch)
tree320c32b25b556124cb354ab06a86c8f6ae806d98 /src
parent5b065284dc57bc3a9eaee9f86b0df258b1d3d7af (diff)
downloadcoreclr-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.
Diffstat (limited to 'src')
-rw-r--r--src/inc/corcompile.h13
-rw-r--r--src/inc/corinfo.h9
-rw-r--r--src/inc/readytorun.h15
-rw-r--r--src/inc/readytorunhelpers.h12
-rw-r--r--src/jit/compiler.h10
-rw-r--r--src/jit/importer.cpp291
-rw-r--r--src/vm/amd64/cgenamd64.cpp109
-rw-r--r--src/vm/i386/cgenx86.cpp26
-rw-r--r--src/vm/jitinterface.cpp510
-rw-r--r--src/vm/jitinterface.h44
-rw-r--r--src/vm/prestub.cpp121
-rw-r--r--src/vm/readytoruninfo.h3
-rw-r--r--src/vm/zapsig.cpp16
-rw-r--r--src/zap/zapimage.cpp62
-rw-r--r--src/zap/zapimport.cpp69
-rw-r--r--src/zap/zapimport.h5
-rw-r--r--src/zap/zapinfo.cpp118
-rw-r--r--src/zap/zapinfo.h8
-rw-r--r--src/zap/zapreadytorun.cpp38
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