Repository: dotnet/runtime
File: src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunReader.cs (C#)

Code before:
                    methodTypeArgs = new string[typeArgCount];
                    for (int typeArgIndex = 0; typeArgIndex < typeArgCount; typeArgIndex++)
                    {
                        methodTypeArgs[typeArgIndex] = decoder.ReadTypeSignatureNoEmit();
                    }
                }

                string constrainedType = null;
                if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_Constrained) != 0)
                {
                    constrainedType = decoder.ReadTypeSignatureNoEmit();
                }

                List<string> signaturePrefixes = [];
                if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_AsyncVariant) != 0)
                {
                    signaturePrefixes.Add("[Async]");
                }
                if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0)
                {
                    throw new NotImplementedException("Crossgen2 should not emit code for Instantiating stubs.");
                }
                if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_UnboxingStub) != 0)
                {
                    throw new NotImplementedException("Crossgen2 should not emit code for Unboxing stubs.");
                }

                int runtimeFunctionId;
                int? fixupOffset;
                GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixupOffset);
                ReadyToRunMethod method = new ReadyToRunMethod(
                    this,
                    mdReader,
                    methodHandle,
                    runtimeFunctionId,
                    owningType,
                    constrainedType,
                    methodTypeArgs,
                    signaturePrefixes.ToArray(),
                    fixupOffset);
                if (method.EntryPointRuntimeFunctionId >= 0 && method.EntryPointRuntimeFunctionId < isEntryPoint.Length)
                {
                    isEntryPoint[method.EntryPointRuntimeFunctionId] = true;
                }
                _instanceMethods.Add(new InstanceMethod(curParser.LowHashcode, method));
                curParser = allEntriesEnum.GetNext();
            }
        }

        public IEnumerable<ReadyToRunMethod> Methods
        {

Review comment (bug):
Introducing `NotImplementedException` for `READYTORUN_METHOD_SIG_InstantiatingStub` and `READYTORUN_METHOD_SIG_UnboxingStub` changes behavior from previously ignoring these flags to now hard-failing when they are present. This will cause R2RDump to throw for existing ReadyToRun images that contain such stubs (e.g., images produced by older crossgen), even though the rest of the method decoding is otherwise supported. Consider either handling these flags by adding appropriate signature prefixes, or at least skipping/ignoring them rather than throwing, to preserve the ability to analyze existing binaries.

Code after:

            List<string> signaturePrefixes = [];
            if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_UnboxingStub) != 0)
            {
                signaturePrefixes.Add("[UNBOX]");
            }
            if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_InstantiatingStub) != 0)
            {
                signaturePrefixes.Add("
");
            }
            if ((methodFlags & (uint)ReadyToRunMethodSigFlags.READYTORUN_METHOD_SIG_AsyncVariant) != 0)
            {
                signaturePrefixes.Add("[ASYNC]");
            }

            return new DecodedMethodSignature(owningType, methodHandle, methodTypeArgs, constrainedType, signaturePrefixes.ToArray());
        }

        /// <summary>
        /// Initialize generic method instances with argument types and runtime function indices from InstanceMethodEntrypoints
        /// </summary>
        private void ParseInstanceMethodEntrypoints(bool[] isEntryPoint)
        {
            if (!ReadyToRunHeader.Sections.TryGetValue(ReadyToRunSectionType.InstanceMethodEntryPoints, out ReadyToRunSection instMethodEntryPointSection))
            {
                return;
            }
            int instMethodEntryPointsOffset = GetOffset(instMethodEntryPointSection.RelativeVirtualAddress);
            NativeParser parser = new NativeParser(ImageReader, (uint)instMethodEntryPointsOffset);
            NativeHashtable instMethodEntryPoints = new NativeHashtable(ImageReader, parser, (uint)(instMethodEntryPointsOffset + instMethodEntryPointSection.Size));
            NativeHashtable.AllEntriesEnumerator allEntriesEnum = instMethodEntryPoints.EnumerateAllEntries();
            NativeParser curParser = allEntriesEnum.GetNext();
            while (!curParser.IsNull())
            {
                IAssemblyMetadata mdReader = GetGlobalMetadata();
                SignatureFormattingOptions dummyOptions = new SignatureFormattingOptions();
                SignatureDecoder decoder = new SignatureDecoder(_assemblyResolver, dummyOptions, mdReader?.MetadataReader, this, (int)curParser.Offset);

                var sig = DecodeMethodSignature(ref mdReader, ref decoder);

                int runtimeFunctionId;
                int? fixupOffset;
                GetRuntimeFunctionIndexFromOffset((int)decoder.Offset, out runtimeFunctionId, out fixupOffset);
                ReadyToRunMethod method = new ReadyToRunMethod(
                    this,
                    mdReader,
                    sig.MethodHandle,
                    runtimeFunctionId,
                    sig.OwningType,
                    sig.ConstrainedType,
                    sig.MethodTypeArgs,