Skip to content

Commit ad38529

Browse files
committed
Convert JIT_Box* to C#
1 parent 8fa9785 commit ad38529

File tree

15 files changed

+77
-343
lines changed

15 files changed

+77
-343
lines changed

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

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

520+
// Helpers for boxing
521+
[DebuggerHidden]
522+
private static unsafe object? Box_Nullable(IntPtr handle, ref byte nullableData)
523+
{
524+
MethodTable* srcMT = new TypeHandle((void*)handle).AsMethodTable();
525+
return BoxNullableImpl(srcMT, ref nullableData);
526+
}
527+
528+
[DebuggerHidden]
529+
internal static object? BoxNullableImpl(MethodTable* srcMT, ref byte nullableData)
530+
{
531+
Debug.Assert(srcMT->IsNullable);
532+
533+
// If 'hasValue' is false, return null.
534+
if (!Unsafe.As<byte, bool>(ref nullableData))
535+
return null;
536+
537+
// Allocate a new instance of the T in Nullable<T>.
538+
MethodTable* dstMT = srcMT->InstantiationArg0();
539+
object dst = RuntimeTypeHandle.InternalAllocNoChecks(dstMT);
540+
541+
// Copy data from the Nullable<T>.
542+
ref byte srcData = ref Unsafe.Add(ref nullableData, srcMT->NullableValueAddrOffset);
543+
ref byte dstData = ref RuntimeHelpers.GetRawData(dst);
544+
if (dstMT->ContainsGCPointers)
545+
Buffer.BulkMoveWithWriteBarrier(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytesIfContainsGCPointers());
546+
else
547+
SpanHelpers.Memmove(ref dstData, ref srcData, dstMT->GetNumInstanceFieldBytes());
548+
549+
return dst;
550+
}
551+
552+
[DebuggerHidden]
553+
internal static unsafe object Box(IntPtr handle, ref byte unboxedData)
554+
{
555+
MethodTable* typeMT = new TypeHandle((void*)handle).AsMethodTable();
556+
Debug.Assert(typeMT->IsValueType && !typeMT->IsNullable);
557+
558+
return BoxImpl(typeMT, ref unboxedData);
559+
}
560+
561+
[DebuggerHidden]
562+
internal static unsafe object BoxImpl(MethodTable* typeMT, ref byte unboxedData)
563+
{
564+
Debug.Assert(typeMT != null);
565+
Debug.Assert(typeMT->IsValueType);
566+
567+
object boxed = RuntimeTypeHandle.InternalAlloc(typeMT);
568+
if (typeMT->ContainsGCPointers)
569+
{
570+
Buffer.BulkMoveWithWriteBarrier(ref boxed.GetRawData(), ref unboxedData,
571+
typeMT->GetNumInstanceFieldBytesIfContainsGCPointers());
572+
}
573+
else
574+
{
575+
SpanHelpers.Memmove(ref boxed.GetRawData(), ref unboxedData, typeMT->GetNumInstanceFieldBytes());
576+
}
577+
578+
return boxed;
579+
}
580+
520581
// Helpers for Unboxing
521582
#if FEATURE_TYPEEQUIVALENCE
522583
[DebuggerHidden]
@@ -619,23 +680,7 @@ internal static void Unbox_Nullable(ref byte destPtr, MethodTable* typeMT, objec
619680

620681
ref byte nullableData = ref src.GetRawData();
621682

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;
683+
return BoxNullableImpl(srcMT, ref nullableData);
639684
}
640685

641686
[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.BoxNullableImpl(methodTable, ref data) : CastHelpers.BoxImpl(methodTable, ref data);
450450

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

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 & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ endif
4141

4242
JIT_NEW equ ?JIT_New@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@@Z
4343
CopyValueClassUnchecked equ ?CopyValueClassUnchecked@@YAXPEAX0PEAVMethodTable@@@Z
44-
JIT_Box equ ?JIT_Box@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@PEAX@Z
4544
g_pStringClass equ ?g_pStringClass@@3PEAVMethodTable@@EA
4645
FramedAllocateString equ ?FramedAllocateString@@YAPEAVStringObject@@K@Z
4746
JIT_NewArr1 equ ?JIT_NewArr1@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@_J@Z
@@ -50,7 +49,6 @@ INVALIDGCVALUE equ 0CCCCCCCDh
5049

5150
extern JIT_NEW:proc
5251
extern CopyValueClassUnchecked:proc
53-
extern JIT_Box:proc
5452
extern g_pStringClass:QWORD
5553
extern FramedAllocateString:proc
5654
extern JIT_NewArr1:proc
@@ -197,69 +195,6 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT
197195
jmp JIT_NEW
198196
LEAF_END JIT_TrialAllocSFastSP, _TEXT
199197

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-
263198
LEAF_ENTRY AllocateStringFastUP, _TEXT
264199

265200
; 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: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ FCFuncStart(gRuntimeHelpers)
337337
FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack)
338338
FCFuncElement("AllocTailCallArgBufferWorker", TailCallHelp::AllocTailCallArgBufferWorker)
339339
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
340-
FCFuncElement("Box", JIT_Box)
341340
FCFuncEnd()
342341

343342
FCFuncStart(gMethodTableFuncs)

0 commit comments

Comments
 (0)