diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index a946110869fc..be3085aacf9f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -670,7 +670,6 @@ enum CorInfoHelpFunc CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP, - CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP, CORINFO_HELP_LLVM_EH_CATCH, CORINFO_HELP_LLVM_EH_POP_UNWOUND_VIRTUAL_FRAMES, CORINFO_HELP_LLVM_EH_PUSH_VIRTUAL_UNWIND_FRAME, diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 8a7798c166b7..5dedc2f18324 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -361,7 +361,6 @@ #endif JITHELPER(CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP, NULL, CORINFO_HELP_SIG_UNDEF) - JITHELPER(CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP, NULL, CORINFO_HELP_SIG_UNDEF) JITHELPER(CORINFO_HELP_LLVM_EH_CATCH, NULL, CORINFO_HELP_SIG_UNDEF) JITHELPER(CORINFO_HELP_LLVM_EH_POP_UNWOUND_VIRTUAL_FRAMES, NULL, CORINFO_HELP_SIG_UNDEF) JITHELPER(CORINFO_HELP_LLVM_EH_PUSH_VIRTUAL_UNWIND_FRAME, NULL, CORINFO_HELP_SIG_UNDEF) diff --git a/src/coreclr/jit/llvm.cpp b/src/coreclr/jit/llvm.cpp index 1c52f253ac77..8175b61915e8 100644 --- a/src/coreclr/jit/llvm.cpp +++ b/src/coreclr/jit/llvm.cpp @@ -23,7 +23,6 @@ enum class EEApiId GetMangledFilterFuncletName, GetSignatureForMethodSymbol, AddCodeReloc, - IsRuntimeImport, GetPrimitiveTypeForTrivialWasmStruct, GetTypeDescriptor, GetAlternativeFunctionName, @@ -174,31 +173,6 @@ GCInfo* Llvm::getGCInfo() return _gcInfo; } -bool Llvm::callRequiresShadowStackSave(const GenTreeCall* call) const -{ - // In general, if the call is itself not managed (does not have a shadow stack argument) **and** may call - // back into managed code, we need to save the shadow stack pointer, so that the RPI frame can pick it up. - // Another case where the save/restore is required is when calling into native runtime code that can trigger - // a GC (canonical example: allocators), to communicate shadow stack bounds to the roots scan. - // - if (call->IsHelperCall()) - { - return helperCallRequiresShadowStackSave(call->GetHelperNum()); - } - - // SPGCT calls are assumed to never RPI by contract. - return !callHasShadowStackArg(call) && !call->IsSuppressGCTransition(); -} - -bool Llvm::helperCallRequiresShadowStackSave(CorInfoHelpFunc helperFunc) const -{ - // Save/restore is needed if the helper doesn't have a shadow stack argument, unless we know it won't call - // back into managed code or has special semantics. TODO-LLVM-CQ: mark (make, if required) more helpers - // "HFIF_NO_RPI_OR_GC". - unsigned helperFlags = getHelperFuncInfo(helperFunc).Flags; - return (helperFlags & (HFIF_SS_ARG | HFIF_NO_RPI_OR_GC)) == HFIF_NONE; -} - bool Llvm::callHasShadowStackArg(const GenTreeCall* call) const { return callHasManagedCallingConvention(call); @@ -216,12 +190,6 @@ bool Llvm::callHasManagedCallingConvention(const GenTreeCall* call) const return helperCallHasManagedCallingConvention(call->GetHelperNum()); } - // Runtime imports are effectively unmanaged but are not tracked as such. - if ((call->gtCallType == CT_USER_FUNC) && IsRuntimeImport(call->gtCallMethHnd)) - { - return false; - } - return !call->IsUnmanaged(); } @@ -275,10 +243,10 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_UMOD) CORINFO_TYPE_UINT, { CORINFO_TYPE_UINT, CORINFO_TYPE_UINT }, HFIF_SS_ARG }, // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_LLSH) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT } }, - { FUNC(CORINFO_HELP_LRSH) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT } }, - { FUNC(CORINFO_HELP_LRSZ) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT } }, - { FUNC(CORINFO_HELP_LMUL) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_LONG } }, + { FUNC(CORINFO_HELP_LLSH) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_LRSH) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_LRSZ) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_INT }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_LMUL) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_LONG }, HFIF_SS_ARG }, // Implemented in "CoreLib\src\Internal\Runtime\CompilerHelpers\MathHelpers.cs". { FUNC(CORINFO_HELP_LMUL_OVF) CORINFO_TYPE_LONG, { CORINFO_TYPE_LONG, CORINFO_TYPE_LONG }, HFIF_SS_ARG }, @@ -289,36 +257,36 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_ULMOD) CORINFO_TYPE_ULONG, { CORINFO_TYPE_ULONG, CORINFO_TYPE_ULONG }, HFIF_SS_ARG }, // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_LNG2DBL) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_LONG } }, - { FUNC(CORINFO_HELP_ULNG2DBL) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_ULONG } }, - { FUNC(CORINFO_HELP_DBL2INT) CORINFO_TYPE_INT, { CORINFO_TYPE_DOUBLE } }, + { FUNC(CORINFO_HELP_LNG2DBL) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_LONG }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_ULNG2DBL) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_ULONG }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_DBL2INT) CORINFO_TYPE_INT, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "CoreLib\src\Internal\Runtime\CompilerHelpers\MathHelpers.cs". { FUNC(CORINFO_HELP_DBL2INT_OVF) CORINFO_TYPE_INT, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_DBL2LNG) CORINFO_TYPE_LONG, { CORINFO_TYPE_DOUBLE } }, + { FUNC(CORINFO_HELP_DBL2LNG) CORINFO_TYPE_LONG, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "CoreLib\src\Internal\Runtime\CompilerHelpers\MathHelpers.cs". { FUNC(CORINFO_HELP_DBL2LNG_OVF) CORINFO_TYPE_LONG, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_DBL2UINT) CORINFO_TYPE_UINT, { CORINFO_TYPE_DOUBLE } }, + { FUNC(CORINFO_HELP_DBL2UINT) CORINFO_TYPE_UINT, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "CoreLib\src\Internal\Runtime\CompilerHelpers\MathHelpers.cs". { FUNC(CORINFO_HELP_DBL2UINT_OVF) CORINFO_TYPE_UINT, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_DBL2ULNG) CORINFO_TYPE_ULONG, { CORINFO_TYPE_DOUBLE } }, + { FUNC(CORINFO_HELP_DBL2ULNG) CORINFO_TYPE_ULONG, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, // Implemented in "CoreLib\src\Internal\Runtime\CompilerHelpers\MathHelpers.cs". { FUNC(CORINFO_HELP_DBL2ULNG_OVF) CORINFO_TYPE_ULONG, { CORINFO_TYPE_DOUBLE }, HFIF_SS_ARG }, - // Implemented in "Runtime\MathHelpers.cpp". - { FUNC(CORINFO_HELP_FLTREM) CORINFO_TYPE_FLOAT, { CORINFO_TYPE_FLOAT, CORINFO_TYPE_FLOAT } }, - { FUNC(CORINFO_HELP_DBLREM) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_DOUBLE, CORINFO_TYPE_DOUBLE } }, - { FUNC(CORINFO_HELP_FLTROUND) CORINFO_TYPE_FLOAT, { CORINFO_TYPE_FLOAT } }, - { FUNC(CORINFO_HELP_DBLROUND) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_DOUBLE } }, + // Implemented as "fmodf"/"fmod". + { FUNC(CORINFO_HELP_FLTREM) CORINFO_TYPE_FLOAT, { CORINFO_TYPE_FLOAT, CORINFO_TYPE_FLOAT }, HFIF_NO_RPI_OR_GC }, + { FUNC(CORINFO_HELP_DBLREM) CORINFO_TYPE_DOUBLE, { CORINFO_TYPE_DOUBLE, CORINFO_TYPE_DOUBLE }, HFIF_NO_RPI_OR_GC }, + { FUNC(CORINFO_HELP_FLTROUND) }, + { FUNC(CORINFO_HELP_DBLROUND) }, // Runtime export, implemented in "Runtime.Base\src\System\Runtime\RuntimeExports.cs". { FUNC(CORINFO_HELP_NEWFAST) CORINFO_TYPE_CLASS, { CORINFO_TYPE_PTR }, HFIF_SS_ARG }, @@ -380,7 +348,7 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_RETHROW) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_SS_ARG }, // Implemented in "Runtime\MiscHelpers.cpp". - { FUNC(CORINFO_HELP_USER_BREAKPOINT) CORINFO_TYPE_VOID, { } }, + { FUNC(CORINFO_HELP_USER_BREAKPOINT) CORINFO_TYPE_VOID, { }, HFIF_SS_ARG}, // Implemented in "Runtime.Base\src\System\ThrowHelpers.cs". { FUNC(CORINFO_HELP_RNGCHKFAIL) CORINFO_TYPE_VOID, { }, HFIF_SS_ARG }, @@ -393,7 +361,7 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_VERIFICATION) }, // Implemented in "Runtime\EHHelpers.cpp". - { FUNC(CORINFO_HELP_FAIL_FAST) CORINFO_TYPE_VOID, { }, HFIF_NO_RPI_OR_GC }, + { FUNC(CORINFO_HELP_FAIL_FAST) CORINFO_TYPE_VOID, { }, HFIF_SS_ARG | HFIF_NO_RPI_OR_GC }, // NYI in NativeAOT. { FUNC(CORINFO_HELP_METHOD_ACCESS_EXCEPTION) }, @@ -415,10 +383,10 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_STOP_FOR_GC) }, // (Not) implemented in "Runtime\portable.cpp". - { FUNC(CORINFO_HELP_POLL_GC) CORINFO_TYPE_VOID, { } }, + { FUNC(CORINFO_HELP_POLL_GC) CORINFO_TYPE_VOID, { }, HFIF_SS_ARG}, // Debug-only helpers, implemented in "Runtime\wasm\GcStress.cpp". - { FUNC(CORINFO_HELP_STRESS_GC) CORINFO_TYPE_BYREF, { CORINFO_TYPE_BYREF, CORINFO_TYPE_PTR } }, + { FUNC(CORINFO_HELP_STRESS_GC) CORINFO_TYPE_BYREF, { CORINFO_TYPE_BYREF, CORINFO_TYPE_PTR }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_CHECK_OBJ) CORINFO_TYPE_CLASS, { CORINFO_TYPE_CLASS }, HFIF_NO_RPI_OR_GC }, // Write barriers, implemented in "Runtime\portable.cpp". @@ -493,7 +461,7 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_MEMCPY) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR, CORINFO_TYPE_PTR, CORINFO_TYPE_NATIVEUINT }, HFIF_SS_ARG }, // Implemented as plain "memset". - { FUNC(CORINFO_HELP_NATIVE_MEMSET) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR, CORINFO_TYPE_INT, CORINFO_TYPE_NATIVEUINT } }, + { FUNC(CORINFO_HELP_NATIVE_MEMSET) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR, CORINFO_TYPE_INT, CORINFO_TYPE_NATIVEUINT }, HFIF_NO_RPI_OR_GC }, // Not used in NativeAOT. { FUNC(CORINFO_HELP_RUNTIMEHANDLE_METHOD) }, @@ -528,7 +496,7 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_READYTORUN_THREADSTATIC_BASE) CORINFO_TYPE_PTR, { }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR) CORINFO_TYPE_PTR, { }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE) CORINFO_TYPE_PTR, { }, HFIF_SS_ARG }, - { FUNC(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR) CORINFO_TYPE_PTR, { CORINFO_TYPE_CLASS } }, + { FUNC(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR) CORINFO_TYPE_PTR, { CORINFO_TYPE_CLASS }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_READYTORUN_GENERIC_HANDLE) CORINFO_TYPE_PTR, { CORINFO_TYPE_PTR }, HFIF_SS_ARG | HFIF_THROW_OR_NO_RPI_OR_GC }, { FUNC(CORINFO_HELP_READYTORUN_DELEGATE_CTOR) CORINFO_TYPE_VOID, { CORINFO_TYPE_CLASS, CORINFO_TYPE_CLASS, CORINFO_TYPE_PTR }, HFIF_SS_ARG | HFIF_VAR_ARG }, { FUNC(CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE) CORINFO_TYPE_PTR, { CORINFO_TYPE_PTR }, HFIF_SS_ARG }, @@ -571,10 +539,10 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const // [R]PI helpers, implemented in "Runtime\thread.cpp". { FUNC(CORINFO_HELP_JIT_PINVOKE_BEGIN) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_SS_ARG | HFIF_NO_RPI_OR_GC }, { FUNC(CORINFO_HELP_JIT_PINVOKE_END) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_NO_RPI_OR_GC }, - { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR } }, - { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR } }, - { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_NO_RPI_OR_GC }, - { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR } }, + { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_SS_ARG }, + { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS) }, + { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR, CORINFO_TYPE_PTR }, HFIF_NO_RPI_OR_GC }, + { FUNC(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS) }, // Implemented in "CoreLib\src\System\Runtime\TypeLoaderExports.cs". { FUNC(CORINFO_HELP_GVMLOOKUP_FOR_SLOT) CORINFO_TYPE_NATIVEINT, { CORINFO_TYPE_CLASS, CORINFO_TYPE_RT_HANDLE }, HFIF_SS_ARG }, // Oddity: IntPtr used for a pointer. @@ -597,7 +565,6 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const { FUNC(CORINFO_HELP_DISPATCH_INDIRECT_CALL) }, { FUNC(CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP) CORINFO_TYPE_PTR, { }, HFIF_NO_RPI_OR_GC }, - { FUNC(CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR }, HFIF_NO_RPI_OR_GC }, { FUNC(CORINFO_HELP_LLVM_EH_CATCH) CORINFO_TYPE_CLASS, { CORINFO_TYPE_NATIVEUINT }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_LLVM_EH_POP_UNWOUND_VIRTUAL_FRAMES) CORINFO_TYPE_VOID, { }, HFIF_SS_ARG }, { FUNC(CORINFO_HELP_LLVM_EH_PUSH_VIRTUAL_UNWIND_FRAME) CORINFO_TYPE_VOID, { CORINFO_TYPE_PTR, CORINFO_TYPE_PTR, CORINFO_TYPE_NATIVEUINT }, HFIF_NO_RPI_OR_GC }, @@ -611,6 +578,25 @@ bool Llvm::helperCallMayPhysicallyThrow(CorInfoHelpFunc helperFunc) const // Make sure our array is up-to-date. static_assert_no_msg(ArrLen(s_infos) == CORINFO_HELP_COUNT); +#ifdef DEBUG + static bool s_infosVerified = false; + if (!s_infosVerified) + { + for (const HelperFuncInfo& info : s_infos) + { + if (info.IsInitialized()) + { + unsigned flags = info.Flags; + + // Only helpers that will never call managed code are allowed to not have the shadow stack argument. + assert(((flags & HFIF_SS_ARG) != 0) || ((flags & HFIF_NO_RPI_OR_GC) != 0)); + } + } + + s_infosVerified = true; + } +#endif // DEBUG + assert(helperFunc < CORINFO_HELP_COUNT); const HelperFuncInfo& info = s_infos[helperFunc]; @@ -812,11 +798,6 @@ void Llvm::AddCodeReloc(void* handle) CallEEApi(m_pEECorInfo, handle); } -bool Llvm::IsRuntimeImport(CORINFO_METHOD_HANDLE methodHandle) const -{ - return CallEEApi(m_pEECorInfo, methodHandle) != 0; -} - CorInfoType Llvm::GetPrimitiveTypeForTrivialWasmStruct(CORINFO_CLASS_HANDLE structHandle) { return CallEEApi(m_pEECorInfo, structHandle); diff --git a/src/coreclr/jit/llvm.h b/src/coreclr/jit/llvm.h index eefab6ca6d2b..19de5a2f057f 100644 --- a/src/coreclr/jit/llvm.h +++ b/src/coreclr/jit/llvm.h @@ -342,8 +342,6 @@ class Llvm GCInfo* getGCInfo(); - bool callRequiresShadowStackSave(const GenTreeCall* call) const; - bool helperCallRequiresShadowStackSave(CorInfoHelpFunc helperFunc) const; bool callHasShadowStackArg(const GenTreeCall* call) const; bool helperCallHasShadowStackArg(CorInfoHelpFunc helperFunc) const; bool callHasManagedCallingConvention(const GenTreeCall* call) const; @@ -369,7 +367,6 @@ class Llvm const char* GetMangledFilterFuncletName(unsigned index); bool GetSignatureForMethodSymbol(CORINFO_GENERIC_HANDLE symbolHandle, CORINFO_SIG_INFO* pSig); void AddCodeReloc(void* handle); - bool IsRuntimeImport(CORINFO_METHOD_HANDLE methodHandle) const; CorInfoType GetPrimitiveTypeForTrivialWasmStruct(CORINFO_CLASS_HANDLE structHandle); void GetTypeDescriptor(CORINFO_CLASS_HANDLE typeHandle, TypeDescriptor* pTypeDescriptor); const char* GetAlternativeFunctionName(); @@ -437,6 +434,7 @@ class Llvm void lowerVirtualStubCall(GenTreeCall* callNode); void insertNullCheckForCall(GenTreeCall* callNode); void lowerDelegateInvoke(GenTreeCall* callNode); + void lowerReversePInvokeExit(GenTreeCall* callNode); void lowerUnmanagedCall(GenTreeCall* callNode); void lowerCallToShadowStack(GenTreeCall* callNode); void lowerCallReturn(GenTreeCall* callNode); diff --git a/src/coreclr/jit/llvmcodegen.cpp b/src/coreclr/jit/llvmcodegen.cpp index 644fd739746a..d60ac8d5e5ab 100644 --- a/src/coreclr/jit/llvmcodegen.cpp +++ b/src/coreclr/jit/llvmcodegen.cpp @@ -41,10 +41,7 @@ void Llvm::initializeFunctions() { const char* mangledName = GetMangledMethodName(m_info->compMethodHnd); Function* rootLlvmFunction = getOrCreateKnownLlvmFunction(mangledName, [=]() { return createFunctionType(); }); - if (!rootLlvmFunction->isDeclaration()) - { - BADCODE("Duplicate definition"); - } + assert(rootLlvmFunction->isDeclaration()); // First function is always the root. m_functions = new (_compiler->getAllocator(CMK_Codegen)) FunctionInfo[_compiler->compFuncCount()](); @@ -794,10 +791,31 @@ void Llvm::fillPhis() void Llvm::generateAuxiliaryArtifacts() { // Currently, the only auxiliary artifact we may need is an alternative exported name for the compiled function. - const char* alternativeName = GetAlternativeFunctionName(); - if (alternativeName != nullptr) - { - llvm::GlobalAlias::create(alternativeName, getRootLlvmFunction()); + StringRef alternativeName = GetAlternativeFunctionName(); + if (!alternativeName.empty()) + { + Function* llvmFuncDef = getRootLlvmFunction(); + llvm::GlobalValue* existingDecl = m_context->Module.getNamedValue(alternativeName); + if (existingDecl != nullptr) + { + // We already have something under this name. Currenly, this can only be a function declaration, e. g. + // if something referenced a helper using this alternative name, which is usually the unmangled one, + // so it's pretty common. We need to replace the declaration with the defined function to avoid double + // definition problems. + assert(llvm::isa(existingDecl)); + if (!existingDecl->isDeclaration()) + { + // E. g. two different UCOs exported under the same name. This BADCODE is not very deterministic, + // since it depends on whether we happen to have the two offending functions in the same module + // or not. Ideally, we would devise a more robust scheme for dealing with this error. + BADCODE("Double definition"); + } + + existingDecl->replaceAllUsesWith(llvmFuncDef); + existingDecl->eraseFromParent(); + } + + llvm::GlobalAlias::create(alternativeName, llvmFuncDef); } } @@ -1752,14 +1770,6 @@ void Llvm::buildCall(GenTreeCall* call) argVec.Push(argValue); } - // We may come back into managed from the unmanaged call so store the shadow stack. Note that for regular unmanaged - // calls, we fold the shadow stack save into the transition helper call, and so don't need to do anything here. - if (!call->IsUnmanaged() && callRequiresShadowStackSave(call)) - { - // TODO-LLVM: set the correct shadow stack for shadow tail calls here. - emitHelperCall(CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP, getShadowStackForCallee()); - } - llvm::FunctionCallee llvmFuncCallee = consumeCallTarget(call); llvm::CallBase* callValue = emitCallOrInvoke(llvmFuncCallee, AsRef(argVec), mayPhysicallyThrow(call)); @@ -2059,11 +2069,6 @@ void Llvm::buildReturn(GenTree* node) return; } - if (node->OperIs(GT_RETURN) && _compiler->opts.IsReversePInvoke()) - { - emitHelperCall(CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP, getShadowStack()); - } - if (node->TypeIs(TYP_VOID)) { _builder.CreateRetVoid(); @@ -2541,12 +2546,6 @@ llvm::CallBase* Llvm::emitHelperCall(CorInfoHelpFunc helperFunc, ArrayRef argVec(_compiler->getAllocator(CMK_Codegen)); @@ -2841,14 +2839,21 @@ void Llvm::annotateHelperFunction(CorInfoHelpFunc helperFunc, Function* llvmFunc Function* Llvm::getOrCreateKnownLlvmFunction( StringRef name, std::function createFunctionType, std::function annotateFunction) { - Function* llvmFunc = m_context->Module.getFunction(name); - if (llvmFunc == nullptr) + llvm::Constant* llvmFuncOrAlias = m_context->Module.getNamedValue(name); + if (llvmFuncOrAlias != nullptr) { - assert(m_context->Module.getNamedValue(name) == nullptr); // No duplicate symbols! - llvmFunc = Function::Create(createFunctionType(), Function::ExternalLinkage, name, m_context->Module); - annotateFunction(llvmFunc); + // TODO-LLVM: we will miss annotating helpers that come through this path. + if (llvm::isa(llvmFuncOrAlias)) + { + // This must be the alias created by "generateAuxiliaryArtifacts". + llvmFuncOrAlias = llvm::cast(llvmFuncOrAlias)->getAliasee(); + } + + return llvm::cast(llvmFuncOrAlias); } + Function* llvmFunc = Function::Create(createFunctionType(), Function::ExternalLinkage, name, m_context->Module); + annotateFunction(llvmFunc); return llvmFunc; } diff --git a/src/coreclr/jit/llvmlower.cpp b/src/coreclr/jit/llvmlower.cpp index 23515c17708f..e3605c26d2c6 100644 --- a/src/coreclr/jit/llvmlower.cpp +++ b/src/coreclr/jit/llvmlower.cpp @@ -434,6 +434,10 @@ void Llvm::lowerCall(GenTreeCall* callNode) { lowerRethrow(callNode); } + else if (callNode->IsHelperCall(_compiler, CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT)) + { + lowerReversePInvokeExit(callNode); + } // "gtFoldExprConst" can attach a superflous argument to the overflow helper. Remove it. else if (callNode->IsHelperCall(_compiler, CORINFO_HELP_OVERFLOW) && !callNode->gtArgs.IsEmpty()) { @@ -794,6 +798,13 @@ void Llvm::lowerDelegateInvoke(GenTreeCall* callNode) lowerIndir(callTarget->AsIndir()); } +void Llvm::lowerReversePInvokeExit(GenTreeCall* callNode) +{ + // The RPI exit call has an additional argument - the shadow stack top on entry to this RPI method. + GenTree* previousShadowStackTop = insertShadowStackAddr(callNode, 0, _shadowStackLclNum); + callNode->gtArgs.PushFront(_compiler, NewCallArg::Primitive(previousShadowStackTop, CORINFO_TYPE_PTR)); +} + void Llvm::lowerUnmanagedCall(GenTreeCall* callNode) { assert(callNode->IsUnmanaged()); diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 865049170fb9..78b61131e4ca 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1818,7 +1818,6 @@ void HelperCallProperties::init() break; case CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP: - case CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP: case CORINFO_HELP_LLVM_EH_CATCH: case CORINFO_HELP_LLVM_EH_POP_UNWOUND_VIRTUAL_FRAMES: case CORINFO_HELP_LLVM_EH_PUSH_VIRTUAL_UNWIND_FRAME: diff --git a/src/coreclr/nativeaot/Bootstrap/main.cpp b/src/coreclr/nativeaot/Bootstrap/main.cpp index 7e2d1951878f..828feacb6dc9 100644 --- a/src/coreclr/nativeaot/Bootstrap/main.cpp +++ b/src/coreclr/nativeaot/Bootstrap/main.cpp @@ -112,18 +112,9 @@ extern "C" void* PalGetModuleHandleFromPointer(void* pointer); #define MANAGED_RUNTIME_EXPORT_NAME(_name) _name #define CDECL __cdecl #else -// The runtime assumes classlib exports have a managed calling convention. -// For WASM, however, they are exported with the native calling convention -// by default so we must explicitly use the managed entrypoint here. -#ifdef HOST_WASM -#define MANAGED_RUNTIME_EXPORT(_name) \ - extern "C" void _name##_Managed(); -#define MANAGED_RUNTIME_EXPORT_NAME(_name) _name##_Managed -#else // !HOST_WASM #define MANAGED_RUNTIME_EXPORT(_name) \ extern "C" void _name(); #define MANAGED_RUNTIME_EXPORT_NAME(_name) _name -#endif // !HOST_WASM #define CDECL #endif diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.Wasm.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.Wasm.cs index 1d3772018f0d..ee595bdd95b6 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.Wasm.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.Wasm.cs @@ -2,10 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // -// Internal calls specific to the WASM target. These can have unusual calling convention conversion -// requirements and so are defined/implemented here separately from the rest. Specifically, some of -// the underlying FCalls have the shadow stack argument, which we don't want to explicitly spell out -// in the managed signature (to keep it cross-target) and so create wrappers that pass it implicitly. +// Internal calls specific to the WASM target. // using System.Runtime.CompilerServices; @@ -21,84 +18,14 @@ internal static partial class InternalCalls [RuntimeImport(Redhawk.BaseName, "RhpThrowNativeException")] [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe void RhpThrowNativeException(); + internal static extern void RhpThrowNativeException(); [RuntimeImport(Redhawk.BaseName, "RhpReleaseNativeException")] [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe void RhpReleaseNativeException(); + internal static extern void RhpReleaseNativeException(); - internal static unsafe object RhpNewFast(MethodTable* pEEType) // BEWARE: not for finalizable objects! - { - [RuntimeImport(Redhawk.BaseName, "RhpNewFast")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType); - } - - internal static unsafe object RhpNewFinalizable(MethodTable* pEEType) - { - [RuntimeImport(Redhawk.BaseName, "RhpNewFinalizable")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType); - } - - internal static unsafe object RhpNewArray(MethodTable* pEEType, int length) - { - [RuntimeImport(Redhawk.BaseName, "RhpNewArray")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType, int length); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType, length); - } - -#if FEATURE_64BIT_ALIGNMENT - internal static unsafe object RhpNewFastAlign8(MethodTable* pEEType) // BEWARE: not for finalizable objects! - { - [RuntimeImport(Redhawk.BaseName, "RhpNewFastAlign8")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType); - - } - - internal static unsafe object RhpNewFinalizableAlign8(MethodTable* pEEType) - { - [RuntimeImport(Redhawk.BaseName, "RhpNewFinalizableAlign8")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType); - - } - - internal static unsafe object RhpNewArrayAlign8(MethodTable* pEEType, int length) - { - [RuntimeImport(Redhawk.BaseName, "RhpNewArrayAlign8")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType, int length); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType, length); - } - - internal static unsafe object RhpNewFastMisalign(MethodTable* pEEType) - { - [RuntimeImport(Redhawk.BaseName, "RhpNewFastMisalign")] - [MethodImpl(MethodImplOptions.InternalCall)] - static extern object Impl(void* pShadowStack, MethodTable* pEEType); - - void* pImpl = (delegate*)&Impl; - return ((delegate*)pImpl)(pEEType); - } -#endif // FEATURE_64BIT_ALIGNMENT + [RuntimeImport(Redhawk.BaseName, "RhpAssignRefWithShadowStack")] + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern void RhpAssignRef(ref object? address, object? obj); } } diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs index 540c995176ce..81244212ff3a 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -115,7 +115,6 @@ internal static int RhEndNoGCRegion() [MethodImpl(MethodImplOptions.InternalCall)] internal static extern IntPtr RhHandleSet(IntPtr handle, object value); -#if !TARGET_WASM // // internal calls for allocation // @@ -148,11 +147,12 @@ internal static int RhEndNoGCRegion() [MethodImpl(MethodImplOptions.InternalCall)] internal static extern unsafe object RhpNewFastMisalign(MethodTable * pEEType); #endif // FEATURE_64BIT_ALIGNMENT -#endif // !TARGET_WASM +#if !TARGET_WASM [RuntimeImport(Redhawk.BaseName, "RhpAssignRef")] [MethodImpl(MethodImplOptions.InternalCall)] internal static extern unsafe void RhpAssignRef(ref object? address, object? obj); +#endif [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(Redhawk.BaseName, "RhpGcSafeZeroMemory")] diff --git a/src/coreclr/nativeaot/Runtime/CMakeLists.txt b/src/coreclr/nativeaot/Runtime/CMakeLists.txt index 060e3d23a505..ced34e9f63b6 100644 --- a/src/coreclr/nativeaot/Runtime/CMakeLists.txt +++ b/src/coreclr/nativeaot/Runtime/CMakeLists.txt @@ -219,8 +219,9 @@ if (CLR_CMAKE_TARGET_ARCH_WASM) ${ARCH_SOURCES_DIR}/AllocFast.cpp ${ARCH_SOURCES_DIR}/ExceptionHandling/ExceptionHandling.cpp ${ARCH_SOURCES_DIR}/GcStress.cpp - ${ARCH_SOURCES_DIR}/StubDispatch.cpp ${ARCH_SOURCES_DIR}/PInvoke.cpp + ${ARCH_SOURCES_DIR}/StubDispatch.cpp + ${ARCH_SOURCES_DIR}/WriteBarriers.cpp ) endif (CLR_CMAKE_TARGET_ARCH_WASM) diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index 4938a1389473..473ddd58a9e9 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -251,36 +251,45 @@ typedef uint8_t CODE_LOCATION; #define FCDECL_RENAME(_rettype, ...) #define FCIMPL_RENAME(_rettype, ...) -#define FCALL_METHOD_ARGS(dummy, ...) (__VA_ARGS__) +#ifdef HOST_WASM +// +// WASM's managed calling convention uses an additional argument - the shadow stack. +// +#define FCALL_METHOD_ARGS_NO_METHOD_NAME(...) (void* pShadowStack __VA_OPT__(,) __VA_ARGS__) +#else +#define FCALL_METHOD_ARGS_NO_METHOD_NAME(...) (__VA_ARGS__) +#endif + +#define FCALL_METHOD_ARGS(dummy, ...) FCALL_METHOD_ARGS_NO_METHOD_NAME(__VA_ARGS__) #define FCALL_METHOD_ARGS_(tuple) FCALL_METHOD_ARGS tuple #define FCIMPL1_F(_rettype, _method, a) \ - EXTERN_C _rettype F_CALL_CONV _method (a) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a) \ { #define FCIMPL1_D(_rettype, _method, a) \ - EXTERN_C _rettype F_CALL_CONV _method (a) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a) \ { #define FCIMPL1_L FCIMPL1_D #define FCIMPL2_FF(_rettype, _method, a, b) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b) \ { #define FCIMPL2_DD(_rettype, _method, a, b) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b) \ { #define FCIMPL2_FI(_rettype, _method, a, b) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b) \ { #define FCIMPL2_DI(_rettype, _method, a, b) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b) \ { #define FCIMPL3_FFF(_rettype, _method, a, b, c) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b, c) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b, c) \ { #define FCIMPL3_DDD(_rettype, _method, a, b, c) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b, c) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b, c) \ { #define FCIMPL3_ILL(_rettype, _method, a, b, c) \ - EXTERN_C _rettype F_CALL_CONV _method (a, b, c) \ + EXTERN_C _rettype F_CALL_CONV _method FCALL_METHOD_ARGS_NO_METHOD_NAME(a, b, c) \ { #endif diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index a80de75942bd..b8e564da3a49 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -351,6 +351,7 @@ FCIMPLEND #if defined(USE_PORTABLE_HELPERS) +#ifndef HOST_WASM #if !defined (HOST_ARM64) FCIMPL2(void, RhpAssignRef, Object ** dst, Object * ref) { @@ -368,6 +369,7 @@ FCIMPL2(void, RhpCheckedAssignRef, Object ** dst, Object * ref) } FCIMPLEND #endif +#endif // !HOST_WASM FCIMPL3(Object *, RhpCheckedLockCmpXchg, Object ** location, Object * value, Object * comparand) { diff --git a/src/coreclr/nativeaot/Runtime/thread.cpp b/src/coreclr/nativeaot/Runtime/thread.cpp index 6e6b6d5d5f0b..f2b68462c608 100644 --- a/src/coreclr/nativeaot/Runtime/thread.cpp +++ b/src/coreclr/nativeaot/Runtime/thread.cpp @@ -1329,6 +1329,7 @@ EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInv // PInvoke // +#ifndef HOST_WASM FCIMPL1(void, RhpReversePInvoke, ReversePInvokeFrame * pFrame) { Thread * pCurThread = ThreadStore::RawGetCurrentThread(); @@ -1348,14 +1349,12 @@ FCIMPLEND #ifdef USE_PORTABLE_HELPERS -#ifndef HOST_WASM FCIMPL1(void, RhpPInvoke, PInvokeTransitionFrame* pFrame) { Thread * pCurThread = ThreadStore::RawGetCurrentThread(); pCurThread->InlinePInvoke(pFrame); } FCIMPLEND -#endif // !HOST_WASM FCIMPL1(void, RhpPInvokeReturn, PInvokeTransitionFrame* pFrame) { @@ -1365,5 +1364,6 @@ FCIMPL1(void, RhpPInvokeReturn, PInvokeTransitionFrame* pFrame) FCIMPLEND #endif //USE_PORTABLE_HELPERS +#endif // !HOST_WASM #endif // !DACCESS_COMPILE diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index 3d724f50829e..fa7f8ebe1b9e 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -489,10 +489,11 @@ EXTERN_C intptr_t* RhpGetThunkData() } #endif //FEATURE_EMULATED_TLS -EXTERN_C intptr_t RhGetCurrentThunkContext() +FCIMPL0(intptr_t, RhGetCurrentThunkContext) { return tls_thunkData; } +FCIMPLEND // Register the thread with OS to be notified when thread is about to be destroyed // It fails fast if a different thread was already registered. diff --git a/src/coreclr/nativeaot/Runtime/wasm/AllocFast.cpp b/src/coreclr/nativeaot/Runtime/wasm/AllocFast.cpp index 51f4a3527bc8..050913f633af 100644 --- a/src/coreclr/nativeaot/Runtime/wasm/AllocFast.cpp +++ b/src/coreclr/nativeaot/Runtime/wasm/AllocFast.cpp @@ -28,22 +28,21 @@ // WASM-specific allocators: we define them to use a shadow stack argument to avoid saving it on the fast path. // extern "C" void* RhpGcAlloc(MethodTable* pEEType, uint32_t uFlags, uintptr_t numElements, void* pTransitionFrame); -extern "C" void* RhpGetShadowStackTop(); -extern "C" void RhpSetShadowStackTop(void* pShadowStack); +void SetShadowStackTop(void* pShadowStack); // Note that the emulated exception handling model requires us to call all managed methods that may/will throw // only in the tail-like position so that control can immediately return to the caller in case of an exception. -extern "C" void RhExceptionHandling_FailedAllocation_Managed(void* pShadowStack, MethodTable* pEEType, bool isOverflow); +extern "C" void RhExceptionHandling_FailedAllocation(void* pShadowStack, MethodTable* pEEType, bool isOverflow); static Object* AllocateObject(void* pShadowStack, MethodTable* pEEType, uint32_t uFlags, uintptr_t numElements) { // Save the current shadow stack before calling into GC; we may need to scan it for live references. - RhpSetShadowStackTop(pShadowStack); + SetShadowStackTop(pShadowStack); Object* pObject = (Object*)RhpGcAlloc(pEEType, uFlags, numElements, nullptr); if (pObject == nullptr) { - RhExceptionHandling_FailedAllocation_Managed(pShadowStack, pEEType, /* isOverflow */ false); + RhExceptionHandling_FailedAllocation(pShadowStack, pEEType, /* isOverflow */ false); } return pObject; @@ -51,7 +50,7 @@ static Object* AllocateObject(void* pShadowStack, MethodTable* pEEType, uint32_t static void ThrowOverflowException(void* pShadowStack, MethodTable* pEEType) { - RhExceptionHandling_FailedAllocation_Managed(pShadowStack, pEEType, /* isOverflow */ true); + RhExceptionHandling_FailedAllocation(pShadowStack, pEEType, /* isOverflow */ true); } struct gc_alloc_context @@ -67,7 +66,7 @@ struct gc_alloc_context // // Allocations // -FCIMPL2(Object*, RhpNewFast, void* pShadowStack, MethodTable* pEEType) +FCIMPL1(Object*, RhpNewFast, MethodTable* pEEType) { ASSERT(!pEEType->HasFinalizer()); @@ -89,14 +88,14 @@ FCIMPL2(Object*, RhpNewFast, void* pShadowStack, MethodTable* pEEType) } FCIMPLEND -FCIMPL2(Object*, RhpNewFinalizable, void* pShadowStack, MethodTable* pEEType) +FCIMPL1(Object*, RhpNewFinalizable, MethodTable* pEEType) { ASSERT(pEEType->HasFinalizer()); return AllocateObject(pShadowStack, pEEType, GC_ALLOC_FINALIZE, 0); } FCIMPLEND -FCIMPL3(Array*, RhpNewArray, void* pShadowStack, MethodTable* pArrayEEType, int numElements) +FCIMPL2(Array*, RhpNewArray, MethodTable* pArrayEEType, int numElements) { Thread* pCurThread = ThreadStore::GetCurrentThread(); gc_alloc_context* acontext = pCurThread->GetAllocContext(); @@ -138,7 +137,6 @@ FCIMPLEND FCIMPL2(String*, RhNewString, MethodTable* pArrayEEType, int numElements) { // TODO: Implement. We call RhpNewArray for now since there's a bunch of TODOs in the places that matter anyway. - void* pShadowStack = RhpGetShadowStackTop(); return (String*)RhpNewArray(pShadowStack, pArrayEEType, numElements); } FCIMPLEND @@ -146,13 +144,13 @@ FCIMPLEND #if defined(FEATURE_64BIT_ALIGNMENT) GPTR_DECL(MethodTable, g_pFreeObjectEEType); -FCIMPL2(Object*, RhpNewFinalizableAlign8, void* pShadowStack, MethodTable* pEEType) +FCIMPL1(Object*, RhpNewFinalizableAlign8, MethodTable* pEEType) { return AllocateObject(pShadowStack, pEEType, GC_ALLOC_FINALIZE | GC_ALLOC_ALIGN8, 0); } FCIMPLEND -FCIMPL2(Object*, RhpNewFastAlign8, void* pShadowStack, MethodTable* pEEType) +FCIMPL1(Object*, RhpNewFastAlign8, MethodTable* pEEType) { ASSERT(!pEEType->HasFinalizer()); @@ -189,7 +187,7 @@ FCIMPL2(Object*, RhpNewFastAlign8, void* pShadowStack, MethodTable* pEEType) } FCIMPLEND -FCIMPL2(Object*, RhpNewFastMisalign, void* pShadowStack, MethodTable* pEEType) +FCIMPL1(Object*, RhpNewFastMisalign, MethodTable* pEEType) { Thread* pCurThread = ThreadStore::GetCurrentThread(); gc_alloc_context* acontext = pCurThread->GetAllocContext(); @@ -223,7 +221,7 @@ FCIMPL2(Object*, RhpNewFastMisalign, void* pShadowStack, MethodTable* pEEType) } FCIMPLEND -FCIMPL3(Array*, RhpNewArrayAlign8, void* pShadowStack, MethodTable* pArrayEEType, int numElements) +FCIMPL2(Array*, RhpNewArrayAlign8, MethodTable* pArrayEEType, int numElements) { Thread* pCurThread = ThreadStore::GetCurrentThread(); gc_alloc_context* acontext = pCurThread->GetAllocContext(); diff --git a/src/coreclr/nativeaot/Runtime/wasm/ExceptionHandling/ExceptionHandling.cpp b/src/coreclr/nativeaot/Runtime/wasm/ExceptionHandling/ExceptionHandling.cpp index 183cff39278b..52b3259a7831 100644 --- a/src/coreclr/nativeaot/Runtime/wasm/ExceptionHandling/ExceptionHandling.cpp +++ b/src/coreclr/nativeaot/Runtime/wasm/ExceptionHandling/ExceptionHandling.cpp @@ -4,6 +4,8 @@ #include "CommonTypes.h" #include "CommonMacros.h" +#include "../wasm.h" + struct VirtualUnwindFrame { VirtualUnwindFrame* Prev; @@ -17,7 +19,7 @@ struct VirtualUnwindFrame // thread_local VirtualUnwindFrame* t_pLastVirtualUnwindFrame = nullptr; -FCIMPL3(void, RhpPushVirtualUnwindFrame, VirtualUnwindFrame* pFrame, void* pUnwindTable, size_t unwindIndex) +FCIMPL_NO_SS(void, RhpPushVirtualUnwindFrame, VirtualUnwindFrame* pFrame, void* pUnwindTable, size_t unwindIndex) { ASSERT(t_pLastVirtualUnwindFrame < pFrame); pFrame->Prev = t_pLastVirtualUnwindFrame; @@ -28,7 +30,7 @@ FCIMPL3(void, RhpPushVirtualUnwindFrame, VirtualUnwindFrame* pFrame, void* pUnwi } FCIMPLEND -FCIMPL0(void, RhpPopVirtualUnwindFrame) +FCIMPL_NO_SS(void, RhpPopVirtualUnwindFrame) { ASSERT(t_pLastVirtualUnwindFrame != nullptr); t_pLastVirtualUnwindFrame = t_pLastVirtualUnwindFrame->Prev; @@ -40,6 +42,7 @@ FCIMPL0(void*, RhpGetRawLastVirtualUnwindFrameRef) return &t_pLastVirtualUnwindFrame; } FCIMPLEND + // We do not use these helpers. TODO-LLVM: exclude them from the WASM build. FCIMPL4(void*, RhpCallCatchFunclet, void*, void*, void*, void*) { abort(); } FCIMPLEND FCIMPL3(bool, RhpCallFilterFunclet, void*, void*, void*) { abort(); } FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/wasm/GcStress.cpp b/src/coreclr/nativeaot/Runtime/wasm/GcStress.cpp index 68fdf47267d3..bc94b13dc97f 100644 --- a/src/coreclr/nativeaot/Runtime/wasm/GcStress.cpp +++ b/src/coreclr/nativeaot/Runtime/wasm/GcStress.cpp @@ -14,6 +14,10 @@ #include "threadstore.inl" #include "thread.inl" +#include "wasm.h" + +void SetShadowStackTop(void* pShadowStack); + FCIMPL2(void*, RhpGcStressOnce, void* obj, uint8_t* pFlag) { if (*pFlag) @@ -40,6 +44,7 @@ FCIMPL2(void*, RhpGcStressOnce, void* obj, uint8_t* pFlag) pThread->PushGCFrameRegistration(&gc); } + SetShadowStackTop(pShadowStack); GCHeapUtilities::GetGCHeap()->GarbageCollect(); if (obj != nullptr) @@ -55,7 +60,7 @@ FCIMPL2(void*, RhpGcStressOnce, void* obj, uint8_t* pFlag) } FCIMPLEND -FCIMPL1(Object*, RhpCheckObj, Object* obj) +FCIMPL_NO_SS(Object*, RhpCheckObj, Object* obj) { if (obj != nullptr) { diff --git a/src/coreclr/nativeaot/Runtime/wasm/PInvoke.cpp b/src/coreclr/nativeaot/Runtime/wasm/PInvoke.cpp index 6a4ca498a1dc..4ff4d1e90ba3 100644 --- a/src/coreclr/nativeaot/Runtime/wasm/PInvoke.cpp +++ b/src/coreclr/nativeaot/Runtime/wasm/PInvoke.cpp @@ -14,6 +14,8 @@ #include "thread.inl" #include "threadstore.inl" +#include "wasm.h" + thread_local void* t_pShadowStackBottom = nullptr; thread_local void* t_pShadowStackTop = nullptr; @@ -27,7 +29,12 @@ void* GetShadowStackTop() return t_pShadowStackTop; } -FCIMPL0(void*, RhpGetOrInitShadowStackTop) +void SetShadowStackTop(void* pShadowStack) +{ + t_pShadowStackTop = pShadowStack; +} + +FCIMPL_NO_SS(void*, RhpGetOrInitShadowStackTop) { void* pShadowStack = t_pShadowStackTop; if (pShadowStack == nullptr) @@ -46,22 +53,39 @@ FCIMPL0(void*, RhpGetOrInitShadowStackTop) } FCIMPLEND -FCIMPL0(void*, RhpGetShadowStackTop) +EXTERN_C NOINLINE void FASTCALL RhpReversePInvokeAttachOrTrapThread2(ReversePInvokeFrame* pFrame); + +FCIMPL1(void, RhpReversePInvoke, ReversePInvokeFrame* pFrame) { - return t_pShadowStackTop; + Thread* pCurThread = ThreadStore::RawGetCurrentThread(); + pFrame->m_savedThread = pCurThread; + if (pCurThread->InlineTryFastReversePInvoke(pFrame)) + return; + + // The slow path may invoke runtime initialization, which runs managed code. + SetShadowStackTop(pShadowStack); + RhpReversePInvokeAttachOrTrapThread2(pFrame); } FCIMPLEND -FCIMPL1(void, RhpSetShadowStackTop, void* pShadowStack) +FCIMPL_NO_SS(void, RhpReversePInvokeReturn, void* pPreviousShadowStackTop, ReversePInvokeFrame* pFrame) { - t_pShadowStackTop = pShadowStack; + pFrame->m_savedThread->InlineReversePInvokeReturn(pFrame); + SetShadowStackTop(pPreviousShadowStackTop); } FCIMPLEND -FCIMPL2(void, RhpPInvoke, void* pShadowStack, PInvokeTransitionFrame* pFrame) +FCIMPL1(void, RhpPInvoke, PInvokeTransitionFrame* pFrame) { - RhpSetShadowStackTop(pShadowStack); + SetShadowStackTop(pShadowStack); Thread* pCurThread = ThreadStore::RawGetCurrentThread(); pCurThread->InlinePInvoke(pFrame); } FCIMPLEND + +FCIMPL_NO_SS(void, RhpPInvokeReturn, PInvokeTransitionFrame* pFrame) +{ + //reenter cooperative mode + pFrame->m_pThread->InlinePInvokeReturn(pFrame); +} +FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/wasm/StubDispatch.cpp b/src/coreclr/nativeaot/Runtime/wasm/StubDispatch.cpp index da33ddfca7d9..af450ec26cce 100644 --- a/src/coreclr/nativeaot/Runtime/wasm/StubDispatch.cpp +++ b/src/coreclr/nativeaot/Runtime/wasm/StubDispatch.cpp @@ -22,9 +22,9 @@ // // Cache miss case, call the runtime to resolve the target and update the cache. -extern "C" PCODE RhpCidResolveWasm_Managed(void* pShadowStack, Object* pObject, void* pCell); +extern "C" PCODE RhpCidResolveWasm(void* pShadowStack, Object* pObject, void* pCell); -FCIMPL3(PCODE, RhpResolveInterfaceDispatch, void* pShadowStack, Object* pObject, InterfaceDispatchCell* pCell) +FCIMPL2(PCODE, RhpResolveInterfaceDispatch, Object* pObject, InterfaceDispatchCell* pCell) { ASSERT(pObject != nullptr); InterfaceDispatchCache* pCache = (InterfaceDispatchCache*)pCell->GetCache(); @@ -41,7 +41,7 @@ FCIMPL3(PCODE, RhpResolveInterfaceDispatch, void* pShadowStack, Object* pObject, } } - return RhpCidResolveWasm_Managed(pShadowStack, pObject, pCell); + return RhpCidResolveWasm(pShadowStack, pObject, pCell); } FCIMPLEND @@ -56,7 +56,7 @@ extern "C" void* RhpInterfaceDispatch32(void*, Object*, InterfaceDispatchCell*) extern "C" void* RhpInterfaceDispatch64(void*, Object*, InterfaceDispatchCell*) __attribute__((alias ("RhpResolveInterfaceDispatch"))); // Stub dispatch routine for dispatch to a vtable slot. -FCIMPL3(void*, RhpVTableOffsetDispatch, void* pShadowStack, Object* pObject, InterfaceDispatchCell* pCell) +FCIMPL2(void*, RhpVTableOffsetDispatch, Object* pObject, InterfaceDispatchCell* pCell) { uintptr_t pVTable = reinterpret_cast(pObject->GetMethodTable()); uintptr_t offset = pCell->m_pCache; diff --git a/src/coreclr/nativeaot/Runtime/wasm/WriteBarriers.cpp b/src/coreclr/nativeaot/Runtime/wasm/WriteBarriers.cpp new file mode 100644 index 000000000000..7da5850e28e8 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/wasm/WriteBarriers.cpp @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +class Object; + +#include "daccess.h" +#include "CommonTypes.h" +#include "CommonMacros.h" +#include "CommonMacros.inl" +#include "GCMemoryHelpers.inl" + +#include "wasm.h" + +FCIMPL_NO_SS(void, RhpAssignRef, Object** dst, Object* ref) +{ + // Note: the caller (codegen) is responsible for null checking. + *dst = ref; + InlineWriteBarrier(dst, ref); +} +FCIMPLEND + +FCIMPL_NO_SS(void, RhpCheckedAssignRef, Object** dst, Object* ref) +{ + // Note: the caller (codegen) is responsible for null checking. + *dst = ref; + InlineCheckedWriteBarrier(dst, ref); +} +FCIMPLEND + +FCIMPL2(void, RhpAssignRefWithShadowStack, Object** dst, Object* ref) +{ + // This "overload" is only used by the class library. + ASSERT(dst != nullptr); + return RhpAssignRef(dst, ref); +} +FCIMPLEND diff --git a/src/coreclr/nativeaot/Runtime/wasm/wasm.h b/src/coreclr/nativeaot/Runtime/wasm/wasm.h new file mode 100644 index 000000000000..bd86484b1b25 --- /dev/null +++ b/src/coreclr/nativeaot/Runtime/wasm/wasm.h @@ -0,0 +1,8 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Define for a small subset of performance-critical FCalls that do not +// have a shadow stack argument. Has no real functional importance and +// serves as simply a marker for such FCalls. +// +#define FCIMPL_NO_SS(_rettype, _name, ...) extern "C" _rettype _name(__VA_ARGS__) { diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj index 3db91025155c..821f1bf2fe55 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj @@ -233,6 +233,7 @@ + diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.Wasm.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.Wasm.cs new file mode 100644 index 000000000000..f5fd9b8f3915 --- /dev/null +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.Wasm.cs @@ -0,0 +1,215 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Runtime imports specific to WASM. Currently these are mostly PInvoke-based +// redefinitions of the math-related methods, as the runtime import mechanism +// assumes a managed calling convention (with a shadow stack), while those +// functions are native. + +using System.Runtime.InteropServices; + +namespace System.Runtime +{ + internal static partial class RuntimeImports + { + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double acos(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float acosf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double acosh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float acoshf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double asin(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float asinf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double asinh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float asinhf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double atan(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float atanf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double atan2(double y, double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float atan2f(float y, float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double atanh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float atanhf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double cbrt(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float cbrtf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double ceil(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float ceilf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double cos(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float cosf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double cosh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float coshf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double exp(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float expf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double floor(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float floorf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double log(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float logf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double log2(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float log2f(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double log10(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float log10f(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double pow(double x, double y); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float powf(float x, float y); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double sin(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float sinf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double sinh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float sinhf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double sqrt(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float sqrtf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double tan(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float tanf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double tanh(double x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float tanhf(float x); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double fmod(double x, double y); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float fmodf(float x, float y); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial double fma(double x, double y, double z); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static partial float fmaf(float x, float y, float z); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static unsafe partial double modf(double x, double* intptr); + + [LibraryImport(RuntimeLibrary)] + [SuppressGCTransition] + internal static unsafe partial float modff(float x, float* intptr); + } +} diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index 17a0bca07e13..d0d5db57a2a3 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -661,6 +661,7 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe [RuntimeImport(RuntimeLibrary, "RhpCheckedXchg")] internal static extern object InterlockedExchange([NotNullIfNotNull(nameof(value))] ref object? location1, object? value); +#if !TARGET_WASM [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "acos")] internal static extern double acos(double x); @@ -860,6 +861,7 @@ internal static IntPtr RhGetModuleSection(TypeManagerHandle module, ReadyToRunSe [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "modff")] internal static extern unsafe float modff(float x, float* intptr); +#endif [LibraryImport(RuntimeImports.RuntimeLibrary)] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index a4a6cb925814..80632204e915 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -312,7 +312,6 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP, - CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP, CORINFO_HELP_LLVM_EH_CATCH, CORINFO_HELP_LLVM_EH_POP_UNWOUND_VIRTUAL_FRAMES, CORINFO_HELP_LLVM_EH_PUSH_VIRTUAL_UNWIND_FRAME, diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmNodeFactory.cs deleted file mode 100644 index a9341dbabd4a..000000000000 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_Wasm/WasmNodeFactory.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace ILCompiler.DependencyAnalysis -{ - public partial class NodeFactory - { - // WASM uses the shadow stack calling convention, which makes native entry points to runtime - // exports incur a penalty of saving the shadow stack and setting up arguments. This method may - // be overriden by a derived class to redirect from a native entry point to the managed one. - public virtual IMethodNode RuntimeExportManagedEntrypoint(string name) => null; - } -} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 8ccb841bb25c..aa9855ed284f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -441,7 +441,6 @@ - diff --git a/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMCodegenCompilation.CodeGen.cs b/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMCodegenCompilation.CodeGen.cs index e998138b4e5d..2817a53f9d60 100644 --- a/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMCodegenCompilation.CodeGen.cs +++ b/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMCodegenCompilation.CodeGen.cs @@ -17,19 +17,6 @@ namespace ILCompiler { public sealed partial class LLVMCodegenCompilation { - // We define an alternative entrypoint for the runtime exports, one that has the (original) managed calling convention. - // This allows low-level runtime helpers to avoid the overhead of shadow stack save/restore when calling the export. - // Thus, the "mangling" we use here is effectively an ABI contract between the compiler and runtime. - public override string GetRuntimeExportManagedEntrypointName(MethodDesc method) - { - if (method is EcmaMethod ecmaMethod && ecmaMethod.GetRuntimeExportName() is string name) - { - return name + "_Managed"; - } - - return null; - } - public override ISymbolNode GetExternalMethodAccessor(MethodDesc method, ReadOnlySpan sig) { Debug.Assert(!sig.IsEmpty); diff --git a/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMObjectWriter.cs b/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMObjectWriter.cs index 02523da9d913..01b6d07f308d 100644 --- a/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMObjectWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.LLVM/CodeGen/LLVMObjectWriter.cs @@ -82,12 +82,6 @@ public static void EmitObject(string objectFilePath, IEnumerable { foreach (DependencyNode depNode in nodes) { - if (depNode is LLVMMethodCodeNode runtimeExportNode && runtimeExportNode.Method.HasCustomAttribute("System.Runtime", "RuntimeExportAttribute")) - { - objectWriter.EmitRuntimeExportThunk(runtimeExportNode); - continue; - } - ObjectNode node = depNode as ObjectNode; if (node == null) continue; @@ -407,54 +401,6 @@ private void EmitKeepAliveList() } } - private void EmitRuntimeExportThunk(LLVMMethodCodeNode methodNode) - { - MethodDesc method = methodNode.Method; - Debug.Assert(method.HasCustomAttribute("System.Runtime", "RuntimeExportAttribute") && methodNode.CompilationCompleted); - - LLVMValueRef managedFunc = GetOrCreateLLVMFunction(methodNode); - LLVMTypeRef managedFuncType = managedFunc.GetValueType(); - - // Native signature: managed minus the shadow stack. - LLVMTypeRef[] managedFuncParamTypes = managedFuncType.ParamTypes; - LLVMTypeRef[] nativeFuncParamTypes = new LLVMTypeRef[managedFuncParamTypes.Length - 1]; - Array.Copy(managedFuncParamTypes, 1, nativeFuncParamTypes, 0, nativeFuncParamTypes.Length); - - LLVMTypeRef nativeFuncType = LLVMTypeRef.CreateFunction(managedFuncType.ReturnType, nativeFuncParamTypes, false); - using Utf8Name nativeFuncName = GetUtf8Name(_compilation.NodeFactory.GetSymbolAlternateName(methodNode)); - LLVMValueRef nativeFunc = GetOrCreateLLVMFunction(nativeFuncName, nativeFuncType); - - using LLVMBuilderRef builder = _module.Context.CreateBuilder(); - LLVMBasicBlockRef block = nativeFunc.AppendBasicBlock("ManagedCallBlock"); - builder.PositionAtEnd(block); - - // Get the shadow stack. Since we are wrapping a runtime export, the caller is (by definition) managed, so we must have set up the shadow - // stack already and can bypass the init check. - LLVMTypeRef getShadowStackFuncSig = LLVMTypeRef.CreateFunction(_ptrType, Array.Empty()); - LLVMValueRef getShadowStackFunc = GetOrCreateLLVMFunction("RhpGetShadowStackTop"u8, getShadowStackFuncSig); - LLVMValueRef shadowStack = builder.BuildCall2(getShadowStackFuncSig, getShadowStackFunc, Array.Empty()); - - int argsCount = managedFuncParamTypes.Length; - Span args = argsCount > 100 ? new LLVMValueRef[argsCount] : stackalloc LLVMValueRef[argsCount]; - args[0] = shadowStack; - - for (int i = 0; i < nativeFuncParamTypes.Length; i++) - { - args[i + 1] = nativeFunc.GetParam((uint)i); - } - - LLVMValueRef returnValue = CreateCall(builder, managedFunc, args, ""); - - if (method.Signature.ReturnType.IsVoid) - { - builder.BuildRetVoid(); - } - else - { - builder.BuildRet(returnValue); - } - } - private void GetCodeForReadyToRunGenericHelper(ReadyToRunGenericHelperNode node, NodeFactory factory) { if (node.Id == ReadyToRunHelperId.DelegateCtor) @@ -555,9 +501,10 @@ private void GetCodeForReadyToRunHelper(ReadyToRunHelperNode node, NodeFactory f return; } + LLVMTypeRef helperFuncType = node.Id == ReadyToRunHelperId.ResolveVirtualFunction + ? LLVMTypeRef.CreateFunction(_ptrType, [_ptrType, /* this */ _ptrType], IsVarArg: false) + : LLVMTypeRef.CreateFunction(_ptrType, [_ptrType], IsVarArg: false); using Utf8Name helperFuncName = GetMangledUtf8Name(node); - LLVMTypeRef helperFuncType = LLVMTypeRef.CreateFunction( - _ptrType, stackalloc[] { _ptrType /* shadow stack or "this" */ }, IsVarArg: false); LLVMValueRef helperFunc = GetOrCreateLLVMFunction(helperFuncName, helperFuncType); using LLVMBuilderRef builder = _module.Context.CreateBuilder(); @@ -612,23 +559,24 @@ private void GetCodeForReadyToRunHelper(ReadyToRunHelperNode node, NodeFactory f case ReadyToRunHelperId.ResolveVirtualFunction: { MethodDesc targetMethod = (MethodDesc)node.Target; + LLVMValueRef objThis = helperFunc.GetParam(1); if (targetMethod.OwningType.IsInterface) { // TODO-LLVM: would be nice to use pointers instead of IntPtr in "RhpResolveInterfaceMethod". LLVMTypeRef resolveFuncType = LLVMTypeRef.CreateFunction( - _intPtrType, stackalloc[] { _ptrType, _intPtrType }, IsVarArg: false); + _intPtrType, [_ptrType, _ptrType, _intPtrType], IsVarArg: false); LLVMValueRef resolveFunc = GetOrCreateLLVMFunction("RhpResolveInterfaceMethod"u8, resolveFuncType); LLVMValueRef cell = GetSymbolReferenceValue(factory.InterfaceDispatchCell(targetMethod)); LLVMValueRef cellArg = builder.BuildPtrToInt(cell, _intPtrType, "cellArg"); - result = builder.BuildCall2(resolveFuncType, resolveFunc, stackalloc[] { helperFunc.GetParam(0), cellArg }, ""); + result = CreateCall(builder, resolveFunc, [helperFunc.GetParam(0), objThis, cellArg]); result = builder.BuildIntToPtr(result, _ptrType, "pInterfaceFunc"); } else { Debug.Assert(!targetMethod.CanMethodBeInSealedVTable(factory)); - result = OutputCodeForVTableLookup(builder, helperFunc.GetParam(0), targetMethod); + result = OutputCodeForVTableLookup(builder, objThis, targetMethod); } } break; diff --git a/src/coreclr/tools/aot/ILCompiler.LLVM/Compiler/DependencyAnalysis/LLVMCodegenNodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.LLVM/Compiler/DependencyAnalysis/LLVMCodegenNodeFactory.cs index 9488b35a6ab5..98f4357fadd5 100644 --- a/src/coreclr/tools/aot/ILCompiler.LLVM/Compiler/DependencyAnalysis/LLVMCodegenNodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.LLVM/Compiler/DependencyAnalysis/LLVMCodegenNodeFactory.cs @@ -14,7 +14,6 @@ namespace ILCompiler.DependencyAnalysis public sealed class LLVMCodegenNodeFactory : NodeFactory { private readonly Dictionary _externSymbolsWithAccessors = new(); - private readonly Dictionary _runtimeExports = new(); public LLVMCodegenNodeFactory( CompilerTypeSystemContext context, @@ -41,12 +40,6 @@ public LLVMCodegenNodeFactory( preinitializationManager, devirtualizationManager) { - InitializeRuntimeExportsMap(roots); - } - - public override IMethodNode RuntimeExportManagedEntrypoint(string name) - { - return _runtimeExports.TryGetValue(name, out EcmaMethod export) ? MethodEntrypoint(export) : null; } internal ExternMethodAccessorNode ExternSymbolWithAccessor(string name, MethodDesc method, ReadOnlySpan sig) @@ -93,11 +86,6 @@ protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method) } else if (method.HasCustomAttribute("System.Runtime", "RuntimeImportAttribute")) { - if (RuntimeExportManagedEntrypoint(((EcmaMethod)method).GetRuntimeImportName()) is IMethodNode methodNode) - { - return methodNode; - } - return new RuntimeImportMethodNode(method, NameMangler); } } @@ -132,25 +120,5 @@ protected override ISymbolNode CreateReadyToRunHelperNode(ReadyToRunHelperKey he { return new ReadyToRunHelperNode(helperCall.HelperId, helperCall.Target); } - - private void InitializeRuntimeExportsMap(IEnumerable roots) - { - foreach (ICompilationRootProvider root in roots) - { - if (root is UnmanagedEntryPointsRootProvider unmanagedRoot) - { - foreach (EcmaMethod export in unmanagedRoot.ExportedMethods) - { - if (CompilationModuleGroup.ContainsMethodBody(export, unboxingStub: false)) - { - if (export.GetRuntimeExportName() is string name) - { - _runtimeExports.Add(name, export); - } - } - } - } - } - } } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs index 9f31fe5bf982..110f3463d85f 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/Compiler/RyuJitCompilation.cs @@ -221,7 +221,6 @@ private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeN public virtual TypeDesc GetPrimitiveTypeForTrivialWasmStruct(TypeDesc type) => throw new NotImplementedException(); public virtual int PadOffset(TypeDesc type, int atOffset) => throw new NotImplementedException(); - public virtual string GetRuntimeExportManagedEntrypointName(MethodDesc method) => throw new NotImplementedException(); public virtual ISymbolNode GetExternalMethodAccessor(MethodDesc method, ReadOnlySpan signature) => throw new NotImplementedException(); public virtual CorInfoLlvmEHModel GetLlvmExceptionHandlingModel() => throw new NotImplementedException(); } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.Llvm.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.Llvm.cs index 9b0e17121c31..9705419fe682 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.Llvm.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.Llvm.cs @@ -105,11 +105,10 @@ public static int getSignatureForMethodSymbol(IntPtr thisHandle, void* symbolHan if (method != null) { _this.Get_CORINFO_SIG_INFO(method, pSig, scope: null); - if (method.IsUnmanagedCallersOnly || node is RuntimeImportMethodNode) + if (method.IsUnmanagedCallersOnly) { pSig->callConv = CorInfoCallConv.CORINFO_CALLCONV_UNMANAGED; } - return 1; } @@ -140,14 +139,6 @@ public static int getSignatureForMethodSymbol(IntPtr thisHandle, void* symbolHan return 0; } - [UnmanagedCallersOnly] - public static uint isRuntimeImport(IntPtr thisHandle, CORINFO_METHOD_STRUCT_* ftn) - { - CorInfoImpl _this = GetThis(thisHandle); - MethodDesc method = _this.HandleToObject(ftn); - return method.IsInternalCall && _this._compilation.NodeFactory.MethodEntrypoint(method) is RuntimeImportMethodNode ? 1u : 0u; - } - [UnmanagedCallersOnly] public static CorInfoType getPrimitiveTypeForTrivialWasmStruct(IntPtr thisHandle, CORINFO_CLASS_STRUCT_* structHnd) { @@ -168,10 +159,7 @@ public static CorInfoType getPrimitiveTypeForTrivialWasmStruct(IntPtr thisHandle IMethodNode methodNode = _this._methodCodeNode; RyuJitCompilation compilation = _this._compilation; - string alternativeName = - compilation.GetRuntimeExportManagedEntrypointName(methodNode.Method) ?? - compilation.NodeFactory.GetSymbolAlternateName(methodNode); - + string alternativeName = compilation.NodeFactory.GetSymbolAlternateName(methodNode); return (alternativeName != null) ? (byte*)_this.GetPin(StringToUTF8(alternativeName)) : null; } @@ -409,7 +397,6 @@ private enum EEApiId GetMangledFilterFuncletName, GetSignatureForMethodSymbol, AddCodeReloc, - IsRuntimeImport, GetPrimitiveTypeForTrivialWasmStruct, GetTypeDescriptor, GetAlternativeFunctionName, @@ -443,7 +430,6 @@ public static void JitStartCompilation() jitImports[(int)EEApiId.GetMangledFilterFuncletName] = (delegate* unmanaged)&getMangledFilterFuncletName; jitImports[(int)EEApiId.GetSignatureForMethodSymbol] = (delegate* unmanaged)&getSignatureForMethodSymbol; jitImports[(int)EEApiId.AddCodeReloc] = (delegate* unmanaged)&addCodeReloc; - jitImports[(int)EEApiId.IsRuntimeImport] = (delegate* unmanaged)&isRuntimeImport; jitImports[(int)EEApiId.GetPrimitiveTypeForTrivialWasmStruct] = (delegate* unmanaged)&getPrimitiveTypeForTrivialWasmStruct; jitImports[(int)EEApiId.GetTypeDescriptor] = (delegate* unmanaged)&getTypeDescriptor; jitImports[(int)EEApiId.GetAlternativeFunctionName] = (delegate* unmanaged)&getAlternativeFunctionName; diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 777fe0f74955..1a45d472b253 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -795,9 +795,6 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) case CorInfoHelpFunc.CORINFO_HELP_LLVM_GET_OR_INIT_SHADOW_STACK_TOP: mangledName = "RhpGetOrInitShadowStackTop"; break; - case CorInfoHelpFunc.CORINFO_HELP_LLVM_SET_SHADOW_STACK_TOP: - mangledName = "RhpSetShadowStackTop"; - break; case CorInfoHelpFunc.CORINFO_HELP_LLVM_EH_CATCH: mangledName = "RhpHandleExceptionWasmCatch"; break; @@ -832,8 +829,7 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) ISymbolNode entryPoint; if (mangledName != null) { - entryPoint = _compilation.NodeFactory.RuntimeExportManagedEntrypoint(mangledName); - entryPoint ??= _compilation.NodeFactory.ExternSymbol(mangledName); + entryPoint = _compilation.NodeFactory.ExternSymbol(mangledName); } else {