@@ -469,16 +469,177 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g
469
469
}
470
470
case TBL_MethodRef:
471
471
{
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);
474
488
break ;
475
489
}
476
490
case TBL_TypeDef:
477
491
{
492
+ // A genuine TypeDef token—print its (possibly non‐generic) name.
478
493
LOOKUP_ELEMENT_IDX (index, TypeDef, TYPEDEF);
479
494
CLR_RT_DUMP::TYPE (s);
480
495
break ;
481
496
}
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
+
482
643
case TBL_FieldDef:
483
644
{
484
645
LOOKUP_ELEMENT_IDX (index, FieldDef, FIELDDEF);
@@ -493,8 +654,20 @@ void CLR_RT_Assembly::DumpToken(CLR_UINT32 token, const CLR_RT_TypeSpec_Index *g
493
654
}
494
655
case TBL_MethodSpec:
495
656
{
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);
498
671
break ;
499
672
}
500
673
case TBL_Strings:
@@ -675,12 +848,34 @@ void CLR_RT_Assembly::DumpOpcodeDirect(
675
848
676
849
if (IsOpParamToken (opParam))
677
850
{
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
+ }
679
875
}
680
876
else
681
877
{
682
- CLR_UINT32 argLo;
683
- CLR_UINT32 argHi;
878
+ CLR_UINT32 argLo, argHi;
684
879
685
880
switch (c_CLR_opParamSizeCompressed[opParam])
686
881
{
0 commit comments