Skip to content

Commit c0cd43a

Browse files
committed
Fix dumping closed generic types
- Add new API for BuildMethodRefName and BuildMethodSpecName. - Fix dump token for TypeSpec.
1 parent 8f5db09 commit c0cd43a

File tree

3 files changed

+267
-13
lines changed

3 files changed

+267
-13
lines changed

src/CLR/Core/TypeSystem.cpp

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,16 +1027,17 @@ bool CLR_RT_TypeDef_Instance::ResolveToken(
10271027
auto &tsi = *caller->genericType;
10281028
CLR_UINT32 closedTsRow = tsi.TypeSpec();
10291029

1030-
CLR_RT_TypeDef_Index realTd;
1031-
NanoCLRDataType realDt;
1030+
CLR_RT_TypeDef_Index realTypeDef;
1031+
NanoCLRDataType realDataType;
10321032

10331033
// Only call this once to map (e.g. !T→Int32)
1034-
caller->assembly->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTd, realDt);
1034+
caller->assembly
1035+
->FindGenericParamAtTypeSpec(closedTsRow, (CLR_UINT32)pos, realTypeDef, realDataType);
10351036

10361037
// populate this instance
1037-
data = realTd.data;
1038-
assembly = g_CLR_RT_TypeSystem.m_assemblies[realTd.Assembly() - 1];
1039-
target = assembly->GetTypeDef(realTd.Type());
1038+
data = realTypeDef.data;
1039+
assembly = g_CLR_RT_TypeSystem.m_assemblies[realTypeDef.Assembly() - 1];
1040+
target = assembly->GetTypeDef(realTypeDef.Type());
10401041

10411042
return true;
10421043
}
@@ -6256,7 +6257,31 @@ HRESULT CLR_RT_TypeSystem::BuildMethodRefName(const CLR_RT_MethodRef_Index &meth
62566257

62576258
NANOCLR_NOCLEANUP();
62586259
}
6260+
HRESULT CLR_RT_TypeSystem::BuildMethodRefName(
6261+
const CLR_RT_MethodRef_Index &mri,
6262+
const CLR_RT_TypeSpec_Index *callerGeneric, // may be nullptr if none
6263+
char *&szBuffer,
6264+
size_t &iBuffer)
6265+
{
6266+
NATIVE_PROFILE_CLR_CORE();
6267+
NANOCLR_HEADER();
6268+
6269+
// 1) Grab the assembly that owns this MethodRef
6270+
CLR_RT_Assembly *assembly = g_CLR_RT_TypeSystem.m_assemblies[mri.Assembly() - 1];
62596271

6272+
// 2) Pull the raw CLR_RECORD_METHODREF
6273+
const CLR_RECORD_METHODREF *mr = assembly->GetMethodRef(mri.Method());
6274+
6275+
// 3) Build the corresponding MethodDef_Index
6276+
// (MethodRef.method is the metadata token for the definition)
6277+
CLR_RT_MethodDef_Index md;
6278+
md.Set(mri.Assembly(), mr->OwnerIndex());
6279+
6280+
// 4) Delegate to your existing BuildMethodName, passing the *declaring type’s* TypeSpec
6281+
NANOCLR_CHECK_HRESULT(BuildMethodName(md, callerGeneric, szBuffer, iBuffer));
6282+
6283+
NANOCLR_NOCLEANUP();
6284+
}
62606285
HRESULT CLR_RT_TypeSystem::BuildMethodSpecName(const CLR_RT_MethodSpec_Index &ms, char *&szBuffer, size_t &iBuffer)
62616286
{
62626287
NATIVE_PROFILE_CLR_CORE();
@@ -6344,7 +6369,31 @@ HRESULT CLR_RT_TypeSystem::BuildMethodSpecName(const CLR_RT_MethodSpec_Index &ms
63446369

63456370
NANOCLR_NOCLEANUP();
63466371
}
6372+
HRESULT CLR_RT_TypeSystem::BuildMethodSpecName(
6373+
const CLR_RT_MethodSpec_Index &msi,
6374+
const CLR_RT_TypeSpec_Index *callerGeneric, // may be nullptr if none
6375+
char *&szBuffer,
6376+
size_t &iBuffer)
6377+
{
6378+
NATIVE_PROFILE_CLR_CORE();
6379+
NANOCLR_HEADER();
6380+
6381+
// 1) Grab the assembly that owns this MethodSpec
6382+
CLR_RT_Assembly *assembly = g_CLR_RT_TypeSystem.m_assemblies[msi.Assembly() - 1];
63476383

6384+
// 2) Pull the raw CLR_RECORD_METHODSPEC
6385+
const CLR_RECORD_METHODSPEC *ms = assembly->GetMethodSpec(msi.Method());
6386+
6387+
// 3) Build the corresponding MethodDef_Index
6388+
// (MethodSpec.method is the metadata token for the definition)
6389+
CLR_RT_MethodDef_Index md;
6390+
md.Set(msi.Assembly(), ms->MethodIndex());
6391+
6392+
// 4) Delegate to BuildMethodName, again passing the closed declaring‐type
6393+
NANOCLR_CHECK_HRESULT(BuildMethodName(md, callerGeneric, szBuffer, iBuffer));
6394+
6395+
NANOCLR_NOCLEANUP();
6396+
}
63486397
//--//
63496398

63506399
bool CLR_RT_TypeSystem::FindVirtualMethodDef(

src/CLR/Diagnostics/Info.cpp

Lines changed: 202 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -469,16 +469,177 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g
469469
}
470470
case TBL_MethodRef:
471471
{
472-
LOOKUP_ELEMENT_IDX(index, MethodRef, METHODREF);
473-
CLR_RT_DUMP::METHODREF(s);
472+
CLR_UINT32 idx = CLR_DataFromTk(token);
473+
auto &xref = crossReferenceMethodRef[idx];
474+
475+
// Build a MethodRef_Index so we can format the reference
476+
CLR_RT_MethodRef_Index mri;
477+
mri.Set(assemblyIndex, idx);
478+
479+
// Pass the *target* method’s closed genericType, not "callGeneric"!
480+
char buf[256], *p = buf;
481+
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);
487+
CLR_Debug::Printf("%s", buf);
474488
break;
475489
}
476490
case TBL_TypeDef:
477491
{
492+
// A genuine TypeDef token—print its (possibly non‐generic) name.
478493
LOOKUP_ELEMENT_IDX(index, TypeDef, TYPEDEF);
479494
CLR_RT_DUMP::TYPE(s);
480495
break;
481496
}
497+
case TBL_TypeSpec:
498+
{
499+
//
500+
// The TypeSpec token can represent:
501+
// - a generic parameter (DATATYPE_VAR/ MVAR), e.g. !0
502+
// - a primitive or class (DATATYPE_CLASS / VALUETYPE), e.g. Int32
503+
// - an n-dimensional array (DATATYPE_ARRAY) or a single‐dim SZARRAY inside the signature
504+
// - a closed generic instantiation (DATATYPE_GENERICINST) like List`1<Int32>
505+
//
506+
// When DumpToken is called for “newarr”, often the token is the element‐type alone,
507+
// so if that token is exactly “VAR0” (or “MVAR0”), we must substitute “!0→I4” right here.
508+
// Only if it is not a plain VAR/MVAR do we then check for arrays or else fall
509+
// back to BuildTypeName for the full concrete name.
510+
//
511+
512+
CLR_RT_TypeSpec_Index tsIdx;
513+
tsIdx.Set(assemblyIndex, index);
514+
515+
// bind to get the signature blob
516+
CLR_RT_TypeSpec_Instance tsInst{};
517+
if (!tsInst.InitializeFromIndex(tsIdx))
518+
{
519+
// unable to bind; dump raw RID
520+
CLR_Debug::Printf("[TYPESPEC:%08x]", token);
521+
break;
522+
}
523+
524+
// start parsing the signature
525+
CLR_RT_SignatureParser parser;
526+
parser.Initialize_TypeSpec(tsInst.assembly, tsInst.target);
527+
528+
// read first element
529+
CLR_RT_SignatureParser::Element elem;
530+
if (FAILED(parser.Advance(elem)))
531+
{
532+
// corrupt signature: just fallback to full type name
533+
char bufCorrupt[256];
534+
char *pCorrupt = bufCorrupt;
535+
size_t cbCorrupt = sizeof(bufCorrupt);
536+
g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pCorrupt, cbCorrupt);
537+
CLR_Debug::Printf("%s", bufCorrupt);
538+
break;
539+
}
540+
541+
if (elem.DataType == DATATYPE_VAR || elem.DataType == DATATYPE_MVAR)
542+
{
543+
int gpIndex = elem.GenericParamPosition;
544+
545+
// if the caller's genericType is non‐null, ask the CLR to map !n→actual argument:
546+
if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType))
547+
{
548+
CLR_RT_TypeDef_Index tdArg{};
549+
NanoCLRDataType dtArg;
550+
551+
bool ok =
552+
tsInst.assembly->FindGenericParamAtTypeSpec(genericType->TypeSpec(), gpIndex, tdArg, dtArg);
553+
if (ok)
554+
{
555+
// Print that bound argument (e.g. "I4" or full class name)
556+
char bufArg[256];
557+
char *pArg = bufArg;
558+
size_t cbArg = sizeof(bufArg);
559+
g_CLR_RT_TypeSystem.BuildTypeName(tdArg, pArg, cbArg);
560+
CLR_Debug::Printf("%s", bufArg);
561+
break;
562+
}
563+
}
564+
565+
// Couldn't resolve or caller was not generic: print "!n" or "!!n" literally
566+
if (elem.DataType == DATATYPE_VAR)
567+
{
568+
CLR_Debug::Printf("!%d", gpIndex);
569+
}
570+
else
571+
{
572+
CLR_Debug::Printf("!!%d", gpIndex);
573+
}
574+
break;
575+
}
576+
577+
if (elem.DataType == DATATYPE_SZARRAY)
578+
{
579+
// advance to see what’s inside the array
580+
if (FAILED(parser.Advance(elem)))
581+
{
582+
// seems to be malformed: print SZARRAY and stop
583+
CLR_Debug::Printf("SZARRAY");
584+
break;
585+
}
586+
587+
// inner element is a VAR/MVAR, it describes “!n[]”
588+
if (elem.DataType == DATATYPE_VAR || elem.DataType == DATATYPE_MVAR)
589+
{
590+
int gpIndex = elem.GenericParamPosition;
591+
592+
if (genericType != nullptr && NANOCLR_INDEX_IS_VALID(*genericType))
593+
{
594+
CLR_RT_TypeDef_Index tdArg{};
595+
NanoCLRDataType dtArg;
596+
597+
bool genericParamFound =
598+
tsInst.assembly->FindGenericParamAtTypeSpec(genericType->TypeSpec(), gpIndex, tdArg, dtArg);
599+
if (genericParamFound)
600+
{
601+
// print "I4[]" or the bound argument plus []
602+
char bufArg[256];
603+
char *pArg = bufArg;
604+
size_t cbArg = sizeof(bufArg);
605+
g_CLR_RT_TypeSystem.BuildTypeName(tdArg, pArg, cbArg);
606+
CLR_Debug::Printf("%s[]", bufArg);
607+
break;
608+
}
609+
}
610+
611+
// Fallback if we couldn’t resolve: "!n[]" or "!!n[]"
612+
if (elem.DataType == DATATYPE_VAR)
613+
{
614+
CLR_Debug::Printf("!%d[]", gpIndex);
615+
}
616+
else
617+
{
618+
CLR_Debug::Printf("!!%d[]", gpIndex);
619+
}
620+
break;
621+
}
622+
623+
// If it's SZARRAY of a primitive or class (e.g. "Int32[]"), just print full name:
624+
{
625+
char bufArr[256];
626+
char *pArr = bufArr;
627+
size_t cbArr = sizeof(bufArr);
628+
g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pArr, cbArr);
629+
CLR_Debug::Printf("%s", bufArr);
630+
break;
631+
}
632+
}
633+
634+
// now all the rest: just print the full type name
635+
char bufGeneric[256];
636+
char *pGeneric = bufGeneric;
637+
size_t cbGeneric = sizeof(bufGeneric);
638+
g_CLR_RT_TypeSystem.BuildTypeName(tsIdx, pGeneric, cbGeneric);
639+
CLR_Debug::Printf("%s", bufGeneric);
640+
break;
641+
}
642+
482643
case TBL_FieldDef:
483644
{
484645
LOOKUP_ELEMENT_IDX(index, FieldDef, FIELDDEF);
@@ -493,8 +654,20 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g
493654
}
494655
case TBL_MethodSpec:
495656
{
496-
LOOKUP_ELEMENT_IDX(index, MethodSpec, METHODSPEC);
497-
CLR_RT_DUMP::METHODSPEC(s);
657+
CLR_UINT32 idx = CLR_DataFromTk(token);
658+
auto &xref = crossReferenceMethodSpec[idx];
659+
660+
CLR_RT_MethodSpec_Index msi;
661+
msi.Set(assemblyIndex, idx);
662+
663+
char buf[256], *p = buf;
664+
size_t cb = sizeof(buf);
665+
g_CLR_RT_TypeSystem.BuildMethodSpecName(
666+
msi,
667+
&xref.genericType, // again: the closed declaring type
668+
p,
669+
cb);
670+
CLR_Debug::Printf("%s", buf);
498671
break;
499672
}
500673
case TBL_Strings:
@@ -675,12 +848,34 @@ void CLR_RT_Assembly::DumpOpcodeDirect(
675848

676849
if (IsOpParamToken(opParam))
677850
{
678-
DumpToken(CLR_ReadTokenCompressed(ip, op), call.genericType);
851+
// Read the raw 32-bit “token” out of the IL stream:
852+
CLR_UINT32 token = CLR_ReadTokenCompressed(ip, op);
853+
854+
// If this is a CALL or CALLVIRT, force a MethodDef_Instance resolve and
855+
// use CLR_RT_DUMP::METHOD to print “TypeName::MethodName”. Otherwise fall
856+
// back to the existing DumpToken logic (fields, types, strings, etc.).
857+
if (op == CEE_CALL || op == CEE_CALLVIRT)
858+
{
859+
CLR_RT_MethodDef_Instance mdInst{};
860+
if (mdInst.ResolveToken(token, call.assembly))
861+
{
862+
// mdInst now holds the target MethodDef (or MethodSpec) plus any genericType.
863+
CLR_RT_DUMP::METHOD(mdInst, mdInst.genericType);
864+
}
865+
else
866+
{
867+
// In the unlikely case ResolveToken fails, fall back to raw DumpToken:
868+
DumpToken(token, call.genericType);
869+
}
870+
}
871+
else
872+
{
873+
DumpToken(token, call.genericType);
874+
}
679875
}
680876
else
681877
{
682-
CLR_UINT32 argLo;
683-
CLR_UINT32 argHi;
878+
CLR_UINT32 argLo, argHi;
684879

685880
switch (c_CLR_opParamSizeCompressed[opParam])
686881
{

src/CLR/Include/nanoCLR_Runtime.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,7 +2013,17 @@ struct CLR_RT_TypeSystem // EVENT HEAP - NO RELOCATION -
20132013
size_t &size);
20142014
HRESULT BuildFieldName(const CLR_RT_FieldDef_Index &fd, char *&szBuffer, size_t &size);
20152015
HRESULT BuildMethodRefName(const CLR_RT_MethodRef_Index &method, char *&szBuffer, size_t &iBuffer);
2016+
HRESULT BuildMethodRefName(
2017+
const CLR_RT_MethodRef_Index &mri,
2018+
const CLR_RT_TypeSpec_Index *callerGeneric, // may be nullptr if none
2019+
char *&szBuffer,
2020+
size_t &iBuffer);
20162021
HRESULT BuildMethodSpecName(const CLR_RT_MethodSpec_Index &ms, char *&szBuffer, size_t &iBuffer);
2022+
HRESULT BuildMethodSpecName(
2023+
const CLR_RT_MethodSpec_Index &msi,
2024+
const CLR_RT_TypeSpec_Index *callerGeneric, // may be nullptr if none
2025+
char *&szBuffer,
2026+
size_t &iBuffer);
20172027

20182028
HRESULT QueueStringToBuffer(char *&szBuffer, size_t &size, const char *szText);
20192029

0 commit comments

Comments
 (0)