Skip to content

Commit 658f03b

Browse files
authored
Initial hot cold splitting support for crossgen2/VM
2 parents 8b3be89 + 3ce1cd5 commit 658f03b

File tree

21 files changed

+386
-20
lines changed

21 files changed

+386
-20
lines changed

src/coreclr/inc/readytorun.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ enum class ReadyToRunSectionType : uint32_t
8383
OwnerCompositeExecutable = 116, // Added in V4.1
8484
PgoInstrumentationData = 117, // Added in V5.2
8585
ManifestAssemblyMvids = 118, // Added in V5.3
86+
Scratch = 119, // This is meant to be a scratch area just for prototyping
8687

8788
// If you add a new section consider whether it is a breaking or non-breaking change.
8889
// Usually it is non-breaking, but if it is preferable to have older runtimes fail

src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public enum ReadyToRunSectionType
6767
OwnerCompositeExecutable = 116, // Added in 4.1
6868
PgoInstrumentationData = 117, // Added in 5.2
6969
ManifestAssemblyMvids = 118, // Added in 5.3
70+
Scratch = 119, // This is meant to be a scratch area for prototyping only
7071

7172
//
7273
// NativeAOT ReadyToRun sections

src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,19 @@ private void PublishCode()
422422
, isFoldable: (_compilation._compilationOptions & RyuJitCompilationOptions.MethodBodyFolding) != 0
423423
#endif
424424
);
425+
#if READYTORUN
426+
if (_methodColdCodeNode != null)
427+
{
428+
var relocs2 = _coldCodeRelocs.ToArray();
429+
Array.Sort(relocs2, (x, y) => (x.Offset - y.Offset));
430+
var coldObjectData = new ObjectNode.ObjectData(_coldCode,
431+
relocs2,
432+
alignment,
433+
new ISymbolDefinitionNode[] { _methodColdCodeNode });
434+
_methodColdCodeNode.SetCode(coldObjectData);
435+
_methodCodeNode.SetColdCodeNode(_methodColdCodeNode);
436+
}
437+
#endif
425438

426439
_methodCodeNode.InitializeFrameInfos(_frameInfos);
427440
_methodCodeNode.InitializeDebugEHClauseInfos(debugEHClauseInfos);
@@ -563,7 +576,9 @@ private void CompileMethodCleanup()
563576
}
564577

565578
_methodCodeNode = null;
566-
579+
#if READYTORUN
580+
_methodColdCodeNode = null;
581+
#endif
567582
_code = null;
568583
_coldCode = null;
569584

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

573588
_codeRelocs = new ArrayBuilder<Relocation>();
574589
_roDataRelocs = new ArrayBuilder<Relocation>();
575-
590+
#if READYTORUN
591+
_coldCodeRelocs = new ArrayBuilder<Relocation>();
592+
#endif
576593
_numFrameInfos = 0;
577594
_usedFrameInfos = 0;
578595
_frameInfos = null;
@@ -3396,6 +3413,10 @@ private void allocMem(ref AllocMemArgs args)
33963413

33973414
if (args.coldCodeSize != 0)
33983415
{
3416+
3417+
#if READYTORUN
3418+
this._methodColdCodeNode = new MethodColdCodeNode(MethodBeingCompiled);
3419+
#endif
33993420
args.coldCodeBlock = (void*)GetPin(_coldCode = new byte[args.coldCodeSize]);
34003421
args.coldCodeBlockRW = args.coldCodeBlock;
34013422
}
@@ -3443,7 +3464,10 @@ private void allocMem(ref AllocMemArgs args)
34433464

34443465
private void reserveUnwindInfo(bool isFunclet, bool isColdCode, uint unwindSize)
34453466
{
3446-
_numFrameInfos++;
3467+
if (!isColdCode)
3468+
{
3469+
_numFrameInfos++;
3470+
}
34473471
}
34483472

34493473
private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset, uint endOffset, uint unwindSize, byte* pUnwindBlock, CorJitFuncKind funcKind)
@@ -3474,8 +3498,12 @@ private void allocUnwindInfo(byte* pHotCode, byte* pColdCode, uint startOffset,
34743498
blobData = CompressARM64CFI(blobData);
34753499
}
34763500
#endif
3477-
3478-
_frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData);
3501+
#if READYTORUN
3502+
if (blobData.Length > 0)
3503+
#endif
3504+
{
3505+
_frameInfos[_usedFrameInfos++] = new FrameInfo(flags, (int)startOffset, (int)endOffset, blobData);
3506+
}
34793507
}
34803508

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

35113539
private ArrayBuilder<Relocation> _codeRelocs;
35123540
private ArrayBuilder<Relocation> _roDataRelocs;
3513-
3541+
#if READYTORUN
3542+
private ArrayBuilder<Relocation> _coldCodeRelocs;
3543+
#endif
35143544

35153545
/// <summary>
35163546
/// Various type of block.
@@ -3588,6 +3618,11 @@ private ref ArrayBuilder<Relocation> findRelocBlock(BlockType blockType, out int
35883618
case BlockType.ROData:
35893619
length = _roData.Length;
35903620
return ref _roDataRelocs;
3621+
#if READYTORUN
3622+
case BlockType.ColdCode:
3623+
length = _coldCode.Length;
3624+
return ref _coldCodeRelocs;
3625+
#endif
35913626
default:
35923627
throw new NotImplementedException("Arbitrary relocs");
35933628
}
@@ -3640,8 +3675,13 @@ private void recordRelocation(void* location, void* locationRW, void* target, us
36403675
break;
36413676

36423677
case BlockType.ColdCode:
3643-
// TODO: Arbitrary relocs
3678+
#if READYTORUN
3679+
Debug.Assert(_methodColdCodeNode != null);
3680+
relocTarget = _methodColdCodeNode;
3681+
break;
3682+
#else
36443683
throw new NotImplementedException("ColdCode relocs");
3684+
#endif
36453685

36463686
case BlockType.ROData:
36473687
relocTarget = _roDataBlob;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Diagnostics;
6+
using Internal.Text;
7+
using Internal.TypeSystem;
8+
9+
namespace ILCompiler.DependencyAnalysis.ReadyToRun
10+
{
11+
public class MethodColdCodeNode : ObjectNode, ISymbolDefinitionNode
12+
{
13+
private ObjectData _methodColdCode;
14+
private MethodDesc _owningMethod;
15+
16+
public MethodColdCodeNode(MethodDesc owningMethod)
17+
{
18+
_owningMethod = owningMethod;
19+
}
20+
21+
public int Offset => 0;
22+
23+
public override ObjectNodeSection Section
24+
{
25+
get
26+
{
27+
// TODO, Unix
28+
return ObjectNodeSection.ManagedCodeWindowsContentSection;
29+
}
30+
}
31+
32+
public override bool IsShareable => false;
33+
34+
// This ClassCode must be larger than that of MethodCodeNode to ensure it got sorted at the end of the code
35+
public override int ClassCode => 788492408;
36+
37+
public override bool StaticDependenciesAreComputed => _methodColdCode != null;
38+
39+
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
40+
{
41+
sb.Append("__coldcode_" + nameMangler.GetMangledMethodName(_owningMethod));
42+
}
43+
44+
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
45+
{
46+
MethodColdCodeNode otherNode = (MethodColdCodeNode)other;
47+
return comparer.Compare(_owningMethod, otherNode._owningMethod);
48+
}
49+
50+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) => _methodColdCode;
51+
52+
protected override string GetName(NodeFactory context) => throw new NotImplementedException();
53+
54+
public void SetCode(ObjectData data)
55+
{
56+
Debug.Assert(_methodColdCode == null);
57+
_methodColdCode = data;
58+
}
59+
60+
public int GetColdCodeSize()
61+
{
62+
return _methodColdCode.Data.Length;
63+
}
64+
}
65+
}

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodGCInfoNode.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@ protected override void OnMarked(NodeFactory factory)
3939

4040
public int[] CalculateFuncletOffsets(NodeFactory factory)
4141
{
42-
int[] offsets = new int[_methodNode.FrameInfos.Length];
42+
int coldCodeUnwindInfoCount = 0;
43+
if (_methodNode.GetColdCodeNode() != null)
44+
{
45+
coldCodeUnwindInfoCount = 1;
46+
}
47+
int[] offsets = new int[_methodNode.FrameInfos.Length + coldCodeUnwindInfoCount];
4348
if (!factory.RuntimeFunctionsGCInfo.Deduplicator.TryGetValue(this, out var deduplicatedResult))
4449
{
4550
throw new Exception("Did not properly initialize deduplicator");
@@ -60,6 +65,10 @@ public int[] CalculateFuncletOffsets(NodeFactory factory)
6065
offset += (-offset & 3); // 4-alignment after GC info in 1st funclet
6166
}
6267
}
68+
if (coldCodeUnwindInfoCount == 1)
69+
{
70+
offsets[_methodNode.FrameInfos.Length] = offset;
71+
}
6372
return offsets;
6473
}
6574

@@ -164,6 +173,22 @@ private IEnumerable<GCInfoComponent> EncodeDataCore(NodeFactory factory)
164173
yield return new GCInfoComponent(_methodNode.GCInfo);
165174
}
166175
}
176+
#if READYTORUN
177+
if (_methodNode.GetColdCodeNode() != null)
178+
{
179+
byte[] header = new byte[4];
180+
int i = 0;
181+
header[i++] = 1 + (4 << 3); // Version = 1, UNW_FLAG_CHAININFO
182+
header[i++] = 0; // SizeOfProlog = 0
183+
header[i++] = 0; // CountOfCode = 0
184+
header[i++] = 0; // Frame = 0
185+
yield return new GCInfoComponent(header);
186+
yield return new GCInfoComponent(_methodNode, 0);
187+
yield return new GCInfoComponent(_methodNode, _methodNode.Size);
188+
// TODO: Is this correct?
189+
yield return new GCInfoComponent(factory.RuntimeFunctionsGCInfo.StartSymbol, this.OffsetFromBeginningOfArray);
190+
}
191+
#endif
167192
}
168193

169194
class MethodGCInfoNodeDeduplicatingComparer : IEqualityComparer<MethodGCInfoNode>

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/MethodWithGCInfo.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics;
7-
7+
using System.Linq;
88
using Internal.JitInterface;
99
using Internal.Text;
1010
using Internal.TypeSystem;
@@ -19,6 +19,9 @@ public class MethodWithGCInfo : ObjectNode, IMethodBodyNode, ISymbolDefinitionNo
1919
private readonly MethodDesc _method;
2020

2121
private ObjectData _methodCode;
22+
#if READYTORUN
23+
private MethodColdCodeNode _methodColdCodeNode;
24+
#endif
2225
private FrameInfo[] _frameInfos;
2326
private byte[] _gcInfo;
2427
private ObjectData _ehInfo;
@@ -129,11 +132,27 @@ public int Compare(FixupCell a, FixupCell b)
129132
}
130133
}
131134

135+
public MethodColdCodeNode GetColdCodeNode() => _methodColdCodeNode;
132136

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

141+
#if READYTORUN
142+
if (_methodColdCodeNode != null)
143+
{
144+
Relocation[] coldRelocations = _methodColdCodeNode.GetData(factory, relocsOnly: true).Relocs;
145+
if (relocations == null)
146+
{
147+
relocations = coldRelocations;
148+
}
149+
else if (coldRelocations != null)
150+
{
151+
relocations = Enumerable.Concat(relocations, coldRelocations).ToArray();
152+
}
153+
}
154+
#endif
155+
137156
if (relocations == null)
138157
{
139158
return null;
@@ -358,5 +377,12 @@ public void InitializeInliningInfo(MethodDesc[] inlinedMethods, NodeFactory fact
358377
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory) => IsEmpty;
359378

360379
public override string ToString() => _method.ToString();
380+
381+
#if READYTORUN
382+
public void SetColdCodeNode(MethodColdCodeNode methodColdCodeNode)
383+
{
384+
_methodColdCodeNode = methodColdCodeNode;
385+
}
386+
#endif
361387
}
362388
}

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/RuntimeFunctionsTableNode.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ private void LayoutRuntimeFunctions()
6060
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
6161
{
6262
// This node does not trigger generation of other nodes.
63+
// TODO: Make this generate the generation of the Scratch node
6364
if (relocsOnly)
6465
return new ObjectData(Array.Empty<byte>(), Array.Empty<Relocation>(), 1, new ISymbolDefinitionNode[] { this });
6566

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

76+
uint runtimeFunctionIndex = 0;
7577
foreach (MethodWithGCInfo method in _methodNodes)
7678
{
7779
int[] funcletOffsets = method.GCInfoNode.CalculateFuncletOffsets(factory);
@@ -94,9 +96,42 @@ public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
9496
runtimeFunctionsBuilder.EmitReloc(method, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: frameInfo.EndOffset);
9597
}
9698
runtimeFunctionsBuilder.EmitReloc(factory.RuntimeFunctionsGCInfo.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB, funcletOffsets[frameIndex]);
99+
runtimeFunctionIndex++;
97100
}
98101
}
99102

103+
List<uint> mapping = new List<uint>();
104+
#if READYTORUN
105+
// Emitting a RuntimeFunction entry for cold code
106+
foreach (MethodWithGCInfo method in _methodNodes)
107+
{
108+
MethodColdCodeNode methodColdCodeNode = method.GetColdCodeNode();
109+
if (methodColdCodeNode != null)
110+
{
111+
int[] funcletOffsets = method.GCInfoNode.CalculateFuncletOffsets(factory);
112+
// TODO: Avoid code duplication
113+
// StartOffset of the runtime function
114+
int codeDelta = 0;
115+
if (Target.Architecture == TargetArchitecture.ARM)
116+
{
117+
// THUMB_CODE
118+
codeDelta = 1;
119+
}
120+
runtimeFunctionsBuilder.EmitReloc(methodColdCodeNode, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: codeDelta);
121+
if (!relocsOnly && Target.Architecture == TargetArchitecture.X64)
122+
{
123+
// On Amd64, the 2nd word contains the EndOffset of the runtime function
124+
runtimeFunctionsBuilder.EmitReloc(methodColdCodeNode, RelocType.IMAGE_REL_BASED_ADDR32NB, delta: methodColdCodeNode.GetColdCodeSize());
125+
}
126+
runtimeFunctionsBuilder.EmitReloc(factory.RuntimeFunctionsGCInfo.StartSymbol, RelocType.IMAGE_REL_BASED_ADDR32NB, funcletOffsets[funcletOffsets.Length - 1]);
127+
mapping.Add(runtimeFunctionIndex);
128+
mapping.Add((uint)_insertedMethodNodes[method]);
129+
runtimeFunctionIndex++;
130+
}
131+
}
132+
#endif
133+
_nodeFactory.Scratch.mapping = mapping.ToArray();
134+
100135
// Emit sentinel entry
101136
runtimeFunctionsBuilder.EmitUInt(~0u);
102137

0 commit comments

Comments
 (0)