Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View File

@@ -0,0 +1,217 @@
// 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.IO;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using Internal.IL;
using Internal.IL.Stubs;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Debug = System.Diagnostics.Debug;
using AssemblyName = System.Reflection.AssemblyName;
namespace ILCompiler
{
public abstract class Compilation : ICompilation
{
protected readonly DependencyAnalyzerBase<NodeFactory> _dependencyGraph;
protected readonly NameMangler _nameMangler;
protected readonly NodeFactory _nodeFactory;
protected readonly Logger _logger;
internal NameMangler NameMangler => _nameMangler;
internal NodeFactory NodeFactory => _nodeFactory;
internal CompilerTypeSystemContext TypeSystemContext => NodeFactory.TypeSystemContext;
internal Logger Logger => _logger;
internal PInvokeILProvider PInvokeILProvider { get; }
private readonly TypeGetTypeMethodThunkCache _typeGetTypeMethodThunks;
protected Compilation(
DependencyAnalyzerBase<NodeFactory> dependencyGraph,
NodeFactory nodeFactory,
IEnumerable<ICompilationRootProvider> compilationRoots,
NameMangler nameMangler,
Logger logger)
{
_dependencyGraph = dependencyGraph;
_nodeFactory = nodeFactory;
_nameMangler = nameMangler;
_logger = logger;
_dependencyGraph.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;
NodeFactory.AttachToDependencyGraph(_dependencyGraph);
// TODO: hacky static field
NodeFactory.NameMangler = nameMangler;
var rootingService = new RootingServiceProvider(dependencyGraph, nodeFactory);
foreach (var rootProvider in compilationRoots)
rootProvider.AddCompilationRoots(rootingService);
_typeGetTypeMethodThunks = new TypeGetTypeMethodThunkCache(nodeFactory.CompilationModuleGroup.GeneratedAssembly.GetGlobalModuleType());
bool? forceLazyPInvokeResolution = null;
// TODO: Workaround lazy PInvoke resolution not working with CppCodeGen yet
// https://github.com/dotnet/corert/issues/2454
// https://github.com/dotnet/corert/issues/2149
if (this is CppCodegenCompilation) forceLazyPInvokeResolution = false;
// TODO: Workaround missing PInvokes with multifile compilation
// https://github.com/dotnet/corert/issues/2454
if (!nodeFactory.CompilationModuleGroup.IsSingleFileCompilation) forceLazyPInvokeResolution = true;
PInvokeILProvider = new PInvokeILProvider(new PInvokeILEmitterConfiguration(forceLazyPInvokeResolution));
_methodILCache = new ILProvider(PInvokeILProvider);
}
private ILProvider _methodILCache;
internal MethodIL GetMethodIL(MethodDesc method)
{
// Flush the cache when it grows too big
if (_methodILCache.Count > 1000)
_methodILCache = new ILProvider(PInvokeILProvider);
return _methodILCache.GetMethodIL(method);
}
protected abstract void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> obj);
protected abstract void CompileInternal(string outputFile);
public DelegateCreationInfo GetDelegateCtor(TypeDesc delegateType, MethodDesc target)
{
return DelegateCreationInfo.Create(delegateType, target, NodeFactory);
}
/// <summary>
/// Gets an object representing the static data for RVA mapped fields from the PE image.
/// </summary>
public ObjectNode GetFieldRvaData(FieldDesc field)
{
if (field.GetType() == typeof(Internal.IL.Stubs.PInvokeLazyFixupField))
{
var pInvokeFixup = (Internal.IL.Stubs.PInvokeLazyFixupField)field;
PInvokeMetadata metadata = pInvokeFixup.PInvokeMetadata;
return NodeFactory.PInvokeMethodFixup(metadata.Module, metadata.Name);
}
else
{
// Use the typical field definition in case this is an instantiated generic type
field = field.GetTypicalFieldDefinition();
return NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize);
}
}
public bool HasLazyStaticConstructor(TypeDesc type)
{
return TypeSystemContext.HasLazyStaticConstructor(type);
}
public MethodDebugInformation GetDebugInfo(MethodIL methodIL)
{
// This method looks odd right now, but it's an extensibility point that lets us generate
// fake debugging information for things that don't have physical symbols.
return methodIL.GetDebugInfo();
}
/// <summary>
/// Resolves a reference to an intrinsic method to a new method that takes it's place in the compilation.
/// This is used for intrinsics where the intrinsic expansion depends on the callsite.
/// </summary>
/// <param name="intrinsicMethod">The intrinsic method called.</param>
/// <param name="callsiteMethod">The callsite that calls the intrinsic.</param>
/// <returns>The intrinsic implementation to be called for this specific callsite.</returns>
public MethodDesc ExpandIntrinsicForCallsite(MethodDesc intrinsicMethod, MethodDesc callsiteMethod)
{
Debug.Assert(intrinsicMethod.IsIntrinsic);
var intrinsicOwningType = intrinsicMethod.OwningType as MetadataType;
if (intrinsicOwningType == null)
return intrinsicMethod;
if (intrinsicOwningType.Module != TypeSystemContext.SystemModule)
return intrinsicMethod;
if (intrinsicOwningType.Name == "Type" && intrinsicOwningType.Namespace == "System")
{
if (intrinsicMethod.Signature.IsStatic && intrinsicMethod.Name == "GetType")
{
ModuleDesc callsiteModule = (callsiteMethod.OwningType as MetadataType)?.Module;
if (callsiteModule != null)
{
Debug.Assert(callsiteModule is IAssemblyDesc, "Multi-module assemblies");
return _typeGetTypeMethodThunks.GetHelper(intrinsicMethod, ((IAssemblyDesc)callsiteModule).GetName().FullName);
}
}
}
return intrinsicMethod;
}
void ICompilation.Compile(string outputFile)
{
// In multi-module builds, set the compilation unit prefix to prevent ambiguous symbols in linked object files
_nameMangler.CompilationUnitPrefix = _nodeFactory.CompilationModuleGroup.IsSingleFileCompilation ? "" : NodeFactory.NameMangler.SanitizeName(Path.GetFileNameWithoutExtension(outputFile));
CompileInternal(outputFile);
}
void ICompilation.WriteDependencyLog(string fileName)
{
using (FileStream dgmlOutput = new FileStream(fileName, FileMode.Create))
{
DgmlWriter.WriteDependencyGraphToStream(dgmlOutput, _dependencyGraph);
dgmlOutput.Flush();
}
}
private class RootingServiceProvider : IRootingServiceProvider
{
private DependencyAnalyzerBase<NodeFactory> _graph;
private NodeFactory _factory;
public RootingServiceProvider(DependencyAnalyzerBase<NodeFactory> graph, NodeFactory factory)
{
_graph = graph;
_factory = factory;
}
public void AddCompilationRoot(MethodDesc method, string reason, string exportName = null)
{
var methodEntryPoint = _factory.MethodEntrypoint(method);
_graph.AddRoot(methodEntryPoint, reason);
if (exportName != null)
_factory.NodeAliases.Add(methodEntryPoint, exportName);
}
public void AddCompilationRoot(TypeDesc type, string reason)
{
if (!ConstructedEETypeNode.CreationAllowed(type))
{
_graph.AddRoot(_factory.NecessaryTypeSymbol(type), reason);
}
else
{
_graph.AddRoot(_factory.ConstructedTypeSymbol(type), reason);
}
}
}
}
// Interface under which Compilation is exposed externally.
public interface ICompilation
{
void Compile(string outputFileName);
void WriteDependencyLog(string outputFileName);
}
}

View File

@@ -0,0 +1,90 @@
// 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 ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
namespace ILCompiler
{
public abstract class CompilationBuilder
{
protected NodeFactory _nodeFactory;
// These need to provide reasonable defaults so that the user can optionally skip
// calling the Use/Configure methods and still get something reasonable back.
protected Logger _logger = Logger.Null;
private DependencyTrackingLevel _dependencyTrackingLevel = DependencyTrackingLevel.None;
protected IEnumerable<ICompilationRootProvider> _compilationRoots = Array.Empty<ICompilationRootProvider>();
public CompilationBuilder(NodeFactory nodeFactory)
{
_nodeFactory = nodeFactory;
}
public CompilationBuilder UseLogger(Logger logger)
{
_logger = logger;
return this;
}
public CompilationBuilder UseDependencyTracking(DependencyTrackingLevel trackingLevel)
{
_dependencyTrackingLevel = trackingLevel;
return this;
}
public CompilationBuilder UseCompilationRoots(IEnumerable<ICompilationRootProvider> compilationRoots)
{
_compilationRoots = compilationRoots;
return this;
}
public abstract CompilationBuilder UseBackendOptions(IEnumerable<string> options);
protected DependencyAnalyzerBase<NodeFactory> CreateDependencyGraph()
{
// Choose which dependency graph implementation to use based on the amount of logging requested.
switch (_dependencyTrackingLevel)
{
case DependencyTrackingLevel.None:
return new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null);
case DependencyTrackingLevel.First:
return new DependencyAnalyzer<FirstMarkLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null);
case DependencyTrackingLevel.All:
return new DependencyAnalyzer<FullGraphLogStrategy<NodeFactory>, NodeFactory>(_nodeFactory, null);
default:
throw new InvalidOperationException();
}
}
public abstract ICompilation ToCompilation();
}
/// <summary>
/// Represents the level of dependency tracking within the dependency analysis system.
/// </summary>
public enum DependencyTrackingLevel
{
/// <summary>
/// Tracking disabled. This is the most performant and memory efficient option.
/// </summary>
None,
/// <summary>
/// The graph keeps track of the first dependency.
/// </summary>
First,
/// <summary>
/// The graph keeps track of all dependencies.
/// </summary>
All
}
}

View File

@@ -0,0 +1,88 @@
// 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.Reflection;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
public abstract class CompilationModuleGroup
{
/// <summary>
/// Gets the synthetic assembly that holds types generated by the compiler as part of the compilation process.
/// Types and members that declare this module as their owning module are always generated.
/// </summary>
public ModuleDesc GeneratedAssembly { get; }
public CompilationModuleGroup(TypeSystemContext context)
{
GeneratedAssembly = new CompilerGeneratedAssembly(context);
}
/// <summary>
/// If true, "type" is in the set of input assemblies being compiled
/// </summary>
public abstract bool ContainsType(TypeDesc type);
/// <summary>
/// If true, "method" is in the set of input assemblies being compiled
/// </summary>
public abstract bool ContainsMethod(MethodDesc method);
/// <summary>
/// If true, all code is compiled into a single module
/// </summary>
public abstract bool IsSingleFileCompilation { get; }
/// <summary>
/// If true, the full type should be generated. This occurs in situations where the type is
/// shared between modules (generics, parameterized types), or the type lives in a different module
/// and therefore needs a full VTable
/// </summary>
public abstract bool ShouldProduceFullType(TypeDesc type);
/// <summary>
/// If true, the type will not be linked into the same module as the current compilation and therefore
/// accessed through the target platform's import mechanism (ie, Import Address Table on Windows)
/// </summary>
public abstract bool ShouldReferenceThroughImportTable(TypeDesc type);
private class CompilerGeneratedAssembly : ModuleDesc, IAssemblyDesc
{
private MetadataType _globalModuleType;
public CompilerGeneratedAssembly(TypeSystemContext context)
: base(context)
{
_globalModuleType = new CompilerGeneratedType(this, "<Module>");
}
public override IEnumerable<MetadataType> GetAllTypes()
{
return Array.Empty<MetadataType>();
}
public override MetadataType GetGlobalModuleType()
{
return _globalModuleType;
}
public AssemblyName GetName()
{
return new AssemblyName("System.Private.CompilerGenerated");
}
public override MetadataType GetType(string nameSpace, string name, bool throwIfNotFound = true)
{
Debug.Assert(false, "Resolving a TypeRef in the compiler generated assembly?");
if (throwIfNotFound)
throw new TypeSystemException.TypeLoadException(nameSpace, name, this);
return null;
}
}
}
}

View File

@@ -0,0 +1,189 @@
// 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 Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
using TypeHashingAlgorithms = Internal.NativeFormat.TypeHashingAlgorithms;
namespace ILCompiler
{
/// <summary>
/// A pseudo-type that owns helper methods generated by the compiler.
/// This type should never be allocated (we should never see an EEType for it).
/// </summary>
internal sealed class CompilerGeneratedType : MetadataType
{
private int _hashcode;
public CompilerGeneratedType(ModuleDesc module, string name)
{
Module = module;
Name = name;
}
public override TypeSystemContext Context
{
get
{
return Module.Context;
}
}
public override string Name
{
get;
}
public override string Namespace
{
get
{
return "Internal.CompilerGenerated";
}
}
public override int GetHashCode()
{
if (_hashcode != 0)
return _hashcode;
return InitializeHashCode();
}
private int InitializeHashCode()
{
string ns = Namespace;
var hashCodeBuilder = new TypeHashingAlgorithms.HashCodeBuilder(ns);
if (ns.Length > 0)
hashCodeBuilder.Append(".");
hashCodeBuilder.Append(Name);
_hashcode = hashCodeBuilder.ToHashCode();
return _hashcode;
}
public override bool IsCanonicalSubtype(CanonicalFormKind policy)
{
Debug.Assert(!HasInstantiation, "Why is this generic?");
return false;
}
protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
{
return TypeFlags.Class |
TypeFlags.ContainsGenericVariablesComputed |
TypeFlags.HasGenericVarianceComputed |
TypeFlags.HasStaticConstructorComputed;
}
public override ClassLayoutMetadata GetClassLayout()
{
return new ClassLayoutMetadata
{
Offsets = null,
PackingSize = 0,
Size = 0,
};
}
public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
{
return false;
}
public override IEnumerable<MetadataType> GetNestedTypes()
{
return Array.Empty<MetadataType>();
}
public override MetadataType GetNestedType(string name)
{
return null;
}
protected override MethodImplRecord[] ComputeVirtualMethodImplsForType()
{
return Array.Empty<MethodImplRecord>();
}
public override MethodImplRecord[] FindMethodsImplWithMatchingDeclName(string name)
{
return Array.Empty<MethodImplRecord>();
}
public override ModuleDesc Module
{
get;
}
public override PInvokeStringFormat PInvokeStringFormat
{
get
{
return PInvokeStringFormat.AutoClass;
}
}
public override bool IsExplicitLayout
{
get
{
return false;
}
}
public override bool IsSequentialLayout
{
get
{
return false;
}
}
public override bool IsBeforeFieldInit
{
get
{
return false;
}
}
public override MetadataType MetadataBaseType
{
get
{
// Since this type should never be allocated and only serves the purpose of grouping things,
// it can act like a <Module> type and have no base type.
return null;
}
}
public override bool IsSealed
{
get
{
return true;
}
}
public override DefType ContainingType
{
get
{
return null;
}
}
public override DefType[] ExplicitlyImplementedInterfaces
{
get
{
return Array.Empty<DefType>();
}
}
}
}

View File

@@ -0,0 +1,35 @@
// 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 Internal.TypeSystem;
namespace ILCompiler
{
internal class CompilerMetadataFieldLayoutAlgorithm : MetadataFieldLayoutAlgorithm
{
protected override void PrepareRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
{
// GC statics start with a pointer to the "EEType" that signals the size and GCDesc to the GC
layout.GcStatics.Size = context.Target.PointerSize;
layout.ThreadStatics.Size = context.Target.PointerSize;
}
protected override void FinalizeRuntimeSpecificStaticFieldLayout(TypeSystemContext context, ref ComputedStaticFieldLayout layout)
{
// If the size of GCStatics is equal to the size set in PrepareRuntimeSpecificStaticFieldLayout, we
// don't have any GC statics
if (layout.GcStatics.Size == context.Target.PointerSize)
{
layout.GcStatics.Size = 0;
}
if (layout.ThreadStatics.Size == context.Target.PointerSize)
{
layout.ThreadStatics.Size = 0;
}
}
}
}

View File

@@ -0,0 +1,48 @@
// 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 Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
// Manages policies around static constructors (.cctors) and static data initialization.
partial class CompilerTypeSystemContext
{
// Eventually, this will also manage preinitialization (interpreting cctors at compile
// time and converting them to blobs of preinitialized data), and the various
// System.Runtime.CompilerServices.PreInitializedAttribute/InitDataBlobAttribute/etc. placed on
// types and their members by toolchain components.
/// <summary>
/// Returns true if '<paramref name="type"/>' has a lazily executed static constructor.
/// A lazy static constructor gets executed on first access to type's members.
/// </summary>
public bool HasLazyStaticConstructor(TypeDesc type)
{
return type.HasStaticConstructor && !HasEagerConstructorAttribute(type);
}
/// <summary>
/// Returns true if '<paramref name="type"/>' has a static constructor that is eagerly
/// executed at process startup time.
/// </summary>
public bool HasEagerStaticConstructor(TypeDesc type)
{
return type.HasStaticConstructor && HasEagerConstructorAttribute(type);
}
private static bool HasEagerConstructorAttribute(TypeDesc type)
{
MetadataType mdType = type as MetadataType;
return mdType != null &&
mdType.HasCustomAttribute("System.Runtime.CompilerServices", "EagerStaticClassConstructionAttribute");
}
}
}

View File

@@ -0,0 +1,405 @@
// 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.IO;
using System.IO.MemoryMappedFiles;
using System.Diagnostics;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Internal.IL;
namespace ILCompiler
{
public partial class CompilerTypeSystemContext : MetadataTypeSystemContext, IMetadataStringDecoderProvider
{
private MetadataFieldLayoutAlgorithm _metadataFieldLayoutAlgorithm = new CompilerMetadataFieldLayoutAlgorithm();
private MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm();
private ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm;
private MetadataVirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm();
private MetadataStringDecoder _metadataStringDecoder;
private class ModuleData
{
public string SimpleName;
public string FilePath;
public EcmaModule Module;
public MemoryMappedViewAccessor MappedViewAccessor;
}
private class ModuleHashtable : LockFreeReaderHashtable<EcmaModule, ModuleData>
{
protected override int GetKeyHashCode(EcmaModule key)
{
return key.GetHashCode();
}
protected override int GetValueHashCode(ModuleData value)
{
return value.Module.GetHashCode();
}
protected override bool CompareKeyToValue(EcmaModule key, ModuleData value)
{
return Object.ReferenceEquals(key, value.Module);
}
protected override bool CompareValueToValue(ModuleData value1, ModuleData value2)
{
return Object.ReferenceEquals(value1.Module, value2.Module);
}
protected override ModuleData CreateValueFromKey(EcmaModule key)
{
Debug.Assert(false, "CreateValueFromKey not supported");
return null;
}
}
private ModuleHashtable _moduleHashtable = new ModuleHashtable();
private class SimpleNameHashtable : LockFreeReaderHashtable<string, ModuleData>
{
StringComparer _comparer = StringComparer.OrdinalIgnoreCase;
protected override int GetKeyHashCode(string key)
{
return _comparer.GetHashCode(key);
}
protected override int GetValueHashCode(ModuleData value)
{
return _comparer.GetHashCode(value.SimpleName);
}
protected override bool CompareKeyToValue(string key, ModuleData value)
{
return _comparer.Equals(key, value.SimpleName);
}
protected override bool CompareValueToValue(ModuleData value1, ModuleData value2)
{
return _comparer.Equals(value1.SimpleName, value2.SimpleName);
}
protected override ModuleData CreateValueFromKey(string key)
{
Debug.Assert(false, "CreateValueFromKey not supported");
return null;
}
}
private SimpleNameHashtable _simpleNameHashtable = new SimpleNameHashtable();
private class DelegateInfoHashtable : LockFreeReaderHashtable<TypeDesc, DelegateInfo>
{
protected override int GetKeyHashCode(TypeDesc key)
{
return key.GetHashCode();
}
protected override int GetValueHashCode(DelegateInfo value)
{
return value.Type.GetHashCode();
}
protected override bool CompareKeyToValue(TypeDesc key, DelegateInfo value)
{
return Object.ReferenceEquals(key, value.Type);
}
protected override bool CompareValueToValue(DelegateInfo value1, DelegateInfo value2)
{
return Object.ReferenceEquals(value1.Type, value2.Type);
}
protected override DelegateInfo CreateValueFromKey(TypeDesc key)
{
return new DelegateInfo(key);
}
}
private DelegateInfoHashtable _delegateInfoHashtable = new DelegateInfoHashtable();
private SharedGenericsMode _genericsMode;
public CompilerTypeSystemContext(TargetDetails details, SharedGenericsMode genericsMode)
: base(details)
{
_genericsMode = genericsMode;
}
public IReadOnlyDictionary<string, string> InputFilePaths
{
get;
set;
}
public IReadOnlyDictionary<string, string> ReferenceFilePaths
{
get;
set;
}
public override ModuleDesc ResolveAssembly(System.Reflection.AssemblyName name, bool throwIfNotFound)
{
return GetModuleForSimpleName(name.Name, throwIfNotFound);
}
public EcmaModule GetModuleForSimpleName(string simpleName, bool throwIfNotFound = true)
{
ModuleData existing;
if (_simpleNameHashtable.TryGetValue(simpleName, out existing))
return existing.Module;
string filePath;
if (!InputFilePaths.TryGetValue(simpleName, out filePath))
{
if (!ReferenceFilePaths.TryGetValue(simpleName, out filePath))
{
// TODO: the exception is wrong for two reasons: for one, this should be assembly full name, not simple name.
// The other reason is that on CoreCLR, the exception also captures the reason. We should be passing two
// string IDs. This makes this rather annoying.
if (throwIfNotFound)
throw new TypeSystemException.FileNotFoundException(ExceptionStringID.FileLoadErrorGeneric, simpleName);
return null;
}
}
return AddModule(filePath, simpleName);
}
public EcmaModule GetModuleFromPath(string filePath)
{
// This method is not expected to be called frequently. Linear search is acceptable.
foreach (var entry in ModuleHashtable.Enumerator.Get(_moduleHashtable))
{
if (entry.FilePath == filePath)
return entry.Module;
}
return AddModule(filePath, null);
}
private static unsafe PEReader OpenPEFile(string filePath, out MemoryMappedViewAccessor mappedViewAccessor)
{
// System.Reflection.Metadata has heuristic that tries to save virtual address space. This heuristic does not work
// well for us since it can make IL access very slow (call to OS for each method IL query). We will map the file
// ourselves to get the desired performance characteristics reliably.
FileStream fileStream = null;
MemoryMappedFile mappedFile = null;
MemoryMappedViewAccessor accessor = null;
try
{
// Create stream because CreateFromFile(string, ...) uses FileShare.None which is too strict
fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false);
mappedFile = MemoryMappedFile.CreateFromFile(
fileStream, null, fileStream.Length, MemoryMappedFileAccess.Read, HandleInheritability.None, true);
accessor = mappedFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);
var safeBuffer = accessor.SafeMemoryMappedViewHandle;
var peReader = new PEReader((byte*)safeBuffer.DangerousGetHandle(), (int)safeBuffer.ByteLength);
// MemoryMappedFile does not need to be kept around. MemoryMappedViewAccessor is enough.
mappedViewAccessor = accessor;
accessor = null;
return peReader;
}
finally
{
if (accessor != null)
accessor.Dispose();
if (mappedFile != null)
mappedFile.Dispose();
if (fileStream != null)
fileStream.Dispose();
}
}
private EcmaModule AddModule(string filePath, string expectedSimpleName)
{
MemoryMappedViewAccessor mappedViewAccessor = null;
PdbSymbolReader pdbReader = null;
try
{
PEReader peReader = OpenPEFile(filePath, out mappedViewAccessor);
pdbReader = OpenAssociatedSymbolFile(filePath);
EcmaModule module = EcmaModule.Create(this, peReader, pdbReader);
MetadataReader metadataReader = module.MetadataReader;
string simpleName = metadataReader.GetString(metadataReader.GetAssemblyDefinition().Name);
if (expectedSimpleName != null && !simpleName.Equals(expectedSimpleName, StringComparison.OrdinalIgnoreCase))
throw new FileNotFoundException("Assembly name does not match filename " + filePath);
ModuleData moduleData = new ModuleData()
{
SimpleName = simpleName,
FilePath = filePath,
Module = module,
MappedViewAccessor = mappedViewAccessor
};
lock (this)
{
ModuleData actualModuleData = _simpleNameHashtable.AddOrGetExisting(moduleData);
if (actualModuleData != moduleData)
{
if (actualModuleData.FilePath != filePath)
throw new FileNotFoundException("Module with same simple name already exists " + filePath);
return actualModuleData.Module;
}
mappedViewAccessor = null; // Ownership has been transfered
pdbReader = null; // Ownership has been transferred
_moduleHashtable.AddOrGetExisting(moduleData);
}
return module;
}
finally
{
if (mappedViewAccessor != null)
mappedViewAccessor.Dispose();
if (pdbReader != null)
pdbReader.Dispose();
}
}
public DelegateInfo GetDelegateInfo(TypeDesc delegateType)
{
return _delegateInfoHashtable.GetOrCreateValue(delegateType);
}
public override FieldLayoutAlgorithm GetLayoutAlgorithmForType(DefType type)
{
return _metadataFieldLayoutAlgorithm;
}
protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForNonPointerArrayType(ArrayType type)
{
if (_arrayOfTRuntimeInterfacesAlgorithm == null)
{
_arrayOfTRuntimeInterfacesAlgorithm = new ArrayOfTRuntimeInterfacesAlgorithm(SystemModule.GetKnownType("System", "Array`1"));
}
return _arrayOfTRuntimeInterfacesAlgorithm;
}
protected override RuntimeInterfacesAlgorithm GetRuntimeInterfacesAlgorithmForDefType(DefType type)
{
return _metadataRuntimeInterfacesAlgorithm;
}
public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc type)
{
Debug.Assert(!type.IsArray, "Wanted to call GetClosestMetadataType?");
return _virtualMethodAlgorithm;
}
protected override IEnumerable<MethodDesc> GetAllMethods(TypeDesc type)
{
if (type.IsDelegate)
{
return GetAllMethodsForDelegate(type);
}
return type.GetMethods();
}
private IEnumerable<MethodDesc> GetAllMethodsForDelegate(TypeDesc type)
{
// Inject the synthetic GetThunk virtual override
InstantiatedType instantiatedType = type as InstantiatedType;
if (instantiatedType != null)
{
DelegateInfo info = GetDelegateInfo(type.GetTypeDefinition());
yield return GetMethodForInstantiatedType(info.GetThunkMethod, instantiatedType);
}
else
{
DelegateInfo info = GetDelegateInfo(type);
yield return info.GetThunkMethod;
}
// Append all the methods defined in metadata
foreach (var m in type.GetMethods())
yield return m;
}
protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed)
{
if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes)
return RuntimeDeterminedCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed);
Debug.Assert(_genericsMode == SharedGenericsMode.Disabled);
changed = false;
return instantiation;
}
protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind)
{
if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes)
return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind);
Debug.Assert(_genericsMode == SharedGenericsMode.Disabled);
return typeToConvert;
}
protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind)
{
if (_genericsMode == SharedGenericsMode.CanonicalReferenceTypes)
return RuntimeDeterminedCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, ref kind);
Debug.Assert(_genericsMode == SharedGenericsMode.Disabled);
return typeToConvert;
}
public MetadataStringDecoder GetMetadataStringDecoder()
{
if (_metadataStringDecoder == null)
_metadataStringDecoder = new CachingMetadataStringDecoder(0x10000); // TODO: Tune the size
return _metadataStringDecoder;
}
protected override bool ComputeHasGCStaticBase(FieldDesc field)
{
Debug.Assert(field.IsStatic);
TypeDesc fieldType = field.FieldType;
if (fieldType.IsValueType)
return ((DefType)fieldType).ContainsGCPointers;
else
return fieldType.IsGCPointer;
}
//
// Symbols
//
private PdbSymbolReader OpenAssociatedSymbolFile(string peFilePath)
{
// Assume that the .pdb file is next to the binary
var pdbFilename = Path.ChangeExtension(peFilePath, ".pdb");
if (!File.Exists(pdbFilename))
return null;
// Try to open the symbol file as portable pdb first
PdbSymbolReader reader = PortablePdbSymbolReader.TryOpen(pdbFilename, GetMetadataStringDecoder());
if (reader == null)
{
// Fallback to the diasymreader for non-portable pdbs
reader = UnmanagedPdbSymbolReader.TryOpenSymbolReaderForMetadataFile(peFilePath);
}
return reader;
}
}
/// <summary>
/// Specifies the mode in which canonicalization should occur.
/// </summary>
public enum SharedGenericsMode
{
Disabled,
CanonicalReferenceTypes,
}
}

View File

@@ -0,0 +1,92 @@
// 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.Collections.Generic;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis;
using ILCompiler.DependencyAnalysisFramework;
using ILCompiler.CppCodeGen;
namespace ILCompiler
{
public sealed class CppCodegenCompilation : Compilation
{
private CppWriter _cppWriter = null;
internal CppCodegenConfigProvider Options { get; }
internal CppCodegenCompilation(
DependencyAnalyzerBase<NodeFactory> dependencyGraph,
NodeFactory nodeFactory,
IEnumerable<ICompilationRootProvider> roots,
Logger logger,
CppCodegenConfigProvider options)
: base(dependencyGraph, nodeFactory, GetCompilationRoots(roots, nodeFactory), new NameMangler(true), logger)
{
Options = options;
}
private static IEnumerable<ICompilationRootProvider> GetCompilationRoots(IEnumerable<ICompilationRootProvider> existingRoots, NodeFactory factory)
{
yield return new CppCodegenCompilationRootProvider(factory.TypeSystemContext);
foreach (var existingRoot in existingRoots)
yield return existingRoot;
}
protected override void CompileInternal(string outputFile)
{
_cppWriter = new CppWriter(this, outputFile);
var nodes = _dependencyGraph.MarkedNodeList;
_cppWriter.OutputCode(nodes, NodeFactory);
}
protected override void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> obj)
{
foreach (CppMethodCodeNode methodCodeNodeNeedingCode in obj)
{
_cppWriter.CompileMethod(methodCodeNodeNeedingCode);
}
}
private class CppCodegenCompilationRootProvider : ICompilationRootProvider
{
private TypeSystemContext _context;
public CppCodegenCompilationRootProvider(TypeSystemContext context)
{
_context = context;
}
private void RootWellKnownType(WellKnownType wellKnownType, IRootingServiceProvider rootProvider)
{
var type = _context.GetWellKnownType(wellKnownType);
rootProvider.AddCompilationRoot(type, "Enables CPP codegen");
}
public void AddCompilationRoots(IRootingServiceProvider rootProvider)
{
RootWellKnownType(WellKnownType.Void, rootProvider);
RootWellKnownType(WellKnownType.Boolean, rootProvider);
RootWellKnownType(WellKnownType.Char, rootProvider);
RootWellKnownType(WellKnownType.SByte, rootProvider);
RootWellKnownType(WellKnownType.Byte, rootProvider);
RootWellKnownType(WellKnownType.Int16, rootProvider);
RootWellKnownType(WellKnownType.UInt16, rootProvider);
RootWellKnownType(WellKnownType.Int32, rootProvider);
RootWellKnownType(WellKnownType.UInt32, rootProvider);
RootWellKnownType(WellKnownType.Int64, rootProvider);
RootWellKnownType(WellKnownType.UInt64, rootProvider);
RootWellKnownType(WellKnownType.IntPtr, rootProvider);
RootWellKnownType(WellKnownType.UIntPtr, rootProvider);
RootWellKnownType(WellKnownType.Single, rootProvider);
RootWellKnownType(WellKnownType.Double, rootProvider);
}
}
}
}

View File

@@ -0,0 +1,51 @@
// 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 ILCompiler.DependencyAnalysis;
namespace ILCompiler
{
public sealed class CppCodegenCompilationBuilder : CompilationBuilder
{
// These need to provide reasonable defaults so that the user can optionally skip
// calling the Use/Configure methods and still get something reasonable back.
CppCodegenConfigProvider _config = new CppCodegenConfigProvider(Array.Empty<string>());
public CppCodegenCompilationBuilder(CompilerTypeSystemContext context, CompilationModuleGroup group)
: base(new CppCodegenNodeFactory(context, group))
{
}
public override CompilationBuilder UseBackendOptions(IEnumerable<string> options)
{
_config = new CppCodegenConfigProvider(options);
return this;
}
public override ICompilation ToCompilation()
{
return new CppCodegenCompilation(CreateDependencyGraph(), _nodeFactory, _compilationRoots, _logger, _config);
}
}
internal class CppCodegenConfigProvider
{
private readonly HashSet<string> _options;
public const string NoLineNumbersString = "NoLineNumbers";
public CppCodegenConfigProvider(IEnumerable<string> options)
{
_options = new HashSet<string>(options, StringComparer.OrdinalIgnoreCase);
}
public bool HasOption(string optionName)
{
return _options.Contains(optionName);
}
}
}

View File

@@ -0,0 +1,144 @@
// 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 Internal.IL;
using Internal.IL.Stubs;
using Internal.TypeSystem;
using ILCompiler.DependencyAnalysis;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler
{
/// <summary>
/// Captures information required to generate a ReadyToRun helper to create a delegate type instance
/// pointing to a specific target method.
/// </summary>
public sealed class DelegateCreationInfo
{
/// <summary>
/// Gets the node corresponding to the method that initializes the delegate.
/// </summary>
public IMethodNode Constructor
{
get;
}
/// <summary>
/// Gets the node representing the target method of the delegate.
/// </summary>
public ISymbolNode Target
{
get;
}
/// <summary>
/// Gets an optional node passed as an additional argument to the constructor.
/// </summary>
public IMethodNode Thunk
{
get;
}
private DelegateCreationInfo(IMethodNode constructor, ISymbolNode target, IMethodNode thunk = null)
{
Constructor = constructor;
Target = target;
Thunk = thunk;
}
/// <summary>
/// Constructs a new instance of <see cref="DelegateCreationInfo"/> set up to construct a delegate of type
/// '<paramref name="delegateType"/>' pointing to '<paramref name="targetMethod"/>'.
/// </summary>
public static DelegateCreationInfo Create(TypeDesc delegateType, MethodDesc targetMethod, NodeFactory factory)
{
var context = (CompilerTypeSystemContext)delegateType.Context;
var systemDelegate = targetMethod.Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType;
int paramCountTargetMethod = targetMethod.Signature.Length;
if (!targetMethod.Signature.IsStatic)
{
paramCountTargetMethod++;
}
DelegateInfo delegateInfo = context.GetDelegateInfo(delegateType.GetTypeDefinition());
int paramCountDelegateClosed = delegateInfo.Signature.Length + 1;
bool closed = false;
if (paramCountDelegateClosed == paramCountTargetMethod)
{
closed = true;
}
else
{
Debug.Assert(paramCountDelegateClosed == paramCountTargetMethod + 1);
}
if (targetMethod.Signature.IsStatic)
{
MethodDesc invokeThunk;
MethodDesc initMethod;
if (!closed)
{
// Open delegate to a static method
invokeThunk = delegateInfo.Thunks[DelegateThunkKind.OpenStaticThunk];
initMethod = systemDelegate.GetKnownMethod("InitializeOpenStaticThunk", null);
}
else
{
// Closed delegate to a static method (i.e. delegate to an extension method that locks the first parameter)
invokeThunk = delegateInfo.Thunks[DelegateThunkKind.ClosedStaticThunk];
initMethod = systemDelegate.GetKnownMethod("InitializeClosedStaticThunk", null);
}
var instantiatedDelegateType = delegateType as InstantiatedType;
if (instantiatedDelegateType != null)
invokeThunk = context.GetMethodForInstantiatedType(invokeThunk, instantiatedDelegateType);
return new DelegateCreationInfo(
factory.MethodEntrypoint(initMethod),
factory.MethodEntrypoint(targetMethod),
factory.MethodEntrypoint(invokeThunk));
}
else
{
if (!closed)
throw new NotImplementedException("Open instance delegates");
bool useUnboxingStub = targetMethod.OwningType.IsValueType;
string initializeMethodName = "InitializeClosedInstance";
if (targetMethod.HasInstantiation)
{
Debug.Assert(!targetMethod.IsVirtual, "TODO: delegate to generic virtual method");
// Closed delegates to generic instance methods need to be constructed through a slow helper that
// checks for the fat function pointer case (function pointer + instantiation argument in a single
// pointer) and injects an invocation thunk to unwrap the fat function pointer as part of
// the invocation if necessary.
initializeMethodName = "InitializeClosedInstanceSlow";
}
return new DelegateCreationInfo(
factory.MethodEntrypoint(systemDelegate.GetKnownMethod(initializeMethodName, null)),
factory.MethodEntrypoint(targetMethod, useUnboxingStub));
}
}
public override bool Equals(object obj)
{
var other = obj as DelegateCreationInfo;
return other != null && Constructor == other.Constructor
&& Target == other.Target && Thunk == other.Thunk;
}
public override int GetHashCode()
{
return Constructor.GetHashCode() ^ Target.GetHashCode();
}
}
}

View File

@@ -0,0 +1,82 @@
// 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.IO;
using Internal.NativeFormat;
using Internal.Text;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents a hash table of array types generated into the image.
/// </summary>
internal sealed class ArrayMapNode : ObjectNode, ISymbolNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
public ArrayMapNode(ExternalReferencesTableNode externalReferences)
{
_endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__array_type_map_End", true);
_externalReferences = externalReferences;
}
public ISymbolNode EndSymbol => _endSymbol;
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__array_type_map");
}
public int Offset => 0;
public override bool IsShareable => false;
public override ObjectNodeSection Section => ObjectNodeSection.DataSection;
public override bool StaticDependenciesAreComputed => true;
protected override string GetName() => this.GetMangledName();
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
// This node does not trigger generation of other nodes.
if (relocsOnly)
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolNode[] { this });
var writer = new NativeWriter();
var typeMapHashTable = new VertexHashtable();
Section hashTableSection = writer.NewSection();
hashTableSection.Place(typeMapHashTable);
foreach (var arrayType in factory.MetadataManager.GetArrayTypeMapping())
{
if (!arrayType.IsSzArray)
continue;
if (!factory.MetadataManager.TypeGeneratesEEType(arrayType))
continue;
// TODO: This should only be emitted for arrays of value types. The type loader builds everything else.
// Go with a necessary type symbol. It will be upgraded to a constructed one if a constructed was emitted.
IEETypeNode arrayTypeSymbol = factory.NecessaryTypeSymbol(arrayType);
Vertex vertex = writer.GetUnsignedConstant(_externalReferences.GetIndex(arrayTypeSymbol));
int hashCode = arrayType.GetHashCode();
typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
}
MemoryStream ms = new MemoryStream();
writer.Save(ms);
byte[] hashTableBytes = ms.ToArray();
_endSymbol.SetSymbolOffset(hashTableBytes.Length);
return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolNode[] { this, _endSymbol });
}
}
}

View File

@@ -0,0 +1,109 @@
// 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.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents an array of <typeparamref name="TEmbedded"/> nodes. The contents of this node will be emitted
/// by placing a starting symbol, followed by contents of <typeparamref name="TEmbedded"/> nodes (optionally
/// sorted using provided comparer), followed by ending symbol.
/// </summary>
public class ArrayOfEmbeddedDataNode<TEmbedded> : ObjectNode
where TEmbedded : EmbeddedObjectNode
{
private HashSet<TEmbedded> _nestedNodes = new HashSet<TEmbedded>();
private List<TEmbedded> _nestedNodesList = new List<TEmbedded>();
private ObjectAndOffsetSymbolNode _startSymbol;
private ObjectAndOffsetSymbolNode _endSymbol;
private IComparer<TEmbedded> _sorter;
public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<TEmbedded> nodeSorter)
{
_startSymbol = new ObjectAndOffsetSymbolNode(this, 0, startSymbolMangledName, true);
_endSymbol = new ObjectAndOffsetSymbolNode(this, 0, endSymbolMangledName, true);
_sorter = nodeSorter;
}
internal ObjectAndOffsetSymbolNode StartSymbol => _startSymbol;
internal ObjectAndOffsetSymbolNode EndSymbol => _endSymbol;
public void AddEmbeddedObject(TEmbedded symbol)
{
if (_nestedNodes.Add(symbol))
{
_nestedNodesList.Add(symbol);
}
}
public int IndexOfEmbeddedObject(TEmbedded symbol)
{
Debug.Assert(_sorter == null);
return _nestedNodesList.IndexOf(symbol);
}
protected override string GetName() => $"Region {_startSymbol.GetMangledName()}";
public override ObjectNodeSection Section => ObjectNodeSection.DataSection;
public override bool IsShareable => false;
public override bool StaticDependenciesAreComputed => true;
protected IEnumerable<TEmbedded> NodesList => _nestedNodesList;
protected virtual void GetElementDataForNodes(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly)
{
foreach (TEmbedded node in NodesList)
{
if (!relocsOnly)
node.Offset = builder.CountBytes;
node.EncodeData(ref builder, factory, relocsOnly);
if (node is ISymbolNode)
{
builder.DefinedSymbols.Add((ISymbolNode)node);
}
}
}
public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory);
builder.Alignment = factory.Target.PointerSize;
if (_sorter != null)
_nestedNodesList.Sort(_sorter);
builder.DefinedSymbols.Add(_startSymbol);
GetElementDataForNodes(ref builder, factory, relocsOnly);
_endSymbol.SetSymbolOffset(builder.CountBytes);
builder.DefinedSymbols.Add(_endSymbol);
ObjectData objData = builder.ToObjectData();
return objData;
}
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
{
return _nestedNodesList.Count == 0;
}
}
// TODO: delete this once we review each use of this and put it on the generic plan with the
// right element type
public class ArrayOfEmbeddedDataNode : ArrayOfEmbeddedDataNode<EmbeddedObjectNode>
{
public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<EmbeddedObjectNode> nodeSorter)
: base(startSymbolMangledName, endSymbolMangledName, nodeSorter)
{
}
}
}

View File

@@ -0,0 +1,134 @@
// 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 Internal.Text;
namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// Represents an array of pointers to symbols. <typeparamref name="TTarget"/> is the type
/// of node each pointer within the vector points to.
/// </summary>
public sealed class ArrayOfEmbeddedPointersNode<TTarget> : ArrayOfEmbeddedDataNode<EmbeddedPointerIndirectionNode<TTarget>>
where TTarget : ISymbolNode
{
private int _nextId;
private string _startSymbolMangledName;
/// <summary>
/// Provides a callback mechanism for notification when an EmbeddedPointerIndirectionNode is marked and added to the
/// parent ArrayOfEmbeddedPointersNode's internal list
/// </summary>
public delegate void OnMarkedDelegate(EmbeddedPointerIndirectionNode<TTarget> embeddedObject);
public ArrayOfEmbeddedPointersNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<TTarget> nodeSorter)
: base(
startSymbolMangledName,
endSymbolMangledName,
nodeSorter != null ? new PointerIndirectionNodeComparer(nodeSorter) : null)
{
_startSymbolMangledName = startSymbolMangledName;
}
public EmbeddedObjectNode NewNode(TTarget target)
{
return new SimpleEmbeddedPointerIndirectionNode(this, target);
}
public EmbeddedObjectNode NewNodeWithSymbol(TTarget target)
{
return new EmbeddedPointerIndirectionWithSymbolNode(this, target, GetNextId());
}
public EmbeddedObjectNode NewNodeWithSymbol(TTarget target, OnMarkedDelegate callback)
{
return new EmbeddedPointerIndirectionWithSymbolAndOnMarkedCallbackNode(this, target, GetNextId(), callback);
}
int GetNextId()
{
return System.Threading.Interlocked.Increment(ref _nextId);
}
private class PointerIndirectionNodeComparer : IComparer<EmbeddedPointerIndirectionNode<TTarget>>
{
private IComparer<TTarget> _innerComparer;
public PointerIndirectionNodeComparer(IComparer<TTarget> innerComparer)
{
_innerComparer = innerComparer;
}
public int Compare(EmbeddedPointerIndirectionNode<TTarget> x, EmbeddedPointerIndirectionNode<TTarget> y)
{
return _innerComparer.Compare(x.Target, y.Target);
}
}
private class SimpleEmbeddedPointerIndirectionNode : EmbeddedPointerIndirectionNode<TTarget>
{
protected ArrayOfEmbeddedPointersNode<TTarget> _parentNode;
public SimpleEmbeddedPointerIndirectionNode(ArrayOfEmbeddedPointersNode<TTarget> futureParent, TTarget target)
: base(target)
{
_parentNode = futureParent;
}
protected override string GetName() => $"Embedded pointer to {Target.GetMangledName()}";
protected override void OnMarked(NodeFactory factory)
{
// We don't want the child in the parent collection unless it's necessary.
// Only when this node gets marked, the parent node becomes the actual parent.
_parentNode.AddEmbeddedObject(this);
}
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
return new[]
{
new DependencyListEntry(Target, "reloc"),
new DependencyListEntry(_parentNode, "Pointer region")
};
}
}
private class EmbeddedPointerIndirectionWithSymbolNode : SimpleEmbeddedPointerIndirectionNode, ISymbolNode
{
private int _id;
public EmbeddedPointerIndirectionWithSymbolNode(ArrayOfEmbeddedPointersNode<TTarget> futureParent, TTarget target, int id)
: base(futureParent, target)
{
_id = id;
}
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(_parentNode._startSymbolMangledName).Append("_").Append(_id.ToStringInvariant());
}
}
private class EmbeddedPointerIndirectionWithSymbolAndOnMarkedCallbackNode : EmbeddedPointerIndirectionWithSymbolNode
{
private OnMarkedDelegate _onMarkedCallback;
public EmbeddedPointerIndirectionWithSymbolAndOnMarkedCallbackNode(ArrayOfEmbeddedPointersNode<TTarget> futureParent, TTarget target, int id, OnMarkedDelegate onMarkedCallback)
: base(futureParent, target, id)
{
_onMarkedCallback = onMarkedCallback;
}
protected override void OnMarked(NodeFactory factory)
{
base.OnMarked(factory);
_onMarkedCallback(this);
}
}
}
}

View File

@@ -0,0 +1,45 @@
// 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 Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
public class ArrayOfFrozenObjectsNode<TEmbedded> : ArrayOfEmbeddedDataNode<TEmbedded>
where TEmbedded : EmbeddedObjectNode
{
public ArrayOfFrozenObjectsNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<TEmbedded> nodeSorter) : base(startSymbolMangledName, endSymbolMangledName, nodeSorter)
{
}
private void AlignNextObject(ref ObjectDataBuilder builder, NodeFactory factory)
{
builder.EmitZeros(AlignmentHelper.AlignUp(builder.CountBytes, factory.Target.PointerSize) - builder.CountBytes);
}
protected override void GetElementDataForNodes(ref ObjectDataBuilder builder, NodeFactory factory, bool relocsOnly)
{
foreach (EmbeddedObjectNode node in NodesList)
{
AlignNextObject(ref builder, factory);
if (!relocsOnly)
node.Offset = builder.CountBytes;
node.EncodeData(ref builder, factory, relocsOnly);
if (node is ISymbolNode)
{
builder.DefinedSymbols.Add((ISymbolNode)node);
}
}
// Terminate with a null pointer as expected by the GC
AlignNextObject(ref builder, factory);
builder.EmitZeroPointer();
}
}
}

View File

@@ -0,0 +1,61 @@
// 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 Internal.TypeSystem;
using Internal.Text;
namespace ILCompiler.DependencyAnalysis
{
public abstract class AssemblyStubNode : ObjectNode, ISymbolNode
{
public AssemblyStubNode()
{
}
public override ObjectNodeSection Section => ObjectNodeSection.TextSection;
public override bool StaticDependenciesAreComputed => true;
public abstract void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb);
public int Offset => 0;
public override bool IsShareable => false;
public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
{
switch (factory.Target.Architecture)
{
case TargetArchitecture.X64:
X64.X64Emitter x64Emitter = new X64.X64Emitter(factory);
EmitCode(factory, ref x64Emitter, relocsOnly);
x64Emitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
x64Emitter.Builder.DefinedSymbols.Add(this);
return x64Emitter.Builder.ToObjectData();
case TargetArchitecture.X86:
X86.X86Emitter x86Emitter = new X86.X86Emitter(factory);
EmitCode(factory, ref x86Emitter, relocsOnly);
x86Emitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
x86Emitter.Builder.DefinedSymbols.Add(this);
return x86Emitter.Builder.ToObjectData();
case TargetArchitecture.ARM:
ARM.ARMEmitter armEmitter = new ARM.ARMEmitter(factory);
EmitCode(factory, ref armEmitter, relocsOnly);
armEmitter.Builder.Alignment = factory.Target.MinimumFunctionAlignment;
armEmitter.Builder.DefinedSymbols.Add(this);
return armEmitter.Builder.ToObjectData();
default:
throw new NotImplementedException();
}
}
protected abstract void EmitCode(NodeFactory factory, ref X64.X64Emitter instructionEncoder, bool relocsOnly);
protected abstract void EmitCode(NodeFactory factory, ref X86.X86Emitter instructionEncoder, bool relocsOnly);
protected abstract void EmitCode(NodeFactory factory, ref ARM.ARMEmitter instructionEncoder, bool relocsOnly);
}
}

View File

@@ -0,0 +1,43 @@
// 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 Internal.Text;
namespace ILCompiler.DependencyAnalysis
{
public class BlobNode : ObjectNode, ISymbolNode
{
private Utf8String _name;
private ObjectNodeSection _section;
private byte[] _data;
private int _alignment;
public BlobNode(Utf8String name, ObjectNodeSection section, byte[] data, int alignment)
{
_name = name;
_section = section;
_data = data;
_alignment = alignment;
}
public override ObjectNodeSection Section => _section;
public override bool StaticDependenciesAreComputed => true;
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(_name);
}
public int Offset => 0;
public override bool IsShareable => false;
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
return new ObjectData(_data, Array.Empty<Relocation>(), _alignment, new ISymbolNode[] { this });
}
protected override string GetName() => this.GetMangledName();
}
}

View File

@@ -0,0 +1,90 @@
// 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.IO;
using Internal.NativeFormat;
using Internal.Text;
using Internal.TypeSystem;
using Debug = System.Diagnostics.Debug;
namespace ILCompiler.DependencyAnalysis
{
class ClassConstructorContextMap : ObjectNode, ISymbolNode
{
private ObjectAndOffsetSymbolNode _endSymbol;
private ExternalReferencesTableNode _externalReferences;
public ClassConstructorContextMap(ExternalReferencesTableNode externalReferences)
{
_endSymbol = new ObjectAndOffsetSymbolNode(this, 0, "__type_to_cctorContext_map_End", true);
_externalReferences = externalReferences;
}
public ISymbolNode EndSymbol => _endSymbol;
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix).Append("__type_to_cctorContext_map");
}
public int Offset => 0;
public override ObjectNodeSection Section => ObjectNodeSection.DataSection;
public override bool IsShareable => false;
public override bool StaticDependenciesAreComputed => true;
protected override string GetName() => this.GetMangledName();
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
// This node does not trigger generation of other nodes.
if (relocsOnly)
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolNode[] { this });
var writer = new NativeWriter();
var typeMapHashTable = new VertexHashtable();
Section hashTableSection = writer.NewSection();
hashTableSection.Place(typeMapHashTable);
foreach (var node in factory.MetadataManager.GetCctorContextMapping())
{
MetadataType type = node.Type;
Debug.Assert(factory.TypeSystemContext.HasLazyStaticConstructor(type));
// If this type doesn't generate an EEType in the current compilation, don't report it in the table.
// If nobody can get to the EEType, they can't ask to run the cctor. We don't need to force generate it.
if (!factory.MetadataManager.TypeGeneratesEEType(type))
continue;
// Hash table is hashed by the hashcode of the owning type.
// Each entry has: the EEType of the type, followed by the non-GC static base.
// The non-GC static base is prefixed by the class constructor context.
// Unfortunately we need to adjust for the cctor context just so that we can subtract it again at runtime...
int delta = NonGCStaticsNode.GetClassConstructorContextStorageSize(factory.TypeSystemContext.Target, type);
Vertex vertex = writer.GetTuple(
writer.GetUnsignedConstant(_externalReferences.GetIndex(factory.NecessaryTypeSymbol(type))),
writer.GetUnsignedConstant(_externalReferences.GetIndex(node, delta))
);
int hashCode = type.GetHashCode();
typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
}
MemoryStream ms = new MemoryStream();
writer.Save(ms);
byte[] hashTableBytes = ms.ToArray();
_endSymbol.SetSymbolOffset(hashTableBytes.Length);
return new ObjectData(hashTableBytes, Array.Empty<Relocation>(), 1, new ISymbolNode[] { this, _endSymbol });
}
}
}

View File

@@ -0,0 +1,36 @@
// 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 Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
internal sealed class ClonedConstructedEETypeNode : ConstructedEETypeNode, ISymbolNode
{
public ClonedConstructedEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
}
protected override string GetName() => this.GetMangledName() + " cloned";
//
// A cloned type must be named differently than the type it is a clone of so the linker
// will have an unambiguous symbol to resolve
//
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("__Cloned_EEType_").Append(nameMangler.GetMangledTypeName(_type));
}
public override bool IsShareable => true;
protected override void OutputRelatedType(NodeFactory factory, ref ObjectDataBuilder objData)
{
//
// Cloned types use the related type field to point via an IAT slot at their true implementation
//
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(_type));
}
}
}

View File

@@ -0,0 +1,269 @@
// 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 Internal.Runtime;
using Internal.Text;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
internal class ConstructedEETypeNode : EETypeNode
{
public ConstructedEETypeNode(NodeFactory factory, TypeDesc type) : base(factory, type)
{
CheckCanGenerateConstructedEEType(factory, type);
}
protected override string GetName() => this.GetMangledName() + " constructed";
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
{
return false;
}
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
DefType closestDefType = _type.GetClosestDefType();
DependencyList dependencyList = new DependencyList();
if (_type.RuntimeInterfaces.Length > 0)
{
dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map");
// If any of the implemented interfaces have variance, calls against compatible interface methods
// could result in interface methods of this type being used (e.g. IEnumberable<object>.GetEnumerator()
// can dispatch to an implementation of IEnumerable<string>.GetEnumerator()).
// For now, we will not try to optimize this and we will pretend all interface methods are necessary.
foreach (var implementedInterface in _type.RuntimeInterfaces)
{
if (implementedInterface.HasVariance)
{
foreach (var interfaceMethod in implementedInterface.GetAllMethods())
{
if (interfaceMethod.Signature.IsStatic)
continue;
MethodDesc implMethod = closestDefType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
if (implMethod != null)
{
dependencyList.Add(factory.VirtualMethodUse(interfaceMethod), "Variant interface method");
dependencyList.Add(factory.VirtualMethodUse(implMethod), "Variant interface method");
}
}
}
}
}
if (_type.IsArray)
{
// Array EEType depends on System.Array's virtuals. Array EETypes don't point to
// their base type (i.e. there's no reloc based dependency making this "just work").
dependencyList.Add(factory.ConstructedTypeSymbol(_type.BaseType), "Array base type");
}
dependencyList.Add(factory.VTable(_type), "VTable");
if (closestDefType.HasGenericDictionarySlot())
{
// Generic dictionary pointer is part of the vtable and as such it gets only laid out
// at the final data emission phase. We need to report it as a non-relocation dependency.
dependencyList.Add(factory.TypeGenericDictionary(closestDefType), "Type generic dictionary");
}
// Include the optional fields by default. We don't know if optional fields will be needed until
// all of the interface usage has been stabilized. If we end up not needing it, the EEType node will not
// generate any relocs to it, and the optional fields node will instruct the object writer to skip
// emitting it.
dependencyList.Add(_optionalFieldsNode, "Optional fields");
// The fact that we generated an EEType means that someone can call RuntimeHelpers.RunClassConstructor.
// We need to make sure this is possible - we need the class constructor context.
if (factory.TypeSystemContext.HasLazyStaticConstructor(_type))
{
dependencyList.Add(factory.TypeNonGCStaticsSymbol((MetadataType)_type), "Class constructor");
}
return dependencyList;
}
public override bool HasConditionalStaticDependencies
{
get
{
// Since the vtable is dependency driven, generate conditional static dependencies for
// all possible vtable entries
foreach (var method in _type.GetClosestDefType().GetAllMethods())
{
if (method.IsVirtual)
return true;
}
// If the type implements at least one interface, calls against that interface could result in this type's
// implementation being used.
if (_type.RuntimeInterfaces.Length > 0)
return true;
return false;
}
}
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
{
DefType defType = _type.GetClosestDefType();
foreach (MethodDesc decl in defType.EnumAllVirtualSlots())
{
if (decl.HasInstantiation)
continue;
MethodDesc impl = defType.FindVirtualFunctionTargetMethodOnObjectType(decl);
if (impl.OwningType == defType && !impl.IsAbstract)
{
MethodDesc canonImpl = impl.GetCanonMethodTarget(CanonicalFormKind.Specific);
yield return new CombinedDependencyListEntry(factory.MethodEntrypoint(canonImpl, _type.IsValueType), factory.VirtualMethodUse(decl), "Virtual method");
}
}
Debug.Assert(
_type == defType ||
((System.Collections.IStructuralEquatable)defType.RuntimeInterfaces).Equals(_type.RuntimeInterfaces,
EqualityComparer<DefType>.Default));
// Add conditional dependencies for interface methods the type implements. For example, if the type T implements
// interface IFoo which has a method M1, add a dependency on T.M1 dependent on IFoo.M1 being called, since it's
// possible for any IFoo object to actually be an instance of T.
foreach (DefType interfaceType in defType.RuntimeInterfaces)
{
Debug.Assert(interfaceType.IsInterface);
foreach (MethodDesc interfaceMethod in interfaceType.GetAllMethods())
{
if (interfaceMethod.Signature.IsStatic)
continue;
MethodDesc implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethod);
if (implMethod != null)
{
yield return new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.ReadyToRunHelper(ReadyToRunHelperId.VirtualCall, interfaceMethod), "Interface method");
yield return new CombinedDependencyListEntry(factory.VirtualMethodUse(implMethod), factory.ReadyToRunHelper(ReadyToRunHelperId.ResolveVirtualFunction, interfaceMethod), "Interface method address");
}
}
}
}
protected override ISymbolNode GetBaseTypeNode(NodeFactory factory)
{
return _type.BaseType != null ? factory.ConstructedTypeSymbol(_type.BaseType) : null;
}
protected override int GCDescSize => GCDescEncoder.GetGCDescSize(_type);
protected override void OutputGCDesc(ref ObjectDataBuilder builder)
{
GCDescEncoder.EncodeGCDesc(ref builder, _type);
}
protected override void OutputVirtualSlots(NodeFactory factory, ref ObjectDataBuilder objData, TypeDesc implType, TypeDesc declType)
{
declType = declType.GetClosestDefType();
var baseType = declType.BaseType;
if (baseType != null)
OutputVirtualSlots(factory, ref objData, implType, baseType);
// The generic dictionary pointer occupies the first slot of each type vtable slice
if (declType.HasGenericDictionarySlot())
{
objData.EmitPointerReloc(factory.TypeGenericDictionary(declType));
}
// Actual vtable slots follow
IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(declType).Slots;
for (int i = 0; i < virtualSlots.Count; i++)
{
MethodDesc declMethod = virtualSlots[i];
if (declMethod.HasInstantiation)
{
// Generic virtual methods will "compile", but will fail to link. Check for it here.
throw new NotImplementedException("VTable for " + _type + " has generic virtual methods.");
}
MethodDesc implMethod = implType.GetClosestDefType().FindVirtualFunctionTargetMethodOnObjectType(declMethod);
if (!implMethod.IsAbstract)
{
MethodDesc canonImplMethod = implMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
objData.EmitPointerReloc(factory.MethodEntrypoint(canonImplMethod, implMethod.OwningType.IsValueType));
}
else
{
objData.EmitZeroPointer();
}
}
}
protected override void OutputInterfaceMap(NodeFactory factory, ref ObjectDataBuilder objData)
{
foreach (var itf in _type.RuntimeInterfaces)
{
objData.EmitPointerReloc(factory.NecessaryTypeSymbol(itf));
}
}
protected override void OutputVirtualSlotAndInterfaceCount(NodeFactory factory, ref ObjectDataBuilder objData)
{
int virtualSlotCount = 0;
TypeDesc currentTypeSlice = _type.GetClosestDefType();
while (currentTypeSlice != null)
{
if (currentTypeSlice.HasGenericDictionarySlot())
virtualSlotCount++;
virtualSlotCount += factory.VTable(currentTypeSlice).Slots.Count;
currentTypeSlice = currentTypeSlice.BaseType;
}
objData.EmitShort(checked((short)virtualSlotCount));
objData.EmitShort(checked((short)_type.RuntimeInterfaces.Length));
}
public static bool CreationAllowed(TypeDesc type)
{
switch (type.Category)
{
case TypeFlags.Pointer:
case TypeFlags.FunctionPointer:
case TypeFlags.ByRef:
// Pointers and byrefs are not boxable
return false;
case TypeFlags.Array:
case TypeFlags.SzArray:
// TODO: any validation for arrays?
break;
default:
// Generic definition EETypes can't be allocated
if (type.IsGenericDefinition)
return false;
break;
}
return true;
}
public static void CheckCanGenerateConstructedEEType(NodeFactory factory, TypeDesc type)
{
if (!CreationAllowed(type))
throw new TypeSystemException.TypeLoadException(ExceptionStringID.ClassLoadGeneral, type);
}
}
}

View File

@@ -0,0 +1,42 @@
// 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 ILCompiler.DependencyAnalysisFramework;
using Internal.TypeSystem;
namespace ILCompiler.DependencyAnalysis
{
public sealed class CppCodegenNodeFactory : NodeFactory
{
public CppCodegenNodeFactory(CompilerTypeSystemContext context, CompilationModuleGroup compilationModuleGroup)
: base(context, compilationModuleGroup)
{
}
protected override IMethodNode CreateMethodEntrypointNode(MethodDesc method)
{
if (CompilationModuleGroup.ContainsMethod(method))
{
return new CppMethodCodeNode(method);
}
else
{
return new ExternMethodSymbolNode(method);
}
}
protected override IMethodNode CreateUnboxingStubNode(MethodDesc method)
{
// TODO: this is wrong: this returns an assembly stub node
return new UnboxingStubNode(method);
}
protected override ISymbolNode CreateReadyToRunHelperNode(Tuple<ReadyToRunHelperId, object> helperCall)
{
// TODO: this is wrong: this returns an assembly stub node
return new ReadyToRunHelperNode(this, helperCall.Item1, helperCall.Item2);
}
}
}

Some files were not shown because too many files have changed in this diff Show More