Skip to content
Closed
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
23 changes: 23 additions & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -2206,6 +2206,29 @@ class ICorStaticInfo
// should only be called when the input type is in fact a generic type.
virtual CORINFO_CLASS_HANDLE getTypeDefinition(CORINFO_CLASS_HANDLE type) = 0;

//------------------------------------------------------------------------------
// findTypeByName: Resolve a type by name within the assembly containing the given type.
//
// Arguments:
// typeInAssembly - A type handle identifying the target assembly
// typeNameModule - The module containing the type name string token
// typeNameToken - The metadata token for the string literal with the type name
//
// Return Value:
// The class handle for the resolved type, or NO_CLASS_HANDLE if the type
// cannot be found within the assembly.
//
// Remarks:
// This is used to intrinsify typeof(Foo).Assembly.GetType("Bar") patterns.
// The type name is read from the metadata string token and resolved within
// the assembly that contains typeInAssembly. Only simple type names are
// supported (no arrays, pointers, or generic instantiations).
virtual CORINFO_CLASS_HANDLE findTypeByName(
CORINFO_CLASS_HANDLE typeInAssembly, /* IN */
CORINFO_MODULE_HANDLE typeNameModule, /* IN */
unsigned typeNameToken /* IN */
) = 0;

// Decides if you have any limitations for inlining. If everything's OK, it will return
// INLINE_PASS.
//
Expand Down
5 changes: 5 additions & 0 deletions src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ bool haveSameMethodDefinition(
CORINFO_CLASS_HANDLE getTypeDefinition(
CORINFO_CLASS_HANDLE type) override;

CORINFO_CLASS_HANDLE findTypeByName(
CORINFO_CLASS_HANDLE typeInAssembly,
CORINFO_MODULE_HANDLE typeNameModule,
unsigned typeNameToken) override;

CorInfoInline canInline(
CORINFO_METHOD_HANDLE callerHnd,
CORINFO_METHOD_HANDLE calleeHnd) override;
Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

constexpr GUID JITEEVersionIdentifier = { /* e92fbf65-4856-4729-ab9e-f66f7adcecf9 */
0xe92fbf65,
0x4856,
0x4729,
{0xab, 0x9e, 0xf6, 0x6f, 0x7a, 0xdc, 0xec, 0xf9}
constexpr GUID JITEEVersionIdentifier = { /* 4da26f27-4303-43fb-b707-678fcd27308c */
0x4da26f27,
0x4303,
0x43fb,
{0xb7, 0x07, 0x67, 0x8f, 0xcd, 0x27, 0x30, 0x8c}
};

#endif // JIT_EE_VERSIONING_GUID_H
1 change: 1 addition & 0 deletions src/coreclr/jit/ICorJitInfo_names_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ DEF_CLR_API(getMethodSig)
DEF_CLR_API(getMethodInfo)
DEF_CLR_API(haveSameMethodDefinition)
DEF_CLR_API(getTypeDefinition)
DEF_CLR_API(findTypeByName)
DEF_CLR_API(canInline)
DEF_CLR_API(beginInlining)
DEF_CLR_API(reportInliningDecision)
Expand Down
11 changes: 11 additions & 0 deletions src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getTypeDefinition(
return temp;
}

CORINFO_CLASS_HANDLE WrapICorJitInfo::findTypeByName(
CORINFO_CLASS_HANDLE typeInAssembly,
CORINFO_MODULE_HANDLE typeNameModule,
unsigned typeNameToken)
{
API_ENTER(findTypeByName);
CORINFO_CLASS_HANDLE temp = wrapHnd->findTypeByName(typeInAssembly, typeNameModule, typeNameToken);
API_LEAVE(findTypeByName);
return temp;
}

CorInfoInline WrapICorJitInfo::canInline(
CORINFO_METHOD_HANDLE callerHnd,
CORINFO_METHOD_HANDLE calleeHnd)
Expand Down
114 changes: 113 additions & 1 deletion src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3311,7 +3311,6 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
// boost. We actually have the implementation in managed, however, to keep the JIT simpler.
return nullptr;
}

if (!isIntrinsic)
{
// Outside the cases above, there are many intrinsics which apply to only a
Expand Down Expand Up @@ -3450,6 +3449,8 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
case NI_System_Type_get_TypeHandle:
case NI_System_RuntimeType_get_TypeHandle:
case NI_System_RuntimeTypeHandle_ToIntPtr:
case NI_System_Type_get_Assembly:
case NI_System_Reflection_Assembly_GetType:

// This one is not simple, but it will help us
// to avoid some unnecessary boxing
Expand Down Expand Up @@ -4184,6 +4185,99 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
break;
}

case NI_System_Type_get_Assembly:
{
// We don't expand this intrinsic directly — we just keep it as a special
// intrinsic call on the stack so Assembly.GetType can look through it.
isSpecial = true;
break;
}

case NI_System_Reflection_Assembly_GetType:
{
// Folding typeof(T).Assembly.GetType("Foo") to a constant requires
// findTypeByName to potentially load the type — that's safe and
// expected for AOT (NativeAOT, R2R), but for regular JIT it
// can introduce JIT-time type loading. Gate accordingly:
// - Only when optimizations are enabled
// - On by default for AOT (NativeAOT or R2R)
// - Off by default for CoreCLR JIT (opt-in via JitFoldAssemblyGetType)
if (opts.OptimizationDisabled())
{
break;
}
if (!IsAot() && (JitConfig.JitFoldAssemblyGetType() == 0))
{
break;
}

// Only handle the single-arg overload (no throwOnError / ignoreCase)
if (sig->numArgs != 1)
{
break;
}

GenTree* strArg = impStackTop(0).val;
GenTree* asmArg = impStackTop(1).val;

// Check: is strArg a string literal?
if (!strArg->OperIs(GT_CNS_STR) || strArg->AsStrCon()->IsStringEmptyField())
{
break;
}

// Check: is asmArg a get_Assembly call on a typeof(T)?
GenTreeCall* asmCall = nullptr;
if (asmArg->OperIs(GT_CALL))
{
asmCall = asmArg->AsCall();
}
else if (asmArg->OperIs(GT_RET_EXPR))
{
asmCall = asmArg->AsRetExpr()->gtInlineCandidate;
}

if (asmCall == nullptr || lookupNamedIntrinsic(asmCall->gtCallMethHnd) != NI_System_Type_get_Assembly)
{
break;
}

// Look through get_Assembly to find typeof(T)
GenTree* typeArg = asmCall->gtArgs.GetArgByIndex(0)->GetNode();
CORINFO_CLASS_HANDLE hClass = NO_CLASS_HANDLE;
if (!gtIsTypeof(typeArg, &hClass))
{
break;
}

// We have typeof(Foo).Assembly.GetType("Bar") with known Foo and known "Bar"
GenTreeStrCon* strCon = strArg->AsStrCon();
CORINFO_CLASS_HANDLE resolved =
info.compCompHnd->findTypeByName(hClass, strCon->gtScpHnd, strCon->gtSconCPX);

if (resolved == NO_CLASS_HANDLE)
{
break;
}

JITDUMP("\nIntrinsifying typeof(...).Assembly.GetType(\"...\") to a known type\n");

// Pop both args
impPopStack(); // string
impPopStack(); // assembly

// Bash the get_Assembly call to a NOP since we're discarding it
if (asmArg->OperIs(GT_RET_EXPR))
{
asmCall->gtBashToNOP();
}

// Return the resolved type as CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE(resolvedHandle)
GenTree* handleNode = gtNewIconEmbClsHndNode(resolved);
retNode = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, handleNode);
break;
}

case NI_System_Threading_Thread_get_ManagedThreadId:
{
if (impStackTop().val->OperIs(GT_RET_EXPR))
Expand Down Expand Up @@ -10674,6 +10768,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
result = NI_System_RuntimeType_get_TypeHandle;
}
if (strcmp(methodName, "get_Assembly") == 0)
{
result = NI_System_Type_get_Assembly;
}
}
else if (strcmp(className, "RuntimeTypeHandle") == 0)
{
Expand Down Expand Up @@ -10815,6 +10913,10 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
{
result = NI_System_Type_get_TypeHandle;
}
else if (strcmp(methodName, "get_Assembly") == 0)
{
result = NI_System_Type_get_Assembly;
}
}
break;
}
Expand Down Expand Up @@ -11073,6 +11175,16 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
}
}
}
else if (strcmp(namespaceName, "Reflection") == 0)
{
if (strcmp(className, "Assembly") == 0)
{
if (strcmp(methodName, "GetType") == 0)
{
result = NI_System_Reflection_Assembly_GetType;
}
}
}
else if (strncmp(namespaceName, "Runtime.", 8) == 0)
{
namespaceName += 8;
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ RELEASE_CONFIG_INTEGER(JitInlineBudget, "JitInlineBudget", DEFAULT_INLINE_BUDGET
CONFIG_INTEGER(JitForceInlineDepth, "JitForceInlineDepth", DEFAULT_MAX_FORCE_INLINE_DEPTH)
RELEASE_CONFIG_INTEGER(JitInlineMethodsWithEH, "JitInlineMethodsWithEH", 1)
CONFIG_STRING(JitInlineMethodsWithEHRange, "JitInlineMethodsWithEHRange")
RELEASE_CONFIG_INTEGER(JitFoldAssemblyGetType,
"JitFoldAssemblyGetType",
0) // Fold typeof(T).Assembly.GetType("Foo") to a constant Type handle. Off by default for
// CoreCLR JIT (always on for NativeAOT).

CONFIG_INTEGER(JitLongAddress, "JitLongAddress", 0) // Force using the large pseudo instruction form for long address
CONFIG_INTEGER(JitMaxUncheckedOffset, "JitMaxUncheckedOffset", 8)
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/jit/namedintrinsiclist.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ enum NamedIntrinsic : unsigned short
NI_System_Type_op_Inequality,
NI_System_Type_GetTypeFromHandle,
NI_System_Type_GetGenericTypeDefinition,
NI_System_Type_get_Assembly,
NI_System_Reflection_Assembly_GetType,
NI_System_Array_Clone,
NI_System_Array_GetLength,
NI_System_Array_GetLowerBound,
Expand Down
40 changes: 40 additions & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,46 @@ private bool haveSameMethodDefinition(CORINFO_METHOD_STRUCT_* methHnd1, CORINFO_
return ObjectToHandle(HandleToObject(type).GetTypeDefinition());
}

private CORINFO_CLASS_STRUCT_* findTypeByName(CORINFO_CLASS_STRUCT_* typeInAssembly, CORINFO_MODULE_STRUCT_* typeNameModule, uint typeNameToken)
{
TypeDesc typeInAsm = HandleToObject(typeInAssembly);

// Get the module (assembly) that contains the type
if (typeInAsm is not MetadataType mdType)
return null;

ModuleDesc module = mdType.Module;

// Read the string token from the IL module
MethodILScope methodIL = HandleToObject(typeNameModule);
string typeName = (string)methodIL.GetObject((int)typeNameToken);

if (string.IsNullOrEmpty(typeName))
return null;

// Split fully qualified name into namespace and name at the last '.'
ReadOnlySpan<byte> nameSpaceUtf8;
ReadOnlySpan<byte> nameUtf8;

int lastDot = typeName.LastIndexOf('.');
if (lastDot >= 0)
{
nameSpaceUtf8 = System.Text.Encoding.UTF8.GetBytes(typeName.Substring(0, lastDot));
nameUtf8 = System.Text.Encoding.UTF8.GetBytes(typeName.Substring(lastDot + 1));
}
else
{
nameSpaceUtf8 = default;
nameUtf8 = System.Text.Encoding.UTF8.GetBytes(typeName);
}

MetadataType resolved = module.GetType(nameSpaceUtf8, nameUtf8, throwIfNotFound: false);
if (resolved == null)
return null;

return ObjectToHandle(resolved);
}

private CorInfoInline canInline(CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd)
{
MethodDesc callerMethod = HandleToObject(callerHnd);
Expand Down
17 changes: 17 additions & 0 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ static ICorJitInfoCallbacks()
s_callbacks.getMethodInfo = &_getMethodInfo;
s_callbacks.haveSameMethodDefinition = &_haveSameMethodDefinition;
s_callbacks.getTypeDefinition = &_getTypeDefinition;
s_callbacks.findTypeByName = &_findTypeByName;
s_callbacks.canInline = &_canInline;
s_callbacks.beginInlining = &_beginInlining;
s_callbacks.reportInliningDecision = &_reportInliningDecision;
Expand Down Expand Up @@ -210,6 +211,7 @@ static ICorJitInfoCallbacks()
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_INFO*, CORINFO_CONTEXT_STRUCT*, byte> getMethodInfo;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_STRUCT_*, byte> haveSameMethodDefinition;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_CLASS_STRUCT_*> getTypeDefinition;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_CLASS_STRUCT_*, CORINFO_MODULE_STRUCT_*, uint, CORINFO_CLASS_STRUCT_*> findTypeByName;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CorInfoInline> canInline;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_STRUCT_*, void> beginInlining;
public delegate* unmanaged<IntPtr, IntPtr*, CORINFO_METHOD_STRUCT_*, CORINFO_METHOD_STRUCT_*, CorInfoInline, byte*, void> reportInliningDecision;
Expand Down Expand Up @@ -507,6 +509,21 @@ private static byte _haveSameMethodDefinition(IntPtr thisHandle, IntPtr* ppExcep
}
}

[UnmanagedCallersOnly]
private static CORINFO_CLASS_STRUCT_* _findTypeByName(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* typeInAssembly, CORINFO_MODULE_STRUCT_* typeNameModule, uint typeNameToken)
{
var _this = GetThis(thisHandle);
try
{
return _this.findTypeByName(typeInAssembly, typeNameModule, typeNameToken);
}
catch (Exception ex)
{
*ppException = _this.AllocException(ex);
return default;
}
}

[UnmanagedCallersOnly]
private static CorInfoInline _canInline(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* callerHnd, CORINFO_METHOD_STRUCT_* calleeHnd)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ FUNCTIONS
bool getMethodInfo(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_HANDLE context);
bool haveSameMethodDefinition(CORINFO_METHOD_HANDLE meth1Hnd, CORINFO_METHOD_HANDLE meth2Hnd);
CORINFO_CLASS_HANDLE getTypeDefinition(CORINFO_CLASS_HANDLE type);
CORINFO_CLASS_HANDLE findTypeByName(CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken);
CorInfoInline canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd);
void beginInlining(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd);
void reportInliningDecision(CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char * reason);
Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/tools/aot/jitinterface/jitinterface_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct JitInterfaceCallbacks
bool (* getMethodInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_INFO* info, CORINFO_CONTEXT_HANDLE context);
bool (* haveSameMethodDefinition)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE meth1Hnd, CORINFO_METHOD_HANDLE meth2Hnd);
CORINFO_CLASS_HANDLE (* getTypeDefinition)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE type);
CORINFO_CLASS_HANDLE (* findTypeByName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken);
CorInfoInline (* canInline)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd);
void (* beginInlining)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd);
void (* reportInliningDecision)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE inlinerHnd, CORINFO_METHOD_HANDLE inlineeHnd, CorInfoInline inlineResult, const char* reason);
Expand Down Expand Up @@ -282,6 +283,17 @@ class JitInterfaceWrapper : public ICorJitInfo
return temp;
}

virtual CORINFO_CLASS_HANDLE findTypeByName(
CORINFO_CLASS_HANDLE typeInAssembly,
CORINFO_MODULE_HANDLE typeNameModule,
unsigned typeNameToken)
{
CorInfoExceptionClass* pException = nullptr;
CORINFO_CLASS_HANDLE temp = _callbacks->findTypeByName(_thisHandle, &pException, typeInAssembly, typeNameModule, typeNameToken);
if (pException != nullptr) throw pException;
return temp;
}

virtual CorInfoInline canInline(
CORINFO_METHOD_HANDLE callerHnd,
CORINFO_METHOD_HANDLE calleeHnd)
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/tools/superpmi/superpmi-shared/agnostic.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ struct DLDDD
DWORD D;
};

struct DLDLD
{
DWORDLONG A;
DWORDLONG B;
DWORD C;
};

struct Agnostic_CORINFO_METHODNAME_TOKENin
{
DWORDLONG ftn;
Expand Down
Loading
Loading