-
Notifications
You must be signed in to change notification settings - Fork 5.1k
GC polling in unboxing JIT helpers #32353
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
Changes from all commits
af57efd
367e70e
0af207a
ec839d8
55a812c
7c325e0
3f71c1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2972,6 +2972,7 @@ NOINLINE HCIMPL3(VOID, JIT_Unbox_Nullable_Framed, void * destPtr, MethodTable* t | |
{ | ||
COMPlusThrowInvalidCastException(&objRef, TypeHandle(typeMT)); | ||
} | ||
HELPER_METHOD_POLL(); | ||
HELPER_METHOD_FRAME_END(); | ||
} | ||
HCIMPLEND | ||
|
@@ -2991,6 +2992,7 @@ HCIMPL3(VOID, JIT_Unbox_Nullable, void * destPtr, CORINFO_CLASS_HANDLE type, Obj | |
if (Nullable::UnBoxNoGC(destPtr, objRef, typeMT)) | ||
{ | ||
// exact match (type equivalence not needed) | ||
FC_GC_POLL(); | ||
return; | ||
} | ||
|
||
|
@@ -3001,23 +3003,33 @@ HCIMPL3(VOID, JIT_Unbox_Nullable, void * destPtr, CORINFO_CLASS_HANDLE type, Obj | |
HCIMPLEND | ||
|
||
/*************************************************************/ | ||
/* framed helper that handles full-blown type equivalence */ | ||
NOINLINE HCIMPL2(LPVOID, JIT_Unbox_Helper_Framed, CORINFO_CLASS_HANDLE type, Object* obj) | ||
/* framed Unbox helper that handles enums and full-blown type equivalence */ | ||
NOINLINE HCIMPL2(LPVOID, Unbox_Helper_Framed, MethodTable* pMT1, Object* obj) | ||
{ | ||
FCALL_CONTRACT; | ||
|
||
LPVOID result = NULL; | ||
MethodTable* pMT2 = obj->GetMethodTable(); | ||
|
||
OBJECTREF objRef = ObjectToOBJECTREF(obj); | ||
HELPER_METHOD_FRAME_BEGIN_RET_1(objRef); | ||
if (TypeHandle(type).IsEquivalentTo(objRef->GetTypeHandle())) | ||
HELPER_METHOD_POLL(); | ||
|
||
if (pMT1->GetInternalCorElementType() == pMT2->GetInternalCorElementType() && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moving this inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We return a ref to the boxed value. If I want to poll, I need to protect the box. Is there a way to protect without a frame? In reply to: 379777249 [](ancestors = 379777249) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One way to do this is to use fast path without HMF when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another way to do this would be to introduce There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right. A flag check would not trash the refs and should be much cheaper. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With suggested changes ( That is - as long as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should be also able to make the enum case faster by using |
||
(pMT1->IsEnum() || pMT1->IsTruePrimitive()) && | ||
(pMT2->IsEnum() || pMT2->IsTruePrimitive())) | ||
{ | ||
// we allow enums and their primitive type to be interchangable | ||
result = objRef->GetData(); | ||
} | ||
else if (pMT1->IsEquivalentTo(pMT2)) | ||
{ | ||
// the structures are equivalent | ||
result = objRef->GetData(); | ||
} | ||
else | ||
{ | ||
COMPlusThrowInvalidCastException(&objRef, TypeHandle(type)); | ||
COMPlusThrowInvalidCastException(&objRef, TypeHandle(pMT1)); | ||
} | ||
HELPER_METHOD_FRAME_END(); | ||
|
||
|
@@ -3026,59 +3038,34 @@ NOINLINE HCIMPL2(LPVOID, JIT_Unbox_Helper_Framed, CORINFO_CLASS_HANDLE type, Obj | |
HCIMPLEND | ||
|
||
/*************************************************************/ | ||
/* the uncommon case for the helper below (allowing enums to be unboxed | ||
as their underlying type */ | ||
LPVOID __fastcall JIT_Unbox_Helper(CORINFO_CLASS_HANDLE type, Object* obj) | ||
/* Unbox helper that handles enums */ | ||
HCIMPL2(LPVOID, Unbox_Helper, CORINFO_CLASS_HANDLE type, Object* obj) | ||
{ | ||
FCALL_CONTRACT; | ||
|
||
TypeHandle typeHnd(type); | ||
// boxable types have method tables | ||
_ASSERTE(!typeHnd.IsTypeDesc()); | ||
|
||
CorElementType type1 = typeHnd.GetInternalCorElementType(); | ||
|
||
// we allow enums and their primtive type to be interchangable | ||
MethodTable* pMT1 = typeHnd.AsMethodTable(); | ||
// must be a value type | ||
_ASSERTE(pMT1->IsValueType()); | ||
|
||
MethodTable* pMT2 = obj->GetMethodTable(); | ||
CorElementType type2 = pMT2->GetInternalCorElementType(); | ||
if (type1 == type2) | ||
|
||
// we allow enums and their primitive type to be interchangable. | ||
// if suspension is requested, defer to the framed helper. | ||
if (pMT1->GetInternalCorElementType() == pMT2->GetInternalCorElementType() && | ||
(pMT1->IsEnum() || pMT1->IsTruePrimitive()) && | ||
(pMT2->IsEnum() || pMT2->IsTruePrimitive()) && | ||
g_TrapReturningThreads.LoadWithoutBarrier() == 0) | ||
{ | ||
MethodTable* pMT1 = typeHnd.AsMethodTable(); | ||
if (pMT1 && (pMT1->IsEnum() || pMT1->IsTruePrimitive()) && | ||
(pMT2->IsEnum() || pMT2->IsTruePrimitive())) | ||
{ | ||
_ASSERTE(CorTypeInfo::IsPrimitiveType_NoThrow(type1)); | ||
return(obj->GetData()); | ||
} | ||
return obj->GetData(); | ||
} | ||
|
||
// Even less common cases (type equivalence) go to a framed helper. | ||
// Fall back to a framed helper that can also handle GC suspension and type equivalence. | ||
ENDFORBIDGC(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to keep |
||
return HCCALL2(JIT_Unbox_Helper_Framed, type, obj); | ||
} | ||
|
||
/*************************************************************/ | ||
HCIMPL2(LPVOID, JIT_Unbox, CORINFO_CLASS_HANDLE type, Object* obj) | ||
{ | ||
FCALL_CONTRACT; | ||
|
||
TypeHandle typeHnd(type); | ||
VALIDATEOBJECT(obj); | ||
_ASSERTE(!typeHnd.IsTypeDesc()); // boxable types have method tables | ||
|
||
// This has been tuned so that branch predictions are good | ||
// (fall through for forward branches) for the common case | ||
if (obj != NULL) { | ||
if (obj->GetMethodTable() == typeHnd.AsMethodTable()) | ||
return(obj->GetData()); | ||
else { | ||
// Stuff the uncommon case into a helper so that | ||
// its register needs don't cause spills that effect | ||
// the common case above. | ||
return JIT_Unbox_Helper(type, obj); | ||
} | ||
} | ||
|
||
FCThrow(kNullReferenceException); | ||
return HCCALL2(Unbox_Helper_Framed, pMT1, obj); | ||
} | ||
HCIMPLEND | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This place too?