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 486aeb72faddb..3a7849aa9d9d4 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 @@ -596,6 +596,56 @@ private static void StelemRef(Array array, int index, object? obj) StelemRef_Helper(ref element, elementType, obj); } +#if TARGET_64BIT + [DebuggerHidden] + [StackTraceHidden] + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + private static ref object? LdelemaRefNint(Array array, nint index, void* type) + { + // this will throw appropriate exceptions if array is null or access is out of range. + ref object? element = ref Unsafe.As(array)[index].Value; + void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; + + if (elementType == type) + return ref element; + + return ref ThrowArrayMismatchException(); + } + + [DebuggerHidden] + [StackTraceHidden] + [DebuggerStepThrough] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + private static void StelemRefNint(Array array, nint index, object? obj) + { + // this will throw appropriate exceptions if array is null or access is out of range. + ref object? element = ref Unsafe.As(array)[index].Value; + void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; + + if (obj == null) + goto assigningNull; + + if (elementType != RuntimeHelpers.GetMethodTable(obj)) + goto notExactMatch; + + doWrite: + WriteBarrier(ref element, obj); + return; + + assigningNull: + element = null; + return; + + notExactMatch: + if (array.GetType() == typeof(object[])) + goto doWrite; + + StelemRef_Helper(ref element, elementType, obj); + } +#endif // TARGET_64BIT + + [DebuggerHidden] [StackTraceHidden] [DebuggerStepThrough] diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 91c5734c90588..6429966d88bf0 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -447,6 +447,9 @@ enum CorInfoHelpFunc CORINFO_HELP_ARRADDR_ST, // assign to element of object array with type-checking CORINFO_HELP_LDELEMA_REF, // does a precise type comparision and returns address + CORINFO_HELP_ARRADDR_ST_I_IMPL, // assign to element of object array with type-checking (Native int index parameter) + CORINFO_HELP_LDELEMA_REF_I_IMPL, // does a precise type comparision and returns address (Native int index parameter) + /* Exceptions */ CORINFO_HELP_THROW, // Throw an exception object diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 9a6cbc053e1ce..2a9fc7d7b044b 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* f2faa5fc-a1ec-4244-aebb-5597bfd7153a */ - 0xf2faa5fc, - 0xa1ec, - 0x4244, - {0xae, 0xbb, 0x55, 0x97, 0xbf, 0xd7, 0x15, 0x3a} +constexpr GUID JITEEVersionIdentifier = { /* 0d853657-7a01-421f-b1b0-d22a8e691441 */ + 0x0d853657, + 0x7a01, + 0x421f, + {0xb1, 0xb0, 0xd2, 0x2a, 0x8e, 0x69, 0x14, 0x41} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index a500c298978b6..15f9022e8414c 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -108,6 +108,9 @@ DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST, NULL, CORINFO_HELP_SIG_4_STACK) DYNAMICJITHELPER(CORINFO_HELP_LDELEMA_REF, NULL, CORINFO_HELP_SIG_4_STACK) + DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST_I_IMPL, NULL, CORINFO_HELP_SIG_4_STACK) + DYNAMICJITHELPER(CORINFO_HELP_LDELEMA_REF_I_IMPL, NULL, CORINFO_HELP_SIG_4_STACK) + // Exceptions JITHELPER(CORINFO_HELP_THROW, IL_Throw, CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_RETHROW, IL_Rethrow, CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 5a7b798d084e6..53c09757178c4 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -401,6 +401,10 @@ enum ReadyToRunHelper READYTORUN_HELPER_StackProbe = 0x111, READYTORUN_HELPER_GetCurrentManagedThreadId = 0x112, + + // Array helpers for use with native ints + READYTORUN_HELPER_Stelem_Ref_I = 0x113, + READYTORUN_HELPER_Ldelema_Ref_I = 0x114, }; #include "readytoruninstructionset.h" diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index 66e2d4a3b164e..77c072dff6da9 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -28,6 +28,9 @@ HELPER(READYTORUN_HELPER_ByRefWriteBarrier, CORINFO_HELP_ASSIGN_BYREF, HELPER(READYTORUN_HELPER_Stelem_Ref, CORINFO_HELP_ARRADDR_ST, ) HELPER(READYTORUN_HELPER_Ldelema_Ref, CORINFO_HELP_LDELEMA_REF, ) +HELPER(READYTORUN_HELPER_Stelem_Ref_I, CORINFO_HELP_ARRADDR_ST_I_IMPL, ) +HELPER(READYTORUN_HELPER_Ldelema_Ref_I, CORINFO_HELP_LDELEMA_REF_I_IMPL, ) + HELPER(READYTORUN_HELPER_MemSet, CORINFO_HELP_MEMSET, ) HELPER(READYTORUN_HELPER_MemCpy, CORINFO_HELP_MEMCPY, ) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 3caad0781ac9d..eeb12ad5c2605 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -13717,7 +13717,18 @@ void Compiler::impImportBlockCode(BasicBlock* block) GenTree* type = op1; GenTree* index = impPopStack().val; GenTree* arr = impPopStack().val; - op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type); +#ifdef TARGET_64BIT + // The CLI Spec allows an array to be indexed by either an int32 or a native int. In the case that the index + // is a native int on a 64-bit platform, we will need to use a helper that can process the wider value. + if (index->TypeGet() == TYP_I_IMPL) + { + op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF_I_IMPL, TYP_BYREF, arr, index, type); + } + else +#endif // TARGET_64BIT + { + op1 = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, arr, index, type); + } } impPushOnStack(op1, tiRetVal); @@ -13859,7 +13870,18 @@ void Compiler::impImportBlockCode(BasicBlock* block) impPopStack(3); // Else call a helper function to do the assignment - op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); +#ifdef TARGET_64BIT + // The CLI Spec allows an array to be indexed by either an int32 or a native int. In the case that the index + // is a native int on a 64-bit platform, we will need to use a helper that can process the wider value. + if (index->TypeGet() == TYP_I_IMPL) + { + op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST_I_IMPL, TYP_VOID, array, index, value); + } + else +#endif // TARGET_64BIT + { + op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, array, index, value); + } goto SPILL_APPEND; } diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 07901100d18e1..54917dcee7fc5 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -8426,7 +8426,11 @@ 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->gtCallType == CT_HELPER) && - (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ARRADDR_ST))) + ((call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ARRADDR_ST)) +#ifdef TARGET_64BIT + || (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ARRADDR_ST_I_IMPL)) +#endif + )) { assert(call->gtArgs.CountArgs() == 3); GenTree* value = call->gtArgs.GetArgByIndex(2)->GetNode(); diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp index 2bd24b1223956..7325b2a798a5e 100644 --- a/src/coreclr/jit/optimizer.cpp +++ b/src/coreclr/jit/optimizer.cpp @@ -5509,6 +5509,7 @@ PhaseStatus Compiler::optFindLoopsPhase() case CORINFO_HELP_ASSIGN_BYREF: // Not strictly needed as we don't make a GT_CALL with this case CORINFO_HELP_SETFIELDOBJ: case CORINFO_HELP_ARRADDR_ST: + case CORINFO_HELP_ARRADDR_ST_I_IMPL: return CALLINT_REF_INDIRS; diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 8f3db9050c2d7..583ebb5d2df75 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1372,6 +1372,7 @@ void HelperCallProperties::init() case CORINFO_HELP_UNBOX: case CORINFO_HELP_GETREFANY: case CORINFO_HELP_LDELEMA_REF: + case CORINFO_HELP_LDELEMA_REF_I_IMPL: isPure = true; break; @@ -1443,6 +1444,7 @@ void HelperCallProperties::init() case CORINFO_HELP_SETFIELDFLOAT: case CORINFO_HELP_SETFIELDDOUBLE: case CORINFO_HELP_ARRADDR_ST: + case CORINFO_HELP_ARRADDR_ST_I_IMPL: mutatesHeap = true; break; diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 4a6aeb158117a..02bf938122c1f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -10110,6 +10110,7 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) break; case CORINFO_HELP_LDELEMA_REF: + case CORINFO_HELP_LDELEMA_REF_I_IMPL: vnf = VNF_LdElemA; break; 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 ebf957a22d0b8..ee2cdc5926111 100644 --- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs +++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/TypeCast.cs @@ -778,6 +778,59 @@ public static unsafe void StelemRef(Array array, int index, object obj) InternalCalls.RhpAssignRef(ref element, obj); return; +assigningNull: + element = null; + return; + + notExactMatch: +#if INPLACE_RUNTIME + // This optimization only makes sense for inplace runtime where there's only one System.Object. + if (array.GetMethodTable() == MethodTable.Of()) + goto doWrite; +#endif + + StelemRef_Helper(ref element, elementType, obj); + } + + // + // Array stelem/ldelema helpers with RyuJIT conventions + // + [RuntimeExport("RhpStelemRefNint")] + public static unsafe void StelemRefNint(Array array, nint index, object obj) + { + // This is supported only on arrays + Debug.Assert(array.GetMethodTable()->IsArray, "first argument must be an array"); + +#if INPLACE_RUNTIME + // this will throw appropriate exceptions if array is null or access is out of range. + ref object element = ref Unsafe.As(array)[index].Value; +#else + if (array is null) + { + // TODO: If both array and obj are null, we're likely going to throw Redhawk's NullReferenceException. + // This should blame the caller. + throw obj.MethodTable->GetClasslibException(ExceptionIDs.NullReference); + } + if ((nuint)index >= (nuint)array.Length) + { + throw array.MethodTable->GetClasslibException(ExceptionIDs.IndexOutOfRange); + } + ref object rawData = ref Unsafe.As(ref Unsafe.As(array).Data); + ref object element = ref Unsafe.Add(ref rawData, index); +#endif + + MethodTable* elementType = array.GetMethodTable()->RelatedParameterType; + + if (obj == null) + goto assigningNull; + + if (elementType != obj.GetMethodTable()) + goto notExactMatch; + +doWrite: + InternalCalls.RhpAssignRef(ref element, obj); + return; + assigningNull: element = null; return; @@ -833,6 +886,26 @@ public static unsafe ref object LdelemaRef(Array array, int index, IntPtr elemen return ref Unsafe.Add(ref rawData, index); } + [RuntimeExport("RhpLdelemaRefNint")] + public static unsafe ref object LdelemaRefNint(Array array, nint index, IntPtr elementType) + { + Debug.Assert(array.GetMethodTable()->IsArray, "first argument must be an array"); + + MethodTable* elemType = (MethodTable*)elementType; + MethodTable* arrayElemType = array.GetMethodTable()->RelatedParameterType; + + if (!AreTypesEquivalent(elemType, arrayElemType)) + { + // Throw the array type mismatch exception defined by the classlib, using the input array's MethodTable* + // to find the correct classlib. + + throw array.GetMethodTable()->GetClasslibException(ExceptionIDs.ArrayTypeMismatch); + } + + ref object rawData = ref Unsafe.As(ref Unsafe.As(array).Data); + return ref Unsafe.Add(ref rawData, (int)index); + } + internal static unsafe bool IsDerived(MethodTable* pDerivedType, MethodTable* pBaseType) { Debug.Assert(!pDerivedType->IsArray, "did not expect array type"); diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs index 1a14ebfaf75d0..ef2382ff3f4bf 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs @@ -321,6 +321,10 @@ public enum ReadyToRunHelper GetCurrentManagedThreadId = 0x112, + // Array helpers for use with native ints + Stelem_Ref_I = 0x113, + Ldelema_Ref_I = 0x114, + // ********************************************************************************************** // // These are not actually part of the R2R file format. We have them here because it's convenient. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 3bb774ed11b50..e16569d483342 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -93,6 +93,9 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_ARRADDR_ST, // assign to element of object array with type-checking CORINFO_HELP_LDELEMA_REF, // does a precise type comparision and returns address + CORINFO_HELP_ARRADDR_ST_I_IMPL, // assign to element of object array with type-checking (with native int index) + CORINFO_HELP_LDELEMA_REF_I_IMPL,// does a precise type comparision and returns address (with native int index) + /* Exceptions */ CORINFO_HELP_THROW, // Throw an exception object diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs index a4ae4c40a6687..8f777fd776aec 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/JitHelper.cs @@ -112,6 +112,13 @@ public static void GetEntryPoint(TypeSystemContext context, ReadyToRunHelper id, mangledName = "RhpLdelemaRef"; break; + case ReadyToRunHelper.Stelem_Ref_I: + mangledName = "RhpStelemRefNint"; + break; + case ReadyToRunHelper.Ldelema_Ref_I: + mangledName = "RhpLdelemaRefNint"; + break; + case ReadyToRunHelper.MemCpy: mangledName = "memcpy"; // TODO: Null reference handling break; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 2e708498a5618..6784038af475b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -739,6 +739,13 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) id = ReadyToRunHelper.Ldelema_Ref; break; + case CorInfoHelpFunc.CORINFO_HELP_ARRADDR_ST_I_IMPL: + id = ReadyToRunHelper.Stelem_Ref_I; + break; + case CorInfoHelpFunc.CORINFO_HELP_LDELEMA_REF_I_IMPL: + id = ReadyToRunHelper.Ldelema_Ref_I; + break; + case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: id = ReadyToRunHelper.GenericGcStaticBase; 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 bfdae7869892b..29b385fd2bfba 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -506,6 +506,13 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) id = ReadyToRunHelper.Ldelema_Ref; break; + case CorInfoHelpFunc.CORINFO_HELP_ARRADDR_ST_I_IMPL: + id = ReadyToRunHelper.Stelem_Ref_I; + break; + case CorInfoHelpFunc.CORINFO_HELP_LDELEMA_REF_I_IMPL: + id = ReadyToRunHelper.Ldelema_Ref_I; + break; + case CorInfoHelpFunc.CORINFO_HELP_MEMSET: id = ReadyToRunHelper.MemSet; break; diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index cd4995aa32141..1634490a5a0b3 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1228,6 +1228,10 @@ DEFINE_METHOD(CASTHELPERS, CHKCASTCLASSSPECIAL, ChkCastClassSpecial, SM_Ptr DEFINE_METHOD(CASTHELPERS, UNBOX, Unbox, SM_PtrVoid_Obj_RetRefByte) DEFINE_METHOD(CASTHELPERS, STELEMREF, StelemRef, SM_Array_Int_Obj_RetVoid) DEFINE_METHOD(CASTHELPERS, LDELEMAREF, LdelemaRef, SM_Array_Int_PtrVoid_RetRefObj) +#ifdef TARGET_64BIT +DEFINE_METHOD(CASTHELPERS, STELEMREF_NINT, StelemRefNint, SM_Array_IntPtr_Obj_RetVoid) +DEFINE_METHOD(CASTHELPERS, LDELEMAREF_NINT, LdelemaRefNint, SM_Array_IntPtr_PtrVoid_RetRefObj) +#endif DEFINE_CLASS_U(System, GCMemoryInfoData, GCMemoryInfoData) DEFINE_FIELD_U(_highMemoryLoadThresholdBytes, GCMemoryInfoData, highMemLoadThresholdBytes) diff --git a/src/coreclr/vm/ecall.cpp b/src/coreclr/vm/ecall.cpp index ad93743a9cbfa..d95ed9aeff72f 100644 --- a/src/coreclr/vm/ecall.cpp +++ b/src/coreclr/vm/ecall.cpp @@ -137,6 +137,19 @@ void ECall::PopulateManagedCastHelpers() pDest = pMD->GetMultiCallableAddrOfCode(); SetJitHelperFunction(CORINFO_HELP_UNBOX, pDest); +#ifdef TARGET_64BIT + // On 64bit we have different helpers for array indexing with a native int so that + // we can properly throw exceptions; however, these helpers are relatively rarely used + // and do not need the aggressive optimization of the integer based helpers + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__STELEMREF_NINT)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_ARRADDR_ST_I_IMPL, pDest); + + pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__LDELEMAREF_NINT)); + pDest = pMD->GetMultiCallableAddrOfCode(); + SetJitHelperFunction(CORINFO_HELP_LDELEMA_REF_I_IMPL, pDest); +#endif + // Array element accessors are more perf sensitive than other managed helpers and indirection // costs introduced by PreStub could be noticeable (7% to 30% depending on platform). // Other helpers are either more complex, less common, or have their trivial case inlined by the JIT, @@ -151,6 +164,9 @@ void ECall::PopulateManagedCastHelpers() // This helper is marked AggressiveOptimization and its native code is in its final form. // Get the code directly to avoid PreStub indirection. pDest = pMD->GetNativeCode(); +#ifndef TARGET_64BIT + SetJitHelperFunction(CORINFO_HELP_ARRADDR_ST_I_IMPL, pDest); +#endif SetJitHelperFunction(CORINFO_HELP_ARRADDR_ST, pDest); pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__CASTHELPERS__LDELEMAREF)); @@ -158,6 +174,9 @@ void ECall::PopulateManagedCastHelpers() // This helper is marked AggressiveOptimization and its native code is in its final form. // Get the code directly to avoid PreStub indirection. pDest = pMD->GetNativeCode(); +#ifndef TARGET_64BIT + SetJitHelperFunction(CORINFO_HELP_LDELEMA_REF_I_IMPL, pDest); +#endif SetJitHelperFunction(CORINFO_HELP_LDELEMA_REF, pDest); } diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 9653fc2967e46..5b5bfc2d42746 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -604,6 +604,8 @@ DEFINE_METASIG(GM(RetT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, _, M(0))) DEFINE_METASIG_T(SM(Array_Int_Array_Int_Int_RetVoid, C(ARRAY) i C(ARRAY) i i, v)) DEFINE_METASIG_T(SM(Array_Int_Obj_RetVoid, C(ARRAY) i j, v)) DEFINE_METASIG_T(SM(Array_Int_PtrVoid_RetRefObj, C(ARRAY) i P(v), r(j))) +DEFINE_METASIG_T(SM(Array_IntPtr_Obj_RetVoid, C(ARRAY) I j, v)) +DEFINE_METASIG_T(SM(Array_IntPtr_PtrVoid_RetRefObj, C(ARRAY) I P(v), r(j))) DEFINE_METASIG(SM(Obj_IntPtr_Bool_RetVoid, j I F, v)) DEFINE_METASIG(SM(IntPtr_Obj_RetVoid, I j, v)) diff --git a/src/tests/JIT/Directed/Arrays/nintindexoutofrange.cs b/src/tests/JIT/Directed/Arrays/nintindexoutofrange.cs new file mode 100644 index 0000000000000..ab62238c5e1aa --- /dev/null +++ b/src/tests/JIT/Directed/Arrays/nintindexoutofrange.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +using System; +using System.Runtime.CompilerServices; + +class NintIndexOutOfRangeTest +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static void Stelem_Ref(object[] arr, nint i, Object value) + => arr[i] = value; + + [MethodImpl(MethodImplOptions.NoInlining)] + static void LdElemATestHelper(ref object nothingOfInterest) + {} + + [MethodImpl(MethodImplOptions.NoInlining)] + static void LdElemA(object[] arr, nint i) + { + LdElemATestHelper(ref arr[i]); + } + + public static int Main() + { + long longIndex = ((long)1) << 32; + nint index = (nint)longIndex; + bool failed = false; + + // On a 32bit platform, just succeed. + if ((long)index != longIndex) + return 100; + + var arr = new Object[10]; + // Try store to invalid index with null + try + { + Stelem_Ref(arr, index, null); + failed = true; + Console.WriteLine("Failed to throw IndexOutOfRange when storing null"); + } + catch (IndexOutOfRangeException) {} + + // Try store to invalid index with actual value + try + { + Stelem_Ref(arr, index, new object()); + failed = true; + Console.WriteLine("Failed to throw IndexOutOfRange when storing object"); + } + catch (IndexOutOfRangeException) {} + + // Try to load element address + try + { + LdElemA(arr, index); + failed = true; + Console.WriteLine("Failed to throw IndexOutOfRange when accessing element"); + } + catch (IndexOutOfRangeException) {} + + if (failed) + return 1; + else + return 100; + } +} diff --git a/src/tests/JIT/Directed/Arrays/nintindexoutofrange.csproj b/src/tests/JIT/Directed/Arrays/nintindexoutofrange.csproj new file mode 100644 index 0000000000000..8561b69a9ee56 --- /dev/null +++ b/src/tests/JIT/Directed/Arrays/nintindexoutofrange.csproj @@ -0,0 +1,12 @@ + + + Exe + 0 + + + PdbOnly + + + + +