Skip to content

Remove HMFs from JIT helpers #111134

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

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,11 @@ static void NotifyOfCrossThreadDependencySlow()
// report the notification depending on its settings.
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "DebugDebugger_CustomNotification")]
private static partial void CustomNotification(ObjectHandleOnStack data);

// implementation of CORINFO_HELP_USER_BREAKPOINT
[StackTraceHidden]
[DebuggerStepThrough]
[DebuggerHidden]
internal static void UserBreakpoint() => Break();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,22 @@ public uint GetNumInstanceFieldBytesIfContainsGCPointers()
}
}

// Subset of src\vm\typedesc.h
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct TypeDesc
{
private uint _typeAndFlags;
private nint _exposedClassObject;

public RuntimeType? ExposedClassObject
{
get
{
return *(RuntimeType*)Unsafe.AsPointer(ref _exposedClassObject);
}
}
}

[StructLayout(LayoutKind.Sequential)]
internal unsafe ref struct DynamicStaticsInfo
{
Expand Down Expand Up @@ -1090,6 +1106,18 @@ public bool IsTypeDesc
return (MethodTable*)m_asTAddr;
}

/// <summary>
/// Gets the <see cref="TypeDesc"/> pointer wrapped by the current instance.
/// </summary>
/// <remarks>This is only safe to call if <see cref="IsTypeDesc"/> returned <see langword="true"/>.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TypeDesc* AsTypeDesc()
{
Debug.Assert(IsTypeDesc);

return (TypeDesc*)((nint)m_asTAddr & ~2); // Drop the second lowest bit.
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TypeHandle TypeHandleOf<T>()
{
Expand Down
22 changes: 17 additions & 5 deletions src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal RuntimeType GetRuntimeTypeChecked() =>
/// <param name="value">An IntPtr handle to a RuntimeType to create a <see cref="RuntimeTypeHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeTypeHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeTypeHandle FromIntPtr(IntPtr value) =>
new RuntimeTypeHandle(value == IntPtr.Zero ? null : GetRuntimeTypeFromHandle(value));
new RuntimeTypeHandle(GetRuntimeTypeFromHandleMaybeNull(value));

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow")]
private static partial void GetRuntimeTypeFromHandleSlow(
Expand All @@ -46,12 +46,24 @@ private static RuntimeType GetRuntimeTypeFromHandleSlow(IntPtr handle)
return typeObject!;
}

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeType? GetRuntimeTypeFromHandleIfExists(IntPtr handle);
// implementation of CORINFO_HELP_GETSYNCFROMCLASSHANDLE, CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE
internal static unsafe RuntimeType GetRuntimeTypeFromHandle(IntPtr handle)
{
TypeHandle h = new((void*)handle);
return (h.IsTypeDesc
? h.AsTypeDesc()->ExposedClassObject
: h.AsMethodTable()->AuxiliaryData->ExposedClassObject) ?? GetRuntimeTypeFromHandleSlow(handle);
}

private static RuntimeType GetRuntimeTypeFromHandle(IntPtr handle)
// implementation of CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL
internal static RuntimeType? GetRuntimeTypeFromHandleMaybeNull(IntPtr handle)
{
return GetRuntimeTypeFromHandleIfExists(handle) ?? GetRuntimeTypeFromHandleSlow(handle);
if (handle == IntPtr.Zero)
{
return null;
}

return GetRuntimeTypeFromHandle(handle);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/debug/ee/frameinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct FrameInfo

// Set to true if we are dealing with an internal explicit frame. Currently this is only true
// for prestub frames, security frames, funceval frames, and certain debugger-specific frames
// (e.g. DebuggerClassInitMarkFrame, DebuggerSecurityCodeMarkFrame).
// (e.g. DebuggerClassInitMarkFrame).
// This affects HasMethodFrame() below.
bool internal;

Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@
// Exceptions
DYNAMICJITHELPER(CORINFO_HELP_THROW, IL_Throw, METHOD__NIL)
DYNAMICJITHELPER(CORINFO_HELP_RETHROW, IL_Rethrow, METHOD__NIL)
JITHELPER(CORINFO_HELP_USER_BREAKPOINT, JIT_UserBreakpoint, METHOD__NIL)
DYNAMICJITHELPER(CORINFO_HELP_USER_BREAKPOINT, NULL, METHOD__DEBUGGER__USERBREAKPOINT)
DYNAMICJITHELPER_NOINDIRECT(CORINFO_HELP_RNGCHKFAIL, NULL, METHOD__THROWHELPERS__THROWINDEXOUTOFRANGEEXCEPTION)
DYNAMICJITHELPER_NOINDIRECT(CORINFO_HELP_OVERFLOW, NULL, METHOD__THROWHELPERS__THROWOVERFLOWEXCEPTION)
DYNAMICJITHELPER_NOINDIRECT(CORINFO_HELP_THROWDIVZERO, NULL, METHOD__THROWHELPERS__THROWDIVIDEBYZEROEXCEPTION)
Expand All @@ -145,7 +145,7 @@
JITHELPER(CORINFO_HELP_MON_EXIT, JIT_MonExitWorker, METHOD__NIL)

JITHELPER(CORINFO_HELP_GETCLASSFROMMETHODPARAM, JIT_GetClassFromMethodParam, METHOD__NIL)
JITHELPER(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, JIT_GetRuntimeType, METHOD__NIL)
DYNAMICJITHELPER(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLE)

// GC support
DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, METHOD__NIL)
Expand Down Expand Up @@ -228,12 +228,12 @@
// Generics
DYNAMICJITHELPER(CORINFO_HELP_RUNTIMEHANDLE_METHOD, NULL, METHOD__GENERICSHELPERS__METHOD)
DYNAMICJITHELPER(CORINFO_HELP_RUNTIMEHANDLE_CLASS, NULL, METHOD__GENERICSHELPERS__CLASS)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, JIT_GetRuntimeType, METHOD__NIL)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, JIT_GetRuntimeType_MaybeNull, METHOD__NIL)
DYNAMICJITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLE)
DYNAMICJITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLEMAYBENULL)
DYNAMICJITHELPER(CORINFO_HELP_METHODDESC_TO_STUBRUNTIMEMETHOD, NULL, METHOD__STUBMETHODINFO__FROMPTR)
DYNAMICJITHELPER(CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD, NULL, METHOD__STUBFIELDINFO__FROMPTR)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, JIT_GetRuntimeType, METHOD__NIL)
JITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, JIT_GetRuntimeType_MaybeNull, METHOD__NIL)
DYNAMICJITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLE)
DYNAMICJITHELPER(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, NULL, METHOD__RT_TYPE_HANDLE__GETRUNTIMETYPEFROMHANDLEMAYBENULL)

DYNAMICJITHELPER(CORINFO_HELP_VIRTUAL_FUNC_PTR, NULL, METHOD__VIRTUALDISPATCHHELPERS__VIRTUALFUNCTIONPOINTER)

Expand Down
1 change: 0 additions & 1 deletion src/coreclr/inc/vptr_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ VPTR_CLASS(ComPrestubMethodFrame)
VPTR_CLASS(InterpreterFrame)
#endif // FEATURE_INTERPRETER
VPTR_CLASS(DebuggerClassInitMarkFrame)
VPTR_CLASS(DebuggerSecurityCodeMarkFrame)
VPTR_CLASS(DebuggerExitFrame)
VPTR_CLASS(DebuggerU2MCatchHandlerFrame)
VPTR_CLASS(FaultingExceptionFrame)
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ DEFINE_METHOD(THREAD_START_EXCEPTION,EX_CTOR, .ctor,
DEFINE_CLASS(TYPE_HANDLE, System, RuntimeTypeHandle)
DEFINE_CLASS(RT_TYPE_HANDLE, System, RuntimeTypeHandle)
DEFINE_METHOD(RT_TYPE_HANDLE, PVOID_CTOR, .ctor, IM_RuntimeType_RetVoid)
DEFINE_METHOD(RT_TYPE_HANDLE, GETRUNTIMETYPEFROMHANDLE,GetRuntimeTypeFromHandle, SM_IntPtr_RetRuntimeType)
DEFINE_METHOD(RT_TYPE_HANDLE, GETRUNTIMETYPEFROMHANDLEMAYBENULL,GetRuntimeTypeFromHandleMaybeNull, SM_IntPtr_RetRuntimeType)
DEFINE_METHOD(RT_TYPE_HANDLE, TO_INTPTR, ToIntPtr, SM_RuntimeTypeHandle_RetIntPtr)
#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(RT_TYPE_HANDLE, ALLOCATECOMOBJECT, AllocateComObject, SM_VoidPtr_RetObj)
Expand Down Expand Up @@ -929,7 +931,7 @@ DEFINE_CLASS(WEAKREFERENCE, System, WeakReference)
DEFINE_CLASS(WEAKREFERENCEGENERIC, System, WeakReference`1)

DEFINE_CLASS(DEBUGGER, Diagnostics, Debugger)
DEFINE_METHOD(DEBUGGER, BREAK, Break, SM_RetVoid)
DEFINE_METHOD(DEBUGGER, USERBREAKPOINT, UserBreakpoint, SM_RetVoid)

DEFINE_CLASS(BUFFER, System, Buffer)
DEFINE_METHOD(BUFFER, MEMCPY_PTRBYTE_ARRBYTE, Memcpy, SM_PtrByte_Int_ArrByte_Int_Int_RetVoid)
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables)
FCFuncElement("IsUnmanagedFunctionPointer", RuntimeTypeHandle::IsUnmanagedFunctionPointer)
FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles)
FCFuncElement("GetRuntimeTypeFromHandleIfExists", RuntimeTypeHandle::GetRuntimeTypeFromHandleIfExists)
FCFuncEnd()

FCFuncStart(gMetaDataImport)
Expand Down
6 changes: 1 addition & 5 deletions src/coreclr/vm/frames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,15 +311,11 @@ bool Frame::HasValidVTablePtr(Frame * pFrame)
#ifndef DACCESS_COMPILE
TADDR vptr = pFrame->GetVTablePtr();
//
// Helper MethodFrame,GCFrame,DebuggerSecurityCodeMarkFrame are the most
// common frame types, explicitly check for them.
// Explicitly check for the most common frames.
//
if (vptr == HelperMethodFrame::GetMethodFrameVPtr())
return true;

if (vptr == DebuggerSecurityCodeMarkFrame::GetMethodFrameVPtr())
return true;

//
// otherwise consult the hashtable
//
Expand Down
49 changes: 3 additions & 46 deletions src/coreclr/vm/frames.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@
// |
// +-DebuggerClassInitMarkFrame - marker frame to indicate that "class init" code is running
// |
// +-DebuggerSecurityCodeMarkFrame - marker frame to indicate that security code is running
// |
// +-DebuggerExitFrame - marker frame to indicate that a "break" IL instruction is being executed
// +-DebuggerExitFrame - marker frame to indicate control flow has left the runtime
// |
// +-DebuggerU2MCatchHandlerFrame - marker frame to indicate that native code is going to catch and
// | swallow a managed exception
Expand Down Expand Up @@ -225,7 +223,6 @@ FRAME_TYPE_NAME(InterpreterFrame)
FRAME_TYPE_NAME(ProtectByRefsFrame)
FRAME_TYPE_NAME(ProtectValueClassFrame)
FRAME_TYPE_NAME(DebuggerClassInitMarkFrame)
FRAME_TYPE_NAME(DebuggerSecurityCodeMarkFrame)
FRAME_TYPE_NAME(DebuggerExitFrame)
FRAME_TYPE_NAME(DebuggerU2MCatchHandlerFrame)
FRAME_TYPE_NAME(InlinedCallFrame)
Expand Down Expand Up @@ -2671,50 +2668,10 @@ class DebuggerClassInitMarkFrame : public Frame
DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerClassInitMarkFrame)
};


//------------------------------------------------------------------------
// DebuggerSecurityCodeMarkFrame is a small frame whose only purpose in
// life is to mark for the debugger that "security code" is
// being run. It does nothing useful except return good values from
// GetFrameType and GetInterception.
//------------------------------------------------------------------------

class DebuggerSecurityCodeMarkFrame : public Frame
{
VPTR_VTABLE_CLASS(DebuggerSecurityCodeMarkFrame, Frame)

public:
#ifndef DACCESS_COMPILE
DebuggerSecurityCodeMarkFrame()
{
WRAPPER_NO_CONTRACT;
Push();
}
#endif

virtual int GetFrameType()
{
LIMITED_METHOD_DAC_CONTRACT;
return TYPE_INTERCEPTION;
}

virtual Interception GetInterception()
{
LIMITED_METHOD_DAC_CONTRACT;
return INTERCEPTION_SECURITY;
}

// Keep as last entry in class
DEFINE_VTABLE_GETTER_AND_DTOR(DebuggerSecurityCodeMarkFrame)
};

//------------------------------------------------------------------------
// DebuggerExitFrame is a small frame whose only purpose in
// life is to mark for the debugger that there is an exit transiton on
// the stack. This is special cased for the "break" IL instruction since
// it is an fcall using a helper frame which returns TYPE_CALL instead of
// an ecall (as in System.Diagnostics.Debugger.Break()) which returns
// TYPE_EXIT. This just makes the two consistent for debugging services.
// life is to mark for the debugger that there is an exit transition on
// the stack.
//------------------------------------------------------------------------

class DebuggerExitFrame : public Frame
Expand Down
80 changes: 0 additions & 80 deletions src/coreclr/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1508,61 +1508,6 @@ HCIMPL3(void, Jit_NativeMemSet, void* pDest, int value, size_t length)
}
HCIMPLEND

NOINLINE HCIMPL1(Object*, JIT_GetRuntimeType_Framed, CORINFO_CLASS_HANDLE type)
{
FCALL_CONTRACT;

TypeHandle typeHandle(type);

// Array/other type handle case.
OBJECTREF refType = typeHandle.GetManagedClassObjectIfExists();
if (refType == NULL)
{
HELPER_METHOD_FRAME_BEGIN_RET_1(refType);
refType = typeHandle.GetManagedClassObject();
HELPER_METHOD_FRAME_END();
}

return OBJECTREFToObject(refType);
}
HCIMPLEND

#include <optsmallperfcritical.h>
HCIMPL1(Object*, JIT_GetRuntimeType, CORINFO_CLASS_HANDLE type)
{
FCALL_CONTRACT;

TypeHandle typeHnd(type);

if (!typeHnd.IsTypeDesc())
{
// Most common... and fastest case
OBJECTREF typePtr = typeHnd.AsMethodTable()->GetManagedClassObjectIfExists();
if (typePtr != NULL)
{
return OBJECTREFToObject(typePtr);
}
}

ENDFORBIDGC();
return HCCALL1(JIT_GetRuntimeType_Framed, type);
}
HCIMPLEND

HCIMPL1(Object*, JIT_GetRuntimeType_MaybeNull, CORINFO_CLASS_HANDLE type)
{
FCALL_CONTRACT;

if (type == NULL)
return NULL;;

ENDFORBIDGC();
return HCCALL1(JIT_GetRuntimeType, type);
}
HCIMPLEND
#include <optdefault.h>


// Helper for synchronized static methods in shared generics code
#include <optsmallperfcritical.h>
HCIMPL1(CORINFO_CLASS_HANDLE, JIT_GetClassFromMethodParam, CORINFO_METHOD_HANDLE methHnd_)
Expand Down Expand Up @@ -2100,31 +2045,6 @@ HCIMPLEND
//
//========================================================================

/*********************************************************************/
// Called by the JIT whenever a cee_break instruction should be executed.
//
HCIMPL0(void, JIT_UserBreakpoint)
{
FCALL_CONTRACT;

HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame

#ifdef DEBUGGING_SUPPORTED
FrameWithCookie<DebuggerExitFrame> __def;

MethodDescCallSite debuggerBreak(METHOD__DEBUGGER__BREAK);

debuggerBreak.Call((ARG_SLOT*)NULL);

__def.Pop();
#else // !DEBUGGING_SUPPORTED
_ASSERTE(!"JIT_UserBreakpoint called, but debugging support is not available in this build.");
#endif // !DEBUGGING_SUPPORTED

HELPER_METHOD_FRAME_END_POLL();
}
HCIMPLEND

#if defined(_MSC_VER)
// VC++ Compiler intrinsic.
extern "C" void * _ReturnAddress(void);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ DEFINE_METASIG(IM(ArrChar_Int_Int_RetVoid, a(u) i i, v))
DEFINE_METASIG_T(IM(ArrType_ArrException_Str_RetVoid, a(C(TYPE)) a(C(EXCEPTION)) s, v))
DEFINE_METASIG(IM(RefInt_RefInt_RefInt_RetArrByte, r(i) r(i) r(i), a(b)))
DEFINE_METASIG_T(IM(RefInt_RetRuntimeType, r(i) , C(CLASS)))
DEFINE_METASIG_T(SM(IntPtr_RetRuntimeType, I , C(CLASS)))
DEFINE_METASIG_T(IM(RuntimeType_RetVoid, C(CLASS) , v))

DEFINE_METASIG_T(IM(RuntimeArgumentHandle_PtrVoid_RetVoid, g(ARGUMENT_HANDLE) P(v), v))
Expand Down
11 changes: 0 additions & 11 deletions src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,6 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow(
END_QCALL;
}

FCIMPL1(ReflectClassBaseObject*, RuntimeTypeHandle::GetRuntimeTypeFromHandleIfExists, EnregisteredTypeHandle th)
{
FCALL_CONTRACT;

_ASSERTE(th != NULL);

TypeHandle typeHandle = TypeHandle::FromPtr(th);
return (ReflectClassBaseObject*)OBJECTREFToObject(typeHandle.GetManagedClassObjectIfExists());
}
FCIMPLEND

#ifdef FEATURE_TYPEEQUIVALENCE
extern "C" BOOL QCALLTYPE RuntimeTypeHandle_IsEquivalentTo(QCall::TypeHandle rtType1, QCall::TypeHandle rtType2)
{
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ class RuntimeTypeHandle
ReflectClassBaseObject *pRuntimeTypeDONOTUSEDIRECTLY;

// Static method on RuntimeTypeHandle
static FCDECL1(ReflectClassBaseObject*, GetRuntimeTypeFromHandleIfExists, EnregisteredTypeHandle th);

static FCDECL1(AssemblyBaseObject*, GetAssemblyIfExists, ReflectClassBaseObject *pType);
static FCDECL1(ReflectModuleBaseObject*, GetModuleIfExists, ReflectClassBaseObject* pType);
static FCDECL1(INT32, GetAttributes, ReflectClassBaseObject* pType);
Expand Down
Loading
Loading