Skip to content

Commit f774058

Browse files
committed
Fixes for TypeRef of generic types
- Fix handler for CEE_CALL and CEE_CALVIRT: now checks if callee is a value type and skips resolving it. - Add ownerType to CLR_RT_TypeSpec_CrossReference. - Add new return parameter to FindMethodDef so assembly index is returned upon finding. - Add new CLR_RT_MethodDef_Instance.InitializeFromIndex() taking a TypeSpec to deal with generic types. - Add new CLR_RT_MethodDef_Instance.GetDeclaringType() helper to take advantage of pre-processed type. - Rework CLR_RT_Assembly::FindTypeSpec() to handle generic types referenced in other assembly. - Various fixes in build type and method names to deal with generic types referenced in other assembly. - CLR_RT_Assembly::FindMethodDef() now returns assembly index of method upon succesfull finding. - Fix CLR_RT_GenericParam_Instance::InitializeFromIndex() to deal with generic types referenced in other assembly. - Fix CLR_RT_MethodDef_Instance::ResolveToken() to deal with generic types referenced in other assembly. - CLR_RT_SignatureParser::Advance() now sets datatype for classes and value types.
1 parent 8725065 commit f774058

File tree

3 files changed

+241
-47
lines changed

3 files changed

+241
-47
lines changed

src/CLR/Core/Interpreter.cpp

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,41 +2157,65 @@ HRESULT CLR_RT_Thread::Execute_IL(CLR_RT_StackFrame &stackArg)
21572157
}
21582158
else // Non delegate
21592159
{
2160+
21602161
CLR_RT_MethodDef_Index calleeReal;
21612162

2162-
if ((calleeInst.target->flags & CLR_RECORD_METHODDEF::MD_Static) == 0)
2163+
bool doInstanceResolution = true;
2164+
2165+
if (calleeInst.target->flags & CLR_RECORD_METHODDEF::MD_Static)
2166+
{
2167+
doInstanceResolution = false;
2168+
}
2169+
else
21632170
{
2164-
// Instance method, pThis[ 0 ] is valid
2171+
CLR_RT_TypeDef_Instance declType;
2172+
NANOCLR_CHECK_HRESULT(calleeInst.GetDeclaringType(declType));
21652173

2166-
if (op == CEE_CALL && pThis[0].Dereference() == nullptr)
2174+
if (declType.target->dataType == DATATYPE_VALUETYPE)
21672175
{
2168-
// CALL on a null instance is allowed, and should not throw a NullReferenceException on
2169-
// the call although a NullReferenceException is likely to be thrown soon thereafter if
2170-
// the call tries to access any member variables.
2176+
// any method on a value‐type is called via byref, so skip the object‐dereference path
2177+
// altogether
2178+
doInstanceResolution = false;
21712179
}
2172-
else
2180+
}
2181+
2182+
if (doInstanceResolution)
2183+
{
2184+
if ((calleeInst.target->flags & CLR_RECORD_METHODDEF::MD_Static) == 0)
21732185
{
2174-
NANOCLR_CHECK_HRESULT(CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(pThis[0], cls));
2175-
2176-
// This test is for performance reasons. c# emits a callvirt on all instance methods to
2177-
// make sure that a NullReferenceException is thrown if 'this' is nullptr. However, if
2178-
// the instance method isn't virtual we don't need to do the more expensive virtual
2179-
// method lookup.
2180-
if (op == CEE_CALLVIRT &&
2181-
(calleeInst.target->flags &
2182-
(CLR_RECORD_METHODDEF::MD_Abstract | CLR_RECORD_METHODDEF::MD_Virtual)))
2186+
// Instance method, pThis[ 0 ] is valid
2187+
2188+
if (op == CEE_CALL && pThis[0].Dereference() == nullptr)
21832189
{
2184-
if (g_CLR_RT_EventCache.FindVirtualMethod(cls, calleeInst, calleeReal) == false)
2190+
// CALL on a null instance is allowed, and should not throw a NullReferenceException
2191+
// on the call although a NullReferenceException is likely to be thrown soon
2192+
// thereafter if the call tries to access any member variables.
2193+
}
2194+
else
2195+
{
2196+
NANOCLR_CHECK_HRESULT(
2197+
CLR_RT_TypeDescriptor::ExtractTypeIndexFromObject(pThis[0], cls));
2198+
2199+
// This test is for performance reasons. c# emits a callvirt on all instance
2200+
// methods to make sure that a NullReferenceException is thrown if 'this' is
2201+
// nullptr. However, if the instance method isn't virtual we don't need to do the
2202+
// more expensive virtual method lookup.
2203+
if (op == CEE_CALLVIRT &&
2204+
(calleeInst.target->flags &
2205+
(CLR_RECORD_METHODDEF::MD_Abstract | CLR_RECORD_METHODDEF::MD_Virtual)))
21852206
{
2186-
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
2187-
}
2207+
if (g_CLR_RT_EventCache.FindVirtualMethod(cls, calleeInst, calleeReal) == false)
2208+
{
2209+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
2210+
}
21882211

2189-
calleeInst.InitializeFromIndex(calleeReal);
2190-
}
2212+
calleeInst.InitializeFromIndex(calleeReal);
2213+
}
21912214

21922215
#if defined(NANOCLR_APPDOMAINS)
2193-
fAppDomainTransition = pThis[0].IsTransparentProxy();
2216+
fAppDomainTransition = pThis[0].IsTransparentProxy();
21942217
#endif
2218+
}
21952219
}
21962220
}
21972221
}

src/CLR/Core/TypeSystem.cpp

Lines changed: 189 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,8 @@ HRESULT CLR_RT_SignatureParser::Advance(Element &res)
610610
// sanity check
611611
if (dt == DATATYPE_CLASS || dt == DATATYPE_VALUETYPE)
612612
{
613+
res.DataType = dt;
614+
613615
// parse type
614616
goto parse_type;
615617
}
@@ -1258,6 +1260,43 @@ bool CLR_RT_MethodDef_Instance::InitializeFromIndex(const CLR_RT_MethodDef_Index
12581260
return false;
12591261
}
12601262

1263+
bool CLR_RT_MethodDef_Instance::InitializeFromIndex(
1264+
const CLR_RT_MethodDef_Index &md,
1265+
const CLR_RT_TypeSpec_Index &typeSpec)
1266+
{
1267+
NATIVE_PROFILE_CLR_CORE();
1268+
1269+
// Look up the TypeSpec's cross‐reference to find the *open* generic definition and its assembly
1270+
CLR_INDEX tsAsmIdx = typeSpec.Assembly();
1271+
if (tsAsmIdx == 0 || tsAsmIdx > (int)g_CLR_RT_TypeSystem.c_MaxAssemblies)
1272+
{
1273+
return false;
1274+
}
1275+
CLR_RT_Assembly *tsAsm = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1];
1276+
1277+
int tsRow = (int)typeSpec.TypeSpec();
1278+
const auto &xref = tsAsm->crossReferenceTypeSpec[tsRow];
1279+
1280+
// xref.ownerType is the open‐generic TypeDef_Index of Span`1, List`1, etc.
1281+
CLR_RT_TypeDef_Index ownerType = xref.ownerType;
1282+
1283+
// Compute the MethodDef_Index bound to the owner’s assembly
1284+
CLR_RT_MethodDef_Index mdRebound;
1285+
1286+
// pack the new assembly index (ownerType.Assembly()) with the original row
1287+
mdRebound.data = (ownerType.Assembly() << 24) | md.Method();
1288+
1289+
if (!InitializeFromIndex(mdRebound))
1290+
{
1291+
return false;
1292+
}
1293+
1294+
// set the generic‐type context *before* we lose it
1295+
this->genericType = &typeSpec;
1296+
1297+
return true;
1298+
}
1299+
12611300
void CLR_RT_MethodDef_Instance::ClearInstance()
12621301
{
12631302
NATIVE_PROFILE_CLR_CORE();
@@ -1344,16 +1383,26 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(
13441383
const CLR_RT_TypeSpec_Index *definitiveTypeSpec = useCaller ? callerGeneric : methodOwnerTS;
13451384
genericType = (CLR_RT_TypeSpec_Index *)definitiveTypeSpec;
13461385

1347-
const CLR_RECORD_TYPESPEC *ts = assm->GetTypeSpec(definitiveTypeSpec->TypeSpec());
1386+
CLR_INDEX tsAsmIdx = genericType->Assembly();
1387+
CLR_RT_Assembly *genericTypeAssembly = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1];
1388+
1389+
const CLR_RECORD_TYPESPEC *ts = genericTypeAssembly->GetTypeSpec(definitiveTypeSpec->TypeSpec());
1390+
CLR_UINT32 assemblyIndex = 0xFFFF;
13481391
CLR_RT_MethodDef_Index methodIndex;
13491392

1350-
if (!assm->FindMethodDef(ts, assm->GetString(mr->name), assm, mr->signature, methodIndex))
1393+
if (!genericTypeAssembly->FindMethodDef(
1394+
ts,
1395+
genericTypeAssembly->GetString(mr->name),
1396+
genericTypeAssembly,
1397+
mr->signature,
1398+
methodIndex,
1399+
assemblyIndex))
13511400
{
13521401
return false;
13531402
}
13541403

1355-
Set(assm->assemblyIndex, methodIndex.Method());
1356-
assembly = assm;
1404+
Set(assemblyIndex - 1, methodIndex.Method());
1405+
assembly = g_CLR_RT_TypeSystem.m_assemblies[assemblyIndex - 1];
13571406
target = assembly->GetMethodDef(methodIndex.Method());
13581407
}
13591408
else
@@ -1484,6 +1533,32 @@ bool CLR_RT_MethodDef_Instance::ResolveToken(
14841533
return false;
14851534
}
14861535

1536+
bool CLR_RT_MethodDef_Instance::GetDeclaringType(CLR_RT_TypeDef_Instance &declType) const
1537+
{
1538+
NATIVE_PROFILE_CLR_CORE();
1539+
1540+
if (genericType && NANOCLR_INDEX_IS_VALID(*genericType))
1541+
{
1542+
// Look up the assembly that actually owns that TypeSpec
1543+
auto tsAsm = g_CLR_RT_TypeSystem.m_assemblies[genericType->Assembly() - 1];
1544+
auto tsRec = tsAsm->GetTypeSpec(genericType->TypeSpec());
1545+
1546+
// Parse the signature so we can peel off [GENERICINST CLASS <type> <args>].
1547+
CLR_RT_SignatureParser parser;
1548+
parser.Initialize_TypeSpec(tsAsm, tsRec);
1549+
1550+
CLR_RT_SignatureParser::Element elem;
1551+
parser.Advance(elem);
1552+
1553+
return declType.InitializeFromIndex(elem.Class);
1554+
}
1555+
else
1556+
{
1557+
// Normal (non‐generic or open‐generic)
1558+
return declType.InitializeFromMethod(*this);
1559+
}
1560+
}
1561+
14871562
//////////////////////////////
14881563

14891564
bool CLR_RT_GenericParam_Instance::InitializeFromIndex(const CLR_RT_GenericParam_Index &index)
@@ -3203,8 +3278,15 @@ HRESULT CLR_RT_Assembly::ResolveMethodRef()
32033278
#endif
32043279
}
32053280

3206-
if (typeSpecInstance.assembly
3207-
->FindMethodDef(typeSpecInstance.target, methodName, this, src->signature, dst->target))
3281+
CLR_UINT32 dummyAssemblyIndex = 0xffff;
3282+
3283+
if (typeSpecInstance.assembly->FindMethodDef(
3284+
typeSpecInstance.target,
3285+
methodName,
3286+
this,
3287+
src->signature,
3288+
dst->target,
3289+
dummyAssemblyIndex))
32083290
{
32093291
fGot = true;
32103292

@@ -3376,6 +3458,27 @@ HRESULT CLR_RT_Assembly::ResolveTypeSpec()
33763458
CLR_Debug::Printf(" [%04X]\r\n", i);
33773459
}
33783460
#endif
3461+
3462+
// parse the signature to find the defining type token
3463+
CLR_RT_SignatureParser parser;
3464+
parser.Initialize_TypeSpec(this, GetTypeSpec(i));
3465+
3466+
CLR_RT_SignatureParser::Element elem;
3467+
3468+
parser.Advance(elem);
3469+
3470+
if (elem.DataType == DATATYPE_VALUETYPE)
3471+
{
3472+
// now `elem.Class` is exactly the open Span`1 or List`1
3473+
// store the open‐generic’s token
3474+
dst->ownerType = elem.Class;
3475+
}
3476+
else
3477+
{
3478+
// if the first element is not a generic instantiation, then it must be a type token
3479+
// no open‐generic, so clear the token
3480+
dst->ownerType.Clear();
3481+
}
33793482
}
33803483

33813484
NANOCLR_NOCLEANUP();
@@ -4878,20 +4981,72 @@ bool CLR_RT_Assembly::FindMethodDef(
48784981
const char *methodName,
48794982
CLR_RT_Assembly *base,
48804983
CLR_SIG sig,
4881-
CLR_RT_MethodDef_Index &index)
4984+
CLR_RT_MethodDef_Index &index,
4985+
CLR_UINT32 &assmIndex)
48824986
{
48834987
NATIVE_PROFILE_CLR_CORE();
48844988

48854989
CLR_RT_TypeSpec_Index tsIndex;
4886-
base->FindTypeSpec(base->GetSignature(ts->signature), tsIndex);
4990+
if (!base->FindTypeSpec(base->GetSignature(ts->signature), tsIndex))
4991+
{
4992+
index.Clear();
4993+
return false;
4994+
}
48874995

48884996
CLR_RT_TypeSpec_Instance tsInstance;
4889-
tsInstance.InitializeFromIndex(tsIndex);
4997+
if (!tsInstance.InitializeFromIndex(tsIndex))
4998+
{
4999+
index.Clear();
5000+
return false;
5001+
}
5002+
5003+
// switch to the assembly that declared this TypeSpec
5004+
CLR_RT_Assembly *declAssm = tsInstance.assembly;
5005+
const CLR_RECORD_TYPEDEF *td =
5006+
(const CLR_RECORD_TYPEDEF *)declAssm->GetTable(TBL_TypeDef) + tsInstance.typeDefIndex;
5007+
5008+
if (declAssm->FindMethodDef(td, methodName, base, sig, index))
5009+
{
5010+
assmIndex = declAssm->assemblyIndex;
5011+
return true;
5012+
}
5013+
5014+
// parse the TypeSpec signature to get the *definition* token of the generic type:
5015+
CLR_RT_SignatureParser parser{};
5016+
parser.Initialize_TypeSpec(this, ts);
5017+
CLR_RT_SignatureParser::Element elem{};
5018+
5019+
// advance to get the actual CLASS/VALUETYPE token for the generic definition.
5020+
if (FAILED(parser.Advance(elem)))
5021+
{
5022+
return false;
5023+
}
48905024

4891-
auto *td = (const CLR_RECORD_TYPEDEF *)base->GetTable(TBL_TypeDef);
4892-
td += tsInstance.typeDefIndex;
5025+
CLR_UINT32 genericDefToken = elem.Class.data;
48935026

4894-
return CLR_RT_Assembly::FindMethodDef(td, methodName, base, sig, index);
5027+
CLR_RT_TypeDef_Index typeDef;
5028+
typeDef.Clear();
5029+
typeDef.data = genericDefToken;
5030+
5031+
CLR_RT_TypeDef_Instance typeDefInstance;
5032+
if (typeDefInstance.InitializeFromIndex(typeDef) == false)
5033+
{
5034+
return false;
5035+
}
5036+
5037+
while (NANOCLR_INDEX_IS_VALID(typeDefInstance))
5038+
{
5039+
if (typeDefInstance.assembly->FindMethodDef(typeDefInstance.target, methodName, this, sig, index))
5040+
{
5041+
assmIndex = typeDefInstance.assembly->assemblyIndex;
5042+
5043+
return true;
5044+
}
5045+
5046+
typeDefInstance.SwitchToParent();
5047+
}
5048+
5049+
return false;
48955050
}
48965051

48975052
bool CLR_RT_Assembly::FindTypeSpec(CLR_PMETADATA sig, CLR_RT_TypeSpec_Index &index)
@@ -6166,28 +6321,31 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName(
61666321
NANOCLR_HEADER();
61676322

61686323
CLR_RT_MethodDef_Instance inst{};
6169-
CLR_RT_TypeDef_Instance instOwner{};
61706324

6171-
if (inst.InitializeFromIndex(md) == false)
6325+
if (genericType == nullptr)
61726326
{
6173-
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6174-
}
6327+
if (inst.InitializeFromIndex(md) == false)
6328+
{
6329+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6330+
}
61756331

6176-
if (instOwner.InitializeFromMethod(inst) == false)
6177-
{
6178-
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6179-
}
6332+
CLR_RT_TypeDef_Instance instOwner{};
6333+
if (instOwner.InitializeFromMethod(inst) == false)
6334+
{
6335+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6336+
}
61806337

6181-
if (genericType == nullptr)
6182-
{
61836338
NANOCLR_CHECK_HRESULT(BuildTypeName(instOwner, szBuffer, iBuffer));
61846339

61856340
CLR_SafeSprintf(szBuffer, iBuffer, "::%s", inst.assembly->GetString(inst.target->name));
61866341
}
61876342
else
61886343
{
6344+
CLR_INDEX tsAsmIdx = genericType->Assembly();
6345+
CLR_RT_Assembly *genericTypeAssembly = g_CLR_RT_TypeSystem.m_assemblies[tsAsmIdx - 1];
6346+
61896347
CLR_RT_SignatureParser parser;
6190-
parser.Initialize_TypeSpec(inst.assembly, inst.assembly->GetTypeSpec(genericType->TypeSpec()));
6348+
parser.Initialize_TypeSpec(genericTypeAssembly, genericTypeAssembly->GetTypeSpec(genericType->TypeSpec()));
61916349

61926350
CLR_RT_SignatureParser::Element element;
61936351

@@ -6215,7 +6373,14 @@ HRESULT CLR_RT_TypeSystem::BuildMethodName(
62156373
}
62166374
}
62176375

6218-
CLR_SafeSprintf(szBuffer, iBuffer, ">::%s", inst.assembly->GetString(inst.target->name));
6376+
if (inst.InitializeFromIndex(md, *genericType) == false)
6377+
{
6378+
// this is a MethodDef for a generic type, but the generic type is not bound to an assembly
6379+
// so we cannot build the name of the method.
6380+
NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
6381+
}
6382+
6383+
CLR_SafeSprintf(szBuffer, iBuffer, ">::%s", genericTypeAssembly->GetString(inst.target->name));
62196384
}
62206385

62216386
NANOCLR_NOCLEANUP();

0 commit comments

Comments
 (0)