//
CorHeaderNode,
ReadyToRunHeaderNode,
+ ReadyToRunAssemblyHeaderNode,
ImportSectionsTableNode,
ImportSectionNode,
MethodEntrypointTableNode,
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection.PortableExecutable;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using ObjectData = ILCompiler.DependencyAnalysis.ObjectNode.ObjectData;
using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
using System.Security.Cryptography;
namespace ILCompiler.DependencyAnalysis
/// </summary>
internal class ReadyToRunObjectWriter
{
- // Nodefactory for which ObjectWriter is instantiated for.
+ /// <summary>
+ /// Nodefactory for which ObjectWriter is instantiated for.
+ /// </summary>
private readonly NodeFactory _nodeFactory;
+
+ /// <summary>
+ /// Output executable path.
+ /// </summary>
private readonly string _objectFilePath;
+
+ /// <summary>
+ /// Set to non-null when rewriting MSIL assemblies during composite R2R build;
+ /// we basically publish the input assemblies into the composite build output folder
+ /// using the same ReadyToRunObjectWriter as we're using for emitting the "actual"
+ /// R2R executable, just in this special mode in which we emit a minimal R2R header
+ /// with forwarding information pointing at the composite module with native code.
+ /// </summary>
+ private readonly EcmaModule _componentModule;
+
+ /// <summary>
+ /// Nodes to emit into the output executable as collected by the dependency analysis.
+ /// </summary>
private readonly IEnumerable<DependencyNode> _nodes;
- private readonly PEReader _inputPeReader;
+
+ /// <summary>
+ /// True when the executable generator should output a map file.
+ /// </summary>
private readonly bool _generateMapFile;
#if DEBUG
Dictionary<string, NodeInfo> _previouslyWrittenNodeNames = new Dictionary<string, NodeInfo>();
#endif
- public ReadyToRunObjectWriter(PEReader inputPeReader, string objectFilePath, IEnumerable<DependencyNode> nodes, NodeFactory factory, bool generateMapFile)
+ public ReadyToRunObjectWriter(string objectFilePath, EcmaModule componentModule, IEnumerable<DependencyNode> nodes, NodeFactory factory, bool generateMapFile)
{
_objectFilePath = objectFilePath;
+ _componentModule = componentModule;
_nodes = nodes;
_nodeFactory = factory;
- _inputPeReader = inputPeReader;
_generateMapFile = generateMapFile;
}
if (mapFile != null)
mapFile.WriteLine($@"R2R object emission started: {DateTime.Now}");
+ PEHeaderBuilder headerBuilder;
+ int timeDateStamp;
+ ISymbolNode r2rHeaderExportSymbol;
+
+ if (_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode && _componentModule == null)
+ {
+ headerBuilder = PEHeaderProvider.Create(
+ imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll,
+ dllCharacteristics: default(DllCharacteristics),
+ Subsystem.Unknown,
+ _nodeFactory.Target);
+ // TODO: generate a non-zero timestamp: https://github.com/dotnet/runtime/issues/32507
+ timeDateStamp = 0;
+ r2rHeaderExportSymbol = _nodeFactory.Header;
+ }
+ else
+ {
+ PEReader inputPeReader = (_componentModule != null ? _componentModule.PEReader : _nodeFactory.CompilationModuleGroup.CompilationModuleSet.First().PEReader);
+ headerBuilder = PEHeaderProvider.Copy(inputPeReader.PEHeaders, _nodeFactory.Target);
+ timeDateStamp = inputPeReader.PEHeaders.CoffHeader.TimeDateStamp;
+ r2rHeaderExportSymbol = null;
+ }
+
+ Func<RuntimeFunctionsTableNode> getRuntimeFunctionsTable = null;
+ if (_componentModule == null)
+ {
+ getRuntimeFunctionsTable = GetRuntimeFunctionsTable;
+ }
R2RPEBuilder r2rPeBuilder = new R2RPEBuilder(
_nodeFactory.Target,
- _inputPeReader,
- GetRuntimeFunctionsTable);
+ headerBuilder,
+ r2rHeaderExportSymbol,
+ Path.GetFileName(_objectFilePath),
+ getRuntimeFunctionsTable);
NativeDebugDirectoryEntryNode nativeDebugDirectoryEntryNode = null;
EmitObjectData(r2rPeBuilder, nodeContents, nodeIndex, name, node.Section, mapFile);
}
- r2rPeBuilder.SetCorHeader(_nodeFactory.CopiedCorHeaderNode, _nodeFactory.CopiedCorHeaderNode.Size);
- r2rPeBuilder.SetDebugDirectory(_nodeFactory.DebugDirectoryNode, _nodeFactory.DebugDirectoryNode.Size);
+ if (!_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode || _componentModule != null)
+ {
+ r2rPeBuilder.SetCorHeader(_nodeFactory.CopiedCorHeaderNode, _nodeFactory.CopiedCorHeaderNode.Size);
+ r2rPeBuilder.SetDebugDirectory(_nodeFactory.DebugDirectoryNode, _nodeFactory.DebugDirectoryNode.Size);
+ }
if (_nodeFactory.Win32ResourcesNode != null)
{
using (var peStream = File.Create(_objectFilePath))
{
- r2rPeBuilder.Write(peStream);
+ r2rPeBuilder.Write(peStream, timeDateStamp);
// Compute MD5 hash of the output image and store that in the native DebugDirectory entry
using (var md5Hash = MD5.Create())
r2rPeBuilder.AddObjectData(data, section, name, mapFile);
}
- public static void EmitObject(PEReader inputPeReader, string objectFilePath, IEnumerable<DependencyNode> nodes, NodeFactory factory, bool generateMapFile)
+ public static void EmitObject(string objectFilePath, EcmaModule componentModule, IEnumerable<DependencyNode> nodes, NodeFactory factory, bool generateMapFile)
{
Console.WriteLine($@"Emitting R2R PE file: {objectFilePath}");
- ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter(inputPeReader, objectFilePath, nodes, factory, generateMapFile);
+ ReadyToRunObjectWriter objectWriter = new ReadyToRunObjectWriter(objectFilePath, componentModule, nodes, factory, generateMapFile);
objectWriter.EmitPortableExecutable();
}
}
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using Internal.ReadyToRunConstants;
+using Internal.TypeSystem.Ecma;
+using System.Collections.Generic;
+using System.Linq;
namespace ILCompiler
{
/// Gets the flags to be stored in the generated ReadyToRun module header.
/// </summary>
public abstract ReadyToRunFlags GetReadyToRunFlags();
+
+ /// <summary>
+ /// When set to true, unconditionally add module overrides to all signatures. This is needed in composite
+ /// build mode so that import cells and instance entry point table are caller module-agnostic.
+ /// </summary>
+ public bool EnforceOwningType(EcmaModule module)
+ {
+ return IsCompositeBuildMode || module != CompilationModuleSet.Single();
+ }
+
+ /// <summary>
+ /// Returns true when the compiler is running in composite build mode i.e. building an arbitrary number of
+ /// input MSIL assemblies into a single output R2R binary.
+ /// </summary>
+ public abstract bool IsCompositeBuildMode { get; }
+
+ /// <summary>
+ /// List of input modules to use for the compilation.
+ /// </summary>
+ public abstract IEnumerable<EcmaModule> CompilationModuleSet { get; }
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection.Metadata.Ecma335;
+
+using Internal.JitInterface;
+using Internal.NativeFormat;
+using Internal.Runtime;
+using Internal.Text;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+namespace ILCompiler.DependencyAnalysis.ReadyToRun
+{
+ public class AssemblyTableNode : HeaderTableNode
+ {
+ private readonly List<AssemblyHeaderNode> _assemblyHeaders;
+
+ public AssemblyTableNode(TargetDetails target)
+ : base(target)
+ {
+ _assemblyHeaders = new List<AssemblyHeaderNode>();
+ }
+
+ public void Add(AssemblyHeaderNode componentAssemblyHeader)
+ {
+ _assemblyHeaders.Add(componentAssemblyHeader);
+ }
+
+ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(nameMangler.CompilationUnitPrefix);
+ sb.Append("__ReadyToRunAssemblyTable");
+ }
+
+ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
+ {
+ ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
+ builder.AddSymbol(this);
+ foreach (AssemblyHeaderNode assemblyHeader in _assemblyHeaders)
+ {
+ // TODO: IMAGE_DATA_DIRECTORY CorHeader - no support for embedded MSIL yet
+ builder.EmitInt(0);
+ builder.EmitInt(0);
+ // IMAGE_DATA_DIRECTORY ReadyToRunHeader
+ builder.EmitReloc(assemblyHeader, RelocType.IMAGE_REL_BASED_ADDR32NB);
+ builder.EmitReloc(assemblyHeader, RelocType.IMAGE_REL_SYMBOL_SIZE);
+ }
+ return builder.ToObjectData();
+ }
+
+ public override int ClassCode => 513314416;
+ }
+}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
- sb.Append("__ReadyToRunAttributePresenceFilter");
+ sb.Append("__ReadyToRunAttributePresenceFilter__");
+ sb.Append(_module.Assembly.GetName().Name);
}
private struct CustomAttributeEntry
}
}
- public class HeaderNode : ObjectNode, ISymbolDefinitionNode
+ public abstract class HeaderNode : ObjectNode, ISymbolDefinitionNode
{
struct HeaderItem
{
_items.Add(new HeaderItem(id, node, startSymbol));
}
- public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
- {
- sb.Append(nameMangler.CompilationUnitPrefix);
- sb.Append("__ReadyToRunHeader");
- }
public int Offset => 0;
public override bool IsShareable => false;
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
+ protected abstract void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb);
+
+ public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb) => AppendMangledHeaderName(nameMangler, sb);
+
public override bool StaticDependenciesAreComputed => true;
public override ObjectNodeSection Section
builder.RequireInitialPointerAlignment();
builder.AddSymbol(this);
+ EmitHeaderPrefix(ref builder);
+
// Don't bother sorting if we're not emitting the contents
if (!relocsOnly)
_items.Sort((x, y) => Comparer<int>.Default.Compare((int)x.Id, (int)y.Id));
- // ReadyToRunHeader.Magic
- builder.EmitInt((int)(ReadyToRunHeaderConstants.Signature));
-
- // ReadyToRunHeader.MajorVersion
- builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMajorVersion));
- builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMinorVersion));
-
// ReadyToRunHeader.Flags
builder.EmitInt((int)_flags);
// ReadyToRunHeader.NumberOfSections
ObjectDataBuilder.Reservation sectionCountReservation = builder.ReserveInt();
-
+
int count = 0;
foreach (var item in _items)
{
continue;
builder.EmitInt((int)item.Id);
-
+
builder.EmitReloc(item.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB);
builder.EmitReloc(item.StartSymbol, RelocType.IMAGE_REL_SYMBOL_SIZE);
-
+
count++;
}
builder.EmitInt(sectionCountReservation, count);
-
+
return builder.ToObjectData();
}
+ protected abstract void EmitHeaderPrefix(ref ObjectDataBuilder builder);
+
protected internal override int Phase => (int)ObjectNodePhase.Ordered;
+ }
+
+ public class GlobalHeaderNode : HeaderNode
+ {
+ public GlobalHeaderNode(TargetDetails target, ReadyToRunFlags flags)
+ : base(target, flags)
+ {
+ }
+
+ protected override void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(nameMangler.CompilationUnitPrefix);
+ sb.Append("__ReadyToRunHeader");
+ }
+
+ protected override void EmitHeaderPrefix(ref ObjectDataBuilder builder)
+ {
+ // ReadyToRunHeader.Magic
+ builder.EmitInt((int)(ReadyToRunHeaderConstants.Signature));
+
+ // ReadyToRunHeader.MajorVersion
+ builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMajorVersion));
+ builder.EmitShort((short)(ReadyToRunHeaderConstants.CurrentMinorVersion));
+ }
public override int ClassCode => (int)ObjectNodeOrder.ReadyToRunHeaderNode;
}
+
+ public class AssemblyHeaderNode : HeaderNode
+ {
+ private readonly int _index;
+
+ public AssemblyHeaderNode(TargetDetails target, ReadyToRunFlags flags, int index)
+ : base(target, flags)
+ {
+ _index = index;
+ }
+
+ protected override void EmitHeaderPrefix(ref ObjectDataBuilder builder)
+ {
+ }
+
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ return _index - ((AssemblyHeaderNode)other)._index;
+ }
+
+ protected override void AppendMangledHeaderName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append(nameMangler.CompilationUnitPrefix);
+ sb.Append("__ReadyToRunAssemblyHeader__");
+ sb.Append(_index.ToString());
+ }
+
+ public override int ClassCode => (int)ObjectNodeOrder.ReadyToRunAssemblyHeaderNode;
+ }
}
/// </summary>
public class InliningInfoNode : HeaderTableNode
{
- private readonly EcmaModule _globalContext;
+ private readonly EcmaModule _module;
- public InliningInfoNode(TargetDetails target, EcmaModule globalContext)
+ public InliningInfoNode(TargetDetails target, EcmaModule module)
: base(target)
{
- _globalContext = globalContext;
+ _module = module;
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
- sb.Append("__ReadyToRunInliningInfoTable");
+ sb.Append("__ReadyToRunInliningInfoTable__");
+ sb.Append(_module.Assembly.GetName().Name);
}
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
MethodDesc[] inlinees = methodNode.InlinedMethods;
MethodDesc inliner = methodNode.Method;
- MethodDesc inlinerDefinition = inliner.GetTypicalMethodDefinition();
+ EcmaMethod inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition();
+ if (inlinerDefinition.Module != _module)
+ {
+ // Only encode inlining info for inliners within the active module
+ continue;
+ }
foreach (MethodDesc inlinee in inlinees)
{
var sig = new VertexSequence();
- bool isForeignInlinee = inlinee.Module != _globalContext;
+ bool isForeignInlinee = inlinee.Module != _module;
sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0))));
if (isForeignInlinee)
{
int ridDelta = inlinerRid - baseRid;
baseRid = inlinerRid;
Debug.Assert(ridDelta >= 0);
- bool isForeignInliner = inliner.Module != _globalContext;
+ bool isForeignInliner = inliner.Module != _module;
sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0))));
if (isForeignInliner)
{
definedSymbols: new ISymbolDefinitionNode[] { this });
}
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ InliningInfoNode otherInliningInfo = (InliningInfoNode)other;
+ return _module.Assembly.GetName().Name.CompareTo(otherInliningInfo._module.Assembly.GetName().Name);
+ }
+
public override int ClassCode => -87382891;
}
}
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection.Metadata.Ecma335;
using Internal.JitInterface;
{
public class InstanceEntryPointTableNode : HeaderTableNode
{
- public InstanceEntryPointTableNode(TargetDetails target)
- : base(target)
+ private readonly NodeFactory _factory;
+
+ public InstanceEntryPointTableNode(NodeFactory factory)
+ : base(factory.Target)
{
+ _factory = factory;
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
int methodIndex = factory.RuntimeFunctionsTable.GetIndex(method);
- bool enforceOwningType = false;
- ModuleToken moduleToken = factory.SignatureContext.GetModuleTokenForMethod(method.Method.GetTypicalMethodDefinition());
- if (moduleToken.Module != factory.SignatureContext.GlobalContext)
- {
- enforceOwningType = true;
- }
+ // 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),
enforceDefEncoding: true,
- enforceOwningType,
+ enforceOwningType: _factory.CompilationModuleGroup.EnforceOwningType(moduleToken.Module),
factory.SignatureContext,
- isUnboxingStub: false,
+ isUnboxingStub: false,
isInstantiatingStub: false);
byte[] signature = signatureBuilder.ToArray();
BlobVertex signatureBlob;
using System.Reflection.Metadata.Ecma335;
using Internal.Text;
+using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Debug = System.Diagnostics.Debug;
/// </summary>
private readonly Dictionary<int, AssemblyName> _moduleIdToAssemblyNameMap;
-
/// <summary>
/// Registered signature emitters.
/// </summary>
private bool _emissionCompleted;
/// <summary>
- /// Name of the input assembly.
- /// </summary>
- private string _inputModuleName;
-
- /// <summary>
/// Node factory for the compilation
/// </summary>
private readonly NodeFactory _nodeFactory;
- public ManifestMetadataTableNode(EcmaModule inputModule, NodeFactory nodeFactory)
- : base(inputModule.Context.Target)
+ public ManifestMetadataTableNode(NodeFactory nodeFactory)
+ : base(nodeFactory.Target)
{
_assemblyRefToModuleIdMap = new Dictionary<string, int>();
_moduleIdToAssemblyNameMap = new Dictionary<int, AssemblyName>();
_signatureEmitters = new List<ISignatureEmitter>();
_nodeFactory = nodeFactory;
- _inputModuleName = inputModule.Assembly.GetName().Name;
-
- _assemblyRefCount = inputModule.MetadataReader.GetTableRowCount(TableIndex.AssemblyRef);
- for (int assemblyRefIndex = 1; assemblyRefIndex <= _assemblyRefCount; assemblyRefIndex++)
+ if (!_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode)
{
- AssemblyReferenceHandle assemblyRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
- AssemblyReference assemblyRef = inputModule.MetadataReader.GetAssemblyReference(assemblyRefHandle);
- string assemblyName = inputModule.MetadataReader.GetString(assemblyRef.Name);
- _assemblyRefToModuleIdMap[assemblyName] = assemblyRefIndex;
+ MetadataReader mdReader = _nodeFactory.CompilationModuleGroup.CompilationModuleSet.Single().MetadataReader;
+ _assemblyRefCount = mdReader.GetTableRowCount(TableIndex.AssemblyRef);
+ for (int assemblyRefIndex = 1; assemblyRefIndex <= _assemblyRefCount; assemblyRefIndex++)
+ {
+ AssemblyReferenceHandle assemblyRefHandle = MetadataTokens.AssemblyReferenceHandle(assemblyRefIndex);
+ AssemblyReference assemblyRef = mdReader.GetAssemblyReference(assemblyRefHandle);
+ string assemblyName = mdReader.GetString(assemblyRef.Name);
+ _assemblyRefToModuleIdMap[assemblyName] = assemblyRefIndex;
+ }
}
// AssemblyRefCount + 1 corresponds to ROWID 0 in the manifest metadata
_nextModuleId = _assemblyRefCount + 2;
+
+ if (_nodeFactory.CompilationModuleGroup.IsCompositeBuildMode)
+ {
+ // Fill in entries for all input modules right away to make sure they have parallel indices
+ int nextExpectedId = 2;
+ foreach (EcmaModule inputModule in _nodeFactory.CompilationModuleGroup.CompilationModuleSet)
+ {
+ int acquiredId = ModuleToIndexInternal(inputModule);
+ if (acquiredId != nextExpectedId)
+ {
+ throw new InternalCompilerErrorException($"Manifest metadata consistency error - acquired ID {acquiredId}, expected {nextExpectedId}");
+ }
+ nextExpectedId++;
+ }
+ }
}
public void RegisterEmitter(ISignatureEmitter emitter)
throw new InvalidOperationException("Cannot get ModuleToIndex mapping until marking is complete.");
}
+ return ModuleToIndexInternal(module);
+ }
+
+ private int ModuleToIndexInternal(EcmaModule module)
+ {
AssemblyName assemblyName = module.Assembly.GetName();
int assemblyRefIndex;
if (!_assemblyRefToModuleIdMap.TryGetValue(assemblyName.Name, out assemblyRefIndex))
MetadataBuilder metadataBuilder = new MetadataBuilder();
+ string manifestMetadataAssemblyName = "ManifestMetadata";
metadataBuilder.AddAssembly(
- metadataBuilder.GetOrAddString(_inputModuleName),
+ metadataBuilder.GetOrAddString(manifestMetadataAssemblyName),
new Version(0, 0, 0, 0),
culture: default(StringHandle),
publicKey: default(BlobHandle),
metadataBuilder.AddModule(
0,
- metadataBuilder.GetOrAddString(_inputModuleName),
+ metadataBuilder.GetOrAddString(manifestMetadataAssemblyName),
default(GuidHandle), default(GuidHandle), default(GuidHandle));
// Module type
metadataBuilder.AddTypeDefinition(
- default(TypeAttributes),
- default(StringHandle),
- metadataBuilder.GetOrAddString("<Module>"),
- baseType: default(EntityHandle),
- fieldList: MetadataTokens.FieldDefinitionHandle(1),
- methodList: MetadataTokens.MethodDefinitionHandle(1));
+ default(TypeAttributes),
+ default(StringHandle),
+ metadataBuilder.GetOrAddString("<Module>"),
+ baseType: default(EntityHandle),
+ fieldList: MetadataTokens.FieldDefinitionHandle(1),
+ methodList: MetadataTokens.MethodDefinitionHandle(1));
foreach (var idAndAssemblyName in _moduleIdToAssemblyNameMap.OrderBy(x => x.Key))
{
{
public class MethodEntryPointTableNode : HeaderTableNode
{
+ private readonly EcmaModule _module;
+
private struct EntryPoint
{
public static EntryPoint Null = new EntryPoint(-1, null);
}
}
- public MethodEntryPointTableNode(TargetDetails target)
+ public MethodEntryPointTableNode(EcmaModule module, TargetDetails target)
: base(target)
{
+ _module = module;
}
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
- sb.Append("__ReadyToRunMethodEntryPointTable");
+ sb.Append("__ReadyToRunMethodEntryPointTable__");
+ sb.Append(_module.Assembly.GetName().Name);
}
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
foreach (MethodWithGCInfo method in factory.EnumerateCompiledMethods())
{
- if (method.Method is EcmaMethod ecmaMethod)
+ if (method.Method is EcmaMethod ecmaMethod && ecmaMethod.Module == _module)
{
// Strip away the token type bits, keep just the low 24 bits RID
uint rid = SignatureBuilder.RidFromToken((mdToken)MetadataTokens.GetToken(ecmaMethod.Handle));
alignment: 8,
definedSymbols: new ISymbolDefinitionNode[] { this });
}
+
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ MethodEntryPointTableNode otherMethodEntryPointTable = (MethodEntryPointTableNode)other;
+ return _module.Assembly.GetName().Name.CompareTo(otherMethodEntryPointTable._module.Assembly.GetName().Name);
+ }
+
protected internal override int Phase => (int)ObjectNodePhase.Ordered;
public override int ClassCode => (int)ObjectNodeOrder.MethodEntrypointTableNode;
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Text;
+using Internal.Text;
+using Internal.TypeSystem;
+
+namespace ILCompiler.DependencyAnalysis.ReadyToRun
+{
+ /// <summary>
+ /// R2R header section holding the name of the composite R2R executable with native code
+ /// for this component module. This section gets put into R2R headers emitted when
+ /// rewriting input MSIL into standalone MSIL components of a composite R2R image.
+ /// It is used by the runtime as forwarding information to locate the composite R2R image
+ /// with the native code for a given MSIL assembly.
+ /// </summary>
+ internal class OwnerCompositeExecutableNode : HeaderTableNode
+ {
+ public override ObjectNodeSection Section => ObjectNodeSection.ReadOnlyDataSection;
+
+ public override int ClassCode => 240420333;
+
+ private readonly string _ownerExecutableName;
+
+ public OwnerCompositeExecutableNode(TargetDetails target, string ownerExecutableName)
+ : base(target)
+ {
+ _ownerExecutableName = ownerExecutableName;
+ }
+
+ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
+ {
+ sb.Append("__ReadyToRunHeader_OwnerCompositeExecutable");
+ }
+
+ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
+ {
+ ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
+ builder.RequireInitialPointerAlignment();
+ builder.AddSymbol(this);
+ builder.EmitBytes(Encoding.UTF8.GetBytes(_ownerExecutableName));
+ return builder.ToObjectData();
+ }
+ }
+}
public override int GetHashCode()
{
- return GlobalContext.GetHashCode()
- ^ (LocalContext.GetHashCode() * 31);
+ return (GlobalContext?.GetHashCode() ?? 0) ^ ((LocalContext?.GetHashCode() ?? 0) * 31);
}
public int CompareTo(SignatureContext other, TypeSystemComparer comparer)
{
+ if (GlobalContext == null || other.GlobalContext == null)
+ {
+ return (GlobalContext != null ? 1 : other.GlobalContext != null ? -1 : 0);
+ }
+
int result = GlobalContext.CompareTo(other.GlobalContext);
if (result != 0)
return result;
+ if (LocalContext == null || other.LocalContext == null)
+ {
+ return (LocalContext != null ? 1 : other.LocalContext != null ? -1 : 0);
+ }
+
return LocalContext.CompareTo(other.LocalContext);
}
+
+ public override string ToString()
+ {
+ return (GlobalContext != null ? GlobalContext.Assembly.GetName().Name : "<Composite>");
+ }
}
}
{
public class TypesTableNode : HeaderTableNode
{
- public TypesTableNode(TargetDetails target)
- : base(target) {}
+ private readonly EcmaModule _module;
+
+ public TypesTableNode(TargetDetails target, EcmaModule module)
+ : base(target)
+ {
+ _module = module;
+ }
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
- sb.Append("__ReadyToRunAvailableTypesTable");
+ sb.Append("__ReadyToRunAvailableTypesTable__");
+ sb.Append(_module.Assembly.GetName().Name);
}
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
section.Place(typesHashtable);
ReadyToRunTableManager r2rManager = (ReadyToRunTableManager)factory.MetadataManager;
-
- foreach (TypeInfo<TypeDefinitionHandle> defTypeInfo in r2rManager.GetDefinedTypes())
+ foreach (TypeInfo<TypeDefinitionHandle> defTypeInfo in r2rManager.GetDefinedTypes(_module))
{
TypeDefinitionHandle defTypeHandle = defTypeInfo.Handle;
int hashCode = 0;
typesHashtable.Append(unchecked((uint)hashCode), section.Place(new UnsignedConstant(((uint)MetadataTokens.GetRowNumber(defTypeInfo.Handle) << 1) | 0)));
}
- foreach (TypeInfo<ExportedTypeHandle> expTypeInfo in r2rManager.GetExportedTypes())
+ foreach (TypeInfo<ExportedTypeHandle> expTypeInfo in r2rManager.GetExportedTypes(_module))
{
ExportedTypeHandle expTypeHandle = expTypeInfo.Handle;
int hashCode = 0;
definedSymbols: new ISymbolDefinitionNode[] { this });
}
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
+ {
+ TypesTableNode otherTypesTable = (TypesTableNode)other;
+ return _module.Assembly.GetName().Name.CompareTo(otherTypesTable._module.Assembly.GetName().Name);
+ }
+
public override int ClassCode => -944318825;
}
}
public Win32ResourcesNode(ResourceData resourceData)
{
_resourceData = resourceData;
+ _size = -1;
}
public override ObjectNodeSection Section => ObjectNodeSection.TextSection;
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
+ return GetDataInternal();
+ }
+
+ private ObjectData GetDataInternal()
+ {
ObjectDataBuilder builder = new ObjectDataBuilder();
builder.AddSymbol(this);
_resourceData.WriteResources(this, ref builder);
return "____Win32Resources";
}
- public int Size => _size;
+ public int Size
+ {
+ get
+ {
+ if (_size < 0)
+ {
+ GetDataInternal();
+ }
+ return _size;
+ }
+ }
}
}
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using ILCompiler.DependencyAnalysisFramework;
public IMethodNode MethodEntrypoint(MethodDesc method)
{
+ EcmaModule module = ((EcmaMethod)method.GetTypicalMethodDefinition()).Module;
ModuleToken moduleToken = Resolver.GetModuleTokenForMethod(method, throwIfNotFound: true);
return MethodEntrypoint(
new MethodWithToken(method, moduleToken, constrainedType: null),
CompilerTypeSystemContext context,
CompilationModuleGroup compilationModuleGroup,
NameMangler nameMangler,
- ModuleTokenResolver moduleTokenResolver,
- SignatureContext signatureContext,
CopiedCorHeaderNode corHeaderNode,
DebugDirectoryNode debugDirectoryNode,
ResourceData win32Resources,
- AttributePresenceFilterNode attributePresenceFilterNode,
- HeaderNode headerNode)
+ ReadyToRunFlags flags)
{
TypeSystemContext = context;
CompilationModuleGroup = compilationModuleGroup;
Target = context.Target;
NameMangler = nameMangler;
MetadataManager = new ReadyToRunTableManager(context);
- Resolver = moduleTokenResolver;
- SignatureContext = signatureContext;
CopiedCorHeaderNode = corHeaderNode;
DebugDirectoryNode = debugDirectoryNode;
- AttributePresenceFilter = attributePresenceFilterNode;
- Header = headerNode;
+ Resolver = new ModuleTokenResolver(compilationModuleGroup, TypeSystemContext);
+ Header = new GlobalHeaderNode(Target, flags);
if (!win32Resources.IsEmpty)
Win32ResourcesNode = new Win32ResourcesNode(win32Resources);
+ if (CompilationModuleGroup.IsCompositeBuildMode)
+ {
+ // Create a null top-level signature context to force producing module overrides for all signaturess
+ SignatureContext = new SignatureContext(null, Resolver);
+ }
+ else
+ {
+ SignatureContext = new SignatureContext(CompilationModuleGroup.CompilationModuleSet.Single(), Resolver);
+ }
+
CreateNodeCaches();
}
_importMethods = new NodeCache<TypeAndMethod, IMethodNode>(CreateMethodEntrypoint);
- _localMethodCache = new NodeCache<TypeAndMethod, MethodWithGCInfo>(key =>
+ _localMethodCache = new NodeCache<MethodDesc, MethodWithGCInfo>(key =>
{
- return new MethodWithGCInfo(key.Method.Method);
+ return new MethodWithGCInfo(key);
});
_methodSignatures = new NodeCache<MethodFixupKey, MethodFixupSignature>(key =>
public Win32ResourcesNode Win32ResourcesNode;
- public HeaderNode Header;
+ public GlobalHeaderNode Header;
public RuntimeFunctionsTableNode RuntimeFunctionsTable;
public ProfileDataSectionNode ProfileDataSection;
- public MethodEntryPointTableNode MethodEntryPointTable;
-
public InstanceEntryPointTableNode InstanceEntryPointTable;
public ManifestMetadataTableNode ManifestMetadataTable;
- public TypesTableNode TypesTable;
-
public ImportSectionsTableNode ImportSectionsTable;
public Import ModuleImport;
public DebugInfoTableNode DebugInfoTable;
- public InliningInfoNode InliningInfoTable;
-
- public AttributePresenceFilterNode AttributePresenceFilter;
-
public ImportSectionNode EagerImports;
public ImportSectionNode MethodImports;
return _importMethods.GetOrAdd(key);
}
- private NodeCache<TypeAndMethod, MethodWithGCInfo> _localMethodCache = new NodeCache<TypeAndMethod, MethodWithGCInfo>();
+ private NodeCache<MethodDesc, MethodWithGCInfo> _localMethodCache;
private MethodWithGCInfo CreateMethodEntrypointNodeHelper(MethodWithToken targetMethod)
{
Debug.Assert(CompilationModuleGroup.ContainsMethodBody(targetMethod.Method, false));
MethodDesc localMethod = targetMethod.Method.GetCanonMethodTarget(CanonicalFormKind.Specific);
-
- TypeAndMethod localMethodKey = new TypeAndMethod(localMethod.OwningType,
- new MethodWithToken(localMethod, default(ModuleToken), constrainedType: null),
- isUnboxingStub: false,
- isInstantiatingStub: false,
- isPrecodeImportRequired: false);
- return _localMethodCache.GetOrAdd(localMethodKey);
+ return _localMethodCache.GetOrAdd(localMethod);
}
public IEnumerable<MethodWithGCInfo> EnumerateCompiledMethods()
{
methodCodeNode = localMethodImport.MethodCodeNode;
}
- if (methodCodeNode == null && methodNode is PrecodeMethodImport PrecodeMethodImport)
+ if (methodCodeNode == null && methodNode is PrecodeMethodImport precodeMethodImport)
{
- methodCodeNode = PrecodeMethodImport.MethodCodeNode;
+ methodCodeNode = precodeMethodImport.MethodCodeNode;
}
if (methodCodeNode != null && !methodCodeNode.IsEmpty)
Header.Add(Internal.Runtime.ReadyToRunSectionType.ExceptionInfo, exceptionInfoLookupTableNode, exceptionInfoLookupTableNode);
graph.AddRoot(exceptionInfoLookupTableNode, "ExceptionInfoLookupTable is always generated");
- MethodEntryPointTable = new MethodEntryPointTableNode(Target);
- Header.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, MethodEntryPointTable, MethodEntryPointTable);
-
- ManifestMetadataTable = new ManifestMetadataTableNode(SignatureContext.GlobalContext, this);
+ ManifestMetadataTable = new ManifestMetadataTableNode(this);
Header.Add(Internal.Runtime.ReadyToRunSectionType.ManifestMetadata, ManifestMetadataTable, ManifestMetadataTable);
-
Resolver.SetModuleIndexLookup(ManifestMetadataTable.ModuleToIndex);
- InstanceEntryPointTable = new InstanceEntryPointTableNode(Target);
- Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable);
+ AssemblyTableNode assemblyTable = null;
+
+ if (CompilationModuleGroup.CompilationModuleSet.Skip(1).Any())
+ {
+ assemblyTable = new AssemblyTableNode(Target);
+ Header.Add(Internal.Runtime.ReadyToRunSectionType.ComponentAssemblies, assemblyTable, assemblyTable);
+ }
+
+ // Generate per assembly header tables
+ int assemblyIndex = -1;
+ foreach (EcmaModule inputModule in CompilationModuleGroup.CompilationModuleSet)
+ {
+ assemblyIndex++;
+ HeaderNode tableHeader = Header;
+ if (assemblyTable != null)
+ {
+ AssemblyHeaderNode perAssemblyHeader = new AssemblyHeaderNode(Target, ReadyToRunFlags.READYTORUN_FLAG_Component, assemblyIndex);
+ assemblyTable.Add(perAssemblyHeader);
+ tableHeader = perAssemblyHeader;
+ }
- TypesTable = new TypesTableNode(Target);
- Header.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, TypesTable, TypesTable);
+ MethodEntryPointTableNode methodEntryPointTable = new MethodEntryPointTableNode(inputModule, Target);
+ tableHeader.Add(Internal.Runtime.ReadyToRunSectionType.MethodDefEntryPoints, methodEntryPointTable, methodEntryPointTable);
+
+ TypesTableNode typesTable = new TypesTableNode(Target, inputModule);
+ tableHeader.Add(Internal.Runtime.ReadyToRunSectionType.AvailableTypes, typesTable, typesTable);
+
+ InliningInfoNode inliningInfoTable = new InliningInfoNode(Target, inputModule);
+ tableHeader.Add(Internal.Runtime.ReadyToRunSectionType.InliningInfo2, inliningInfoTable, inliningInfoTable);
+
+ // Core library attributes are checked FAR more often than other dlls
+ // attributes, so produce a highly efficient table for determining if they are
+ // present. Other assemblies *MAY* benefit from this feature, but it doesn't show
+ // as useful at this time.
+ if (inputModule == TypeSystemContext.SystemModule)
+ {
+ AttributePresenceFilterNode attributePresenceTable = new AttributePresenceFilterNode(inputModule);
+ Header.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, attributePresenceTable, attributePresenceTable);
+ }
+ }
+
+ InstanceEntryPointTable = new InstanceEntryPointTableNode(this);
+ Header.Add(Internal.Runtime.ReadyToRunSectionType.InstanceMethodEntryPoints, InstanceEntryPointTable, InstanceEntryPointTable);
ImportSectionsTable = new ImportSectionsTableNode(this);
Header.Add(Internal.Runtime.ReadyToRunSectionType.ImportSections, ImportSectionsTable, ImportSectionsTable.StartSymbol);
DebugInfoTable = new DebugInfoTableNode(Target);
Header.Add(Internal.Runtime.ReadyToRunSectionType.DebugInfo, DebugInfoTable, DebugInfoTable);
- InliningInfoTable = new InliningInfoNode(Target, SignatureContext.GlobalContext);
- Header.Add(Internal.Runtime.ReadyToRunSectionType.InliningInfo2, InliningInfoTable, InliningInfoTable);
-
- // Core library attributes are checked FAR more often than other dlls
- // attributes, so produce a highly efficient table for determining if they are
- // present. Other assemblies *MAY* benefit from this feature, but it doesn't show
- // as useful at this time.
- if (this.AttributePresenceFilter != null)
- {
- Header.Add(Internal.Runtime.ReadyToRunSectionType.AttributePresence, AttributePresenceFilter, AttributePresenceFilter);
- }
-
EagerImports = new ImportSectionNode(
"EagerImports",
CorCompileImportType.CORCOMPILE_IMPORT_TYPE_UNKNOWN,
graph.AddRoot(PrecodeImports, "Precode helper imports are always generated");
graph.AddRoot(StringImports, "String imports are always generated");
graph.AddRoot(Header, "ReadyToRunHeader is always generated");
- graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated");
+ if (!CompilationModuleGroup.IsCompositeBuildMode)
+ {
+ graph.AddRoot(CopiedCorHeaderNode, "MSIL COR header is always generated for single-file R2R files");
+ }
graph.AddRoot(DebugDirectoryNode, "Debug Directory will always contain at least one entry");
if (Win32ResourcesNode != null)
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using ILCompiler.DependencyAnalysisFramework;
+using Internal.TypeSystem.Ecma;
+using System.Linq;
namespace ILCompiler
{
private readonly ConditionalWeakTable<Thread, CorInfoImpl> _corInfoImpls;
/// <summary>
- /// Name of the compilation input MSIL file.
+ /// Input MSIL file names.
/// </summary>
- private readonly string _inputFilePath;
+ private readonly IEnumerable<string> _inputFiles;
private bool _resilient;
ILProvider ilProvider,
Logger logger,
DevirtualizationManager devirtualizationManager,
- string inputFilePath,
- IEnumerable<ModuleDesc> modulesBeingInstrumented,
+ IEnumerable<string> inputFiles,
bool resilient,
bool generateMapFile,
int parallelism)
- : base(dependencyGraph, nodeFactory, roots, ilProvider, devirtualizationManager, modulesBeingInstrumented, logger)
+ : base(
+ dependencyGraph,
+ nodeFactory,
+ roots,
+ ilProvider,
+ devirtualizationManager,
+ modulesBeingInstrumented: nodeFactory.CompilationModuleGroup.CompilationModuleSet,
+ logger)
{
_resilient = resilient;
_parallelism = parallelism;
_generateMapFile = generateMapFile;
SymbolNodeFactory = new ReadyToRunSymbolNodeFactory(nodeFactory);
-
- _inputFilePath = inputFilePath;
-
_corInfoImpls = new ConditionalWeakTable<Thread, CorInfoImpl>();
+ _inputFiles = inputFiles;
}
public override void Compile(string outputFile)
{
- using (FileStream inputFile = File.OpenRead(_inputFilePath))
- {
- PEReader inputPeReader = new PEReader(inputFile);
+ _dependencyGraph.ComputeMarkedNodes();
+ var nodes = _dependencyGraph.MarkedNodeList;
- _dependencyGraph.ComputeMarkedNodes();
- var nodes = _dependencyGraph.MarkedNodeList;
+ using (PerfEventSource.StartStopEvents.EmittingEvents())
+ {
+ NodeFactory.SetMarkingComplete();
+ ReadyToRunObjectWriter.EmitObject(outputFile, componentModule: null, nodes, NodeFactory, _generateMapFile);
+ CompilationModuleGroup moduleGroup = _nodeFactory.CompilationModuleGroup;
- using (PerfEventSource.StartStopEvents.EmittingEvents())
+ if (moduleGroup.IsCompositeBuildMode)
{
- NodeFactory.SetMarkingComplete();
- ReadyToRunObjectWriter.EmitObject(inputPeReader, outputFile, nodes, NodeFactory, _generateMapFile);
+ // In composite mode with standalone MSIL we rewrite all input MSIL assemblies to the
+ // output folder, adding a format R2R header to them with forwarding information to
+ // the composite executable.
+ string outputDirectory = Path.GetDirectoryName(outputFile);
+ string ownerExecutableName = Path.GetFileName(outputFile);
+ foreach (string inputFile in _inputFiles)
+ {
+ string standaloneMsilOutputFile = Path.Combine(outputDirectory, Path.GetFileName(inputFile));
+ RewriteComponentFile(inputFile: inputFile, outputFile: standaloneMsilOutputFile, ownerExecutableName: ownerExecutableName);
+ }
}
}
}
+ private void RewriteComponentFile(string inputFile, string outputFile, string ownerExecutableName)
+ {
+ EcmaModule inputModule = NodeFactory.TypeSystemContext.GetModuleFromPath(inputFile);
+
+ CopiedCorHeaderNode copiedCorHeader = new CopiedCorHeaderNode(inputModule);
+ DebugDirectoryNode debugDirectory = new DebugDirectoryNode(inputModule);
+ NodeFactory componentFactory = new NodeFactory(
+ _nodeFactory.TypeSystemContext,
+ _nodeFactory.CompilationModuleGroup,
+ _nodeFactory.NameMangler,
+ copiedCorHeader,
+ debugDirectory,
+ win32Resources: new Win32Resources.ResourceData(inputModule),
+ Internal.ReadyToRunConstants.ReadyToRunFlags.READYTORUN_FLAG_Component);
+
+ IComparer<DependencyNodeCore<NodeFactory>> comparer = new SortableDependencyNode.ObjectNodeComparer(new CompilerComparer());
+ DependencyAnalyzerBase<NodeFactory> componentGraph = new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(componentFactory, comparer);
+
+ componentGraph.AddRoot(componentFactory.Header, "Component module R2R header");
+ OwnerCompositeExecutableNode ownerExecutableNode = new OwnerCompositeExecutableNode(_nodeFactory.Target, ownerExecutableName);
+ componentGraph.AddRoot(ownerExecutableNode, "Owner composite executable name");
+ componentGraph.AddRoot(copiedCorHeader, "Copied COR header");
+ componentGraph.AddRoot(debugDirectory, "Debug directory");
+ if (componentFactory.Win32ResourcesNode != null)
+ {
+ componentGraph.AddRoot(componentFactory.Win32ResourcesNode, "Win32 resources");
+ }
+ componentGraph.ComputeMarkedNodes();
+ componentFactory.Header.Add(Internal.Runtime.ReadyToRunSectionType.OwnerCompositeExecutable, ownerExecutableNode, ownerExecutableNode);
+ ReadyToRunObjectWriter.EmitObject(outputFile, componentModule: inputModule, componentGraph.MarkedNodeList, componentFactory, generateMapFile: false);
+ }
+
public override void WriteDependencyLog(string outputFileName)
{
using (FileStream dgmlOutput = new FileStream(outputFileName, FileMode.Create))
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using ILCompiler.DependencyAnalysisFramework;
{
public sealed class ReadyToRunCodegenCompilationBuilder : CompilationBuilder
{
- private readonly string _inputFilePath;
- private readonly EcmaModule _inputModule;
+ private readonly IEnumerable<string> _inputFiles;
private bool _ibcTuning;
private bool _resilient;
private bool _generateMapFile;
private int _parallelism;
+
private string _jitPath;
// These need to provide reasonable defaults so that the user can optionally skip
private KeyValuePair<string, string>[] _ryujitOptions = Array.Empty<KeyValuePair<string, string>>();
private ILProvider _ilProvider = new ReadyToRunILProvider();
- public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, string inputFilePath)
+ public ReadyToRunCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group, IEnumerable<string> inputFiles)
: base(context, group, new CoreRTNameMangler())
{
- _inputFilePath = inputFilePath;
- _inputModule = context.GetModuleFromPath(_inputFilePath);
+ _inputFiles = inputFiles;
// R2R field layout needs compilation group information
((ReadyToRunCompilerContext)context).SetCompilationGroup(group);
return this;
}
-
public override ICompilation ToCompilation()
{
- ModuleTokenResolver moduleTokenResolver = new ModuleTokenResolver(_compilationGroup, _context);
- SignatureContext signatureContext = new SignatureContext(_inputModule, moduleTokenResolver);
- CopiedCorHeaderNode corHeaderNode = new CopiedCorHeaderNode(_inputModule);
- AttributePresenceFilterNode attributePresenceFilterNode = null;
- DebugDirectoryNode debugDirectoryNode = new DebugDirectoryNode(_inputModule);
-
- // Core library attributes are checked FAR more often than other dlls
- // attributes, so produce a highly efficient table for determining if they are
- // present. Other assemblies *MAY* benefit from this feature, but it doesn't show
- // as useful at this time.
- if (_inputModule == _inputModule.Context.SystemModule)
- {
- attributePresenceFilterNode = new AttributePresenceFilterNode(_inputModule);
- }
+ // TODO: only copy COR headers for single-assembly build and for composite build with embedded MSIL
+ IEnumerable<EcmaModule> inputModules = _compilationGroup.CompilationModuleSet;
+ CopiedCorHeaderNode corHeaderNode = (_compilationGroup.IsCompositeBuildMode ? null : new CopiedCorHeaderNode(inputModules.First()));
+ // TODO: proper support for multiple input files
+ DebugDirectoryNode debugDirectoryNode = new DebugDirectoryNode(inputModules.First());
// Produce a ResourceData where the IBC PROFILE_DATA entry has been filtered out
- ResourceData win32Resources = new ResourceData(_inputModule, (object type, object name, ushort language) =>
+ // TODO: proper support for multiple input files
+ ResourceData win32Resources = new ResourceData(inputModules.First(), (object type, object name, ushort language) =>
{
if (!(type is string) || !(name is string))
return true;
});
ReadyToRunFlags flags = ReadyToRunFlags.READYTORUN_FLAG_NonSharedPInvokeStubs;
- if (_inputModule.IsPlatformNeutral)
+ if (inputModules.All(module => module.IsPlatformNeutral))
+ {
flags |= ReadyToRunFlags.READYTORUN_FLAG_PlatformNeutralSource;
+ }
flags |= _compilationGroup.GetReadyToRunFlags();
- var header = new HeaderNode(_context.Target, flags);
-
NodeFactory factory = new NodeFactory(
_context,
_compilationGroup,
_nameMangler,
- moduleTokenResolver,
- signatureContext,
corHeaderNode,
debugDirectoryNode,
win32Resources,
- attributePresenceFilterNode,
- header);
+ flags);
IComparer<DependencyNodeCore<NodeFactory>> comparer = new SortableDependencyNode.ObjectNodeComparer(new CompilerComparer());
DependencyAnalyzerBase<NodeFactory> graph = CreateDependencyGraph(factory, comparer);
_ilProvider,
_logger,
new DependencyAnalysis.ReadyToRun.DevirtualizationManager(_compilationGroup),
- _inputFilePath,
- new ModuleDesc[] { _inputModule },
+ _inputFiles,
_resilient,
_generateMapFile,
_parallelism);
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Internal.TypeSystem;
using Internal.TypeSystem.Interop;
using ILCompiler.DependencyAnalysis.ReadyToRun;
using Debug = System.Diagnostics.Debug;
-using System;
namespace ILCompiler
{
public abstract class ReadyToRunCompilationModuleGroupBase : CompilationModuleGroup
{
- protected readonly HashSet<ModuleDesc> _compilationModuleSet;
+ protected readonly HashSet<EcmaModule> _compilationModuleSet;
private readonly HashSet<ModuleDesc> _versionBubbleModuleSet;
private Dictionary<TypeDesc, ModuleToken> _typeRefsInCompilationModuleSet;
private readonly bool _compileGenericDependenciesFromVersionBubbleModuleSet;
+ private readonly bool _isCompositeBuildMode;
private readonly ConcurrentDictionary<TypeDesc, bool> _containsTypeLayoutCache = new ConcurrentDictionary<TypeDesc, bool>();
private readonly ConcurrentDictionary<TypeDesc, bool> _versionsWithTypeCache = new ConcurrentDictionary<TypeDesc, bool>();
private readonly ConcurrentDictionary<MethodDesc, bool> _versionsWithMethodCache = new ConcurrentDictionary<MethodDesc, bool>();
public ReadyToRunCompilationModuleGroupBase(
TypeSystemContext context,
- IEnumerable<ModuleDesc> compilationModuleSet,
+ bool isCompositeBuildMode,
+ IEnumerable<EcmaModule> compilationModuleSet,
IEnumerable<ModuleDesc> versionBubbleModuleSet,
bool compileGenericDependenciesFromVersionBubbleModuleSet)
{
- _compilationModuleSet = new HashSet<ModuleDesc>(compilationModuleSet);
+ _compilationModuleSet = new HashSet<EcmaModule>(compilationModuleSet);
+ _isCompositeBuildMode = isCompositeBuildMode;
+
+ Debug.Assert(_isCompositeBuildMode || _compilationModuleSet.Count == 1);
_versionBubbleModuleSet = new HashSet<ModuleDesc>(versionBubbleModuleSet);
_versionBubbleModuleSet.UnionWith(_compilationModuleSet);
return _typeRefsInCompilationModuleSet.TryGetValue(type, out token);
}
+ public sealed override bool IsCompositeBuildMode => _isCompositeBuildMode;
+
+ public sealed override IEnumerable<EcmaModule> CompilationModuleSet => _compilationModuleSet;
+
private bool ComputeTypeVersionsWithCode(TypeDesc type)
{
if (type.IsCanonicalDefinitionType(CanonicalFormKind.Any))
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
-using Internal.TypeSystem;
+
using Internal.ReadyToRunConstants;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
using Debug = System.Diagnostics.Debug;
private bool _profileGuidedCompileRestrictionSet;
public ReadyToRunSingleAssemblyCompilationModuleGroup(
- TypeSystemContext context,
- IEnumerable<ModuleDesc> compilationModuleSet,
+ TypeSystemContext context,
+ bool isCompositeBuildMode,
+ IEnumerable<EcmaModule> compilationModuleSet,
IEnumerable<ModuleDesc> versionBubbleModuleSet,
bool compileGenericDependenciesFromVersionBubbleModuleSet) :
base(context,
+ isCompositeBuildMode,
compilationModuleSet,
versionBubbleModuleSet,
compileGenericDependenciesFromVersionBubbleModuleSet)
public ReadyToRunTableManager(CompilerTypeSystemContext typeSystemContext)
: base(typeSystemContext) {}
- public IEnumerable<TypeInfo<TypeDefinitionHandle>> GetDefinedTypes()
+ public IEnumerable<TypeInfo<TypeDefinitionHandle>> GetDefinedTypes(EcmaModule module)
{
- foreach (string inputFile in _typeSystemContext.InputFilePaths.Values)
+ foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions)
{
- EcmaModule module = _typeSystemContext.GetModuleFromPath(inputFile);
- foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions)
- {
- yield return new TypeInfo<TypeDefinitionHandle>(module.MetadataReader, typeDefHandle);
- }
+ yield return new TypeInfo<TypeDefinitionHandle>(module.MetadataReader, typeDefHandle);
}
}
- public IEnumerable<TypeInfo<ExportedTypeHandle>> GetExportedTypes()
+ public IEnumerable<TypeInfo<ExportedTypeHandle>> GetExportedTypes(EcmaModule module)
{
- foreach (string inputFile in _typeSystemContext.InputFilePaths.Values)
+ foreach (ExportedTypeHandle exportedTypeHandle in module.MetadataReader.ExportedTypes)
{
- EcmaModule module = _typeSystemContext.GetModuleFromPath(inputFile);
- foreach (ExportedTypeHandle exportedTypeHandle in module.MetadataReader.ExportedTypes)
- {
- yield return new TypeInfo<ExportedTypeHandle>(module.MetadataReader, exportedTypeHandle);
- }
+ yield return new TypeInfo<ExportedTypeHandle>(module.MetadataReader, exportedTypeHandle);
}
}
}
using System.Collections.Generic;
using Internal.ReadyToRunConstants;
using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
namespace ILCompiler
{
public SingleMethodCompilationModuleGroup(
TypeSystemContext context,
- IEnumerable<ModuleDesc> compilationModuleSet,
+ bool isCompositeBuildMode,
+ IEnumerable<EcmaModule> compilationModuleSet,
IEnumerable<ModuleDesc> versionBubbleModuleSet,
bool compileGenericDependenciesFromVersionBubbleModuleSet,
MethodDesc method) :
base(context,
+ isCompositeBuildMode,
compilationModuleSet,
versionBubbleModuleSet,
compileGenericDependenciesFromVersionBubbleModuleSet)
{
foreach (MethodProfileData data in methodData)
{
- if (_methodData.ContainsKey(data.Method))
- throw new Exception("Multiple copies of data for the same method");
-
- _methodData.Add(data.Method, data);
+ if (!_methodData.ContainsKey(data.Method))
+ {
+ _methodData.Add(data.Method, data);
+ }
}
_partialNGen = partialNGen;
}
<Compile Include="Compiler\DependencyAnalysis\EmbeddedObjectNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\EmbeddedPointerIndirectionNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ArgIterator.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\ReadyToRun\AssemblyTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\AttributePresenceFilterNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryEntryNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DebugDirectoryNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InliningInfoNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InstanceEntryPointTableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\IReadyToRunMethodCodeNode.cs" />
+ <Compile Include="Compiler\DependencyAnalysis\ReadyToRun\OwnerCompositeExecutableNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\PrecodeMethodImport.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\LocalMethodImport.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ManifestMetadataTableNode.cs" />
private TargetDetails _target;
/// <summary>
- /// PE reader representing the input MSIL PE file we're copying to the output composite PE file.
- /// </summary>
- private PEReader _peReader;
-
- /// <summary>
- /// Custom sections explicitly injected by the caller.
- /// </summary>
- private HashSet<string> _customSections;
-
- /// <summary>
- /// Complete list of section names includes the sections present in the input MSIL file
- /// (.text, optionally .rsrc and .reloc) and extra questions injected during the R2R PE
- /// creation.
+ /// Complete list of sections to emit into the output R2R executable.
/// </summary>
private ImmutableArray<Section> _sections;
/// Constructor initializes the various control structures and combines the section list.
/// </summary>
/// <param name="target">Target environment specifier</param>
- /// <param name="peReader">Input MSIL PE file reader</param>
+ /// <param name="peHeaderBuilder">PE file header builder</param>
/// <param name="getRuntimeFunctionsTable">Callback to retrieve the runtime functions table</param>
public R2RPEBuilder(
TargetDetails target,
- PEReader peReader,
+ PEHeaderBuilder peHeaderBuilder,
+ ISymbolNode r2rHeaderExportSymbol,
+ string outputFileSimpleName,
Func<RuntimeFunctionsTableNode> getRuntimeFunctionsTable)
- : base(PEHeaderCopier.Copy(peReader.PEHeaders, target), deterministicIdProvider: null)
+ : base(peHeaderBuilder, deterministicIdProvider: null)
{
_target = target;
- _peReader = peReader;
_getRuntimeFunctionsTable = getRuntimeFunctionsTable;
_sectionRvaDeltas = new List<SectionRVADelta>();
_textSectionIndex = _sectionBuilder.AddSection(TextSectionName, SectionCharacteristics.ContainsCode | SectionCharacteristics.MemExecute | SectionCharacteristics.MemRead, 512);
_dataSectionIndex = _sectionBuilder.AddSection(DataSectionName, SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemWrite | SectionCharacteristics.MemRead, 512);
- _customSections = new HashSet<string>();
- foreach (SectionInfo section in _sectionBuilder.GetSections())
+ if (r2rHeaderExportSymbol != null)
{
- _customSections.Add(section.SectionName);
+ _sectionBuilder.AddSection(R2RPEBuilder.ExportDataSectionName, SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemRead, 512);
+ _sectionBuilder.AddExportSymbol("RTR_HEADER", 1, r2rHeaderExportSymbol);
+ _sectionBuilder.SetDllNameForExportDirectoryTable(outputFileSimpleName);
}
if (_sectionBuilder.FindSection(R2RPEBuilder.RelocSectionName) == null)
SectionCharacteristics.ContainsInitializedData |
SectionCharacteristics.MemRead |
SectionCharacteristics.MemDiscardable,
- peReader.PEHeaders.PEHeader.SectionAlignment);
+ PEHeaderConstants.SectionAlignment);
}
ImmutableArray<Section>.Builder sectionListBuilder = ImmutableArray.CreateBuilder<Section>();
/// Emit built sections into the R2R PE file.
/// </summary>
/// <param name="outputStream">Output stream for the final R2R PE file</param>
- public void Write(Stream outputStream)
+ /// <param name="timeDateStamp">Timestamp to set in the PE header of the output R2R executable</param>
+ public void Write(Stream outputStream, int timeDateStamp)
{
BlobBuilder outputPeFile = new BlobBuilder();
Serialize(outputPeFile);
_sectionBuilder.RelocateOutputFile(outputPeFile, Header.ImageBase, outputStream);
+
UpdateSectionRVAs(outputStream);
ApplyMachineOSOverride(outputStream);
- CopyTimeStampFromInputImage(outputStream);
+ SetPEHeaderTimeStamp(outputStream, timeDateStamp);
_written = true;
}
}
/// <summary>
- /// Copy over the timestamp from IL image for determinism.
+ /// Set PE header timestamp in the output R2R image to a given value.
/// </summary>
/// <param name="outputStream">Output stream representing the R2R PE executable</param>
- private void CopyTimeStampFromInputImage(Stream outputStream)
+ /// <param name="timeDateStamp">Timestamp to set in the R2R PE header</param>
+ private void SetPEHeaderTimeStamp(Stream outputStream, int timeDateStamp)
{
- byte[] patchedTimestamp = BitConverter.GetBytes(_peReader.PEHeaders.CoffHeader.TimeDateStamp);
+ byte[] patchedTimestamp = BitConverter.GetBytes(timeDateStamp);
int seekSize =
DosHeaderSize +
PESignatureSize +
_sectionBuilder.UpdateDirectories(builder);
- RuntimeFunctionsTableNode runtimeFunctionsTable = _getRuntimeFunctionsTable();
- builder.ExceptionTable = new DirectoryEntry(
- relativeVirtualAddress: _sectionBuilder.GetSymbolRVA(runtimeFunctionsTable),
- size: runtimeFunctionsTable.TableSize);
+ if (_getRuntimeFunctionsTable != null)
+ {
+ RuntimeFunctionsTableNode runtimeFunctionsTable = _getRuntimeFunctionsTable();
+ builder.ExceptionTable = new DirectoryEntry(
+ relativeVirtualAddress: _sectionBuilder.GetSymbolRVA(runtimeFunctionsTable),
+ size: runtimeFunctionsTable.TableSize);
+ }
return builder;
}
}
/// <summary>
- /// Simple helper for copying the various global values in the PE header.
+ /// Simple helper for filling in PE header information by either copying over
+ /// data from a pre-existing input PE header (used for single-assembly R2R files)
+ /// or by explicitly specifying the image characteristics (for composite R2R).
/// </summary>
- static class PEHeaderCopier
+ static class PEHeaderProvider
{
/// <summary>
/// Copy PE headers into a PEHeaderBuilder used by PEBuilder.
/// <param name="target">Target architecture to set in the header</param>
public static PEHeaderBuilder Copy(PEHeaders peHeaders, TargetDetails target)
{
- // Default base addresses used by Roslyn
- const ulong DefaultExeBaseAddress64Bit = 0x1_4000_0000;
- const ulong DefaultDllBaseAddress64Bit = 0x1_8000_0000;
+ return Create(
+ peHeaders.CoffHeader.Characteristics,
+ peHeaders.PEHeader.DllCharacteristics,
+ peHeaders.PEHeader.Subsystem,
+ target);
+ }
+ /// <summary>
+ /// Fill in PE header information into a PEHeaderBuilder used by PEBuilder.
+ /// </summary>
+ /// <param name="relocsStripped">Relocs are not present in the PE executable</param>
+ /// <param name="dllCharacteristics">Extra DLL characteristics to apply</param>
+ /// <param name="subsystem">Targeting subsystem</param>
+ /// <param name="target">Target architecture to set in the header</param>
+ public static PEHeaderBuilder Create(Characteristics imageCharacteristics, DllCharacteristics dllCharacteristics, Subsystem subsystem, TargetDetails target)
+ {
bool is64BitTarget = target.PointerSize == sizeof(long);
- Characteristics imageCharacteristics = peHeaders.CoffHeader.Characteristics;
- if (is64BitTarget)
- {
- imageCharacteristics &= ~Characteristics.Bit32Machine;
- imageCharacteristics |= Characteristics.LargeAddressAware;
- }
+ imageCharacteristics &= ~(Characteristics.Bit32Machine | Characteristics.LargeAddressAware);
+ imageCharacteristics |= (is64BitTarget ? Characteristics.LargeAddressAware : Characteristics.Bit32Machine);
- ulong imageBase = peHeaders.PEHeader.ImageBase;
+ ulong imageBase = PE32HeaderConstants.ImageBase;
if (target.IsWindows && is64BitTarget && (imageBase <= uint.MaxValue))
{
// Base addresses below 4 GiB are reserved for WoW on x64 and disallowed on ARM64.
// If the input assembly was compiled for anycpu, its base address is 32-bit and we need to fix it.
- imageBase = (imageCharacteristics & Characteristics.Dll) != 0 ? DefaultDllBaseAddress64Bit : DefaultExeBaseAddress64Bit;
+ imageBase = (imageCharacteristics & Characteristics.Dll) != 0 ? PE64HeaderConstants.DllImageBase : PE64HeaderConstants.ExeImageBase;
}
int fileAlignment = 0x200;
sectionAlignment = fileAlignment;
}
- DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible;
+ dllCharacteristics &= (DllCharacteristics.NxCompatible | DllCharacteristics.TerminalServerAware | DllCharacteristics.AppContainer);
- // Copy over selected DLL characteristics bits from IL image
- dllCharacteristics |= peHeaders.PEHeader.DllCharacteristics &
- (DllCharacteristics.TerminalServerAware | DllCharacteristics.AppContainer);
+ // In Crossgen1, this is under a debug-specific condition 'if (0 == CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NoASLRForNgen))'
+ dllCharacteristics |= DllCharacteristics.DynamicBase;
if (is64BitTarget)
{
machine: target.MachineFromTarget(),
sectionAlignment: sectionAlignment,
fileAlignment: fileAlignment,
- imageBase: imageBase,
- majorLinkerVersion: 11,
- minorLinkerVersion: 0,
- majorOperatingSystemVersion: 5,
- // Win2k = 5.0 for 32-bit images, Win2003 = 5.2 for 64-bit images
- minorOperatingSystemVersion: is64BitTarget ? (ushort)2 : (ushort)0,
- majorImageVersion: peHeaders.PEHeader.MajorImageVersion,
- minorImageVersion: peHeaders.PEHeader.MinorImageVersion,
- majorSubsystemVersion: peHeaders.PEHeader.MajorSubsystemVersion,
- minorSubsystemVersion: peHeaders.PEHeader.MinorSubsystemVersion,
- subsystem: peHeaders.PEHeader.Subsystem,
+ majorLinkerVersion: PEHeaderConstants.MajorLinkerVersion,
+ minorLinkerVersion: PEHeaderConstants.MinorLinkerVersion,
+ majorOperatingSystemVersion: PEHeaderConstants.MajorOperatingSystemVersion,
+ minorOperatingSystemVersion: PEHeaderConstants.MinorOperatingSystemVersion,
+ majorImageVersion: PEHeaderConstants.MajorImageVersion,
+ minorImageVersion: PEHeaderConstants.MinorImageVersion,
+ majorSubsystemVersion: PEHeaderConstants.MajorSubsystemVersion,
+ minorSubsystemVersion: PEHeaderConstants.MinorSubsystemVersion,
+ subsystem: subsystem,
dllCharacteristics: dllCharacteristics,
imageCharacteristics: imageCharacteristics,
- sizeOfStackReserve: peHeaders.PEHeader.SizeOfStackReserve,
- sizeOfStackCommit: peHeaders.PEHeader.SizeOfStackCommit,
- sizeOfHeapReserve: 0,
- sizeOfHeapCommit: 0);
+ sizeOfStackReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfStackReserve : PE32HeaderConstants.SizeOfStackReserve),
+ sizeOfStackCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfStackCommit : PE32HeaderConstants.SizeOfStackCommit),
+ sizeOfHeapReserve: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapReserve : PE32HeaderConstants.SizeOfHeapReserve),
+ sizeOfHeapCommit: (is64BitTarget ? PE64HeaderConstants.SizeOfHeapCommit : PE32HeaderConstants.SizeOfHeapCommit));
}
}
}
DirectoryEntry _relocationDirectoryEntry;
/// <summary>
- /// Symbol representing the ready-to-run header table.
+ /// Symbol representing the ready-to-run COR (MSIL) header table.
+ /// Only present in single-file R2R executables. Composite R2R
+ /// executables don't have a COR header and locate the ReadyToRun
+ /// header directly using the well-known export symbol RTR_HEADER.
/// </summary>
ISymbolNode _corHeaderSymbol;
}
}
- if (_exportSymbols.Count != 0 && FindSection(R2RPEBuilder.ExportDataSectionName) == null)
- {
- sectionList.Add(new SectionInfo(R2RPEBuilder.ExportDataSectionName, SectionCharacteristics.ContainsInitializedData | SectionCharacteristics.MemRead));
- }
-
return sectionList;
}
NetBSD = 0x1993,
}
+ /// <summary>
+ /// Constants for emission of Windows PE file mostly copied from CoreCLR pewriter.cpp.
+ /// </summary>
+ public static class PEHeaderConstants
+ {
+ public const int SectionAlignment = 0x1000;
+
+ public const byte MajorLinkerVersion = 11;
+ public const byte MinorLinkerVersion = 0;
+
+ public const byte MajorOperatingSystemVersion = 4;
+ public const byte MinorOperatingSystemVersion = 0;
+
+ public const ushort MajorImageVersion = 0;
+ public const ushort MinorImageVersion = 0;
+
+ public const ushort MajorSubsystemVersion = 4;
+ public const ushort MinorSubsystemVersion = 0;
+ }
+
+ public static class PE32HeaderConstants
+ {
+ public const uint ImageBase = 0x0040_0000;
+
+ public const uint SizeOfStackReserve = 0x100000;
+ public const uint SizeOfStackCommit = 0x1000;
+ public const uint SizeOfHeapReserve = 0x100000;
+ public const uint SizeOfHeapCommit = 0x1000;
+ }
+
+ public static class PE64HeaderConstants
+ {
+ // Default base addresses used by Roslyn
+ public const ulong ExeImageBase = 0x1_4000_0000;
+ public const ulong DllImageBase = 0x1_8000_0000;
+
+ public const ulong SizeOfStackReserve = 0x400000;
+ public const ulong SizeOfStackCommit = 0x4000;
+ public const ulong SizeOfHeapReserve = 0x100000;
+ public const ulong SizeOfHeapCommit = 0x2000;
+ }
+
public static class TargetExtensions
{
/// <summary>
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.ComponentModel;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
{
int runtimeFunctionSize = CalculateRuntimeFunctionSize();
uint nRuntimeFunctions = (uint)(runtimeFunctionSection.Size / runtimeFunctionSize);
- int runtimeFunctionOffset = GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
+ int runtimeFunctionOffset = PEReader.GetOffset(runtimeFunctionSection.RelativeVirtualAddress);
bool[] isEntryPoint = new bool[nRuntimeFunctions];
// initialize R2RMethods
public class CommandLineOptions
{
public FileInfo[] InputFilePaths { get; set; }
+ public FileInfo[] UnrootedInputFilePaths { get; set; }
public FileInfo[] Mibc { get; set; }
public string[] Reference { get; set; }
public FileInfo OutputFilePath { get; set; }
public bool InputBubble { get; set; }
public bool CompileBubbleGenerics { get; set; }
public bool Verbose { get; set; }
+ public bool Composite { get; set; }
public FileInfo DgmlLogFileName { get; set; }
public bool GenerateFullDgmlLog { get; set; }
Description = SR.InputFilesToCompile,
Arity = arbitraryArity,
},
+ new Option(new[] { "--unrooted-input-file-paths", "-u" }, SR.UnrootedInputFilesToCompile)
+ {
+ Argument = new Argument<FileInfo[]>()
+ {
+ Arity = arbitraryArity
+ }
+ },
new Option(new[] { "--reference", "-r" }, SR.ReferenceFiles)
- {
+ {
Argument = new Argument<string[]>()
{
Arity = arbitraryArity
},
new Option(new[] { "--optimize-time", "--Ot" }, SR.OptimizeSpeedOption),
new Option(new[] { "--inputbubble" }, SR.InputBubbleOption),
+ new Option(new[] { "--composite" }, SR.CompositeBuildMode),
new Option(new[] { "--tuning" }, SR.TuningImageOption)
{
Argument = new Argument<bool>()
public TargetArchitecture _targetArchitecture;
public OptimizationMode _optimizationMode;
private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ private Dictionary<string, string> _unrootedInputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private Program(CommandLineOptions commandLineOptions)
foreach (var input in _commandLineOptions.InputFilePaths ?? Enumerable.Empty<FileInfo>())
Helpers.AppendExpandedPaths(_inputFilePaths, input.FullName, true);
+ foreach (var input in _commandLineOptions.UnrootedInputFilePaths ?? Enumerable.Empty<FileInfo>())
+ Helpers.AppendExpandedPaths(_unrootedInputFilePaths, input.FullName, true);
+
foreach (var reference in _commandLineOptions.Reference ?? Enumerable.Empty<string>())
Helpers.AppendExpandedPaths(_referenceFilePaths, reference, false);
}
// When we undo this this hack, replace this foreach with
// typeSystemContext.InputFilePaths = _inputFilePaths;
//
+ Dictionary<string, string> allInputFilePaths = new Dictionary<string, string>();
Dictionary<string, string> inputFilePaths = new Dictionary<string, string>();
List<ModuleDesc> referenceableModules = new List<ModuleDesc>();
foreach (var inputFile in _inputFilePaths)
try
{
var module = typeSystemContext.GetModuleFromPath(inputFile.Value);
+ allInputFilePaths.Add(inputFile.Key, inputFile.Value);
inputFilePaths.Add(inputFile.Key, inputFile.Value);
referenceableModules.Add(module);
}
}
}
- typeSystemContext.InputFilePaths = inputFilePaths;
+ Dictionary<string, string> unrootedInputFilePaths = new Dictionary<string, string>();
+ foreach (var unrootedInputFile in _unrootedInputFilePaths)
+ {
+ try
+ {
+ var module = typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
+ if (!allInputFilePaths.ContainsKey(unrootedInputFile.Key))
+ {
+ allInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
+ unrootedInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
+ referenceableModules.Add(module);
+ }
+ }
+ catch (TypeSystemException.BadImageFormatException)
+ {
+ // Keep calm and carry on.
+ }
+ }
+
+ typeSystemContext.InputFilePaths = allInputFilePaths;
typeSystemContext.ReferenceFilePaths = _referenceFilePaths;
List<EcmaModule> inputModules = new List<EcmaModule>();
+ List<EcmaModule> rootingModules = new List<EcmaModule>();
HashSet<ModuleDesc> versionBubbleModulesHash = new HashSet<ModuleDesc>();
- foreach (var inputFile in typeSystemContext.InputFilePaths)
+ foreach (var inputFile in inputFilePaths)
{
EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value);
inputModules.Add(module);
+ rootingModules.Add(module);
versionBubbleModulesHash.Add(module);
if (!_commandLineOptions.InputBubble)
}
}
+ foreach (var unrootedInputFile in unrootedInputFilePaths)
+ {
+ EcmaModule module = typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
+ inputModules.Add(module);
+ versionBubbleModulesHash.Add(module);
+ }
+
string systemModuleName = _commandLineOptions.SystemModule ?? DefaultSystemModule;
- typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(systemModuleName));
+ typeSystemContext.SetSystemModule((EcmaModule)typeSystemContext.GetModuleForSimpleName(systemModuleName));
if (typeSystemContext.InputFilePaths.Count == 0)
throw new CommandLineException(SR.NoInputFiles);
try
{
EcmaModule module = typeSystemContext.GetModuleFromPath(referenceFile);
+ if (versionBubbleModulesHash.Contains(module))
+ {
+ // Ignore reference assemblies that have also been passed as inputs
+ continue;
+ }
referenceableModules.Add(module);
if (_commandLineOptions.InputBubble)
{
List<ModuleDesc> versionBubbleModules = new List<ModuleDesc>(versionBubbleModulesHash);
+ if (!_commandLineOptions.Composite && inputModules.Count != 1)
+ {
+ throw new Exception(string.Format(SR.ErrorMultipleInputFilesCompositeModeOnly, string.Join("; ", inputModules)));
+ }
+
ReadyToRunCompilationModuleGroupBase compilationGroup;
List<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
if (singleMethod != null)
{
// Compiling just a single method
- compilationGroup = new SingleMethodCompilationModuleGroup(typeSystemContext, inputModules, versionBubbleModules, _commandLineOptions.CompileBubbleGenerics, singleMethod);
+ compilationGroup = new SingleMethodCompilationModuleGroup(
+ typeSystemContext,
+ _commandLineOptions.Composite,
+ inputModules,
+ versionBubbleModules,
+ _commandLineOptions.CompileBubbleGenerics,
+ singleMethod);
compilationRoots.Add(new SingleMethodRootProvider(singleMethod));
}
else
{
// Single assembly compilation.
compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(
- typeSystemContext, inputModules, versionBubbleModules, _commandLineOptions.CompileBubbleGenerics);
+ typeSystemContext,
+ _commandLineOptions.Composite,
+ inputModules,
+ versionBubbleModules,
+ _commandLineOptions.CompileBubbleGenerics);
}
// Examine profile guided information as appropriate
if (singleMethod == null)
{
// For non-single-method compilations add compilation roots.
- foreach (var module in inputModules)
+ foreach (var module in rootingModules)
{
compilationRoots.Add(new ReadyToRunRootProvider(module, profileDataManager, _commandLineOptions.Partial));
// Compile
//
- string inputFilePath = "";
- foreach (var input in typeSystemContext.InputFilePaths)
- {
- inputFilePath = input.Value;
- break;
- }
- ReadyToRunCodegenCompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(typeSystemContext, compilationGroup, inputFilePath);
+ ReadyToRunCodegenCompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(
+ typeSystemContext, compilationGroup, allInputFilePaths.Values);
string compilationUnitPrefix = "";
builder.UseCompilationUnitPrefix(compilationUnitPrefix);
<data name="InputBubbleOption" xml:space="preserve">
<value>True when the entire input forms a version bubble (default = per-assembly bubble)</value>
</data>
+ <data name="CompositeBuildMode" xml:space="preserve">
+ <value>Emit a composite R2R image comprising a number of input assemblies</value>
+ </data>
<data name="InputFilesToCompile" xml:space="preserve">
<value>Input file(s) to compile</value>
</data>
+ <data name="UnrootedInputFilesToCompile" xml:space="preserve">
+ <value>"Input files without automatic rooting of all methods</value>
+ </data>
<data name="JitPathOption" xml:space="preserve">
<value>Path to JIT compiler library</value>
</data>
<data name="WarningOverridingOptimizeSpace" xml:space="preserve">
<value>Warning: overriding -Ot with -Os</value>
</data>
+ <data name="ErrorMultipleInputFilesCompositeModeOnly" xml:space="preserve">
+ <value>Error: multiple input files are only supported in composite build mode: {0}</value>
+ </data>
</root>
\ No newline at end of file