Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Managed StelemRef and LdelemaRef #32722

Merged
merged 11 commits into from
Mar 4, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ private static CastResult TryGet(nuint source, nuint target)
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern ref byte Unbox_Helper(void* toTypeHnd, object 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
Expand Down Expand Up @@ -249,7 +252,7 @@ private static CastResult TryGet(nuint source, nuint target)
return obj;

slowPath:
return IsInstanceHelper(toTypeHnd, obj);
return IsInstance_Helper(toTypeHnd, obj);
}

[DebuggerHidden]
Expand Down Expand Up @@ -304,14 +307,14 @@ private static CastResult TryGet(nuint source, nuint target)
return obj;

slowPath:
return IsInstanceHelper(toTypeHnd, obj);
return IsInstance_Helper(toTypeHnd, obj);
}

[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.NoInlining)]
private static object? IsInstanceHelper(void* toTypeHnd, object obj)
private static object? IsInstance_Helper(void* toTypeHnd, object obj)
{
CastResult result = TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd);
if (result == CastResult.CanCast)
Expand Down Expand Up @@ -364,7 +367,7 @@ private static CastResult TryGet(nuint source, nuint target)
[StackTraceHidden]
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.NoInlining)]
private static object? ChkCastHelper(void* toTypeHnd, object obj)
private static object? ChkCast_Helper(void* toTypeHnd, object obj)
{
CastResult result = TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd);
if (result == CastResult.CanCast)
Expand Down Expand Up @@ -416,7 +419,7 @@ private static CastResult TryGet(nuint source, nuint target)
return obj;

slowPath:
return ChkCastHelper(toTypeHnd, obj);
return ChkCast_Helper(toTypeHnd, obj);
}

[DebuggerHidden]
Expand Down Expand Up @@ -477,7 +480,7 @@ private static CastResult TryGet(nuint source, nuint target)
return obj;

slowPath:
return ChkCastHelper(toTypeHnd, obj);
return ChkCast_Helper(toTypeHnd, obj);
}

[DebuggerHidden]
Expand All @@ -491,5 +494,97 @@ private static ref byte Unbox(void* toTypeHnd, object obj)

return ref Unbox_Helper(toTypeHnd, obj);
}

internal struct ArrayElement
{
public object? Value;
}

[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
private static ref object? ThrowArrayMismatchException()
{
throw new ArrayTypeMismatchException();
}

[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ref object? LdelemaRef(Array array, int index, void* type)
{
// this will throw appropriate exceptions if array is null or access is out of range.
ref object? element = ref Unsafe.As<ArrayElement[]>(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 StelemRef(Array array, int index, object? obj)
{
// this will throw appropriate exceptions if array is null or access is out of range.
ref object? element = ref Unsafe.As<ArrayElement[]>(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);
}

[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
private static void StelemRef_Helper(ref object? element, void* elementType, object obj)
{
CastResult result = TryGet((nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType);
if (result == CastResult.CanCast)
{
WriteBarrier(ref element, obj);
return;
}

StelemRef_Helper_NoCacheLookup(ref element, elementType, obj);
}

[DebuggerHidden]
[StackTraceHidden]
[DebuggerStepThrough]
private static void StelemRef_Helper_NoCacheLookup(ref object? element, void* elementType, object obj)
{
Debug.Assert(obj != null);

obj = IsInstanceOfAny_NoCacheLookup(elementType, obj);
if (obj != null)
{
WriteBarrier(ref element, obj);
return;
}

throw new ArrayTypeMismatchException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ internal unsafe struct MethodTable
public ushort InterfaceCount;
[FieldOffset(ParentMethodTableOffset)]
public MethodTable* ParentMethodTable;
[FieldOffset(ElementTypeOffset)]
public void* ElementType;
[FieldOffset(InterfaceMapOffset)]
public MethodTable** InterfaceMap;

Expand All @@ -322,6 +324,16 @@ internal unsafe struct MethodTable
#endif
;

#if TARGET_64BIT
private const int ElementTypeOffset = 0x30
#else
private const int ElementTypeOffset = 0x20
#endif
#if DEBUG
+ sizeof(nuint) // adjust for debug_m_szClassName
#endif
;

#if TARGET_64BIT
private const int InterfaceMapOffset = 0x38
#else
Expand Down
8 changes: 2 additions & 6 deletions src/coreclr/src/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,8 @@
JITHELPER(CORINFO_HELP_UNBOX_NULLABLE, JIT_Unbox_Nullable, CORINFO_HELP_SIG_4_STACK)

JITHELPER(CORINFO_HELP_GETREFANY, JIT_GetRefAny, CORINFO_HELP_SIG_8_STACK)
#if defined(TARGET_ARM)
DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST, JIT_Stelem_Ref, CORINFO_HELP_SIG_4_STACK)
#else
JITHELPER(CORINFO_HELP_ARRADDR_ST, JIT_Stelem_Ref, CORINFO_HELP_SIG_4_STACK)
#endif // TARGET_ARM
JITHELPER(CORINFO_HELP_LDELEMA_REF, JIT_Ldelema_Ref, CORINFO_HELP_SIG_4_STACK)
DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST, NULL, CORINFO_HELP_SIG_4_STACK)
DYNAMICJITHELPER(CORINFO_HELP_LDELEMA_REF, NULL, CORINFO_HELP_SIG_4_STACK)

// Exceptions
JITHELPER(CORINFO_HELP_THROW, IL_Throw, CORINFO_HELP_SIG_REG_ONLY)
Expand Down
123 changes: 0 additions & 123 deletions src/coreclr/src/vm/amd64/JitHelpers_Fast.asm
Original file line number Diff line number Diff line change
Expand Up @@ -390,129 +390,6 @@ endif
LEAF_END_MARKED JIT_ByRefWriteBarrier, _TEXT


g_pObjectClass equ ?g_pObjectClass@@3PEAVMethodTable@@EA

EXTERN g_pObjectClass:qword
extern ArrayStoreCheck:proc
extern ObjIsInstanceOfCached:proc

; TODO: put definition for this in asmconstants.h
CanCast equ 1

;__declspec(naked) void F_CALL_CONV JIT_Stelem_Ref(PtrArray* array, unsigned idx, Object* val)
LEAF_ENTRY JIT_Stelem_Ref, _TEXT
; check for null PtrArray*
test rcx, rcx
je ThrowNullReferenceException

; we only want the lower 32-bits of edx, it might be dirty
or edx, edx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original code truncates the index to 32bit


; check that index is in bounds
cmp edx, dword ptr [rcx + OFFSETOF__PtrArray__m_NumComponents] ; 8h -> array size offset
jae ThrowIndexOutOfRangeException

; r10 = Array MT
mov r10, [rcx]

; if we're assigning a null object* then we don't need a write barrier
test r8, r8
jz AssigningNull

mov r9, [r10 + OFFSETOF__MethodTable__m_ElementType] ; 10h -> typehandle offset

; check for exact match
cmp r9, [r8]
jne NotExactMatch

DoWrite:
lea rcx, [rcx + 8*rdx + OFFSETOF__PtrArray__m_Array]
mov rdx, r8

; JIT_WriteBarrier(Object** dst, Object* src)
jmp JIT_WriteBarrier

AssigningNull:
; write barrier is not needed for assignment of NULL references
mov [rcx + 8*rdx + OFFSETOF__PtrArray__m_Array], r8
ret

NotExactMatch:
cmp r9, [g_pObjectClass]
je DoWrite

jmp JIT_Stelem_Ref__ObjIsInstanceOfCached_Helper

ThrowNullReferenceException:
mov rcx, CORINFO_NullReferenceException_ASM
jmp JIT_InternalThrow

ThrowIndexOutOfRangeException:
mov rcx, CORINFO_IndexOutOfRangeException_ASM
jmp JIT_InternalThrow
LEAF_END JIT_Stelem_Ref, _TEXT

NESTED_ENTRY JIT_Stelem_Ref__ObjIsInstanceOfCached_Helper, _TEXT
alloc_stack MIN_SIZE
save_reg_postrsp rcx, MIN_SIZE + 8h
save_reg_postrsp rdx, MIN_SIZE + 10h
save_reg_postrsp r8, MIN_SIZE + 18h
END_PROLOGUE

; need to get TypeHandle before setting rcx to be the Obj* because that trashes the PtrArray*
mov rdx, r9
mov rcx, r8

; TypeHandle::CastResult ObjIsInstanceOfCached(Object *pElement, TypeHandle toTypeHnd)
call ObjIsInstanceOfCached

mov rcx, [rsp + MIN_SIZE + 8h]
mov rdx, [rsp + MIN_SIZE + 10h]
mov r8, [rsp + MIN_SIZE + 18h]

cmp eax, CanCast
jne NeedCheck

lea rcx, [rcx + 8*rdx + OFFSETOF__PtrArray__m_Array]
mov rdx, r8
add rsp, MIN_SIZE

; JIT_WriteBarrier(Object** dst, Object* src)
jmp JIT_WriteBarrier

NeedCheck:
add rsp, MIN_SIZE
jmp JIT_Stelem_Ref__ArrayStoreCheck_Helper
NESTED_END JIT_Stelem_Ref__ObjIsInstanceOfCached_Helper, _TEXT

; Need to save r8 to provide a stack address for the Object*
NESTED_ENTRY JIT_Stelem_Ref__ArrayStoreCheck_Helper, _TEXT
alloc_stack MIN_SIZE
save_reg_postrsp rcx, MIN_SIZE + 8h
save_reg_postrsp rdx, MIN_SIZE + 10h
save_reg_postrsp r8, MIN_SIZE + 18h
END_PROLOGUE

lea rcx, [rsp + MIN_SIZE + 18h]
lea rdx, [rsp + MIN_SIZE + 8h]

; HCIMPL2(FC_INNER_RET, ArrayStoreCheck, Object** pElement, PtrArray** pArray)
call ArrayStoreCheck

mov rcx, [rsp + MIN_SIZE + 8h]
mov rdx, [rsp + MIN_SIZE + 10h]
mov r8, [rsp + MIN_SIZE + 18h]

lea rcx, [rcx + 8*rdx + OFFSETOF__PtrArray__m_Array]
mov rdx, r8
add rsp, MIN_SIZE

; JIT_WriteBarrier(Object** dst, Object* src)
jmp JIT_WriteBarrier

NESTED_END JIT_Stelem_Ref__ArrayStoreCheck_Helper, _TEXT


extern JIT_FailFast:proc
extern s_gsCookie:qword

Expand Down
1 change: 0 additions & 1 deletion src/coreclr/src/vm/amd64/cgencpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,6 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain

#define JIT_Stelem_Ref JIT_Stelem_Ref

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Call counting
Expand Down
Loading