From 7c12d8172ceb5c1f6d49b363faa9db2abc167884 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Fri, 3 Apr 2026 18:43:28 -0700 Subject: [PATCH] =?UTF-8?q?Revert=20"Inline=20CORINFO=5FHELP=5FARRADDR=5FS?= =?UTF-8?q?T=20helper=20call,=20remove=20WriteBarrier=20FCall=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit a3b2d40328be0be3f8dd43f0e5cc925b8827b044. --- .../Runtime/CompilerServices/CastHelpers.cs | 9 ++- src/coreclr/jit/compiler.h | 24 -------- src/coreclr/jit/gentree.cpp | 31 ---------- src/coreclr/jit/gentree.h | 2 - src/coreclr/jit/importer.cpp | 7 +-- src/coreclr/jit/importercalls.cpp | 61 ------------------- src/coreclr/jit/morph.cpp | 11 +--- src/coreclr/jit/namedintrinsiclist.h | 1 - .../CompilerServices/RuntimeHelpers.cs | 3 - .../src/System/Runtime/InternalCalls.cs | 4 ++ .../src/System/Runtime/TypeCast.cs | 6 +- .../src/System/Runtime/RuntimeHelpers.cs | 3 - src/coreclr/vm/amd64/JitHelpers_Fast.asm | 5 ++ src/coreclr/vm/amd64/jithelpers_fast.S | 8 +++ src/coreclr/vm/arm/asmhelpers.S | 15 +++++ src/coreclr/vm/arm64/asmhelpers.S | 14 +++++ src/coreclr/vm/arm64/asmhelpers.asm | 15 +++++ src/coreclr/vm/ecalllist.h | 4 ++ src/coreclr/vm/i386/jithelp.S | 17 ++++++ src/coreclr/vm/i386/jithelp.asm | 8 +++ src/coreclr/vm/jitinterface.h | 6 ++ src/coreclr/vm/loongarch64/asmhelpers.S | 14 +++++ src/coreclr/vm/riscv64/asmhelpers.S | 12 ++++ src/coreclr/vm/wasm/helpers.cpp | 5 ++ .../CompilerServices/RuntimeHelpers.cs | 5 +- 25 files changed, 139 insertions(+), 151 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs index cdcd1891cd3cb8..785705d31abb07 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs @@ -59,6 +59,9 @@ private static object ChkCastAny_NoCacheLookup(void* toTypeHnd, object obj) return obj; } + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void WriteBarrier(ref object? dst, object? obj); + // IsInstanceOf test used for unusual cases (naked type parameters, variant generic types) // Unlike the IsInstanceOfInterface and IsInstanceOfClass functions, // this test must deal with all kinds of type tests @@ -468,7 +471,7 @@ private static void StelemRef(object?[] array, nint index, object? obj) goto notExactMatch; doWrite: - RuntimeHelpers.WriteBarrier(ref element, obj); + WriteBarrier(ref element, obj); return; assigningNull: @@ -490,7 +493,7 @@ private static void StelemRef_Helper(ref object? element, void* elementType, obj CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType); if (result == CastResult.CanCast) { - RuntimeHelpers.WriteBarrier(ref element, obj); + WriteBarrier(ref element, obj); return; } @@ -509,7 +512,7 @@ private static void StelemRef_Helper_NoCacheLookup(ref object? element, void* el ThrowArrayMismatchException(); } - RuntimeHelpers.WriteBarrier(ref element, obj2); + WriteBarrier(ref element, obj2); } [DebuggerHidden] diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 78785fc4bee84f..79d46b87601ec6 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5348,30 +5348,6 @@ class Compiler GenTree* dereferencedAddress, InlArgInfo* inlArgInfo); - typedef JitHashTable, CORINFO_METHOD_HANDLE> HelperToManagedMap; - HelperToManagedMap* m_helperToManagedMap = nullptr; - -public: - HelperToManagedMap* GetHelperToManagedMap() - { - if (m_helperToManagedMap == nullptr) - { - m_helperToManagedMap = new (getAllocator()) HelperToManagedMap(getAllocator()); - } - return m_helperToManagedMap; - } - bool HelperToManagedMapLookup(CORINFO_METHOD_HANDLE helperCallHnd, CORINFO_METHOD_HANDLE* userCallHnd) - { - if (m_helperToManagedMap == nullptr) - { - return false; - } - bool found = m_helperToManagedMap->Lookup(helperCallHnd, userCallHnd); - return found; - } -private: - - void impConvertToUserCallAndMarkForInlining(GenTreeCall* call); void impMarkInlineCandidate(GenTree* call, CORINFO_CONTEXT_HANDLE exactContextHnd, bool exactContextNeedsRuntimeLookup, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 5ff83ee8f0b09e..9b166fd05aac3d 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2398,34 +2398,6 @@ bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const return IsHelperCall(compiler->eeFindHelper(helper)); } -//------------------------------------------------------------------------- -// IsHelperCallOrUserEquivalent: Determine if this GT_CALL node is a specific helper call -// or its CT_USER equivalent. -// -// Arguments: -// compiler - the compiler instance so that we can call eeFindHelper -// -// Return Value: -// Returns true if this GT_CALL node is a call to the specified helper. -// -bool GenTreeCall::IsHelperCallOrUserEquivalent(Compiler* compiler, unsigned helper) const -{ - CORINFO_METHOD_HANDLE helperCallHnd = Compiler::eeFindHelper(helper); - if (IsHelperCall()) - { - return helperCallHnd == gtCallMethHnd; - } - - if (gtCallType == CT_USER_FUNC) - { - CORINFO_METHOD_HANDLE userCallHnd = NO_METHOD_HANDLE; - return compiler->impInlineRoot()->HelperToManagedMapLookup(helperCallHnd, &userCallHnd) && - (userCallHnd == gtCallMethHnd); - } - - return false; -} - //------------------------------------------------------------------------- // IsRuntimeLookupHelperCall: Determine if this GT_CALL node represents a runtime lookup helper call. // @@ -13039,9 +13011,6 @@ void Compiler::gtDispTree(GenTree* tree, case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: printf(" isKnownConst"); break; - case NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier: - printf(" WriteBarrier"); - break; #if defined(FEATURE_SIMD) case NI_SIMD_UpperRestore: printf(" simdUpperRestore"); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 94e783e62d2bc2..178cfd3c48e864 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5877,8 +5877,6 @@ struct GenTreeCall final : public GenTree bool IsHelperCall(Compiler* compiler, unsigned helper) const; - bool IsHelperCallOrUserEquivalent(Compiler* compiler, unsigned helper) const; - bool IsRuntimeLookupHelperCall(Compiler* compiler) const; bool IsSpecialIntrinsic(Compiler* compiler, NamedIntrinsic ni) const; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e454fe16814915..d31fd28da5e5e7 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -7268,12 +7268,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) // The array helper takes a native int for array length. // So if we have an int, explicitly extend it to be a native int. index = impImplicitIorI4Cast(index, TYP_I_IMPL); - - GenTreeCall* call = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); - INDEBUG(call->gtRawILOffset = opcodeOffs); - impConvertToUserCallAndMarkForInlining(call); - op1 = call; - + op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); goto SPILL_APPEND; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 609b48cf27385b..03999e90208dd3 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -3411,8 +3411,6 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, // This one is just `return true/false` case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: - case NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier: - // Not expanding this can lead to noticeable allocations in T0 case NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan: @@ -3642,14 +3640,6 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, break; } - case NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier: - { - GenTree* val = impPopStack().val; - GenTree* dst = impPopStack().val; - retNode = gtNewStoreIndNode(TYP_REF, dst, val, GTF_IND_TGT_HEAP); - break; - } - case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: { GenTree* op1 = impPopStack().val; @@ -7988,53 +7978,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, call->AddGDVCandidateInfo(this, pInfo); } -//------------------------------------------------------------------------ -// impConvertToUserCallAndMarkForInlining: convert a helper call to a user call -// and mark it for inlining. This is used for helper calls that are -// known to be backed by a user method that can be inlined. -// -// Arguments: -// call - the helper call to convert -// -void Compiler::impConvertToUserCallAndMarkForInlining(GenTreeCall* call) -{ - assert(call->IsHelperCall()); - - if (!opts.OptEnabled(CLFLG_INLINING)) - { - return; - } - - CORINFO_METHOD_HANDLE helperCallHnd = call->gtCallMethHnd; - CORINFO_METHOD_HANDLE managedCallHnd = NO_METHOD_HANDLE; - CORINFO_CONST_LOOKUP pNativeEntrypoint = {}; - info.compCompHnd->getHelperFtn(eeGetHelperNum(helperCallHnd), &pNativeEntrypoint, &managedCallHnd); - - if (managedCallHnd != NO_METHOD_HANDLE) - { - call->gtCallMethHnd = managedCallHnd; - call->gtCallType = CT_USER_FUNC; - - CORINFO_CALL_INFO hCallInfo = {}; - hCallInfo.hMethod = managedCallHnd; - hCallInfo.methodFlags = info.compCompHnd->getMethodAttribs(hCallInfo.hMethod); - impMarkInlineCandidate(call, nullptr, false, &hCallInfo, compInlineContext); - -#if DEBUG - CORINFO_METHOD_HANDLE existingValue = NO_METHOD_HANDLE; - if (impInlineRoot()->HelperToManagedMapLookup(helperCallHnd, &existingValue)) - { - // Let's make sure HelperToManagedMap::Overwrite behavior always overwrites the same value. - assert(existingValue == managedCallHnd); - } -#endif - - impInlineRoot()->GetHelperToManagedMap()->Set(helperCallHnd, managedCallHnd, HelperToManagedMap::Overwrite); - JITDUMP("Converting helperCall [%06u] to user call [%s] and marking for inlining\n", dspTreeID(call), - eeGetMethodFullName(managedCallHnd)); - } -} - //------------------------------------------------------------------------ // impMarkInlineCandidate: determine if this call can be subsequently inlined // @@ -10988,10 +10931,6 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) { result = NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant; } - else if (strcmp(methodName, "WriteBarrier") == 0) - { - result = NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier; - } else if (strcmp(methodName, "IsReferenceOrContainsReferences") == 0) { result = diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 0e1e4871a54658..e2a1f11b3d0c1a 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -6459,7 +6459,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) // Morph stelem.ref helper call to store a null value, into a store into an array without the helper. // This needs to be done after the arguments are morphed to ensure constant propagation has already taken place. - if (opts.OptimizationEnabled() && call->IsHelperCallOrUserEquivalent(this, CORINFO_HELP_ARRADDR_ST)) + if (opts.OptimizationEnabled() && call->IsHelperCall(this, CORINFO_HELP_ARRADDR_ST)) { assert(call->gtArgs.CountUserArgs() == 3); @@ -6467,15 +6467,6 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) GenTree* index = call->gtArgs.GetUserArgByIndex(1)->GetNode(); GenTree* value = call->gtArgs.GetUserArgByIndex(2)->GetNode(); - if (!call->IsHelperCall()) - { - // Convert back to helper call if it wasn't inlined. - // Currently, only helper calls are eligible to be direct calls if the target has reached - // its final tier. TODO: remove this workaround and convert this user call to direct as well. - call->gtCallMethHnd = eeFindHelper(CORINFO_HELP_ARRADDR_ST); - call->gtCallType = CT_HELPER; - } - if (gtCanSkipCovariantStoreCheck(value, arr)) { // Either or both of the array and index arguments may have been spilled to temps by `fgMorphArgs`. Copy diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 07a77dc651bd50..5856f644e20e89 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -123,7 +123,6 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant, NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences, NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable, - NI_System_Runtime_CompilerServices_RuntimeHelpers_WriteBarrier, NI_System_Runtime_CompilerServices_RuntimeHelpers_SetNextCallGenericContext, NI_System_Runtime_CompilerServices_RuntimeHelpers_SetNextCallAsyncContinuation, diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 142ba1ce162ec6..b06f2f3d5eb30c 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -18,8 +18,5 @@ public static int OffsetToStringData [Intrinsic] public static extern void InitializeArray(Array array, RuntimeFieldHandle fldHandle); - - [Intrinsic] - internal static void WriteBarrier(ref object? dst, object? obj) => dst = 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 abfb0d4b3bcd58..d25dfcd400d6c3 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InternalCalls.cs @@ -121,6 +121,10 @@ internal static class InternalCalls internal static extern unsafe object RhpNewFastMisalign(MethodTable * pEEType); #endif // FEATURE_64BIT_ALIGNMENT + [RuntimeImport(RuntimeLibrary, "RhpAssignRef")] + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern unsafe void RhpAssignRef(ref object? address, object? obj); + [MethodImplAttribute(MethodImplOptions.InternalCall)] [RuntimeImport(RuntimeLibrary, "RhpGcSafeZeroMemory")] internal static extern unsafe ref byte RhpGcSafeZeroMemory(ref byte dmem, nuint size); diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs index c42653bf18f524..428e686eb9ce98 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -803,7 +803,7 @@ public static unsafe void StelemRef(object?[] array, nint index, object? obj) goto notExactMatch; doWrite: - RuntimeHelpers.WriteBarrier(ref element, obj); + InternalCalls.RhpAssignRef(ref element, obj); return; assigningNull: @@ -826,7 +826,7 @@ private static unsafe void StelemRef_Helper(ref object? element, MethodTable* el CastResult result = s_castCache.TryGet((nuint)obj.GetMethodTable() + (int)AssignmentVariation.BoxedSource, (nuint)elementType); if (result == CastResult.CanCast) { - RuntimeHelpers.WriteBarrier(ref element, obj); + InternalCalls.RhpAssignRef(ref element, obj); return; } @@ -843,7 +843,7 @@ private static unsafe void StelemRef_Helper_NoCacheLookup(ref object? element, M throw elementType->GetClasslibException(ExceptionIDs.ArrayTypeMismatch); } - RuntimeHelpers.WriteBarrier(ref element, obj); + InternalCalls.RhpAssignRef(ref element, obj); } private static unsafe object IsInstanceOfArray(MethodTable* pTargetType, object obj) diff --git a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeHelpers.cs b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeHelpers.cs index 0846fa36d191db..6c91965f67a1bd 100644 --- a/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeHelpers.cs +++ b/src/coreclr/nativeaot/Test.CoreLib/src/System/Runtime/RuntimeHelpers.cs @@ -15,8 +15,5 @@ public static int OffsetToStringData return string.FIRST_CHAR_OFFSET; } } - - [Intrinsic] - internal static void WriteBarrier(ref object? dst, object? obj) => dst = obj; } } diff --git a/src/coreclr/vm/amd64/JitHelpers_Fast.asm b/src/coreclr/vm/amd64/JitHelpers_Fast.asm index 149b38f11754e9..f5b26b662441c4 100644 --- a/src/coreclr/vm/amd64/JitHelpers_Fast.asm +++ b/src/coreclr/vm/amd64/JitHelpers_Fast.asm @@ -265,6 +265,11 @@ Section segment para 'DATA' JIT_WriteBarrier_Loc: dq 0 +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + ; JIT_WriteBarrier(Object** dst, Object* src) + jmp QWORD PTR [JIT_WriteBarrier_Loc] +LEAF_END JIT_WriteBarrier_Callable, _TEXT + ; There is an even more optimized version of these helpers possible which takes ; advantage of knowledge of which way the ephemeral heap is growing to only do 1/2 ; that check (this is more significant in the JIT_WriteBarrier case). diff --git a/src/coreclr/vm/amd64/jithelpers_fast.S b/src/coreclr/vm/amd64/jithelpers_fast.S index d559ee8e844987..37c2f5f98fd19d 100644 --- a/src/coreclr/vm/amd64/jithelpers_fast.S +++ b/src/coreclr/vm/amd64/jithelpers_fast.S @@ -224,6 +224,14 @@ LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT .text #endif +// ------------------------------------------------------------------ +// __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) +.balign 16 +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + // JIT_WriteBarrier(Object** dst, Object* src) + jmp [rip + C_FUNC(JIT_WriteBarrier_Loc)] +LEAF_END JIT_WriteBarrier_Callable, _TEXT + // The following helper will access ("probe") a word on each page of the stack // starting with the page right beneath rsp down to the one pointed to by r11. diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index 03ccf381f8e476..58eb054f468c62 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -675,6 +675,21 @@ g_rgWriteBarrierDescriptors: .global g_rgWriteBarrierDescriptors +// ------------------------------------------------------------------ +// __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) + LEAF_ENTRY JIT_WriteBarrier_Callable + + // Branch to the write barrier +#if defined(__clang__) + ldr r2, =JIT_WriteBarrier_Loc-(1f+4) // or R3? See targetarm.h +1: + add r2, pc +#else + ldr r2, =JIT_WriteBarrier_Loc +#endif + ldr pc, [r2] + + LEAF_END JIT_WriteBarrier_Callable #ifdef FEATURE_READYTORUN diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index b60f2a118be155..76ab00eb6700f3 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -80,6 +80,20 @@ PATCH_LABEL ThePreStubPatchLabel ret lr LEAF_END ThePreStubPatch, _TEXT +// ------------------------// ------------------------------------------------------------------ +// __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + + // Setup args for JIT_WriteBarrier. x14 = dst ; x15 = val + mov x14, x0 // x14 = dst + mov x15, x1 // x15 = val + + // Branch to the write barrier + PREPARE_EXTERNAL_VAR JIT_WriteBarrier_Loc, x17 + ldr x17, [x17] + br x17 +LEAF_END JIT_WriteBarrier_Callable, _TEXT + // // x12 = UMEntryThunkData* // diff --git a/src/coreclr/vm/arm64/asmhelpers.asm b/src/coreclr/vm/arm64/asmhelpers.asm index e7f6f8083b6d58..47de4524f974ae 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -693,6 +693,21 @@ CallHelper2 br x1 LEAF_END +; ------------------------------------------------------------------ +; __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) + LEAF_ENTRY JIT_WriteBarrier_Callable + + ; Setup args for JIT_WriteBarrier. x14 = dst ; x15 = val + mov x14, x0 ; x14 = dst + mov x15, x1 ; x15 = val + + ; Branch to the write barrier + adrp x17, JIT_WriteBarrier_Loc + ldr x17, [x17, JIT_WriteBarrier_Loc] + br x17 + + LEAF_END + #ifdef PROFILING_SUPPORTED ; ------------------------------------------------------------------ diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index a32d6969f32fbb..2b55b0c95bfaf9 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -269,6 +269,9 @@ FCFuncStart(gMonitorFuncs) FCFuncElement("GetLockHandleIfExists", Monitor_GetLockHandleIfExists) FCFuncEnd() +FCFuncStart(gCastHelpers) + FCFuncElement("WriteBarrier", ::WriteBarrier_Helper) +FCFuncEnd() FCFuncStart(gArrayFuncs) FCFuncElement("GetCorElementTypeOfElementType", ArrayNative::GetCorElementTypeOfElementType) @@ -392,6 +395,7 @@ FCClassElement("AssemblyLoadContext", "System.Runtime.Loader", gAssemblyLoadCont FCClassElement("AsyncHelpers", "System.Runtime.CompilerServices", gAsyncHelpers) #endif FCClassElement("Buffer", "System", gBufferFuncs) +FCClassElement("CastHelpers", "System.Runtime.CompilerServices", gCastHelpers) FCClassElement("Delegate", "System", gDelegateFuncs) FCClassElement("DependentHandle", "System.Runtime", gDependentHandleFuncs) FCClassElement("Environment", "System", gEnvironmentFuncs) diff --git a/src/coreclr/vm/i386/jithelp.S b/src/coreclr/vm/i386/jithelp.S index 13a6f48f167f86..dc7c8568e05097 100644 --- a/src/coreclr/vm/i386/jithelp.S +++ b/src/coreclr/vm/i386/jithelp.S @@ -385,6 +385,23 @@ C_FUNC(JIT_WriteBarrierEAX_Loc): .word 0 .text +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + mov eax, edx + mov edx, ecx + push eax + call 1f +1: + pop eax +2: +.att_syntax + addl $_GLOBAL_OFFSET_TABLE_+(2b-1b), %eax +.intel_syntax noprefix + mov eax, dword ptr [eax + C_FUNC(JIT_WriteBarrierEAX_Loc)@GOT] + mov eax, [eax] + xchg eax, dword ptr [esp] + ret +LEAF_END JIT_WriteBarrier_Callable, _TEXT + .macro UniversalWriteBarrierHelper name .align 4 diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index cfbe93ccd6d38e..e131dee95a9312 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -423,6 +423,14 @@ _JIT_WriteBarrierGroup@0 PROC ret _JIT_WriteBarrierGroup@0 ENDP + ALIGN 4 +PUBLIC @JIT_WriteBarrier_Callable@8 +@JIT_WriteBarrier_Callable@8 PROC + mov eax,edx + mov edx,ecx + jmp DWORD PTR [_JIT_WriteBarrierEAX_Loc] + +@JIT_WriteBarrier_Callable@8 ENDP UniversalWriteBarrierHelper MACRO name ALIGN 4 diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 839df4ca92455b..fed6eb751560ff 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -209,6 +209,12 @@ extern "C" FCDECL2(VOID, RhpAssignRef, Object **dst, Object *ref); extern "C" FCDECL2(VOID, JIT_WriteBarrier, Object **dst, Object *ref); extern "C" FCDECL2(VOID, JIT_WriteBarrierEnsureNonHeapTarget, Object **dst, Object *ref); +// ARM64 JIT_WriteBarrier uses special ABI and thus is not callable directly +// Copied write barriers must be called at a different location +extern "C" FCDECL2(VOID, JIT_WriteBarrier_Callable, Object **dst, Object *ref); + +#define WriteBarrier_Helper JIT_WriteBarrier_Callable + EXTERN_C FCDECL2_VV(INT64, JIT_LMul, INT64 val1, INT64 val2); #ifndef HOST_64BIT diff --git a/src/coreclr/vm/loongarch64/asmhelpers.S b/src/coreclr/vm/loongarch64/asmhelpers.S index 3b47125fa8dfdb..4fc1b89510d55a 100644 --- a/src/coreclr/vm/loongarch64/asmhelpers.S +++ b/src/coreclr/vm/loongarch64/asmhelpers.S @@ -112,6 +112,20 @@ LOCAL_LABEL(EphemeralCheckEnabled): WRITE_BARRIER_END JIT_UpdateWriteBarrierState +// ---------------------------------------------------------------------------------------- +// __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + + // Setup args for JIT_WriteBarrier. $t0 = dst ; $t1 = val + ori $t6, $a0, 0 // $t6 = dst + ori $t7, $a1, 0 // $t7 = val + + // Branch to the write barrier + la.local $r21, JIT_WriteBarrier_Loc + ld.d $r21, $r21, 0 + jirl $r0, $r21, 0 +LEAF_END JIT_WriteBarrier_Callable, _TEXT + .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index de4a8ae7408be4..b4faa319193164 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -98,6 +98,18 @@ LOCAL_LABEL(EphemeralCheckEnabled): WRITE_BARRIER_END JIT_UpdateWriteBarrierState +// ---------------------------------------------------------------------------------------- +// __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) +LEAF_ENTRY JIT_WriteBarrier_Callable, _TEXT + // Setup args for JIT_WriteBarrier. a0 = dst ; a1 = val + addi t3, a0, 0 // t3 = dst + addi t4, a1, 0 // t4 = val + + // Branch to the write barrier + ld t1, JIT_WriteBarrier_Loc + jr t1 +LEAF_END JIT_WriteBarrier_Callable, _TEXT + .balign 64 // Align to power of two at least as big as patchable literal pool so that it fits optimally in cache line // ------------------------------------------------------------------ diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp index bd0f618e7b1afe..afb6d2f739a8b8 100644 --- a/src/coreclr/vm/wasm/helpers.cpp +++ b/src/coreclr/vm/wasm/helpers.cpp @@ -198,6 +198,11 @@ extern "C" PCODE CID_VirtualOpenDelegateDispatch(TransitionBlock * pTransitionBl return 0; } +extern "C" FCDECL2(VOID, JIT_WriteBarrier_Callable, Object **dst, Object *ref) +{ + PORTABILITY_ASSERT("JIT_WriteBarrier_Callable is not implemented on wasm"); +} + EXTERN_C void JIT_WriteBarrier_End() { PORTABILITY_ASSERT("JIT_WriteBarrier_End is not implemented on wasm"); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index bb51c339b119db..ab7a9d30b74153 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -181,10 +181,7 @@ public static ReadOnlySpan CreateSpan(RuntimeFieldHandle fldHandle) /// true if the given type is a reference type or a value type that contains references or by-refs; otherwise, false. [Intrinsic] - public static bool IsReferenceOrContainsReferences() where T : allows ref struct => IsReferenceOrContainsReferences(); - - [Intrinsic] - internal static void WriteBarrier(ref object? dst, object? obj) => dst = obj; + public static bool IsReferenceOrContainsReferences() where T: allows ref struct => IsReferenceOrContainsReferences(); [Intrinsic] [RequiresUnsafe]