@@ -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 {
0 commit comments