From ed93c298c7515a54914754279f2054a9db7827ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 5 Jun 2025 16:44:54 +0100 Subject: [PATCH] Fix resolving token for MedthodRef - Now takes new parameter with the TypeSpec of the caller. - Add new code to validate if TypeSpec is the same as the caller generic type. If that's the case, it will prefer the closed generic type. - Update callers as needed. - Improvements in DumpToken to properly output TypeDef and MethodRef. --- src/CLR/Core/Interpreter.cpp | 12 ++--- src/CLR/Core/TypeSystem.cpp | 73 +++++++++++++++++++++++++++---- src/CLR/Diagnostics/Info.cpp | 37 +++++++++++----- src/CLR/Include/nanoCLR_Runtime.h | 2 +- 4 files changed, 97 insertions(+), 27 deletions(-) diff --git a/src/CLR/Core/Interpreter.cpp b/src/CLR/Core/Interpreter.cpp index d846f6caf4..51595099ef 100644 --- a/src/CLR/Core/Interpreter.cpp +++ b/src/CLR/Core/Interpreter.cpp @@ -2107,7 +2107,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip); CLR_RT_MethodDef_Instance calleeInst{}; - if (calleeInst.ResolveToken(arg, assm) == false) + if (calleeInst.ResolveToken(arg, assm, stack->m_call.genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -2345,7 +2345,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip); CLR_RT_MethodDef_Instance calleeInst{}; - if (calleeInst.ResolveToken(arg, assm) == false) + if (calleeInst.ResolveToken(arg, assm, stack->m_call.genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3223,7 +3223,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) case TBL_MethodDef: { CLR_RT_MethodDef_Instance method{}; - if (method.ResolveToken(arg, assm) == false) + if (method.ResolveToken(arg, assm, stack->m_call.genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3247,7 +3247,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) case TBL_MethodSpec: { CLR_RT_MethodDef_Instance method{}; - if (!method.ResolveToken(arg, assm)) + if (!method.ResolveToken(arg, assm, stack->m_call.genericType)) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3403,7 +3403,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) CHECKSTACK(stack, evalPos); CLR_RT_MethodDef_Instance method{}; - if (method.ResolveToken(arg, assm) == false) + if (method.ResolveToken(arg, assm, stack->m_call.genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } @@ -3421,7 +3421,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg) FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip); CLR_RT_MethodDef_Instance callee{}; - if (callee.ResolveToken(arg, assm) == false) + if (callee.ResolveToken(arg, assm, stack->m_call.genericType) == false) { NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE); } diff --git a/src/CLR/Core/TypeSystem.cpp b/src/CLR/Core/TypeSystem.cpp index 0d7a155a85..eba8240180 100644 --- a/src/CLR/Core/TypeSystem.cpp +++ b/src/CLR/Core/TypeSystem.cpp @@ -1268,7 +1268,10 @@ void CLR_RT_MethodDef_Instance::ClearInstance() genericType = nullptr; } -bool CLR_RT_MethodDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm) +bool CLR_RT_MethodDef_Instance::ResolveToken( + CLR_UINT32 tk, + CLR_RT_Assembly *assm, + const CLR_RT_TypeSpec_Index *callerGeneric) { NATIVE_PROFILE_CLR_CORE(); if (assm) @@ -1285,21 +1288,73 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *ass { // owner is TypeSpec - genericType = &assm->crossReferenceMethodRef[index].genericType; + // The raw MethodRef* says "Owner = a TypeSpec row". + // That TypeSpec row might be either the *open* generic or a purely nested flavor. + // Even if we know we are inside a closed instantiation of that same generic. + // We want to prefer the calling method's closed TypeSpec (callerGeneric) ONLY if they refer to the + // same TypeDef token. + // - const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(genericType->TypeSpec()); + // grab the MethodRef *declared* owner: + const CLR_RT_TypeSpec_Index *methodOwnerTS = &assm->crossReferenceMethodRef[index].genericType; - CLR_RT_MethodDef_Index method; + // check if MethodRef TypeDef token is the same TypeDef as in that caller + bool useCaller = false; - if (!assm->FindMethodDef(ts, assm->GetString(mr->name), assm, mr->signature, method)) + if (callerGeneric != nullptr && NANOCLR_INDEX_IS_VALID(*callerGeneric)) { - return false; + CLR_RT_TypeSpec_Instance callerInst{}; + if (callerInst.InitializeFromIndex(*callerGeneric)) + { + CLR_RT_SignatureParser parserCaller; + parserCaller.Initialize_TypeSpec(callerInst.assembly, callerInst.target); + + CLR_RT_SignatureParser::Element elemCaller; + + // advance to the generic instance which will point to the class + parserCaller.Advance(elemCaller); + + CLR_UINT32 callerTypeDefToken = elemCaller.Class.data; + + // parse the MethodRef declared TypeSpec + CLR_RT_TypeSpec_Instance ownerInst{}; + if (ownerInst.InitializeFromIndex(*methodOwnerTS)) + { + CLR_RT_SignatureParser parserOwner; + parserOwner.Initialize_TypeSpec(ownerInst.assembly, ownerInst.target); + + CLR_RT_SignatureParser::Element elemOwner; + + // advance to the generic instance which will point to the class + parserOwner.Advance(elemOwner); + + CLR_UINT32 ownerTypeDefToken = elemOwner.Class.data; + + if (callerTypeDefToken == ownerTypeDefToken) + { + // we have a match on the typeDef, so they refer to the same type + // lets bind using the closed generic + useCaller = true; + } + } + } } - Set(assm->assemblyIndex, method.Method()); + // Pick the “winner” between methodOwnerTS or callerGeneric: + const CLR_RT_TypeSpec_Index *definitiveTypeSpec = useCaller ? callerGeneric : methodOwnerTS; + genericType = (CLR_RT_TypeSpec_Index *)definitiveTypeSpec; + + const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(definitiveTypeSpec->TypeSpec()); + CLR_RT_MethodDef_Index methodIndex; + + if (!assm->FindMethodDef(ts, assm->GetString(mr->name), assm, mr->signature, methodIndex)) + { + return false; + } + Set(assm->assemblyIndex, methodIndex.Method()); assembly = assm; - target = assembly->GetMethodDef(method.Method()); + target = assembly->GetMethodDef(methodIndex.Method()); } else { @@ -6594,7 +6649,7 @@ bool CLR_RT_AttributeEnumerator::Advance() // get the method definition, by resolving the token CLR_RT_MethodDef_Instance method{}; - if (method.ResolveToken(token, m_assm) == false) + if (method.ResolveToken(token, m_assm, nullptr) == false) { ASSERT(0); } diff --git a/src/CLR/Diagnostics/Info.cpp b/src/CLR/Diagnostics/Info.cpp index a0c3c1e452..fe4bd48131 100644 --- a/src/CLR/Diagnostics/Info.cpp +++ b/src/CLR/Diagnostics/Info.cpp @@ -472,26 +472,41 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g CLR_UINT32 idx = CLR_DataFromTk(token); auto &xref = crossReferenceMethodRef[idx]; - // Build a MethodRef_Index so we can format the reference + // Build a MethodRef_Index so we can format the reference: CLR_RT_MethodRef_Index mri; mri.Set(assemblyIndex, idx); - // Pass the *target* method’s closed genericType, not "callGeneric"! + // Decide which TypeSpec to supply to BuildMethodRefName: + // 1) If the caller passed a non-null genericType (i.e. we’re inside SimpleList), + // use that, so ResizeArray prints as SimpleList::ResizeArray. + // 2) Otherwise, fall back to xref.genericType (the raw MethodRef own owner). + const CLR_RT_TypeSpec_Index *ownerTypeSpec; + if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType)) + { + ownerTypeSpec = genericType; + } + else + { + ownerTypeSpec = &xref.genericType; + } + char buf[256], *p = buf; size_t cb = sizeof(buf); - g_CLR_RT_TypeSystem.BuildMethodRefName( - mri, - &xref.genericType, // THIS is the TypeSpec for SimpleList - p, - cb); + g_CLR_RT_TypeSystem.BuildMethodRefName(mri, ownerTypeSpec, p, cb); CLR_Debug::Printf("%s", buf); break; } case TBL_TypeDef: { - // A genuine TypeDef token—print its (possibly non‐generic) name. - LOOKUP_ELEMENT_IDX(index, TypeDef, TYPEDEF); - CLR_RT_DUMP::TYPE(s); + CLR_UINT32 idx = CLR_DataFromTk(token); + CLR_RT_TypeDef_Index td; + td.Set(assemblyIndex, idx); + + char buf[256], *p = buf; + size_t cb = sizeof(buf); + + g_CLR_RT_TypeSystem.BuildTypeName(td, p, cb); + CLR_Debug::Printf("%s", buf); break; } case TBL_TypeSpec: @@ -857,7 +872,7 @@ void CLR_RT_Assembly::DumpOpcodeDirect( if (op == CEE_CALL || op == CEE_CALLVIRT) { CLR_RT_MethodDef_Instance mdInst{}; - if (mdInst.ResolveToken(token, call.assembly)) + if (mdInst.ResolveToken(token, call.assembly, call.genericType)) { // mdInst now holds the target MethodDef (or MethodSpec) plus any genericType. CLR_RT_DUMP::METHOD(mdInst, mdInst.genericType); diff --git a/src/CLR/Include/nanoCLR_Runtime.h b/src/CLR/Include/nanoCLR_Runtime.h index 65e857ea5e..53ef7a825c 100644 --- a/src/CLR/Include/nanoCLR_Runtime.h +++ b/src/CLR/Include/nanoCLR_Runtime.h @@ -2172,7 +2172,7 @@ struct CLR_RT_MethodDef_Instance : public CLR_RT_MethodDef_Index bool InitializeFromIndex(const CLR_RT_MethodDef_Index &index); void ClearInstance(); - bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm); + bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_TypeSpec_Index *callerGeneric); //--//