From 2f44fcf42b7b7c5f5177cf19fc525708952ed18a Mon Sep 17 00:00:00 2001 From: Adeel <3840695+am11@users.noreply.github.com> Date: Mon, 4 May 2026 10:01:49 +0300 Subject: [PATCH] Intrinsify typeof().Assembly.GetType() --- src/coreclr/inc/corinfo.h | 23 ++++ src/coreclr/inc/icorjitinfoimpl_generated.h | 5 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 11 ++ src/coreclr/jit/importercalls.cpp | 114 +++++++++++++++++- src/coreclr/jit/jitconfigvalues.h | 4 + src/coreclr/jit/namedintrinsiclist.h | 2 + .../tools/Common/JitInterface/CorInfoImpl.cs | 40 ++++++ .../JitInterface/CorInfoImpl_generated.cs | 17 +++ .../ThunkGenerator/ThunkInput.txt | 1 + .../aot/jitinterface/jitinterface_generated.h | 12 ++ .../tools/superpmi/superpmi-shared/agnostic.h | 7 ++ .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 30 +++++ .../superpmi/superpmi-shared/methodcontext.h | 5 + .../superpmi-shim-collector/icorjitinfo.cpp | 11 ++ .../icorjitinfo_generated.cpp | 9 ++ .../icorjitinfo_generated.cpp | 8 ++ .../tools/superpmi/superpmi/icorjitinfo.cpp | 10 ++ src/coreclr/vm/jitinterface.cpp | 57 +++++++++ .../src/System/Reflection/Assembly.cs | 2 + .../System.Private.CoreLib/src/System/Type.cs | 2 +- 23 files changed, 375 insertions(+), 7 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 5aa999e2745fa8..7cac26e5528180 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -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. // diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 7a67f9ea0ff3cd..5d76dab2e8cf76 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -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; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index fe5749d03fdda1..fb717390322ca9 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -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 diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index d03d03b1007970..915e06c4001356 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -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) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 80411912d6c9cc..16b6965f78e727 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -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) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 6ef07513ee4b10..e1c58733e9b5cc 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -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 @@ -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 @@ -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)) @@ -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) { @@ -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; } @@ -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; diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index a87b20f8491c78..1a42159963e1bd 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -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) diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 0a0bd8805859c3..51511807d346fe 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -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, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 6c44f4e6ebfdbc..053c433d8f5d27 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -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 nameSpaceUtf8; + ReadOnlySpan 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); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index a1eebc3762aaa1..fd230d8dd5f0bd 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -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; @@ -210,6 +211,7 @@ static ICorJitInfoCallbacks() public delegate* unmanaged getMethodInfo; public delegate* unmanaged haveSameMethodDefinition; public delegate* unmanaged getTypeDefinition; + public delegate* unmanaged findTypeByName; public delegate* unmanaged canInline; public delegate* unmanaged beginInlining; public delegate* unmanaged reportInliningDecision; @@ -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) { diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 8e605002f90174..045da7202f7b65 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -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); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index dec68b1eb53d4f..b282317db64937 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -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); @@ -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) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 91b26c9caaa256..670d10f8f69ece 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -98,6 +98,13 @@ struct DLDDD DWORD D; }; +struct DLDLD +{ + DWORDLONG A; + DWORDLONG B; + DWORD C; +}; + struct Agnostic_CORINFO_METHODNAME_TOKENin { DWORDLONG ftn; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index b464feef60b3f6..8b82e41e950ad6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -110,6 +110,7 @@ LWM(GetMethodHash, DWORDLONG, DWORD) LWM(GetMethodInfo, DLDL, Agnostic_GetMethodInfo) LWM(HaveSameMethodDefinition, DLDL, DWORD) LWM(GetTypeDefinition, DWORDLONG, DWORDLONG) +LWM(FindTypeByName, DLDLD, DWORDLONG) LWM(GetMethodNameFromMetadata, Agnostic_CORINFO_METHODNAME_TOKENin, Agnostic_CORINFO_METHODNAME_TOKENout) LWM(GetMethodSig, DLDL, Agnostic_CORINFO_SIG_INFO) LWM(GetMethodVTableOffset, DWORDLONG, DDD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 64775fb58cfe52..a854d04e38f079 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3062,6 +3062,36 @@ CORINFO_CLASS_HANDLE MethodContext::repGetTypeDefinition(CORINFO_CLASS_HANDLE cl return result; } +void MethodContext::recFindTypeByName(CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken, CORINFO_CLASS_HANDLE result) +{ + if (FindTypeByName == nullptr) + FindTypeByName = new LightWeightMap(); + + DLDLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(typeInAssembly); + key.B = CastHandle(typeNameModule); + key.C = (DWORD)typeNameToken; + DWORDLONG value = CastHandle(result); + FindTypeByName->Add(key, value); + DEBUG_REC(dmpFindTypeByName(key, value)); +} +void MethodContext::dmpFindTypeByName(DLDLD key, DWORDLONG value) +{ + printf("FindTypeByName key cls-%016" PRIX64 " mod-%016" PRIX64 " tok-%08X, value cls-%016" PRIX64 "", key.A, key.B, key.C, value); +} +CORINFO_CLASS_HANDLE MethodContext::repFindTypeByName(CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken) +{ + DLDLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(typeInAssembly); + key.B = CastHandle(typeNameModule); + key.C = (DWORD)typeNameToken; + DWORDLONG value = LookupByKeyOrMiss(FindTypeByName, key, ": key %016" PRIX64 " %016" PRIX64 " %08X", key.A, key.B, key.C); + DEBUG_REP(dmpFindTypeByName(key, value)); + return (CORINFO_CLASS_HANDLE)value; +} + void MethodContext::recGetNewHelper(CORINFO_CLASS_HANDLE classHandle, bool hasSideEffects, CorInfoHelpFunc result, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 449a18a91caeb5..85a4d706cd2664 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -410,6 +410,10 @@ class MethodContext void dmpGetTypeDefinition(DWORDLONG key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetTypeDefinition(CORINFO_CLASS_HANDLE type); + void recFindTypeByName(CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken, CORINFO_CLASS_HANDLE result); + void dmpFindTypeByName(DLDLD key, DWORDLONG value); + CORINFO_CLASS_HANDLE repFindTypeByName(CORINFO_CLASS_HANDLE typeInAssembly, CORINFO_MODULE_HANDLE typeNameModule, unsigned typeNameToken); + void recGetNewHelper(CORINFO_CLASS_HANDLE classHandle, bool hasSideEffects, CorInfoHelpFunc result, @@ -1222,6 +1226,7 @@ enum mcPackets Packet_GetWasmTypeSymbol = 235, Packet_GetWasmLowering = 236, Packet_GetAsyncOtherVariant = 237, + Packet_FindTypeByName = 238, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index e29ba7b5cc97ff..d8871e74610b51 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -124,6 +124,17 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( return result; } +CORINFO_CLASS_HANDLE interceptor_ICJI::findTypeByName( + CORINFO_CLASS_HANDLE typeInAssembly, + CORINFO_MODULE_HANDLE typeNameModule, + unsigned typeNameToken) +{ + CORINFO_CLASS_HANDLE result = original_ICorJitInfo->findTypeByName(typeInAssembly, typeNameModule, typeNameToken); + mc->recFindTypeByName(typeInAssembly, typeNameModule, typeNameToken, result); + + return result; +} + // Decides if you have any limitations for inlining. If everything's OK, it will return // INLINE_PASS. // diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 8058b6802159e8..a916124b05e039 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -74,6 +74,15 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( return original_ICorJitInfo->getTypeDefinition(type); } +CORINFO_CLASS_HANDLE interceptor_ICJI::findTypeByName( + CORINFO_CLASS_HANDLE typeInAssembly, + CORINFO_MODULE_HANDLE typeNameModule, + unsigned typeNameToken) +{ + mcs->AddCall("findTypeByName"); + return original_ICorJitInfo->findTypeByName(typeInAssembly, typeNameModule, typeNameToken); +} + CorInfoInline interceptor_ICJI::canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd) diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 852a318f83c225..f16b65a344bfb1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -66,6 +66,14 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeDefinition( return original_ICorJitInfo->getTypeDefinition(type); } +CORINFO_CLASS_HANDLE interceptor_ICJI::findTypeByName( + CORINFO_CLASS_HANDLE typeInAssembly, + CORINFO_MODULE_HANDLE typeNameModule, + unsigned typeNameToken) +{ + return original_ICorJitInfo->findTypeByName(typeInAssembly, typeNameModule, typeNameToken); +} + CorInfoInline interceptor_ICJI::canInline( CORINFO_METHOD_HANDLE callerHnd, CORINFO_METHOD_HANDLE calleeHnd) diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 20372434076341..826c568f097834 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -104,6 +104,16 @@ CORINFO_CLASS_HANDLE MyICJI::getTypeDefinition( return value; } +CORINFO_CLASS_HANDLE MyICJI::findTypeByName( + CORINFO_CLASS_HANDLE typeInAssembly, + CORINFO_MODULE_HANDLE typeNameModule, + unsigned typeNameToken) +{ + jitInstance->mc->cr->AddCall("findTypeByName"); + CORINFO_CLASS_HANDLE value = jitInstance->mc->repFindTypeByName(typeInAssembly, typeNameModule, typeNameToken); + return value; +} + // Decides if you have any limitations for inlining. If everything's OK, it will return // INLINE_PASS. // diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d06b57ed47c5b8..7252538e5486ea 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -7820,6 +7820,63 @@ CORINFO_CLASS_HANDLE CEEInfo::getTypeDefinition(CORINFO_CLASS_HANDLE type) return result; } +CORINFO_CLASS_HANDLE CEEInfo::findTypeByName( + CORINFO_CLASS_HANDLE typeInAssembly, + CORINFO_MODULE_HANDLE typeNameModule, + unsigned typeNameToken) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_CLASS_HANDLE result = NULL; + + JIT_TO_EE_TRANSITION(); + + // Get the assembly from the type handle + TypeHandle th(typeInAssembly); + Assembly* pAssembly = th.GetAssembly(); + + // Read the string token from the module + Module* pModule = GetModule(typeNameModule); + ULONG cchString = 0; + LPCWSTR pString = nullptr; + + if (FAILED(pModule->GetMDImport()->GetUserString(typeNameToken, &cchString, nullptr, &pString)) || + pString == nullptr || cchString == 0) + { + goto Done; + } + + { + // Convert UTF16 type name to UTF8 + StackSString typeNameStr(pString, cchString); + LPCUTF8 typeNameUtf8 = typeNameStr.GetUTF8(); + + // Try to load the type by name within the assembly. + // Pass NULL for namespace - LoadTypeByNameThrowing will parse the fully qualified name. + TypeHandle resolvedType = ClassLoader::LoadTypeByNameThrowing( + pAssembly, + nullptr, // namespace (parsed from name) + typeNameUtf8, // fully qualified type name + ClassLoader::ReturnNullIfNotFound, + ClassLoader::LoadTypes); + + if (!resolvedType.IsNull()) + { + result = CORINFO_CLASS_HANDLE(resolvedType.AsPtr()); + } + } + +Done: + + EE_TO_JIT_TRANSITION(); + + return result; +} + /************************************************************* * Check if the caller and calle are in the same assembly * i.e. do not inline across assemblies diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs index 9866c0e660c04a..db68d14ed63e4e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Assembly.cs @@ -101,8 +101,10 @@ public virtual IEnumerable ExportedTypes public virtual AssemblyName GetName() => GetName(copiedName: false); public virtual AssemblyName GetName(bool copiedName) { throw NotImplemented.ByDesign; } + [Intrinsic] [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")] public virtual Type? GetType(string name) => GetType(name, throwOnError: false, ignoreCase: false); + [Intrinsic] [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")] public virtual Type? GetType(string name, bool throwOnError) => GetType(name, throwOnError: throwOnError, ignoreCase: false); [RequiresUnreferencedCode("Types might be removed by trimming. If the type name is a string literal, consider using Type.GetType instead.")] diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index 60bf2923b2b6f0..b8f0d5325fad82 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -24,7 +24,7 @@ protected Type() { } public abstract string? AssemblyQualifiedName { get; } public abstract string? FullName { get; } - public abstract Assembly Assembly { get; } + public abstract Assembly Assembly { [Intrinsic] get; } public new abstract Module Module { get; } public bool IsInterface