From e1d4d2bb71debcbc010852b50d047c0354151593 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Sun, 9 Oct 2022 20:25:46 +0200 Subject: [PATCH] JIT: Move impImportIndirectCall, impPopArgsForUnmanagedCall --- src/coreclr/jit/importer.cpp | 145 -------------------------------------- src/coreclr/jit/importercalls.cpp | 145 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 145 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index f2f34f4..39657dd 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -7927,151 +7927,6 @@ void Compiler::impCheckForPInvokeCall( } } -GenTreeCall* Compiler::impImportIndirectCall(CORINFO_SIG_INFO* sig, const DebugInfo& di) -{ - var_types callRetTyp = JITtype2varType(sig->retType); - - /* The function pointer is on top of the stack - It may be a - * complex expression. As it is evaluated after the args, - * it may cause registered args to be spilled. Simply spill it. - */ - - // Ignore this trivial case. - if (impStackTop().val->gtOper != GT_LCL_VAR) - { - impSpillStackEntry(verCurrentState.esStackDepth - 1, - BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impImportIndirectCall")); - } - - /* Get the function pointer */ - - GenTree* fptr = impPopStack().val; - - // The function pointer is typically a sized to match the target pointer size - // However, stubgen IL optimization can change LDC.I8 to LDC.I4 - // See ILCodeStream::LowerOpcode - assert(genActualType(fptr->gtType) == TYP_I_IMPL || genActualType(fptr->gtType) == TYP_INT); - -#ifdef DEBUG - // This temporary must never be converted to a double in stress mode, - // because that can introduce a call to the cast helper after the - // arguments have already been evaluated. - - if (fptr->OperGet() == GT_LCL_VAR) - { - lvaTable[fptr->AsLclVarCommon()->GetLclNum()].lvKeepType = 1; - } -#endif - - /* Create the call node */ - - GenTreeCall* call = gtNewIndCallNode(fptr, callRetTyp, di); - - call->gtFlags |= GTF_EXCEPT | (fptr->gtFlags & GTF_GLOB_EFFECT); -#ifdef UNIX_X86_ABI - call->gtFlags &= ~GTF_CALL_POP_ARGS; -#endif - - return call; -} - -/*****************************************************************************/ - -void Compiler::impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig) -{ - assert(call->gtFlags & GTF_CALL_UNMANAGED); - - /* Since we push the arguments in reverse order (i.e. right -> left) - * spill any side effects from the stack - * - * OBS: If there is only one side effect we do not need to spill it - * thus we have to spill all side-effects except last one - */ - - unsigned lastLevelWithSideEffects = UINT_MAX; - - unsigned argsToReverse = sig->numArgs; - - // For "thiscall", the first argument goes in a register. Since its - // order does not need to be changed, we do not need to spill it - - if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall) - { - assert(argsToReverse); - argsToReverse--; - } - -#ifndef TARGET_X86 - // Don't reverse args on ARM or x64 - first four args always placed in regs in order - argsToReverse = 0; -#endif - - for (unsigned level = verCurrentState.esStackDepth - argsToReverse; level < verCurrentState.esStackDepth; level++) - { - if (verCurrentState.esStack[level].val->gtFlags & GTF_ORDER_SIDEEFF) - { - assert(lastLevelWithSideEffects == UINT_MAX); - - impSpillStackEntry(level, - BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impPopArgsForUnmanagedCall - other side effect")); - } - else if (verCurrentState.esStack[level].val->gtFlags & GTF_SIDE_EFFECT) - { - if (lastLevelWithSideEffects != UINT_MAX) - { - /* We had a previous side effect - must spill it */ - impSpillStackEntry(lastLevelWithSideEffects, - BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impPopArgsForUnmanagedCall - side effect")); - - /* Record the level for the current side effect in case we will spill it */ - lastLevelWithSideEffects = level; - } - else - { - /* This is the first side effect encountered - record its level */ - - lastLevelWithSideEffects = level; - } - } - } - - /* The argument list is now "clean" - no out-of-order side effects - * Pop the argument list in reverse order */ - - impPopReverseCallArgs(sig, call, sig->numArgs - argsToReverse); - - if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall) - { - GenTree* thisPtr = call->gtArgs.GetArgByIndex(0)->GetNode(); - impBashVarAddrsToI(thisPtr); - assert(thisPtr->TypeGet() == TYP_I_IMPL || thisPtr->TypeGet() == TYP_BYREF); - } - - for (CallArg& arg : call->gtArgs.Args()) - { - GenTree* argNode = arg.GetEarlyNode(); - - // We should not be passing gc typed args to an unmanaged call. - if (varTypeIsGC(argNode->TypeGet())) - { - // Tolerate byrefs by retyping to native int. - // - // This is needed or we'll generate inconsistent GC info - // for this arg at the call site (gc info says byref, - // pinvoke sig says native int). - // - if (argNode->TypeGet() == TYP_BYREF) - { - argNode->ChangeType(TYP_I_IMPL); - } - else - { - assert(!"*** invalid IL: gc ref passed to unmanaged call"); - } - } - } -} - //------------------------------------------------------------------------ // impInitClass: Build a node to initialize the class before accessing the // field if necessary diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index a20acd2..e5e251f 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -1644,3 +1644,148 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN return call; #endif // FEATURE_MULTIREG_RET } + +GenTreeCall* Compiler::impImportIndirectCall(CORINFO_SIG_INFO* sig, const DebugInfo& di) +{ + var_types callRetTyp = JITtype2varType(sig->retType); + + /* The function pointer is on top of the stack - It may be a + * complex expression. As it is evaluated after the args, + * it may cause registered args to be spilled. Simply spill it. + */ + + // Ignore this trivial case. + if (impStackTop().val->gtOper != GT_LCL_VAR) + { + impSpillStackEntry(verCurrentState.esStackDepth - 1, + BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impImportIndirectCall")); + } + + /* Get the function pointer */ + + GenTree* fptr = impPopStack().val; + + // The function pointer is typically a sized to match the target pointer size + // However, stubgen IL optimization can change LDC.I8 to LDC.I4 + // See ILCodeStream::LowerOpcode + assert(genActualType(fptr->gtType) == TYP_I_IMPL || genActualType(fptr->gtType) == TYP_INT); + +#ifdef DEBUG + // This temporary must never be converted to a double in stress mode, + // because that can introduce a call to the cast helper after the + // arguments have already been evaluated. + + if (fptr->OperGet() == GT_LCL_VAR) + { + lvaTable[fptr->AsLclVarCommon()->GetLclNum()].lvKeepType = 1; + } +#endif + + /* Create the call node */ + + GenTreeCall* call = gtNewIndCallNode(fptr, callRetTyp, di); + + call->gtFlags |= GTF_EXCEPT | (fptr->gtFlags & GTF_GLOB_EFFECT); +#ifdef UNIX_X86_ABI + call->gtFlags &= ~GTF_CALL_POP_ARGS; +#endif + + return call; +} + +/*****************************************************************************/ + +void Compiler::impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig) +{ + assert(call->gtFlags & GTF_CALL_UNMANAGED); + + /* Since we push the arguments in reverse order (i.e. right -> left) + * spill any side effects from the stack + * + * OBS: If there is only one side effect we do not need to spill it + * thus we have to spill all side-effects except last one + */ + + unsigned lastLevelWithSideEffects = UINT_MAX; + + unsigned argsToReverse = sig->numArgs; + + // For "thiscall", the first argument goes in a register. Since its + // order does not need to be changed, we do not need to spill it + + if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall) + { + assert(argsToReverse); + argsToReverse--; + } + +#ifndef TARGET_X86 + // Don't reverse args on ARM or x64 - first four args always placed in regs in order + argsToReverse = 0; +#endif + + for (unsigned level = verCurrentState.esStackDepth - argsToReverse; level < verCurrentState.esStackDepth; level++) + { + if (verCurrentState.esStack[level].val->gtFlags & GTF_ORDER_SIDEEFF) + { + assert(lastLevelWithSideEffects == UINT_MAX); + + impSpillStackEntry(level, + BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impPopArgsForUnmanagedCall - other side effect")); + } + else if (verCurrentState.esStack[level].val->gtFlags & GTF_SIDE_EFFECT) + { + if (lastLevelWithSideEffects != UINT_MAX) + { + /* We had a previous side effect - must spill it */ + impSpillStackEntry(lastLevelWithSideEffects, + BAD_VAR_NUM DEBUGARG(false) DEBUGARG("impPopArgsForUnmanagedCall - side effect")); + + /* Record the level for the current side effect in case we will spill it */ + lastLevelWithSideEffects = level; + } + else + { + /* This is the first side effect encountered - record its level */ + + lastLevelWithSideEffects = level; + } + } + } + + /* The argument list is now "clean" - no out-of-order side effects + * Pop the argument list in reverse order */ + + impPopReverseCallArgs(sig, call, sig->numArgs - argsToReverse); + + if (call->unmgdCallConv == CorInfoCallConvExtension::Thiscall) + { + GenTree* thisPtr = call->gtArgs.GetArgByIndex(0)->GetNode(); + impBashVarAddrsToI(thisPtr); + assert(thisPtr->TypeGet() == TYP_I_IMPL || thisPtr->TypeGet() == TYP_BYREF); + } + + for (CallArg& arg : call->gtArgs.Args()) + { + GenTree* argNode = arg.GetEarlyNode(); + + // We should not be passing gc typed args to an unmanaged call. + if (varTypeIsGC(argNode->TypeGet())) + { + // Tolerate byrefs by retyping to native int. + // + // This is needed or we'll generate inconsistent GC info + // for this arg at the call site (gc info says byref, + // pinvoke sig says native int). + // + if (argNode->TypeGet() == TYP_BYREF) + { + argNode->ChangeType(TYP_I_IMPL); + } + else + { + assert(!"*** invalid IL: gc ref passed to unmanaged call"); + } + } + } +} -- 2.7.4