Skip to content

Commit fd2882e

Browse files
authored
Fix resolving token for MedthodRef to work with closed generic types (#3177)
1 parent 8db7b38 commit fd2882e

File tree

4 files changed

+97
-27
lines changed

4 files changed

+97
-27
lines changed

src/CLR/Core/Interpreter.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,7 +2107,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
21072107
FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip);
21082108

21092109
CLR_RT_MethodDef_Instance calleeInst{};
2110-
if (calleeInst.ResolveToken(arg, assm) == false)
2110+
if (calleeInst.ResolveToken(arg, assm, stack->m_call.genericType) == false)
21112111
{
21122112
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
21132113
}
@@ -2345,7 +2345,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
23452345
FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip);
23462346

23472347
CLR_RT_MethodDef_Instance calleeInst{};
2348-
if (calleeInst.ResolveToken(arg, assm) == false)
2348+
if (calleeInst.ResolveToken(arg, assm, stack->m_call.genericType) == false)
23492349
{
23502350
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
23512351
}
@@ -3223,7 +3223,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
32233223
case TBL_MethodDef:
32243224
{
32253225
CLR_RT_MethodDef_Instance method{};
3226-
if (method.ResolveToken(arg, assm) == false)
3226+
if (method.ResolveToken(arg, assm, stack->m_call.genericType) == false)
32273227
{
32283228
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
32293229
}
@@ -3247,7 +3247,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
32473247
case TBL_MethodSpec:
32483248
{
32493249
CLR_RT_MethodDef_Instance method{};
3250-
if (!method.ResolveToken(arg, assm))
3250+
if (!method.ResolveToken(arg, assm, stack->m_call.genericType))
32513251
{
32523252
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
32533253
}
@@ -3403,7 +3403,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
34033403
CHECKSTACK(stack, evalPos);
34043404

34053405
CLR_RT_MethodDef_Instance method{};
3406-
if (method.ResolveToken(arg, assm) == false)
3406+
if (method.ResolveToken(arg, assm, stack->m_call.genericType) == false)
34073407
{
34083408
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
34093409
}
@@ -3421,7 +3421,7 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
34213421
FETCH_ARG_COMPRESSED_METHODTOKEN(arg, ip);
34223422

34233423
CLR_RT_MethodDef_Instance callee{};
3424-
if (callee.ResolveToken(arg, assm) == false)
3424+
if (callee.ResolveToken(arg, assm, stack->m_call.genericType) == false)
34253425
{
34263426
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
34273427
}

src/CLR/Core/TypeSystem.cpp

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,7 +1268,10 @@ void CLR_RT_MethodDef_Instance::ClearInstance()
12681268
genericType = nullptr;
12691269
}
12701270

1271-
bool CLR_RT_MethodDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm)
1271+
bool CLR_RT_MethodDef_Instance::ResolveToken(
1272+
CLR_UINT32 tk,
1273+
CLR_RT_Assembly *assm,
1274+
const CLR_RT_TypeSpec_Index *callerGeneric)
12721275
{
12731276
NATIVE_PROFILE_CLR_CORE();
12741277
if (assm)
@@ -1285,21 +1288,73 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *ass
12851288
{
12861289
// owner is TypeSpec
12871290

1288-
genericType = &assm->crossReferenceMethodRef[index].genericType;
1291+
// The raw MethodRef* says "Owner = a TypeSpec row".
1292+
// That TypeSpec row might be either the *open* generic or a purely nested flavor.
1293+
// Even if we know we are inside a closed instantiation of that same generic.
1294+
// We want to prefer the calling method's closed TypeSpec (callerGeneric) ONLY if they refer to the
1295+
// same TypeDef token.
1296+
//
12891297

1290-
const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(genericType->TypeSpec());
1298+
// grab the MethodRef *declared* owner:
1299+
const CLR_RT_TypeSpec_Index *methodOwnerTS = &assm->crossReferenceMethodRef[index].genericType;
12911300

1292-
CLR_RT_MethodDef_Index method;
1301+
// check if MethodRef TypeDef token is the same TypeDef as in that caller
1302+
bool useCaller = false;
12931303

1294-
if (!assm->FindMethodDef(ts, assm->GetString(mr->name), assm, mr->signature, method))
1304+
if (callerGeneric != nullptr && NANOCLR_INDEX_IS_VALID(*callerGeneric))
12951305
{
1296-
return false;
1306+
CLR_RT_TypeSpec_Instance callerInst{};
1307+
if (callerInst.InitializeFromIndex(*callerGeneric))
1308+
{
1309+
CLR_RT_SignatureParser parserCaller;
1310+
parserCaller.Initialize_TypeSpec(callerInst.assembly, callerInst.target);
1311+
1312+
CLR_RT_SignatureParser::Element elemCaller;
1313+
1314+
// advance to the generic instance which will point to the class
1315+
parserCaller.Advance(elemCaller);
1316+
1317+
CLR_UINT32 callerTypeDefToken = elemCaller.Class.data;
1318+
1319+
// parse the MethodRef declared TypeSpec
1320+
CLR_RT_TypeSpec_Instance ownerInst{};
1321+
if (ownerInst.InitializeFromIndex(*methodOwnerTS))
1322+
{
1323+
CLR_RT_SignatureParser parserOwner;
1324+
parserOwner.Initialize_TypeSpec(ownerInst.assembly, ownerInst.target);
1325+
1326+
CLR_RT_SignatureParser::Element elemOwner;
1327+
1328+
// advance to the generic instance which will point to the class
1329+
parserOwner.Advance(elemOwner);
1330+
1331+
CLR_UINT32 ownerTypeDefToken = elemOwner.Class.data;
1332+
1333+
if (callerTypeDefToken == ownerTypeDefToken)
1334+
{
1335+
// we have a match on the typeDef, so they refer to the same type
1336+
// lets bind using the closed generic
1337+
useCaller = true;
1338+
}
1339+
}
1340+
}
12971341
}
12981342

1299-
Set(assm->assemblyIndex, method.Method());
1343+
// Pick the “winner” between methodOwnerTS or callerGeneric:
1344+
const CLR_RT_TypeSpec_Index *definitiveTypeSpec = useCaller ? callerGeneric : methodOwnerTS;
1345+
genericType = (CLR_RT_TypeSpec_Index *)definitiveTypeSpec;
1346+
1347+
const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(definitiveTypeSpec->TypeSpec());
1348+
CLR_RT_MethodDef_Index methodIndex;
1349+
1350+
if (!assm->FindMethodDef(ts, assm->GetString(mr->name), assm, mr->signature, methodIndex))
1351+
{
1352+
return false;
1353+
}
13001354

1355+
Set(assm->assemblyIndex, methodIndex.Method());
13011356
assembly = assm;
1302-
target = assembly->GetMethodDef(method.Method());
1357+
target = assembly->GetMethodDef(methodIndex.Method());
13031358
}
13041359
else
13051360
{
@@ -6594,7 +6649,7 @@ bool CLR_RT_AttributeEnumerator::Advance()
65946649

65956650
// get the method definition, by resolving the token
65966651
CLR_RT_MethodDef_Instance method{};
6597-
if (method.ResolveToken(token, m_assm) == false)
6652+
if (method.ResolveToken(token, m_assm, nullptr) == false)
65986653
{
65996654
ASSERT(0);
66006655
}

src/CLR/Diagnostics/Info.cpp

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -472,26 +472,41 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g
472472
CLR_UINT32 idx = CLR_DataFromTk(token);
473473
auto &xref = crossReferenceMethodRef[idx];
474474

475-
// Build a MethodRef_Index so we can format the reference
475+
// Build a MethodRef_Index so we can format the reference:
476476
CLR_RT_MethodRef_Index mri;
477477
mri.Set(assemblyIndex, idx);
478478

479-
// Pass the *target* method’s closed genericType, not "callGeneric"!
479+
// Decide which TypeSpec to supply to BuildMethodRefName:
480+
// 1) If the caller passed a non-null genericType (i.e. we’re inside SimpleList<I4>),
481+
// use that, so ResizeArray prints as SimpleList<I4>::ResizeArray.
482+
// 2) Otherwise, fall back to xref.genericType (the raw MethodRef own owner).
483+
const CLR_RT_TypeSpec_Index *ownerTypeSpec;
484+
if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType))
485+
{
486+
ownerTypeSpec = genericType;
487+
}
488+
else
489+
{
490+
ownerTypeSpec = &xref.genericType;
491+
}
492+
480493
char buf[256], *p = buf;
481494
size_t cb = sizeof(buf);
482-
g_CLR_RT_TypeSystem.BuildMethodRefName(
483-
mri,
484-
&xref.genericType, // THIS is the TypeSpec for SimpleList<I4>
485-
p,
486-
cb);
495+
g_CLR_RT_TypeSystem.BuildMethodRefName(mri, ownerTypeSpec, p, cb);
487496
CLR_Debug::Printf("%s", buf);
488497
break;
489498
}
490499
case TBL_TypeDef:
491500
{
492-
// A genuine TypeDef token—print its (possibly non‐generic) name.
493-
LOOKUP_ELEMENT_IDX(index, TypeDef, TYPEDEF);
494-
CLR_RT_DUMP::TYPE(s);
501+
CLR_UINT32 idx = CLR_DataFromTk(token);
502+
CLR_RT_TypeDef_Index td;
503+
td.Set(assemblyIndex, idx);
504+
505+
char buf[256], *p = buf;
506+
size_t cb = sizeof(buf);
507+
508+
g_CLR_RT_TypeSystem.BuildTypeName(td, p, cb);
509+
CLR_Debug::Printf("%s", buf);
495510
break;
496511
}
497512
case TBL_TypeSpec:
@@ -857,7 +872,7 @@ void CLR_RT_Assembly::DumpOpcodeDirect(
857872
if (op == CEE_CALL || op == CEE_CALLVIRT)
858873
{
859874
CLR_RT_MethodDef_Instance mdInst{};
860-
if (mdInst.ResolveToken(token, call.assembly))
875+
if (mdInst.ResolveToken(token, call.assembly, call.genericType))
861876
{
862877
// mdInst now holds the target MethodDef (or MethodSpec) plus any genericType.
863878
CLR_RT_DUMP::METHOD(mdInst, mdInst.genericType);

src/CLR/Include/nanoCLR_Runtime.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2172,7 +2172,7 @@ struct CLR_RT_MethodDef_Instance : public CLR_RT_MethodDef_Index
21722172
bool InitializeFromIndex(const CLR_RT_MethodDef_Index &index);
21732173
void ClearInstance();
21742174

2175-
bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm);
2175+
bool ResolveToken(CLR_UINT32 tk, CLR_RT_Assembly *assm, const CLR_RT_TypeSpec_Index *callerGeneric);
21762176

21772177
//--//
21782178

0 commit comments

Comments
 (0)