Skip to content
This repository has been archived by the owner on Nov 1, 2020. It is now read-only.

Add support for eager static constructors #889

Merged
merged 1 commit into from
Feb 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/ILCompiler.Compiler/src/Compiler/Compilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public partial class Compilation
{
private readonly CompilerTypeSystemContext _typeSystemContext;
private readonly CompilationOptions _options;
private readonly TypeInitialization _typeInitManager;

private NodeFactory _nodeFactory;
private DependencyAnalyzerBase<NodeFactory> _dependencyGraph;
Expand All @@ -61,6 +62,8 @@ public Compilation(CompilationOptions options)
_typeSystemContext.SetSystemModule(_typeSystemContext.GetModuleForSimpleName(options.SystemModuleName));

_nameMangler = new NameMangler(this);

_typeInitManager = new TypeInitialization();
}

public CompilerTypeSystemContext TypeSystemContext
Expand Down Expand Up @@ -132,7 +135,7 @@ public void CompileSingleFile()
{
NodeFactory.NameMangler = NameMangler;

_nodeFactory = new NodeFactory(_typeSystemContext, _options.IsCppCodeGen);
_nodeFactory = new NodeFactory(_typeSystemContext, _typeInitManager, _options.IsCppCodeGen);

// Choose which dependency graph implementation to use based on the amount of logging requested.
if (_options.DgmlLog == null)
Expand Down Expand Up @@ -329,5 +332,10 @@ public object GetFieldRvaData(FieldDesc field)
return _nodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
((EcmaField)field).GetFieldRvaData(), _typeSystemContext.Target.PointerSize);
}

public bool HasLazyStaticConstructor(TypeDesc type)
{
return _typeInitManager.HasLazyStaticConstructor(type);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,28 @@

namespace ILCompiler.DependencyAnalysis
{
public class ArrayOfEmbeddedDataNode : ObjectNode
/// <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<EmbeddedObjectNode> _nestedNodes = new HashSet<EmbeddedObjectNode>();
private List<EmbeddedObjectNode> _nestedNodesList = new List<EmbeddedObjectNode>();
private HashSet<TEmbedded> _nestedNodes = new HashSet<TEmbedded>();
private List<TEmbedded> _nestedNodesList = new List<TEmbedded>();
private ObjectAndOffsetSymbolNode _startSymbol;
private ObjectAndOffsetSymbolNode _endSymbol;
private IComparer<EmbeddedObjectNode> _sorter;
private IComparer<TEmbedded> _sorter;

public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<EmbeddedObjectNode> nodeSorter)
public ArrayOfEmbeddedDataNode(string startSymbolMangledName, string endSymbolMangledName, IComparer<TEmbedded> nodeSorter)
{
_startSymbol = new ObjectAndOffsetSymbolNode(this, 0, startSymbolMangledName);
_endSymbol = new ObjectAndOffsetSymbolNode(this, 0, endSymbolMangledName);
_sorter = nodeSorter;
}

public void AddEmbeddedObject(EmbeddedObjectNode symbol)
public void AddEmbeddedObject(TEmbedded symbol)
{
if (_nestedNodes.Add(symbol))
{
Expand Down Expand Up @@ -64,7 +70,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
_nestedNodesList.Sort(_sorter);

builder.DefinedSymbols.Add(_startSymbol);
foreach (EmbeddedObjectNode node in _nestedNodesList)
foreach (TEmbedded node in _nestedNodesList)
{
if (!relocsOnly)
node.Offset = builder.CountBytes;
Expand All @@ -82,4 +88,14 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
return objData;
}
}

// 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)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// 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;

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;

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)
{
int id = System.Threading.Interlocked.Increment(ref _nextId);
return new EmbeddedPointerIndirectionWithSymbolNode(this, target, id);
}

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;
}

public override string GetName()
{
return "Embedded pointer to " + Target.MangledName;
}

protected override void OnMarked(NodeFactory context)
{
// 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 context)
{
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 string MangledName
{
get
{
return String.Concat(_parentNode._startSymbolMangledName, "_", _id.ToStringInvariant());
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace ILCompiler.DependencyAnalysis
{
internal class CppMethodCodeNode : DependencyNodeCore<NodeFactory>, ISymbolNode
internal class CppMethodCodeNode : DependencyNodeCore<NodeFactory>, IMethodNode
{
private MethodDesc _method;
private string _methodCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,13 +450,13 @@ private void OutputNullableTypeParameter(NodeFactory factory, ref ObjectDataBuil
/// </summary>
private void ComputeOptionalEETypeFields(NodeFactory factory)
{
ComputeRareFlags();
ComputeRareFlags(factory);
ComputeNullableValueOffset();
ComputeICastableVirtualMethodSlots(factory);
ComputeValueTypeFieldPadding();
}

void ComputeRareFlags()
void ComputeRareFlags(NodeFactory factory)
{
uint flags = 0;

Expand All @@ -465,7 +465,7 @@ void ComputeRareFlags()
flags |= (uint)EETypeRareFlags.IsNullableFlag;
}

if (_type.HasStaticConstructor)
if (factory.TypeInitializationManager.HasLazyStaticConstructor(_type))
{
flags |= (uint)EETypeRareFlags.HasCctorFlag;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// An <see cref="EmbeddedObjectNode"/> whose sole value is a pointer to a different <see cref="ISymbolNode"/>.
/// <typeparamref name="TTarget"/> represents the node type this pointer points to.
/// </summary>
public abstract class EmbeddedPointerIndirectionNode<TTarget> : EmbeddedObjectNode
where TTarget : ISymbolNode
{
private TTarget _targetNode;

/// <summary>
/// Target symbol this node points to.
/// </summary>
public TTarget Target
{
get
{
return _targetNode;
}
}

internal EmbeddedPointerIndirectionNode(TTarget target)
{
_targetNode = target;
}

public override bool StaticDependenciesAreComputed
{
get
{
return true;
}
}

public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
dataBuilder.RequirePointerAlignment();
dataBuilder.EmitPointerReloc(Target);
}

// At minimum, Target needs to be reported as a static dependency by inheritors.
public abstract override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,18 @@ public ISymbolNode GetGCStaticEETypeNode(NodeFactory context)

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
{
return new DependencyListEntry[] { new DependencyListEntry(context.GCStaticsRegion, "GCStatics Region"),
new DependencyListEntry(GetGCStaticEETypeNode(context), "GCStatic EEType")};
DependencyListEntry[] result;
if (context.TypeInitializationManager.HasEagerStaticConstructor(_type))
{
result = new DependencyListEntry[3];
result[2] = new DependencyListEntry(context.EagerCctorIndirection(_type.GetStaticConstructor()), "Eager .cctor");
}
else
result = new DependencyListEntry[2];

result[0] = new DependencyListEntry(context.GCStaticsRegion, "GCStatics Region");
result[1] = new DependencyListEntry(GetGCStaticEETypeNode(context), "GCStatic EEType");
return result;
}

int ISymbolNode.Offset
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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.TypeSystem;

namespace ILCompiler.DependencyAnalysis
{
/// <summary>
/// A dependency analysis node that represents a method.
/// </summary>
public interface IMethodNode : ISymbolNode
{
MethodDesc Method { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace ILCompiler.DependencyAnalysis
{
internal class MethodCodeNode : ObjectNode, INodeWithFrameInfo, INodeWithDebugInfo, ISymbolNode
internal class MethodCodeNode : ObjectNode, IMethodNode, INodeWithFrameInfo, INodeWithDebugInfo
{
private MethodDesc _method;
private ObjectData _methodCode;
Expand Down Expand Up @@ -72,6 +72,19 @@ int ISymbolNode.Offset
}
}

protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory context)
{
TypeDesc owningType = _method.OwningType;
if (context.TypeInitializationManager.HasEagerStaticConstructor(owningType))
{
var result = new DependencyList();
result.Add(context.EagerCctorIndirection(owningType.GetStaticConstructor()), "Eager .cctor");
return result;
}

return null;
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly)
{
return _methodCode;
Expand Down
Loading