You've already forked linux-packaging-mono
Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
parent
1190d13a04
commit
6bdd276d05
217
external/corert/src/ILCompiler.Compiler/src/Compiler/Compilation.cs
vendored
Normal file
217
external/corert/src/ILCompiler.Compiler/src/Compiler/Compilation.cs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
90
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs
vendored
Normal file
90
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilationBuilder.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
88
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs
vendored
Normal file
88
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilationModuleGroup.cs
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
189
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedType.cs
vendored
Normal file
189
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerGeneratedType.cs
vendored
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerMetadataFieldLayoutAlgorithm.cs
vendored
Normal file
35
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerMetadataFieldLayoutAlgorithm.cs
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.TypeInit.cs
vendored
Normal file
48
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.TypeInit.cs
vendored
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
405
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs
vendored
Normal file
405
external/corert/src/ILCompiler.Compiler/src/Compiler/CompilerTypeSystemContext.cs
vendored
Normal 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,
|
||||
}
|
||||
}
|
||||
92
external/corert/src/ILCompiler.Compiler/src/Compiler/CppCodegenCompilation.cs
vendored
Normal file
92
external/corert/src/ILCompiler.Compiler/src/Compiler/CppCodegenCompilation.cs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
external/corert/src/ILCompiler.Compiler/src/Compiler/CppCodegenCompilationBuilder.cs
vendored
Normal file
51
external/corert/src/ILCompiler.Compiler/src/Compiler/CppCodegenCompilationBuilder.cs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
144
external/corert/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs
vendored
Normal file
144
external/corert/src/ILCompiler.Compiler/src/Compiler/DelegateCreationInfo.cs
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs
vendored
Normal file
82
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayMapNode.cs
vendored
Normal 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
109
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs
vendored
Normal file
109
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ArrayOfEmbeddedDataNode.cs
vendored
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
61
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs
vendored
Normal file
61
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/AssemblyStubNode.cs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
43
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlobNode.cs
vendored
Normal file
43
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/BlobNode.cs
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
269
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs
vendored
Normal file
269
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs
vendored
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs
vendored
Normal file
42
external/corert/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CppCodegenNodeFactory.cs
vendored
Normal 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
Reference in New Issue
Block a user