Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial hot cold splitting support for crossgen2/VM #1900

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
1 change: 1 addition & 0 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum class ReadyToRunSectionType : uint32_t
OwnerCompositeExecutable = 116, // Added in V4.1
PgoInstrumentationData = 117, // Added in V5.2
ManifestAssemblyMvids = 118, // Added in V5.3
Scratch = 119, // This is meant to be a scratch area just for prototyping

// If you add a new section consider whether it is a breaking or non-breaking change.
// Usually it is non-breaking, but if it is preferable to have older runtimes fail
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public enum ReadyToRunSectionType
OwnerCompositeExecutable = 116, // Added in 4.1
PgoInstrumentationData = 117, // Added in 5.2
ManifestAssemblyMvids = 118, // Added in 5.3
Scratch = 119, // This is meant to be a scratch area for prototyping only

//
// NativeAOT ReadyToRun sections
Expand Down
54 changes: 47 additions & 7 deletions src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,19 @@ private void PublishCode()
, isFoldable: (_compilation._compilationOptions & RyuJitCompilationOptions.MethodBodyFolding) != 0
#endif
);
#if READYTORUN
if (_methodColdCodeNode != null)
{
var relocs2 = _coldCodeRelocs.ToArray();
Array.Sort(relocs2, (x, y) => (x.Offset - y.Offset));
var coldObjectData = new ObjectNode.ObjectData(_coldCode,
relocs2,
alignment,
new ISymbolDefinitionNode[] { _methodColdCodeNode });
_methodColdCodeNode.SetCode(coldObjectData);
_methodCodeNode.SetColdCodeNode(_methodColdCodeNode);
}
#endif

_methodCodeNode.InitializeFrameInfos(_frameInfos);
_methodCodeNode.InitializeDebugEHClauseInfos(debugEHClauseInfos);
Expand Down Expand Up @@ -563,7 +576,9 @@ private void CompileMethodCleanup()
}

_methodCodeNode = null;

#if READYTORUN
_methodColdCodeNode = null;
#endif
_code = null;
_coldCode = null;

Expand All @@ -572,7 +587,9 @@ private void CompileMethodCleanup()

_codeRelocs = new ArrayBuilder<Relocation>();
_roDataRelocs = new ArrayBuilder<Relocation>();

#if READYTORUN
_coldCodeRelocs = new ArrayBuilder<Relocation>();
#endif
_numFrameInfos = 0;
_usedFrameInfos = 0;
_frameInfos = null;
Expand Down Expand Up @@ -3396,6 +3413,10 @@ private void allocMem(ref AllocMemArgs args)

if (args.coldCodeSize != 0)
{

#if READYTORUN
this._methodColdCodeNode = new MethodColdCodeNode(MethodBeingCompiled);
#endif
args.coldCodeBlock = (void*)GetPin(_coldCode = new byte[args.coldCodeSize]);
args.coldCodeBlockRW = args.coldCodeBlock;
}
Expand Down Expand Up @@ -3443,7 +3464,10 @@ private void allocMem(ref AllocMemArgs args)

private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize)
{
_numFrameInfos++;
if (!isColdCode)
{
_numFrameInfos++;
}
}

private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind)
Expand Down Expand Up @@ -3474,8 +3498,12 @@ private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset,
blobData = CompressARM64CFI(blobData);
}
#endif

_frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData);
#if READYTORUN
if (blobData.Length > 0)
#endif
{
_frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData);
}
}

private void* allocGCInfo(UIntPtr size)
Expand Down Expand Up @@ -3510,7 +3538,9 @@ private void recordCallSite(uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO

private ArrayBuilder<Relocation> _codeRelocs;
private ArrayBuilder<Relocation> _roDataRelocs;

#if READYTORUN
private ArrayBuilder<Relocation> _coldCodeRelocs;
#endif

/// <summary>
/// Various type of block.
Expand Down Expand Up @@ -3588,6 +3618,11 @@ private ref ArrayBuilder<Relocation> findRelocBlock(BlockType blockType, out int
case BlockType.ROData:
length = _roData.Length;
return ref _roDataRelocs;
#if READYTORUN
case BlockType.ColdCode:
length = _coldCode.Length;
return ref _coldCodeRelocs;
#endif
default:
throw new NotImplementedException("Arbitrary relocs");
}
Expand Down Expand Up @@ -3640,8 +3675,13 @@ private void recordRelocation(void* location, void* locationRW, void* target, us
break;

case BlockType.ColdCode:
// TODO: Arbitrary relocs
#if READYTORUN
Debug.Assert(_methodColdCodeNode != null);
relocTarget = _methodColdCodeNode;
break;
#else
throw new NotImplementedException("ColdCode relocs");
#endif

case BlockType.ROData:
relocTarget = _roDataBlob;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using Internal.Text;
using Internal.TypeSystem;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
public class MethodColdCodeNode : ObjectNode, ISymbolDefinitionNode
{
private ObjectData _methodColdCode;
private MethodDesc _owningMethod;

public MethodColdCodeNode(MethodDesc owningMethod)
{
_owningMethod = owningMethod;
}

public int Offset => 0;

public override ObjectNodeSection Section
{
get
{
// TODO, Unix
return ObjectNodeSection.ManagedCodeWindowsContentSection;
}
}

public override bool IsShareable => false;

// This ClassCode must be larger than that of MethodCodeNode to ensure it got sorted at the end of the code
cshung marked this conversation as resolved.
Show resolved Hide resolved
public override int ClassCode => 788492408;

public override bool StaticDependenciesAreComputed => _methodColdCode != null;

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append("__coldcode_" + nameMangler.GetMangledMethodName(_owningMethod));
}

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
MethodColdCodeNode otherNode = (MethodColdCodeNode)other;
return comparer.Compare(_owningMethod, otherNode._owningMethod);
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) => _methodColdCode;

protected override string GetName(NodeFactory context) => throw new NotImplementedException();

public void SetCode(ObjectData data)
{
Debug.Assert(_methodColdCode == null);
_methodColdCode = data;
}

public int GetColdCodeSize()
{
return _methodColdCode.Data.Length;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@ protected override void OnMarked(NodeFactory factory)

public int[] CalculateFuncletOffsets(NodeFactory factory)
{
int[] offsets = new int[_methodNode.FrameInfos.Length];
int coldCodeUnwindInfoCount = 0;
if (_methodNode.GetColdCodeNode() != null)
{
coldCodeUnwindInfoCount = 1;
}
int[] offsets = new int[_methodNode.FrameInfos.Length + coldCodeUnwindInfoCount];
if (!factory.RuntimeFunctionsGCInfo.Deduplicator.TryGetValue(this, out var deduplicatedResult))
{
throw new Exception("Did not properly initialize deduplicator");
Expand All @@ -60,6 +65,10 @@ public int[] CalculateFuncletOffsets(NodeFactory factory)
offset += (-offset & 3); // 4-alignment after GC info in 1st funclet
}
}
if (coldCodeUnwindInfoCount == 1)
{
offsets[_methodNode.FrameInfos.Length] = offset;
}
return offsets;
}

Expand Down Expand Up @@ -164,6 +173,22 @@ private IEnumerable<GCInfoComponent> EncodeDataCore(NodeFactory factory)
yield return new GCInfoComponent(_methodNode.GCInfo);
}
}
#if READYTORUN
if (_methodNode.GetColdCodeNode() != null)
{
byte[] header = new byte[4];
int i = 0;
header[i++] = 1 + (4 << 3); // Version = 1, UNW_FLAG_CHAININFO
header[i++] = 0; // SizeOfProlog = 0
header[i++] = 0; // CountOfCode = 0
header[i++] = 0; // Frame = 0
yield return new GCInfoComponent(header);
yield return new GCInfoComponent(_methodNode, 0);
yield return new GCInfoComponent(_methodNode, _methodNode.Size);
// TODO: Is this correct?
yield return new GCInfoComponent(factory.RuntimeFunctionsGCInfo.StartSymbol, this.OffsetFromBeginningOfArray);
}
#endif
}

class MethodGCInfoNodeDeduplicatingComparer : IEqualityComparer<MethodGCInfoNode>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;

using System.Linq;
using Internal.JitInterface;
using Internal.Text;
using Internal.TypeSystem;
Expand All @@ -19,6 +19,9 @@ public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, ISymbolDefinitionNo
private readonly MethodDesc _method;

private ObjectData _methodCode;
#if READYTORUN
private MethodColdCodeNode _methodColdCodeNode;
#endif
private FrameInfo[] _frameInfos;
private byte[] _gcInfo;
private ObjectData _ehInfo;
Expand Down Expand Up @@ -129,11 +132,27 @@ public int Compare(FixupCell a, FixupCell b)
}
}

public MethodColdCodeNode GetColdCodeNode() => _methodColdCodeNode;

public byte[] GetFixupBlob(NodeFactory factory)
{
Relocation[] relocations = GetData(factory, relocsOnly: true).Relocs;

#if READYTORUN
if (_methodColdCodeNode != null)
{
Relocation[] coldRelocations = _methodColdCodeNode.GetData(factory, relocsOnly: true).Relocs;
if (relocations == null)
{
relocations = coldRelocations;
}
else if (coldRelocations != null)
{
relocations = Enumerable.Concat(relocations, coldRelocations).ToArray();
}
}
#endif

if (relocations == null)
{
return null;
Expand Down Expand Up @@ -358,5 +377,12 @@ public void InitializeInliningInfo(MethodDesc[] inlinedMethods, NodeFactory fact
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => IsEmpty;

public override string ToString() => _method.ToString();

#if READYTORUN
public void SetColdCodeNode(MethodColdCodeNode methodColdCodeNode)
{
_methodColdCodeNode = methodColdCodeNode;
}
#endif
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ private void LayoutRuntimeFunctions()
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
// This node does not trigger generation of other nodes.
// TODO: Make this generate the generation of the Scratch node
if (relocsOnly)
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });

Expand All @@ -72,6 +73,7 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
// Add the symbol representing this object node
runtimeFunctionsBuilder.AddSymbol(this);

uint runtimeFunctionIndex = 0;
foreach (MethodWithGCInfo method in _methodNodes)
{
int[] funcletOffsets = method.GCInfoNode.CalculateFuncletOffsets(factory);
Expand All @@ -94,9 +96,42 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
runtimeFunctionsBuilder.EmitReloc(method, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.EndOffset);
}
runtimeFunctionsBuilder.EmitReloc(factory.RuntimeFunctionsGCInfo.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB, funcletOffsets[frameIndex]);
runtimeFunctionIndex++;
}
}

List<uint> mapping = new List<uint>();
#if READYTORUN
// Emitting a RuntimeFunction entry for cold code
foreach (MethodWithGCInfo method in _methodNodes)
{
MethodColdCodeNode methodColdCodeNode = method.GetColdCodeNode();
if (methodColdCodeNode != null)
{
int[] funcletOffsets = method.GCInfoNode.CalculateFuncletOffsets(factory);
// TODO: Avoid code duplication
// StartOffset of the runtime function
int codeDelta = 0;
if (Target.Architecture == TargetArchitecture.ARM)
{
// THUMB_CODE
codeDelta = 1;
}
runtimeFunctionsBuilder.EmitReloc(methodColdCodeNode, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: codeDelta);
if (!relocsOnly && Target.Architecture == TargetArchitecture.X64)
{
// On Amd64, the 2nd word contains the EndOffset of the runtime function
runtimeFunctionsBuilder.EmitReloc(methodColdCodeNode, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: methodColdCodeNode.GetColdCodeSize());
}
runtimeFunctionsBuilder.EmitReloc(factory.RuntimeFunctionsGCInfo.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB, funcletOffsets[funcletOffsets.Length - 1]);
mapping.Add(runtimeFunctionIndex);
mapping.Add((uint)_insertedMethodNodes[method]);
runtimeFunctionIndex++;
}
}
#endif
_nodeFactory.Scratch.mapping = mapping.ToArray();

// Emit sentinel entry
runtimeFunctionsBuilder.EmitUInt(~0u);

Expand Down
Loading