summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPat Gavlin <pagavlin@microsoft.com>2016-01-20 13:44:43 -0800
committerPat Gavlin <pagavlin@microsoft.com>2016-01-22 16:24:23 -0800
commit626e050f03bff854793798d7abc496621c05ce02 (patch)
treed670dbd840822dfc36cf69a3e7f6ec21ad6ebf64
parent0f14640db10489f70f522436a764c4788db904ae (diff)
downloadcoreclr-626e050f03bff854793798d7abc496621c05ce02.tar.gz
coreclr-626e050f03bff854793798d7abc496621c05ce02.tar.bz2
coreclr-626e050f03bff854793798d7abc496621c05ce02.zip
Generate P/Invoke transitions for CoreRT.
This change adds support for CoreRT-style P/Invoke transitions to RyuJIT. Instead of the usual inlined transition code, these transitions are made up of calls to two new JIT helpers: PInvokeTransitionFrame frame; // opaque local CORINFO_HELP_INIT_PINVOKE_FRAME(&frame); ... CORINFO_HELP_JIT_PINVOKE_BEGIN(&frame); target(...); CORINFO_HELP_JIT_PINVOKE_END(&frame); ... The preemptive mode constraints apply between calls to JIT_PINVOKE_BEGIN and JIT_PINVOKE_END: no managed references may be live only in registers and managed references may not be manipulated.
-rw-r--r--src/inc/corinfo.h3
-rw-r--r--src/inc/corjit.h11
-rw-r--r--src/inc/jithelpers.h3
-rw-r--r--src/jit/codegencommon.cpp24
-rw-r--r--src/jit/flowgraph.cpp8
-rw-r--r--src/jit/gentree.h2
-rw-r--r--src/jit/lclvars.cpp92
-rw-r--r--src/jit/liveness.cpp127
-rw-r--r--src/jit/lower.cpp72
-rw-r--r--src/jit/regalloc.cpp23
10 files changed, 252 insertions, 113 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index fef412678a..3e7094e9a2 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -695,6 +695,9 @@ enum CorInfoHelpFunc
CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException
#endif
+ CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
+ CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
+
CORINFO_HELP_COUNT,
};
diff --git a/src/inc/corjit.h b/src/inc/corjit.h
index 8612d954df..7665fdf9f8 100644
--- a/src/inc/corjit.h
+++ b/src/inc/corjit.h
@@ -124,17 +124,18 @@ enum CorJitFlag
#ifdef MDIL
CORJIT_FLG_MDIL = 0x00004000, // Generate MDIL code instead of machine code
-#else // MDIL
- CORJIT_FLG_UNUSED7 = 0x00004000,
-#endif // MDIL
-#ifdef MDIL
// Safe to overlap with CORJIT_FLG_MAKEFINALCODE below. Not used by the JIT, used internally by NGen only.
CORJIT_FLG_MINIMAL_MDIL = 0x00008000, // Generate MDIL code suitable for use to bind other assemblies.
// Safe to overlap with CORJIT_FLG_READYTORUN below. Not used by the JIT, used internally by NGen only.
CORJIT_FLG_NO_MDIL = 0x00010000, // Generate an MDIL section but no code or CTL. Not used by the JIT, used internally by NGen only.
-#endif // MDIL
+#else // MDIL
+ CORJIT_FLG_PINVOKE_USE_HELPERS = 0x00004000, // Use JIT_PINVOKE_{BEGIN,END} helpers instead of generating transitions inline.
+
+ // TODO: this should probably not overlap with CORJIT_FLG_MAKEFINALCODE, but we've run out of bits.
+ CORJIT_FLG_PINVOKE_DIRECT_CALLS= 0x00008000, // Direct calls to native methods do not require indirections
+#endif
#if defined(FEATURE_INTERPRETER)
CORJIT_FLG_MAKEFINALCODE = 0x00008000, // Use the final code generator, i.e., not the interpreter.
diff --git a/src/inc/jithelpers.h b/src/inc/jithelpers.h
index bd3ad544fb..eac9c45151 100644
--- a/src/inc/jithelpers.h
+++ b/src/inc/jithelpers.h
@@ -403,6 +403,9 @@
#endif // COR_JIT_EE_VERSION
+ JITHELPER1(CORINFO_HELP_JIT_PINVOKE_BEGIN, NULL, CORINFO_HELP_SIG_UNDEF, MDIL_HELP_UNDEF)
+ JITHELPER1(CORINFO_HELP_JIT_PINVOKE_END, NULL, CORINFO_HELP_SIG_UNDEF, MDIL_HELP_UNDEF)
+
#undef JITHELPER1
#undef DYNAMICJITHELPER1
#undef JITHELPER
diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
index 4830342e84..7b14c8858c 100644
--- a/src/jit/codegencommon.cpp
+++ b/src/jit/codegencommon.cpp
@@ -7557,6 +7557,7 @@ void CodeGen::genPrologPadForReJit()
regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
{
assert(compiler->compGeneratingProlog);
+ noway_assert((compiler->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS) == 0);
noway_assert(compiler->info.compCallUnmanaged);
CORINFO_EE_INFO * pInfo = compiler->eeGetEEInfo();
@@ -7776,6 +7777,7 @@ regMaskTP CodeGen::genPInvokeMethodProlog(regMaskTP initRegs)
void CodeGen::genPInvokeMethodEpilog()
{
noway_assert(compiler->info.compCallUnmanaged);
+ noway_assert((compiler->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS) == 0);
noway_assert(compiler->compCurBB == compiler->genReturnBB ||
(compiler->compTailCallUsed && (compiler->compCurBB->bbJumpKind == BBJ_THROW)) ||
(compiler->compJmpOpUsed && (compiler->compCurBB->bbFlags & BBF_HAS_JMP)));
@@ -8517,13 +8519,23 @@ void CodeGen::genFnProlog()
// since they are trashed by the jithelper call to setup the PINVOKE frame
if (compiler->info.compCallUnmanaged)
{
- excludeMask |= (RBM_PINVOKE_FRAME | RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH);
+ excludeMask |= RBM_PINVOKE_FRAME;
+ if (compiler->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(compiler->info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ noway_assert(compiler->info.compLvFrameListRoot < compiler->lvaCount);
- // We also must exclude the register used by compLvFrameListRoot when it is enregistered
- //
- LclVarDsc * varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
- if (varDsc->lvRegister)
- excludeMask |= genRegMask(varDsc->lvRegNum);
+ excludeMask |= (RBM_PINVOKE_TCB | RBM_PINVOKE_SCRATCH);
+
+ // We also must exclude the register used by compLvFrameListRoot when it is enregistered
+ //
+ LclVarDsc * varDsc = &compiler->lvaTable[compiler->info.compLvFrameListRoot];
+ if (varDsc->lvRegister)
+ excludeMask |= genRegMask(varDsc->lvRegNum);
+ }
}
#endif // INLINE_NDIRECT
diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp
index 39fd0a6f49..7d5f2ebd36 100644
--- a/src/jit/flowgraph.cpp
+++ b/src/jit/flowgraph.cpp
@@ -8237,7 +8237,11 @@ void Compiler::fgAddInternal()
#if INLINE_NDIRECT
if (info.compCallUnmanaged != 0)
{
- info.compLvFrameListRoot = lvaGrabTemp(false DEBUGARG("Pinvoke FrameListRoot"));
+ bool usePInvokeHelpers = (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS) != 0;
+ if (!usePInvokeHelpers)
+ {
+ info.compLvFrameListRoot = lvaGrabTemp(false DEBUGARG("Pinvoke FrameListRoot"));
+ }
lvaInlinedPInvokeFrameVar = lvaGrabTempWithImplicitUse(false DEBUGARG("Pinvoke FrameVar"));
@@ -8249,7 +8253,7 @@ void Compiler::fgAddInternal()
#if FEATURE_FIXED_OUT_ARGS
// Grab and reserve space for TCB, Frame regs used in PInvoke epilog to pop the inlined frame.
// See genPInvokeMethodEpilog() for use of the grabbed var.
- if (compJmpOpUsed)
+ if (!usePInvokeHelpers && compJmpOpUsed)
{
lvaPInvokeFrameRegSaveVar = lvaGrabTempWithImplicitUse(false DEBUGARG("PInvokeFrameRegSave Var"));
varDsc = &lvaTable[lvaPInvokeFrameRegSaveVar];
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 9756dcbd6a..c41e15209b 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -2108,7 +2108,7 @@ struct GenTreeLclVar: public GenTreeLclVarCommon
DEBUG_ARG(largeNode)),
gtLclILoffs(ilOffs)
{
- assert(OperIsLocal(oper));
+ assert(OperIsLocal(oper) || OperIsLocalAddr(oper));
}
#if DEBUGGABLE_GENTREE
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index afe8aaf408..cd13b73d57 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -2159,17 +2159,24 @@ void Compiler::lvaDecRefCnts(GenTreePtr tree)
if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
{
- /* Get the special variable descriptor */
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ /* Get the special variable descriptor */
- lclNum = info.compLvFrameListRoot;
-
- noway_assert(lclNum <= lvaCount);
- varDsc = lvaTable + lclNum;
-
- /* Decrement the reference counts twice */
+ lclNum = info.compLvFrameListRoot;
- varDsc->decRefCnts(compCurBB->getBBWeight(this), this);
- varDsc->decRefCnts(compCurBB->getBBWeight(this), this);
+ noway_assert(lclNum <= lvaCount);
+ varDsc = lvaTable + lclNum;
+
+ /* Decrement the reference counts twice */
+
+ varDsc->decRefCnts(compCurBB->getBBWeight(this), this);
+ varDsc->decRefCnts(compCurBB->getBBWeight(this), this);
+ }
}
else
{
@@ -2214,17 +2221,24 @@ void Compiler::lvaIncRefCnts(GenTreePtr tree)
if ((tree->gtOper == GT_CALL) && (tree->gtFlags & GTF_CALL_UNMANAGED))
{
- /* Get the special variable descriptor */
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ /* Get the special variable descriptor */
- lclNum = info.compLvFrameListRoot;
-
- noway_assert(lclNum <= lvaCount);
- varDsc = lvaTable + lclNum;
-
- /* Increment the reference counts twice */
+ lclNum = info.compLvFrameListRoot;
- varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
- varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
+ noway_assert(lclNum <= lvaCount);
+ varDsc = lvaTable + lclNum;
+
+ /* Increment the reference counts twice */
+
+ varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
+ varDsc->incRefCnts(compCurBB->getBBWeight(this), this);
+ }
}
else
{
@@ -2800,16 +2814,23 @@ void Compiler::lvaMarkLclRefs(GenTreePtr tree)
/* Is this a call to unmanaged code ? */
if (tree->gtOper == GT_CALL && tree->gtFlags & GTF_CALL_UNMANAGED)
{
- /* Get the special variable descriptor */
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ /* Get the special variable descriptor */
- unsigned lclNum = info.compLvFrameListRoot;
-
- noway_assert(lclNum <= lvaCount);
- LclVarDsc * varDsc = lvaTable + lclNum;
+ unsigned lclNum = info.compLvFrameListRoot;
+
+ noway_assert(lclNum <= lvaCount);
+ LclVarDsc * varDsc = lvaTable + lclNum;
- /* Increment the ref counts twice */
- varDsc->incRefCnts(lvaMarkRefsWeight, this);
- varDsc->incRefCnts(lvaMarkRefsWeight, this);
+ /* Increment the ref counts twice */
+ varDsc->incRefCnts(lvaMarkRefsWeight, this);
+ varDsc->incRefCnts(lvaMarkRefsWeight, this);
+ }
}
#endif
@@ -3166,15 +3187,22 @@ void Compiler::lvaMarkLocalVars()
if (info.compCallUnmanaged != 0)
{
- noway_assert(info.compLvFrameListRoot >= info.compLocalsCount &&
- info.compLvFrameListRoot < lvaCount);
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ noway_assert(info.compLvFrameListRoot >= info.compLocalsCount &&
+ info.compLvFrameListRoot < lvaCount);
- lvaTable[info.compLvFrameListRoot].lvType = TYP_I_IMPL;
+ lvaTable[info.compLvFrameListRoot].lvType = TYP_I_IMPL;
- /* Set the refCnt, it is used in the prolog and return block(s) */
+ /* Set the refCnt, it is used in the prolog and return block(s) */
- lvaTable[info.compLvFrameListRoot].lvRefCnt = 2;
- lvaTable[info.compLvFrameListRoot].lvRefCntWtd = 2 * BB_UNITY_WEIGHT;
+ lvaTable[info.compLvFrameListRoot].lvRefCnt = 2;
+ lvaTable[info.compLvFrameListRoot].lvRefCntWtd = 2 * BB_UNITY_WEIGHT;
+ }
}
#endif
diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp
index fc22a69eba..a1bd10ac31 100644
--- a/src/jit/liveness.cpp
+++ b/src/jit/liveness.cpp
@@ -437,19 +437,26 @@ void Compiler::fgPerStatementLocalVarLiveness(GenTreePtr startNode, GenTreePtr a
// This ensures that the block->bbVarUse will contain
// the FrameRoot local var if is it a tracked variable.
- if (tree->gtCall.IsUnmanaged() || (tree->gtCall.IsTailCall() && info.compCallUnmanaged))
+ if ((tree->gtCall.IsUnmanaged() || (tree->gtCall.IsTailCall() && info.compCallUnmanaged)))
{
- /* Get the TCB local and mark it as used */
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ /* Get the TCB local and mark it as used */
- noway_assert(info.compLvFrameListRoot < lvaCount);
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- LclVarDsc* varDsc = &lvaTable[info.compLvFrameListRoot];
+ LclVarDsc* varDsc = &lvaTable[info.compLvFrameListRoot];
- if (varDsc->lvTracked)
- {
- if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ if (varDsc->lvTracked)
{
- VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ {
+ VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ }
}
}
}
@@ -629,17 +636,24 @@ void Compiler::fgPerBlockLocalVarLiveness()
/* Get the TCB local and mark it as used */
- if (block->bbJumpKind == BBJ_RETURN && info.compCallUnmanaged)
+ if (block->bbJumpKind == BBJ_RETURN && info.compCallUnmanaged)
{
- noway_assert(info.compLvFrameListRoot < lvaCount);
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- LclVarDsc * varDsc = &lvaTable[info.compLvFrameListRoot];
+ LclVarDsc * varDsc = &lvaTable[info.compLvFrameListRoot];
- if (varDsc->lvTracked)
- {
- if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ if (varDsc->lvTracked)
{
- VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ if (!VarSetOps::IsMember(this, fgCurDefSet, varDsc->lvVarIndex))
+ {
+ VarSetOps::AddElemD(this, fgCurUseSet, varDsc->lvVarIndex);
+ }
}
}
}
@@ -1742,21 +1756,28 @@ SKIP_QMARK:
if (tree->gtCall.IsTailCall() && info.compCallUnmanaged)
{
- /* Get the TCB local and make it live */
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ /* Get the TCB local and make it live */
- noway_assert(info.compLvFrameListRoot < lvaCount);
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- LclVarDsc* frameVarDsc = &lvaTable[info.compLvFrameListRoot];
+ LclVarDsc* frameVarDsc = &lvaTable[info.compLvFrameListRoot];
- if (frameVarDsc->lvTracked)
- {
- VARSET_TP VARSET_INIT_NOCOPY(varBit, VarSetOps::MakeSingleton(this, frameVarDsc->lvVarIndex));
+ if (frameVarDsc->lvTracked)
+ {
+ VARSET_TP VARSET_INIT_NOCOPY(varBit, VarSetOps::MakeSingleton(this, frameVarDsc->lvVarIndex));
- VarSetOps::AddElemD(this, life, frameVarDsc->lvVarIndex);
+ VarSetOps::AddElemD(this, life, frameVarDsc->lvVarIndex);
- /* Record interference with other live variables */
+ /* Record interference with other live variables */
- fgMarkIntf(life, varBit);
+ fgMarkIntf(life, varBit);
+ }
}
}
@@ -1770,38 +1791,44 @@ SKIP_QMARK:
if (tree->gtCall.IsUnmanaged())
{
/* Get the TCB local and make it live */
-
- noway_assert(info.compLvFrameListRoot < lvaCount);
-
- LclVarDsc* frameVarDsc = &lvaTable[info.compLvFrameListRoot];
-
- if (frameVarDsc->lvTracked)
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
{
- unsigned varIndex = frameVarDsc->lvVarIndex;
- noway_assert(varIndex < lvaTrackedCount);
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
+ {
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- // Is the variable already known to be alive?
- //
- if (VarSetOps::IsMember(this, life, varIndex))
+ LclVarDsc* frameVarDsc = &lvaTable[info.compLvFrameListRoot];
+
+ if (frameVarDsc->lvTracked)
{
- // Since we may call this multiple times, clear the GTF_CALL_M_FRAME_VAR_DEATH if set.
+ unsigned varIndex = frameVarDsc->lvVarIndex;
+ noway_assert(varIndex < lvaTrackedCount);
+
+ // Is the variable already known to be alive?
//
- tree->gtCall.gtCallMoreFlags &= ~GTF_CALL_M_FRAME_VAR_DEATH;
- }
- else
- {
- // The variable is just coming to life
- // Since this is a backwards walk of the trees
- // that makes this change in liveness a 'last-use'
+ if (VarSetOps::IsMember(this, life, varIndex))
+ {
+ // Since we may call this multiple times, clear the GTF_CALL_M_FRAME_VAR_DEATH if set.
+ //
+ tree->gtCall.gtCallMoreFlags &= ~GTF_CALL_M_FRAME_VAR_DEATH;
+ }
+ else
+ {
+ // The variable is just coming to life
+ // Since this is a backwards walk of the trees
+ // that makes this change in liveness a 'last-use'
+ //
+ VarSetOps::AddElemD(this, life, varIndex);
+ tree->gtCall.gtCallMoreFlags |= GTF_CALL_M_FRAME_VAR_DEATH;
+ }
+
+ // Record an interference with the other live variables
//
- VarSetOps::AddElemD(this, life, varIndex);
- tree->gtCall.gtCallMoreFlags |= GTF_CALL_M_FRAME_VAR_DEATH;
+ VARSET_TP VARSET_INIT_NOCOPY(varBit, VarSetOps::MakeSingleton(this, varIndex));
+ fgMarkIntf(life, varBit);
}
-
- // Record an interference with the other live variables
- //
- VARSET_TP VARSET_INIT_NOCOPY(varBit, VarSetOps::MakeSingleton(this, varIndex));
- fgMarkIntf(life, varBit);
}
/* Do we have any live variables? */
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index 68fa2c335a..c77c7ee5d0 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -2475,6 +2475,21 @@ void Lowering::InsertPInvokeMethodProlog()
noway_assert(comp->info.compCallUnmanaged);
noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
+ if (comp->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ // Initialize the P/Invoke frame by calling CORINFO_HELP_INIT_PINVOKE_FRAME
+
+ GenTree* frameAddr = new(comp, GT_LCL_VAR_ADDR)
+ GenTreeLclVar(GT_LCL_VAR_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
+
+ GenTree* helperCall = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
+
+ GenTreeStmt* stmt = LowerMorphAndSeqTree(helperCall);
+ comp->fgInsertStmtAtBeg(comp->fgFirstBB, stmt);
+
+ return;
+ }
+
CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
const CORINFO_EE_INFO::InlinedCallFrameInfo& callFrameInfo = pInfo->inlinedCallFrameInfo;
@@ -2555,6 +2570,11 @@ void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
assert(returnBB != nullptr);
assert(comp->info.compCallUnmanaged);
+ if (comp->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ return;
+ }
+
// Method doing Pinvoke calls has exactly one return block unless it has "jmp" or tail calls.
#ifdef DEBUG
bool endsWithTailCallOrJmp = false;
@@ -2612,14 +2632,6 @@ void Lowering::InsertPInvokeMethodEpilog(BasicBlock *returnBB
// field of the frame (methodHandle may be indirected & have a reloc)
void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
{
- // emit the following sequence
- //
- // frame.callTarget := methodHandle
- // (x86) frame.callSiteTracker = SP
- // frame.callSiteReturnAddress = return address
- // thread->gcState = 0
- // (non-stub) - update top Frame on TCB
- //
GenTree* insertBefore = call;
if (call->gtCallType == CT_INDIRECT)
{
@@ -2633,6 +2645,29 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
+ if (comp->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ // First argument is the address of the frame variable.
+ GenTree* frameAddr = new(comp, GT_LCL_VAR_ADDR)
+ GenTreeLclVar(GT_LCL_VAR_ADDR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
+
+ // Insert call to CORINFO_HELP_JIT_PINVOKE_BEGIN
+ GenTree* helperCall = comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_BEGIN, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
+
+ comp->fgMorphTree(helperCall);
+ comp->fgInsertTreeBeforeAsEmbedded(helperCall, insertBefore, comp->compCurStmt->AsStmt(), currBlock);
+ return;
+ }
+
+ // emit the following sequence
+ //
+ // frame.callTarget := methodHandle
+ // (x86) frame.callSiteTracker = SP
+ // frame.callSiteReturnAddress = return address
+ // thread->gcState = 0
+ // (non-stub) - update top Frame on TCB
+ //
+
// ----------------------------------------------------------------------------------
// Setup frame.callSiteTarget (what it referred to in the JIT)
// The actual field is Frame.m_Datum which has many different uses and meanings.
@@ -2751,10 +2786,26 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
comp->fgInsertTreeBeforeAsEmbedded(storeGCState, insertBefore, comp->compCurStmt->AsStmt(), currBlock);
}
-
// insert the code that goes after every inlined pinvoke call
void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
{
+ if (comp->opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(comp->lvaInlinedPInvokeFrameVar != BAD_VAR_NUM);
+
+ // First argument is the address of the frame variable.
+ GenTree* frameAddr = new(comp, GT_LCL_VAR)
+ GenTreeLclVar(GT_LCL_VAR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET);
+ frameAddr->gtOper = GT_LCL_VAR_ADDR;
+
+ // Insert call to CORINFO_HELP_JIT_PINVOKE_END
+ GenTree* helperCall = comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_END, TYP_VOID, 0, comp->gtNewArgList(frameAddr));
+
+ comp->fgMorphTree(helperCall);
+ comp->fgInsertTreeAfterAsEmbedded(helperCall, call, comp->compCurStmt->AsStmt(), currBlock);
+ return;
+ }
+
CORINFO_EE_INFO* pInfo = comp->eeGetEEInfo();
GenTreeStmt* newStmt;
GenTreeStmt* topStmt = comp->compCurStmt->AsStmt();
@@ -2809,7 +2860,7 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
InsertPInvokeCallProlog(call);
- if (call->gtCallType != CT_INDIRECT)
+ if ((comp->opts.eeFlags & CORJIT_FLG_PINVOKE_DIRECT_CALLS) == 0 && call->gtCallType != CT_INDIRECT)
{
GenTree* indir = nullptr;
@@ -2830,6 +2881,7 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
}
result = indir;
}
+
InsertPInvokeCallEpilog(call);
return result;
diff --git a/src/jit/regalloc.cpp b/src/jit/regalloc.cpp
index 78ca194ff3..ff67ac635c 100644
--- a/src/jit/regalloc.cpp
+++ b/src/jit/regalloc.cpp
@@ -6439,15 +6439,24 @@ void Compiler::rpPredictRegUse()
// it must not be in a register trashed by the callee
if (info.compCallUnmanaged != 0)
{
- LclVarDsc * pinvokeVarDsc = &lvaTable[info.compLvFrameListRoot];
-
- if (pinvokeVarDsc->lvTracked)
+ if (opts.eeFlags & CORJIT_FLG_PINVOKE_USE_HELPERS)
+ {
+ noway_assert(info.compLvFrameListRoot == BAD_VAR_NUM);
+ }
+ else
{
- rpRecordRegIntf(RBM_CALLEE_TRASH, VarSetOps::MakeSingleton(this, pinvokeVarDsc->lvVarIndex)
- DEBUGARG("compLvFrameListRoot"));
+ noway_assert(info.compLvFrameListRoot < lvaCount);
- // We would prefer to have this be enregister in the PINVOKE_TCB register
- pinvokeVarDsc->addPrefReg(RBM_PINVOKE_TCB, this);
+ LclVarDsc * pinvokeVarDsc = &lvaTable[info.compLvFrameListRoot];
+
+ if (pinvokeVarDsc->lvTracked)
+ {
+ rpRecordRegIntf(RBM_CALLEE_TRASH, VarSetOps::MakeSingleton(this, pinvokeVarDsc->lvVarIndex)
+ DEBUGARG("compLvFrameListRoot"));
+
+ // We would prefer to have this be enregister in the PINVOKE_TCB register
+ pinvokeVarDsc->addPrefReg(RBM_PINVOKE_TCB, this);
+ }
}
//If we're using a single return block, the p/invoke epilog code trashes ESI and EDI (in the