Skip to content

Commit 1651e0f

Browse files
committed
Early work to make it possible to call the interpreter from ReadyToRun code
1 parent dc643f2 commit 1651e0f

19 files changed

+370
-5
lines changed

src/coreclr/inc/readytorun.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ enum class ReadyToRunSectionType : uint32_t
102102
MethodIsGenericMap = 121, // Added in V9.0
103103
EnclosingTypeMap = 122, // Added in V9.0
104104
TypeGenericInfoMap = 123, // Added in V9.0
105+
InterpreterMap = 124, // Prototype
105106

106107
// If you add a new section consider whether it is a breaking or non-breaking change.
107108
// Usually it is non-breaking, but if it is preferable to have older runtimes fail
@@ -447,6 +448,8 @@ enum ReadyToRunHelper
447448
READYTORUN_HELPER_StackProbe = 0x111,
448449

449450
READYTORUN_HELPER_GetCurrentManagedThreadId = 0x112,
451+
452+
READYTORUN_HELPER_InterpreterRoutine = 0x113,
450453
};
451454

452455
#include "readytoruninstructionset.h"

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ enum ReadyToRunSectionType
7979
MethodIsGenericMap = 121, // Added in V9.0
8080
EnclosingTypeMap = 122, // Added in V9.0
8181
TypeGenericInfoMap = 123, // Added in V9.0
82+
InterpreterMap = 124, // Added for prototyping only
8283

8384
//
8485
// NativeAOT ReadyToRun sections

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,9 @@ public enum ReadyToRunHelper
348348

349349
GetCurrentManagedThreadId = 0x112,
350350

351+
//Interpreter
352+
InterpreterRoutine = 0x113,
353+
351354
// **********************************************************************************************
352355
//
353356
// These are not actually part of the R2R file format. We have them here because it's convenient.

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
4646
{
4747
yield return entry;
4848
}
49+
50+
// It is possible that an instance of DelayLoadMethodImport is constructed by never get into the graph
51+
// So we must delay the construction and rooting of the InterpreterImport
52+
53+
InterpreterImport _interpreterImport = new InterpreterImport();
54+
InterpreterStub _interpreterStub = new InterpreterStub(_interpreterImport);
55+
factory.AddInterpreterMapping(this, _interpreterImport, _interpreterStub);
56+
yield return new DependencyListEntry(_interpreterImport, "Unused reason 1");
57+
yield return new DependencyListEntry(_interpreterStub, "Unused reason 2");
58+
yield return new DependencyListEntry(factory.InterpreterMap, "Unused reason 3");
4959
if (_localMethod != null)
5060
yield return new DependencyListEntry(_localMethod, "Local method import");
5161
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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 Internal.JitInterface;
5+
using Internal.Text;
6+
using Internal.TypeSystem;
7+
using Internal.ReadyToRunConstants;
8+
using ILCompiler.DependencyAnalysisFramework;
9+
using System.Collections.Generic;
10+
11+
namespace ILCompiler.DependencyAnalysis.ReadyToRun
12+
{
13+
// An InterpreterImport simply a pointer sized variable that the
14+
// interpreter stub can use to reference the InterpreterMethodInfo
15+
public class InterpreterImport : ObjectNode, ISymbolDefinitionNode
16+
{
17+
public int _id;
18+
public static int id = 1;
19+
20+
public InterpreterImport()
21+
{
22+
// TODO, andrewau, we need a mechanism to identify the call sites
23+
// using a ID is not going to be deterministic
24+
_id = id++;
25+
}
26+
27+
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
28+
{
29+
return this._id - ((InterpreterImport)(other))._id;
30+
}
31+
32+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
33+
{
34+
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
35+
builder.AddSymbol(this);
36+
builder.EmitZeroPointer();
37+
return builder.ToObjectData();
38+
}
39+
40+
public int Offset { get; set; }
41+
42+
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
43+
=> sb.Append(nameMangler.CompilationUnitPrefix).Append("InterpreterImport").Append(_id.ToString());
44+
45+
public override ObjectNodeSection GetSection(NodeFactory factory)
46+
{
47+
return ObjectNodeSection.DataSection;
48+
}
49+
50+
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
51+
{
52+
yield break;
53+
}
54+
55+
protected override string GetName(NodeFactory context) => "InterpreterImport";
56+
57+
public override int ClassCode => 46709394;
58+
59+
public override bool IsShareable => false;
60+
61+
public override bool StaticDependenciesAreComputed => true;
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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+
6+
using Internal.Text;
7+
using System.Collections.Generic;
8+
using System.Diagnostics;
9+
10+
namespace ILCompiler.DependencyAnalysis.ReadyToRun
11+
{
12+
public class InterpreterMapNode : HeaderTableNode
13+
{
14+
public override int ClassCode => 25687179;
15+
16+
private List<DelayLoadMethodImport> leftItems = new List<DelayLoadMethodImport>();
17+
private List<InterpreterStub> lastItems = new List<InterpreterStub>();
18+
private List<InterpreterImport> rightItems = new List<InterpreterImport>();
19+
20+
public void AddMapping(DelayLoadMethodImport left, InterpreterImport right, InterpreterStub last)
21+
{
22+
// TODO, andrewau, this require proper locking and sorting for multithreaded compilation.
23+
// correctness and determinism
24+
leftItems.Add(left);
25+
rightItems.Add(right);
26+
lastItems.Add(last);
27+
}
28+
29+
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
30+
{
31+
sb.Append(nameMangler.CompilationUnitPrefix);
32+
sb.Append("__InterpreterMap"u8);
33+
}
34+
35+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
36+
{
37+
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
38+
builder.AddSymbol(this);
39+
for (int i = 0; i < leftItems.Count; i++)
40+
{
41+
// This will emit the RVAs for these
42+
builder.EmitReloc(leftItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
43+
builder.EmitReloc(rightItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
44+
builder.EmitReloc(lastItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
45+
}
46+
return builder.ToObjectData();
47+
}
48+
}
49+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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 Internal.JitInterface;
5+
using Internal.Text;
6+
using Internal.TypeSystem;
7+
using Internal.ReadyToRunConstants;
8+
using ILCompiler.DependencyAnalysisFramework;
9+
using System.Collections.Generic;
10+
11+
// TODO, andrewau, other architectures
12+
using ILCompiler.DependencyAnalysis.X64;
13+
14+
namespace ILCompiler.DependencyAnalysis.ReadyToRun
15+
{
16+
// An InterpreterStub is a small trampoline that
17+
// 1.) Push the InterpreterMethodInfo to the stack, and
18+
// 2.) Jump to the InterpreterMethod
19+
public class InterpreterStub : ObjectNode, ISymbolDefinitionNode
20+
{
21+
public InterpreterImport _interpreterImport;
22+
23+
public InterpreterStub(InterpreterImport interpreterImport)
24+
{
25+
_interpreterImport = interpreterImport;
26+
}
27+
28+
public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
29+
{
30+
return _interpreterImport._id - ((InterpreterStub)(other))._interpreterImport._id;
31+
}
32+
33+
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
34+
{
35+
X64Emitter x64Emitter = new X64Emitter(factory, relocsOnly);
36+
x64Emitter.Builder.AddSymbol(this);
37+
x64Emitter.EmitMOV(Register.RCX, _interpreterImport);
38+
// TODO, andrewau, shouldn't have to do this if we can make node represent redirection cell
39+
AddrMode addr = new AddrMode(Register.RCX, null, 0, 0, AddrModeSize.Int64);
40+
x64Emitter.EmitMOV(Register.RCX, ref addr);
41+
x64Emitter.EmitJMP(factory.InterpreterRoutineImport);
42+
return x64Emitter.Builder.ToObjectData();
43+
}
44+
45+
public int Offset { get; set; }
46+
47+
public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
48+
=> sb.Append(nameMangler.CompilationUnitPrefix).Append("InterpreterStub").Append(_interpreterImport._id.ToString());
49+
50+
public override ObjectNodeSection GetSection(NodeFactory factory)
51+
{
52+
return ObjectNodeSection.TextSection;
53+
}
54+
55+
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
56+
{
57+
yield break;
58+
}
59+
60+
protected override string GetName(NodeFactory context) => "InterpreterStub";
61+
62+
public override int ClassCode => 95566084;
63+
64+
public override bool IsShareable => false;
65+
66+
public override bool StaticDependenciesAreComputed => true;
67+
}
68+
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ public void GenerateHotColdMap(DependencyAnalyzerBase<NodeFactory> dependencyGra
9797
dependencyGraph.AddRoot(HotColdMap, "HotColdMap is generated because there is cold code");
9898
}
9999
}
100+
101+
public void AddInterpreterMapping(DelayLoadMethodImport left, InterpreterImport right, InterpreterStub last)
102+
{
103+
if (InterpreterMap == null)
104+
{
105+
InterpreterMap = new InterpreterMapNode();
106+
Header.Add(Internal.Runtime.ReadyToRunSectionType.InterpreterMap, InterpreterMap, InterpreterMap);
107+
}
108+
InterpreterMap.AddMapping(left, right, last);
109+
}
100110

101111
public void SetMarkingComplete()
102112
{
@@ -372,6 +382,8 @@ private void CreateNodeCaches()
372382

373383
public HotColdMapNode HotColdMap;
374384

385+
public InterpreterMapNode InterpreterMap;
386+
375387
public RuntimeFunctionsGCInfoNode RuntimeFunctionsGCInfo;
376388

377389
public DelayLoadMethodCallThunkNodeRange DelayLoadMethodCallThunks;
@@ -387,6 +399,8 @@ private void CreateNodeCaches()
387399

388400
public Import ModuleImport;
389401

402+
public Import InterpreterRoutineImport;
403+
390404
public ISymbolNode PersonalityRoutine;
391405

392406
public ISymbolNode FilterFuncletPersonalityRoutine;
@@ -803,6 +817,10 @@ public void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph, I
803817
ReadyToRunHelper.Module));
804818
graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec");
805819

820+
InterpreterRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
821+
ReadyToRunHelper.InterpreterRoutine));
822+
graph.AddRoot(InterpreterRoutineImport, "This allow ready to run code to bail to interpreter");
823+
806824
if (Target.Architecture != TargetArchitecture.X86)
807825
{
808826
Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(

src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ internal ReadyToRunCodegenCompilation(
348348
{
349349
_computedFixedLayoutTypesUncached = IsLayoutFixedInCurrentVersionBubbleInternal;
350350
_resilient = resilient;
351-
_parallelism = parallelism;
351+
// TODO, andrewau, until we fix the problem in InterpreterMapNode, this is required
352+
_parallelism = 1;
352353
_corInfoImpls = new CorInfoImpl[_parallelism];
353354
_generateMapFile = generateMapFile;
354355
_generateMapCsvFile = generateMapCsvFile;

src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@
193193
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\GCRefMapNode.cs" />
194194
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\GenericLookupSignature.cs" />
195195
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ImportThunk.cs" />
196+
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterImport.cs" />
197+
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterMapNode.cs" />
198+
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterStub.cs" />
196199
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DelegateCtorSignature.cs" />
197200
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DevirtualizationManager.cs" />
198201
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\FieldFixupSignature.cs" />

src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,15 @@ private static mdToken FindGenericMethodArgTypeSpec(EcmaModule module)
511511

512512
public static bool ShouldSkipCompilation(InstructionSetSupport instructionSetSupport, MethodDesc methodNeedingCode)
513513
{
514+
// TODO, andrewau, this will restrict the compilation to only a handful of methods for simplicity only
515+
if (
516+
!string.Equals(methodNeedingCode.Name, "Setup")
517+
&&
518+
!string.Equals(methodNeedingCode.Name, "Collatz")
519+
)
520+
{
521+
return true;
522+
}
514523
if (methodNeedingCode.IsAggressiveOptimization)
515524
{
516525
return true;

src/coreclr/vm/interpreter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12902,7 +12902,7 @@ void Interpreter::PrintILProfile(Interpreter::InstrExecRecord *recs, unsigned in
1290212902
}
1290312903
#endif // INTERP_ILINSTR_PROFILE
1290412904

12905-
void InterpretCallTarget(PCODE pCallTarget, const ARG_SLOT* pArguments, ARG_SLOT* pReturnValue, int cbReturnValue)
12905+
InterpreterMethodInfo* GetInterpreterMethodInfo(PCODE pCallTarget)
1290612906
{
1290712907
_ASSERTE(InterpreterPrecode::IsInstance(pCallTarget));
1290812908

@@ -12925,6 +12925,13 @@ void InterpretCallTarget(PCODE pCallTarget, const ARG_SLOT* pArguments, ARG_SLOT
1292512925
delete jitInfo;
1292612926
}
1292712927

12928+
return methInfo;
12929+
}
12930+
12931+
void InterpretCallTarget(PCODE pCallTarget, const ARG_SLOT* pArguments, ARG_SLOT* pReturnValue, int cbReturnValue)
12932+
{
12933+
InterpreterMethodInfo* methInfo = GetInterpreterMethodInfo(pCallTarget);
12934+
1292812935
ARG_SLOT retVal = Interpreter::InterpretMethodBody(methInfo, true, reinterpret_cast<BYTE*>(const_cast<ARG_SLOT*>(pArguments)), NULL);
1292912936
if (pReturnValue != NULL)
1293012937
*pReturnValue = retVal;

src/coreclr/vm/interpreter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,4 +2098,6 @@ unsigned short Interpreter::NumberOfIntegerRegArgs() { return 8; }
20982098
#error Unsupported architecture.
20992099
#endif
21002100

2101+
InterpreterMethodInfo* GetInterpreterMethodInfo(PCODE pCallTarget);
2102+
21012103
#endif // INTERPRETER_H_DEFINED

src/coreclr/vm/jitinterface.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13788,6 +13788,10 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
1378813788
case READYTORUN_HELPER_DelayLoad_MethodCall:
1378913789
result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
1379013790
break;
13791+
13792+
case READYTORUN_HELPER_InterpreterRoutine:
13793+
result = (size_t)GetEEFuncEntryPoint(InterpretMethod);
13794+
break;
1379113795

1379213796
case READYTORUN_HELPER_DelayLoad_Helper:
1379313797
result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);

src/coreclr/vm/method.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3888,8 +3888,17 @@ PrecodeType MethodDesc::GetPrecodeType()
38883888

38893889
PrecodeType precodeType = PRECODE_INVALID;
38903890
#ifdef FEATURE_INTERPRETER
3891-
precodeType = PRECODE_INTERPRETER;
3892-
#else // !FEATURE_INTERPRETER
3891+
if (
3892+
!m_pszDebugClassName
3893+
||
3894+
!m_pszDebugClassName
3895+
||
3896+
(strcmp("System.AppContext", m_pszDebugClassName) != 0)
3897+
||
3898+
(strcmp("Collatz", m_pszDebugMethodName) != 0)
3899+
)
3900+
return PRECODE_INTERPRETER;
3901+
#endif // FEATURE_INTERPRETER
38933902
#ifdef HAS_FIXUP_PRECODE
38943903
if (!RequiresMethodDescCallingConvention())
38953904
{
@@ -3901,7 +3910,6 @@ PrecodeType MethodDesc::GetPrecodeType()
39013910
{
39023911
precodeType = PRECODE_STUB;
39033912
}
3904-
#endif // FEATURE_INTERPRETER
39053913

39063914
return precodeType;
39073915
}

0 commit comments

Comments
 (0)