diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 748a66f692bf3b..7ca0194fdb11da 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -394,7 +394,7 @@ private void PublishCode()
_methodCodeNode.InitializeDebugLocInfos(_debugLocInfos);
_methodCodeNode.InitializeDebugVarInfos(_debugVarInfos, _compilation.TypeSystemContext.Target);
#if READYTORUN
- _methodCodeNode.InitializeInliningInfo(_inlinedMethods.ToArray());
+ _methodCodeNode.InitializeInliningInfo(_inlinedMethods.ToArray(), _compilation.NodeFactory);
// Detect cases where the instruction set support used is a superset of the baseline instruction set specification
var baselineSupport = _compilation.InstructionSetSupport;
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
index 548abb4d8a5e99..c63e589328b305 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/InstanceEntryPointTableNode.cs
@@ -17,22 +17,58 @@
namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
- public class InstanceEntryPointTableNode : HeaderTableNode
+ public class InstanceEntryPointTableNode : HeaderTableNode, ISignatureEmitter
{
private readonly NodeFactory _factory;
+ private bool _materializedSignature;
public InstanceEntryPointTableNode(NodeFactory factory)
: base(factory.Target)
{
_factory = factory;
+ _factory.ManifestMetadataTable.RegisterEmitter(this);
}
-
+
+ public void MaterializeSignature()
+ {
+ if (!_materializedSignature)
+ {
+ if (_factory.CompilationModuleGroup.IsInputBubble)
+ {
+ foreach (MethodWithGCInfo method in _factory.EnumerateCompiledMethods(null, CompiledMethodCategory.Instantiated))
+ {
+ BuildSignatureForMethod(method, _factory);
+ }
+ }
+
+ _materializedSignature = true;
+ }
+ }
+
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
sb.Append("__ReadyToRunInstanceEntryPointTable");
}
+ private ArraySignatureBuilder BuildSignatureForMethod(MethodWithGCInfo method, NodeFactory factory)
+ {
+ // In composite R2R format, always enforce owning type to let us share generic instantiations among modules
+
+ EcmaMethod typicalMethod = (EcmaMethod)method.Method.GetTypicalMethodDefinition();
+ ModuleToken moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle);
+
+ ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
+ signatureBuilder.EmitMethodSignature(
+ new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false, context: null),
+ enforceDefEncoding: true,
+ enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module),
+ factory.SignatureContext,
+ isInstantiatingStub: false);
+
+ return signatureBuilder;
+ }
+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
if (relocsOnly)
@@ -55,17 +91,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
int methodIndex = factory.RuntimeFunctionsTable.GetIndex(method);
- // In composite R2R format, always enforce owning type to let us share generic instantiations among modules
- EcmaMethod typicalMethod = (EcmaMethod)method.Method.GetTypicalMethodDefinition();
- ModuleToken moduleToken = new ModuleToken(typicalMethod.Module, typicalMethod.Handle);
-
- ArraySignatureBuilder signatureBuilder = new ArraySignatureBuilder();
- signatureBuilder.EmitMethodSignature(
- new MethodWithToken(method.Method, moduleToken, constrainedType: null, unboxing: false, context: null),
- enforceDefEncoding: true,
- enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module),
- factory.SignatureContext,
- isInstantiatingStub: false);
+ ArraySignatureBuilder signatureBuilder = BuildSignatureForMethod(method, factory);
byte[] signature = signatureBuilder.ToArray();
BlobVertex signatureBlob;
if (!uniqueSignatures.TryGetValue(signature, out signatureBlob))
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs
index 80f80b202cecc7..ca6b4fc84d3a7d 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
@@ -63,6 +64,11 @@ public class ManifestMetadataTableNode : HeaderTableNode
///
private int _nextModuleId;
+ ///
+ /// Modules which need to exist in set of modules visible
+ ///
+ private ConcurrentBag _modulesWhichMustBeIndexable = new ConcurrentBag();
+
///
/// Set to true after GetData has been called. After that, ModuleToIndex may be called no more.
///
@@ -136,6 +142,19 @@ public int ModuleToIndex(EcmaModule module)
return ModuleToIndexInternal(module);
}
+ public void EnsureModuleIndexable(ModuleDesc module)
+ {
+ if (_emissionCompleted)
+ {
+ throw new InvalidOperationException("Adding a new assembly after signatures have been materialized.");
+ }
+
+ if (module is EcmaModule ecmaModule && _nodeFactory.CompilationModuleGroup.VersionsWithModule(ecmaModule))
+ {
+ _modulesWhichMustBeIndexable.Add(ecmaModule);
+ }
+ }
+
private int ModuleToIndexInternal(EcmaModule module)
{
AssemblyName assemblyName = module.Assembly.GetName();
@@ -170,13 +189,8 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde
sb.Append("ManifestMetadataTableNode");
}
- public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
+ private void ComputeLastSetOfModuleIndices()
{
- if (relocsOnly)
- {
- return new ObjectData(Array.Empty(), null, 1, null);
- }
-
if (!_emissionCompleted)
{
foreach (ISignatureEmitter emitter in _signatureEmitters)
@@ -184,8 +198,25 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
emitter.MaterializeSignature();
}
+ EcmaModule [] moduleArray = _modulesWhichMustBeIndexable.ToArray();
+ Array.Sort(moduleArray, (EcmaModule moduleA, EcmaModule moduleB) => moduleA.CompareTo(moduleB));
+ foreach (var module in moduleArray)
+ {
+ ModuleToIndex(module);
+ }
+
_emissionCompleted = true;
}
+ }
+
+ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
+ {
+ if (relocsOnly)
+ {
+ return new ObjectData(Array.Empty(), null, 1, null);
+ }
+
+ ComputeLastSetOfModuleIndices();
MetadataBuilder metadataBuilder = new MetadataBuilder();
@@ -277,6 +308,8 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
internal byte[] GetManifestAssemblyMvidTableData()
{
+ ComputeLastSetOfModuleIndices();
+
byte[] manifestAssemblyMvidTable = new byte[ManifestAssemblyMvidTableSize];
for (int i = 0; i < _manifestAssemblyMvids.Count; i++)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
index 720cce1b60b4b7..514441e2ba646a 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs
@@ -8,6 +8,7 @@
using Internal.JitInterface;
using Internal.Text;
using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
@@ -45,6 +46,34 @@ protected override void OnMarked(NodeFactory context)
InitializeFrameInfos(Array.Empty());
}
_lateTriggeredCompilation = context.CompilationCurrentPhase != 0;
+ RegisterInlineeModuleIndices(context);
+ }
+
+ private void RegisterInlineeModuleIndices(NodeFactory factory)
+ {
+ if (_inlinedMethods != null)
+ {
+ foreach (var inlinee in _inlinedMethods)
+ {
+ MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition();
+ if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition))
+ {
+ // We don't record non-ECMA methods because they don't have tokens that
+ // diagnostic tools could reason about anyway.
+ continue;
+ }
+
+ if (!factory.CompilationModuleGroup.VersionsWithMethodBody(inlinee))
+ {
+ // We cannot record inlining info across version bubble as cross-bubble assemblies
+ // are not guaranteed to preserve token values. Only non-versionable methods may be
+ // inlined across the version bubble.
+ Debug.Assert(inlinee.IsNonVersionable());
+ continue;
+ }
+ factory.ManifestMetadataTable.EnsureModuleIndexable(ecmaInlineeDefinition.Module);
+ }
+ }
}
public override int DependencyPhaseForDeferredStaticComputation => _lateTriggeredCompilation ? 2 : 0;
@@ -316,10 +345,12 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer
return comparer.Compare(_method, otherNode._method);
}
- public void InitializeInliningInfo(MethodDesc[] inlinedMethods)
+ public void InitializeInliningInfo(MethodDesc[] inlinedMethods, NodeFactory factory)
{
Debug.Assert(_inlinedMethods == null);
_inlinedMethods = inlinedMethods;
+ if (this.Marked)
+ RegisterInlineeModuleIndices(factory);
}
public int Offset => 0;