Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

PInvoke calli support for CoreRT #18534

Merged
merged 8 commits into from Jun 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
Expand Up @@ -906,6 +906,8 @@ void MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd);
// return a thunk that will copy the arguments for the given signature.
void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTailCallSpecialHandling flags);

bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert);

// return memory manager that the JIT can use to allocate a regular memory
IEEMemoryManager* getMemoryManager();

Expand Down
1 change: 1 addition & 0 deletions src/ToolBox/superpmi/superpmi-shared/lwmlist.h
Expand Up @@ -35,6 +35,7 @@ LWM(CompareTypesForCast, DLDL, DWORD)
LWM(CompareTypesForEquality, DLDL, DWORD)
LWM(CompileMethod, DWORD, Agnostic_CompileMethod)
LWM(ConstructStringLiteral, DLD, DLD)
LWM(ConvertPInvokeCalliToCall, DLD, DWORDLONG)
LWM(EmbedClassHandle, DWORDLONG, DLDL)
LWM(EmbedFieldHandle, DWORDLONG, DLDL)
LWM(EmbedGenericHandle, Agnostic_EmbedGenericHandle, Agnostic_CORINFO_GENERICHANDLE_RESULT)
Expand Down
35 changes: 35 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
Expand Up @@ -2436,6 +2436,41 @@ InfoAccessType MethodContext::repConstructStringLiteral(CORINFO_MODULE_HANDLE mo
return (InfoAccessType)temp2.B;
}

void MethodContext::recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert, bool result)
{
if (ConvertPInvokeCalliToCall == nullptr)
ConvertPInvokeCalliToCall = new LightWeightMap<DLD, DWORDLONG>();

DLD key;
ZeroMemory(&key, sizeof(DLD)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
// out padding too
key.A = (DWORDLONG)pResolvedToken->tokenScope;
key.B = (DWORD)pResolvedToken->token;

DWORDLONG value = (DWORDLONG)(result ? pResolvedToken->hMethod : 0);

ConvertPInvokeCalliToCall->Add(key, value);
DEBUG_REC(dmpConvertPInvokeCalliToCall(key, value));
}
void MethodContext::dmpConvertPInvokeCalliToCall(DLD key, DWORDLONG value)
{
printf("ConvertPInvokeCalliToCall key mod-%016llX tok-%08X, value %016llX", key.A, key.B, value);
}
bool MethodContext::repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
DLD key;
ZeroMemory(&key, sizeof(DLD)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
// out padding too
key.A = (DWORDLONG)pResolvedToken->tokenScope;
key.B = (DWORD)pResolvedToken->token;

DWORDLONG value = ConvertPInvokeCalliToCall->Get(key);
DEBUG_REP(dmpGetArgType(key, value));

pResolvedToken->hMethod = (CORINFO_METHOD_HANDLE)value;
return value != 0;
}

void MethodContext::recEmptyStringLiteral(void** pValue, InfoAccessType result)
{
if (EmptyStringLiteral == nullptr)
Expand Down
5 changes: 5 additions & 0 deletions src/ToolBox/superpmi/superpmi-shared/methodcontext.h
Expand Up @@ -805,6 +805,10 @@ class MethodContext
void dmpConstructStringLiteral(DLD key, DLD value);
InfoAccessType repConstructStringLiteral(CORINFO_MODULE_HANDLE module, mdToken metaTok, void** ppValue);

void recConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert, bool result);
void dmpConvertPInvokeCalliToCall(DLD key, DWORDLONG value);
bool repConvertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert);

void recEmptyStringLiteral(void** ppValue, InfoAccessType result);
void dmpEmptyStringLiteral(DWORD key, DLD value);
InfoAccessType repEmptyStringLiteral(void** ppValue);
Expand Down Expand Up @@ -1311,6 +1315,7 @@ enum mcPackets
Packet_CompareTypesForEquality = 164, // Added 10/4/17
Packet_CompileMethod = 143, // retired as 141 on 2013/07/09
Packet_ConstructStringLiteral = 15,
Packet_ConvertPInvokeCalliToCall = 169, // Added 4/29/18
Packet_EmbedClassHandle = 16,
Packet_EmbedFieldHandle = 17,
Packet_EmbedGenericHandle = 18,
Expand Down
8 changes: 8 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
Expand Up @@ -1825,6 +1825,14 @@ InfoAccessType interceptor_ICJI::constructStringLiteral(CORINFO_MODULE_HANDLE mo
return temp;
}

bool interceptor_ICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
mc->cr->AddCall("convertPInvokeCalliToCall");
bool result = original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, fMustConvert);
mc->recConvertPInvokeCalliToCall(pResolvedToken, fMustConvert, result);
return result;
}

InfoAccessType interceptor_ICJI::emptyStringLiteral(void** ppValue)
{
mc->cr->AddCall("emptyStringLiteral");
Expand Down
6 changes: 6 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
Expand Up @@ -1412,6 +1412,12 @@ InfoAccessType interceptor_ICJI::constructStringLiteral(CORINFO_MODULE_HANDLE mo
return original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue);
}

bool interceptor_ICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
mcs->AddCall("convertPInvokeCalliToCall");
return original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, fMustConvert);
}

InfoAccessType interceptor_ICJI::emptyStringLiteral(void** ppValue)
{
mcs->AddCall("emptyStringLiteral");
Expand Down
5 changes: 5 additions & 0 deletions src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
Expand Up @@ -1266,6 +1266,11 @@ InfoAccessType interceptor_ICJI::constructStringLiteral(CORINFO_MODULE_HANDLE mo
return original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue);
}

bool interceptor_ICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
return original_ICorJitInfo->convertPInvokeCalliToCall(pResolvedToken, fMustConvert);
}

InfoAccessType interceptor_ICJI::emptyStringLiteral(void** ppValue)
{
return original_ICorJitInfo->emptyStringLiteral(ppValue);
Expand Down
6 changes: 6 additions & 0 deletions src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
Expand Up @@ -1580,6 +1580,12 @@ void* MyICJI::getTailCallCopyArgsThunk(CORINFO_SIG_INFO* pSig, CorInfoHelperTail
return jitInstance->mc->repGetTailCallCopyArgsThunk(pSig, flags);
}

bool MyICJI::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
jitInstance->mc->cr->AddCall("convertPInvokeCalliToCall");
return jitInstance->mc->repConvertPInvokeCalliToCall(pResolvedToken, fMustConvert);
}

// Stuff directly on ICorJitInfo

// Returns extended flags for a particular compilation instance.
Expand Down
16 changes: 11 additions & 5 deletions src/inc/corinfo.h
Expand Up @@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif

SELECTANY const GUID JITEEVersionIdentifier = { /* 0ba106c8-81a0-407f-99a1-928448c1eb62 */
0x0ba106c8,
0x81a0,
0x407f,
{0x99, 0xa1, 0x92, 0x84, 0x48, 0xc1, 0xeb, 0x62}
SELECTANY const GUID JITEEVersionIdentifier = { /* dc72a60f-22f2-49fb-809f-00077f3eb1a8 */
0xdc72a60f,
0x22f2,
0x49fb,
{ 0x80, 0x9f, 0x0, 0x7, 0x7f, 0x3e, 0xb1, 0xa8}
};

//////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -3153,6 +3153,12 @@ class ICorDynamicInfo : public ICorStaticInfo
CORINFO_SIG_INFO *pSig,
CorInfoHelperTailCallSpecialHandling flags
) = 0;

// Optionally, convert calli to regular method call. This is for PInvoke argument marshalling.
virtual bool convertPInvokeCalliToCall(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
bool fMustConvert
) = 0;
};

/**********************************************************************************/
Expand Down
2 changes: 2 additions & 0 deletions src/jit/flowgraph.cpp
Expand Up @@ -4752,6 +4752,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
}
break;

#if !defined(FEATURE_CORECLR)
case CEE_CALLI:

// CEE_CALLI should not be inlined if the call indirect target has a calling convention other than
Expand Down Expand Up @@ -4784,6 +4785,7 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
}
}
break;
#endif // FEATURE_CORECLR

case CEE_JMP:
retBlocks++;
Expand Down
81 changes: 34 additions & 47 deletions src/jit/importer.cpp
Expand Up @@ -4753,7 +4753,7 @@ bool Compiler::verCheckTailCallConstraint(
if (opcode == CEE_CALLI)
{
/* Get the call sig */
eeGetSig(pResolvedToken->token, info.compScopeHnd, impTokenLookupContextHandle, &sig);
eeGetSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &sig);

// We don't know the target method, so we have to infer the flags, or
// assume the worst-case.
Expand Down Expand Up @@ -4781,7 +4781,7 @@ bool Compiler::verCheckTailCallConstraint(

if ((sig.callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG)
{
eeGetCallSiteSig(pResolvedToken->token, info.compScopeHnd, impTokenLookupContextHandle, &sig);
eeGetCallSiteSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &sig);
}

// check compatibility of the arguments
Expand Down Expand Up @@ -4849,7 +4849,7 @@ bool Compiler::verCheckTailCallConstraint(
if (methodClassFlgs & CORINFO_FLG_ARRAY)
{
assert(opcode != CEE_CALLI);
eeGetCallSiteSig(pResolvedToken->token, info.compScopeHnd, impTokenLookupContextHandle, &sig);
eeGetCallSiteSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &sig);
}
}

Expand Down Expand Up @@ -6097,8 +6097,11 @@ void Compiler::impCheckForPInvokeCall(
}
optNativeCallCount++;

if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && methHnd == nullptr)
if (methHnd == nullptr && (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) || IsTargetAbi(CORINFO_CORERT_ABI)))
{
// PInvoke in CoreRT ABI must be always inlined. Non-inlineable CALLI cases have been
// converted to regular method calls earlier using convertPInvokeCalliToCall.

// PInvoke CALLI in IL stubs must be inlined
}
else
Expand Down Expand Up @@ -6967,8 +6970,19 @@ var_types Compiler::impImportCall(OPCODE opcode,

if (opcode == CEE_CALLI)
{
if (IsTargetAbi(CORINFO_CORERT_ABI))
{
// See comment in impCheckForPInvokeCall
BasicBlock* block = compIsForInlining() ? impInlineInfo->iciBlock : compCurBB;
if (info.compCompHnd->convertPInvokeCalliToCall(pResolvedToken, !impCanPInvokeInlineCallSite(block)))
{
eeGetCallInfo(pResolvedToken, nullptr, CORINFO_CALLINFO_ALLOWINSTPARAM, callInfo);
return impImportCall(CEE_CALL, pResolvedToken, nullptr, nullptr, prefixFlags, callInfo, rawILOffset);
}
}

/* Get the call site sig */
eeGetSig(pResolvedToken->token, info.compScopeHnd, impTokenLookupContextHandle, &calliSig);
eeGetSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &calliSig);

callRetTyp = JITtype2varType(calliSig.retType);

Expand Down Expand Up @@ -7532,7 +7546,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
#ifdef DEBUG
unsigned numArgsDef = sig->numArgs;
#endif
eeGetCallSiteSig(pResolvedToken->token, info.compScopeHnd, impTokenLookupContextHandle, sig);
eeGetCallSiteSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, sig);

#ifdef DEBUG
// We cannot lazily obtain the signature of a vararg call because using its method
Expand Down Expand Up @@ -13317,7 +13331,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
memset(&resolvedToken, 0, sizeof(resolvedToken));
memset(&callInfo, 0, sizeof(callInfo));

resolvedToken.token = getU4LittleEndian(codeAddr);
resolvedToken.token = getU4LittleEndian(codeAddr);
resolvedToken.tokenContext = impTokenLookupContextHandle;
resolvedToken.tokenScope = info.compScopeHnd;
}

CALL: // memberRef should be set.
Expand Down Expand Up @@ -13416,31 +13432,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// For delegates, this is the call to the delegate constructor, not the access check on the
// LD(virt)FTN.
impHandleAccessAllowed(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);

#if 0 // DevDiv 410397 - This breaks too many obfuscated apps to do this in an in-place release

// DevDiv 291703 - we need to check for accessibility between the caller of InitializeArray
// and the field it is reading, thus it is now unverifiable to not immediately precede with
// ldtoken <filed token>, and we now check accessibility
if ((callInfo.methodFlags & CORINFO_FLG_INTRINSIC) &&
(info.compCompHnd->getIntrinsicID(callInfo.hMethod) == CORINFO_INTRINSIC_InitializeArray))
{
if (prevOpcode != CEE_LDTOKEN)
{
Verify(prevOpcode == CEE_LDTOKEN, "Need ldtoken for InitializeArray");
}
else
{
assert(lastLoadToken != NULL);
// Now that we know we have a token, verify that it is accessible for loading
CORINFO_RESOLVED_TOKEN resolvedLoadField;
impResolveToken(lastLoadToken, &resolvedLoadField, CORINFO_TOKENKIND_Field);
eeGetFieldInfo(&resolvedLoadField, CORINFO_ACCESS_INIT_ARRAY, &fieldInfo);
impHandleAccessAllowed(fieldInfo.accessAllowed, &fieldInfo.accessCalloutHelper);
}
}

#endif // DevDiv 410397
}

if (tiVerificationNeeded)
Expand All @@ -13450,21 +13441,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
&callInfo DEBUGARG(info.compFullName));
}

// Insert delegate callout here.
if (opcode == CEE_NEWOBJ && (mflags & CORINFO_FLG_CONSTRUCTOR) && (clsFlags & CORINFO_FLG_DELEGATE))
{
#ifdef DEBUG
// We should do this only if verification is enabled
// If verification is disabled, delegateCreateStart will not be initialized correctly
if (tiVerificationNeeded)
{
mdMemberRef delegateMethodRef = mdMemberRefNil;
// We should get here only for well formed delegate creation.
assert(verCheckDelegateCreation(delegateCreateStart, codeAddr - 1, delegateMethodRef));
}
#endif
}

callTyp = impImportCall(opcode, &resolvedToken, constraintCall ? &constrainedResolvedToken : nullptr,
newObjThisPtr, prefixFlags, &callInfo, opcodeOffs);
if (compDonotInline())
Expand Down Expand Up @@ -19081,6 +19057,17 @@ void Compiler::impMarkInlineCandidate(GenTree* callNode,
return;
}

/* Check legality of PInvoke callsite (for inlining of marshalling code) */

if (methAttr & CORINFO_FLG_PINVOKE)
{
if (!impCanPInvokeInlineCallSite(compCurBB))
{
inlineResult.NoteFatal(InlineObservation::CALLSITE_PINVOKE_EH);
return;
}
}

InlineCandidateInfo* inlineCandidateInfo = nullptr;
impCheckCanInline(call, fncHandle, methAttr, exactContextHnd, &inlineCandidateInfo, &inlineResult);

Expand Down
1 change: 1 addition & 0 deletions src/jit/inline.def
Expand Up @@ -159,6 +159,7 @@ INLINE_OBSERVATION(REQUIRES_SAME_THIS, bool, "requires same this",
INLINE_OBSERVATION(RETURN_TYPE_MISMATCH, bool, "return type mismatch", FATAL, CALLSITE)
INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLSITE)
INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLSITE)
INLINE_OBSERVATION(PINVOKE_EH, bool, "PInvoke call site with EH", FATAL, CALLSITE)

// ------ Call Site Performance -------

Expand Down
5 changes: 5 additions & 0 deletions src/vm/jitinterface.cpp
Expand Up @@ -13746,6 +13746,11 @@ void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
return ftn;
}

bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
{
return false;
}

void CEEInfo::allocMem (
ULONG hotCodeSize, /* IN */
ULONG coldCodeSize, /* IN */
Expand Down
3 changes: 3 additions & 0 deletions src/vm/jitinterface.h
Expand Up @@ -950,6 +950,9 @@ class CEEInfo : public ICorJitInfo
void* getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
CorInfoHelperTailCallSpecialHandling flags);

bool convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken,
bool fMustConvert);

void getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftn, /* IN */
CORINFO_CONST_LOOKUP * pResult, /* OUT */
CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY);
Expand Down
7 changes: 7 additions & 0 deletions src/zap/zapinfo.cpp
Expand Up @@ -1690,6 +1690,13 @@ void* ZapInfo::getTailCallCopyArgsThunk (
return m_pImage->GetWrappers()->GetStub(pStub);
}

bool ZapInfo::convertPInvokeCalliToCall(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
bool fMustConvert)
{
return false;
}

#ifdef FEATURE_READYTORUN_COMPILER
ReadyToRunHelper MapReadyToRunHelper(CorInfoHelpFunc func, bool * pfOptimizeForSize)
{
Expand Down
4 changes: 4 additions & 0 deletions src/zap/zapinfo.h
Expand Up @@ -360,6 +360,10 @@ class ZapInfo
CORINFO_SIG_INFO *pSig,
CorInfoHelperTailCallSpecialHandling flags);

bool convertPInvokeCalliToCall(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
bool fMustConvert);

void getFunctionEntryPoint(
CORINFO_METHOD_HANDLE ftn, /* IN */
CORINFO_CONST_LOOKUP * pResult, /* OUT */
Expand Down