Skip to content

Commit 113056f

Browse files
committed
Convert JIT_Box* to C#
1 parent d7e5d95 commit 113056f

File tree

21 files changed

+126
-366
lines changed

21 files changed

+126
-366
lines changed

src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,10 @@ private static bool TrySetSlot(object?[] a, int index, object o)
164164
return false;
165165
}
166166

167-
private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready)
167+
private unsafe MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready)
168168
{
169169
// First, allocate a new multicast delegate just like this one, i.e. same type as the this object
170-
MulticastDelegate result = Unsafe.As<MulticastDelegate>(RuntimeTypeHandle.InternalAllocNoChecks((RuntimeType)GetType()));
170+
MulticastDelegate result = Unsafe.As<MulticastDelegate>(RuntimeTypeHandle.InternalAllocNoChecks(RuntimeHelpers.GetMethodTable(this)));
171171

172172
// Performance optimization - if this already points to a true multicast delegate,
173173
// copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/CastHelpers.cs

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,45 @@ private static void ArrayTypeCheck_Helper(object obj, void* elementType)
517517
}
518518
}
519519

520+
// Helpers for boxing
521+
[DebuggerHidden]
522+
internal static object? Box_Nullable(MethodTable* srcMT, ref byte nullableData)
523+
{
524+
Debug.Assert(srcMT->IsNullable);
525+
526+
if (nullableData == 0)
527+
return null;
528+
529+
// Allocate a new instance of the T in Nullable<T>.
530+
MethodTable* dstMT = srcMT->InstantiationArg0();
531+
ref byte srcValue = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset);
532+
533+
// Delegate to non-nullable boxing implementation
534+
return Box(dstMT, ref srcValue);
535+
}
536+
537+
[DebuggerHidden]
538+
internal static object Box(MethodTable* typeMT, ref byte unboxedData)
539+
{
540+
Debug.Assert(typeMT != null);
541+
Debug.Assert(typeMT->IsValueType);
542+
543+
// A null can be passed for boxing of a null ref.
544+
_ = Unsafe.ReadUnaligned<byte>(ref unboxedData);
545+
546+
object boxed = RuntimeTypeHandle.InternalAllocNoChecks(typeMT);
547+
if (typeMT->ContainsGCPointers)
548+
{
549+
Buffer.BulkMoveWithWriteBarrier(ref boxed.GetRawData(), ref unboxedData, typeMT->GetNumInstanceFieldBytesIfContainsGCPointers());
550+
}
551+
else
552+
{
553+
SpanHelpers.Memmove(ref boxed.GetRawData(), ref unboxedData, typeMT->GetNumInstanceFieldBytes());
554+
}
555+
556+
return boxed;
557+
}
558+
520559
// Helpers for Unboxing
521560
#if FEATURE_TYPEEQUIVALENCE
522561
[DebuggerHidden]
@@ -615,27 +654,8 @@ internal static void Unbox_Nullable(ref byte destPtr, MethodTable* typeMT, objec
615654
[DebuggerHidden]
616655
internal static object? ReboxFromNullable(MethodTable* srcMT, object src)
617656
{
618-
Debug.Assert(srcMT->IsNullable);
619-
620657
ref byte nullableData = ref src.GetRawData();
621-
622-
// If 'hasValue' is false, return null.
623-
if (!Unsafe.As<byte, bool>(ref nullableData))
624-
return null;
625-
626-
// Allocate a new instance of the T in Nullable<T>.
627-
MethodTable* dstMT = srcMT->InstantiationArg0();
628-
object dst = RuntimeTypeHandle.InternalAlloc(dstMT);
629-
630-
// Copy data from the Nullable<T>.
631-
ref byte srcData = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset);
632-
ref byte dstData = ref RuntimeHelpers.GetRawData(dst);
633-
if (dstMT->ContainsGCPointers)
634-
Buffer.BulkMoveWithWriteBarrier(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytesIfContainsGCPointers());
635-
else
636-
SpanHelpers.Memmove(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytes());
637-
638-
return dst;
658+
return Box_Nullable(srcMT, ref nullableData);
639659
}
640660

641661
[DebuggerHidden]

src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,8 +445,8 @@ internal static unsafe bool ObjectHasComponentSize(object obj)
445445
/// <param name="data">A reference to the data to box.</param>
446446
/// <returns>A boxed instance of the value at <paramref name="data"/>.</returns>
447447
/// <remarks>This method includes proper handling for nullable value types as well.</remarks>
448-
[MethodImpl(MethodImplOptions.InternalCall)]
449-
internal static extern unsafe object? Box(MethodTable* methodTable, ref byte data);
448+
internal static unsafe object? Box(MethodTable* methodTable, ref byte data) =>
449+
methodTable->IsNullable ? CastHelpers.Box_Nullable(methodTable, ref data) : CastHelpers.Box(methodTable, ref data);
450450

451451
// Given an object reference, returns its MethodTable*.
452452
//

src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -299,25 +299,27 @@ internal static object InternalAlloc(RuntimeType type)
299299
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAlloc")]
300300
private static unsafe partial void InternalAlloc(MethodTable* pMT, ObjectHandleOnStack result);
301301

302+
303+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
302304
internal static object InternalAllocNoChecks(MethodTable* pMT)
303305
{
304-
object? result = null;
305-
InternalAllocNoChecks(pMT, ObjectHandleOnStack.Create(ref result));
306-
return result!;
307-
}
306+
return InternalAllocNoChecks_FastPath(pMT) ?? InternalAllocNoChecksWorker(pMT);
308307

309-
internal static object InternalAllocNoChecks(RuntimeType type)
310-
{
311-
Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc);
312-
object? result = null;
313-
InternalAllocNoChecks(type.GetNativeTypeHandle().AsMethodTable(), ObjectHandleOnStack.Create(ref result));
314-
GC.KeepAlive(type);
315-
return result!;
308+
[MethodImpl(MethodImplOptions.NoInlining)]
309+
static object InternalAllocNoChecksWorker(MethodTable* pMT)
310+
{
311+
object? result = null;
312+
InternalAllocNoChecks(pMT, ObjectHandleOnStack.Create(ref result));
313+
return result!;
314+
}
316315
}
317316

318317
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAllocNoChecks")]
319318
private static unsafe partial void InternalAllocNoChecks(MethodTable* pMT, ObjectHandleOnStack result);
320319

320+
[MethodImpl(MethodImplOptions.InternalCall)]
321+
private static extern object? InternalAllocNoChecks_FastPath(MethodTable* pMT);
322+
321323
/// <summary>
322324
/// Given a RuntimeType, returns information about how to activate it via calli
323325
/// semantics. This method will ensure the type object is fully initialized within

src/coreclr/inc/jithelpers.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@
132132

133133
JITHELPER(CORINFO_HELP_ISINSTANCEOF_EXCEPTION, JIT_IsInstanceOfException, METHOD__NIL)
134134

135-
DYNAMICJITHELPER(CORINFO_HELP_BOX, JIT_Box, METHOD__NIL)
136-
JITHELPER(CORINFO_HELP_BOX_NULLABLE, JIT_Box, METHOD__NIL)
137-
DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, METHOD__CASTHELPERS__UNBOX)
138-
DYNAMICJITHELPER(CORINFO_HELP_UNBOX_TYPETEST,NULL, METHOD__CASTHELPERS__UNBOX_TYPETEST)
139-
DYNAMICJITHELPER(CORINFO_HELP_UNBOX_NULLABLE,NULL, METHOD__CASTHELPERS__UNBOX_NULLABLE)
135+
DYNAMICJITHELPER(CORINFO_HELP_BOX, NULL, METHOD__CASTHELPERS__BOX)
136+
DYNAMICJITHELPER(CORINFO_HELP_BOX_NULLABLE, NULL, METHOD__CASTHELPERS__BOX_NULLABLE)
137+
DYNAMICJITHELPER(CORINFO_HELP_UNBOX, NULL, METHOD__CASTHELPERS__UNBOX)
138+
DYNAMICJITHELPER(CORINFO_HELP_UNBOX_TYPETEST, NULL, METHOD__CASTHELPERS__UNBOX_TYPETEST)
139+
DYNAMICJITHELPER(CORINFO_HELP_UNBOX_NULLABLE, NULL, METHOD__CASTHELPERS__UNBOX_NULLABLE)
140140

141141
DYNAMICJITHELPER(CORINFO_HELP_GETREFANY, NULL, METHOD__TYPED_REFERENCE__GETREFANY)
142142
DYNAMICJITHELPER(CORINFO_HELP_ARRADDR_ST, NULL, METHOD__CASTHELPERS__STELEMREF)

src/coreclr/vm/amd64/JitHelpers_Slow.asm

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,13 @@ EXTERN g_GCShadowEnd:QWORD
4040
endif
4141

4242
JIT_NEW equ ?JIT_New@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@@Z
43-
CopyValueClassUnchecked equ ?CopyValueClassUnchecked@@YAXPEAX0PEAVMethodTable@@@Z
44-
JIT_Box equ ?JIT_Box@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@PEAX@Z
4543
g_pStringClass equ ?g_pStringClass@@3PEAVMethodTable@@EA
4644
FramedAllocateString equ ?FramedAllocateString@@YAPEAVStringObject@@K@Z
4745
JIT_NewArr1 equ ?JIT_NewArr1@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@_J@Z
4846

4947
INVALIDGCVALUE equ 0CCCCCCCDh
5048

5149
extern JIT_NEW:proc
52-
extern CopyValueClassUnchecked:proc
53-
extern JIT_Box:proc
5450
extern g_pStringClass:QWORD
5551
extern FramedAllocateString:proc
5652
extern JIT_NewArr1:proc
@@ -197,69 +193,6 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT
197193
jmp JIT_NEW
198194
LEAF_END JIT_TrialAllocSFastSP, _TEXT
199195

200-
; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
201-
NESTED_ENTRY JIT_BoxFastUP, _TEXT
202-
203-
; m_BaseSize is guaranteed to be a multiple of 8.
204-
mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
205-
206-
inc [g_global_alloc_lock]
207-
jnz JIT_Box
208-
209-
mov rax, [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr] ; alloc_ptr
210-
mov r10, [g_global_alloc_context + OFFSETOF__ee_alloc_context__m_CombinedLimit] ; m_CombinedLimit
211-
212-
add r8, rax
213-
214-
cmp r8, r10
215-
ja NoAlloc
216-
217-
test rdx, rdx
218-
je NullRef
219-
220-
mov qword ptr [g_global_alloc_context + OFFSETOF__ee_alloc_context__alloc_ptr], r8 ; update the alloc ptr
221-
mov [rax], rcx
222-
mov [g_global_alloc_lock], -1
223-
224-
; Check whether the object contains pointers
225-
test dword ptr [rcx + OFFSETOF__MethodTable__m_dwFlags], MethodTable__enum_flag_ContainsGCPointers
226-
jnz ContainsPointers
227-
228-
; We have no pointers - emit a simple inline copy loop
229-
230-
mov ecx, [rcx + OFFSET__MethodTable__m_BaseSize]
231-
sub ecx, 18h ; sizeof(ObjHeader) + sizeof(Object) + last slot
232-
233-
CopyLoop:
234-
mov r8, [rdx+rcx]
235-
mov [rax+rcx+8], r8
236-
237-
sub ecx, 8
238-
jge CopyLoop
239-
REPRET
240-
241-
ContainsPointers:
242-
243-
; Do call to CopyValueClassUnchecked(object, data, pMT)
244-
245-
push_vol_reg rax
246-
alloc_stack 20h
247-
END_PROLOGUE
248-
249-
mov r8, rcx
250-
lea rcx, [rax + 8]
251-
call CopyValueClassUnchecked
252-
253-
add rsp, 20h
254-
pop rax
255-
ret
256-
257-
NoAlloc:
258-
NullRef:
259-
mov [g_global_alloc_lock], -1
260-
jmp JIT_Box
261-
NESTED_END JIT_BoxFastUP, _TEXT
262-
263196
LEAF_ENTRY AllocateStringFastUP, _TEXT
264197

265198
; We were passed the number of characters in ECX

src/coreclr/vm/arm/stubs.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1652,7 +1652,6 @@ void InitJITHelpers1()
16521652
SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable);
16531653
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
16541654
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
1655-
SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable);
16561655

16571656
ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
16581657
}

src/coreclr/vm/arm64/stubs.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,6 @@ void InitJITHelpers1()
878878
SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable);
879879
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
880880
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
881-
SetJitHelperFunction(CORINFO_HELP_BOX, JIT_Box_MP_FastPortable);
882881

883882
ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
884883
}

src/coreclr/vm/corelib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,12 @@ DEFINE_METHOD(CASTHELPERS, CHKCASTANY, ChkCastAny, SM_Ptr
12491249
DEFINE_METHOD(CASTHELPERS, CHKCASTINTERFACE, ChkCastInterface, SM_PtrVoid_Obj_RetObj)
12501250
DEFINE_METHOD(CASTHELPERS, CHKCASTCLASS, ChkCastClass, SM_PtrVoid_Obj_RetObj)
12511251
DEFINE_METHOD(CASTHELPERS, CHKCASTCLASSSPECIAL, ChkCastClassSpecial, SM_PtrVoid_Obj_RetObj)
1252+
DEFINE_METHOD(CASTHELPERS, BOX, Box, NoSig)
12521253
DEFINE_METHOD(CASTHELPERS, UNBOX, Unbox, NoSig)
12531254
DEFINE_METHOD(CASTHELPERS, STELEMREF, StelemRef, SM_ArrObject_IntPtr_Obj_RetVoid)
12541255
DEFINE_METHOD(CASTHELPERS, LDELEMAREF, LdelemaRef, SM_ArrObject_IntPtr_PtrVoid_RetRefObj)
12551256
DEFINE_METHOD(CASTHELPERS, ARRAYTYPECHECK, ArrayTypeCheck, SM_Obj_Array_RetVoid)
1257+
DEFINE_METHOD(CASTHELPERS, BOX_NULLABLE, Box_Nullable, NoSig)
12561258
DEFINE_METHOD(CASTHELPERS, UNBOX_NULLABLE, Unbox_Nullable, NoSig)
12571259
DEFINE_METHOD(CASTHELPERS, UNBOX_TYPETEST, Unbox_TypeTest, NoSig)
12581260

src/coreclr/vm/ecalllist.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ FCFuncStart(gCOMTypeHandleFuncs)
9797
FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables)
9898
FCFuncElement("IsUnmanagedFunctionPointer", RuntimeTypeHandle::IsUnmanagedFunctionPointer)
9999
FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles)
100+
FCFuncElement("InternalAllocNoChecks_FastPath", RuntimeTypeHandle::InternalAllocNoChecks_FastPath)
100101
FCFuncEnd()
101102

102103
FCFuncStart(gMetaDataImport)
@@ -337,7 +338,6 @@ FCFuncStart(gRuntimeHelpers)
337338
FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack)
338339
FCFuncElement("AllocTailCallArgBufferWorker", TailCallHelp::AllocTailCallArgBufferWorker)
339340
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
340-
FCFuncElement("Box", JIT_Box)
341341
FCFuncEnd()
342342

343343
FCFuncStart(gMethodTableFuncs)

0 commit comments

Comments
 (0)