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

Early work to make it possible to call the interpreter from ReadyToRun code #2910

Open
wants to merge 3 commits into
base: feature/CoreclrInterpreter
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ enum class ReadyToRunSectionType : uint32_t
MethodIsGenericMap = 121, // Added in V9.0
EnclosingTypeMap = 122, // Added in V9.0
TypeGenericInfoMap = 123, // Added in V9.0
InterpreterMap = 124, // Prototype

// 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 Expand Up @@ -447,6 +448,9 @@ enum ReadyToRunHelper
READYTORUN_HELPER_StackProbe = 0x111,

READYTORUN_HELPER_GetCurrentManagedThreadId = 0x112,

READYTORUN_HELPER_InterpreterRoutine = 0x113,
READYTORUN_HELPER_InterpreterVirtualRoutine = 0x114,
};

#include "readytoruninstructionset.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,25 @@ public void EmitJMP(ISymbolNode symbol)
{
Builder.EmitByte(0xE9);
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);

}
}

public void EmitCALL(ISymbolNode symbol)
{
if (symbol.RepresentsIndirectionCell)
{
// CALL instruction with indirection
Builder.EmitByte(0xFF);
Builder.EmitByte(0x15);
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
}
else
{
// Regular CALL instruction
Builder.EmitByte(0xE8);
Builder.EmitReloc(symbol, RelocType.IMAGE_REL_BASED_REL32);
}
}
public void EmitJE(ISymbolNode symbol)
{
if (symbol.RepresentsIndirectionCell)
Expand Down Expand Up @@ -141,6 +156,14 @@ public void EmitJmpToAddrMode(ref AddrMode addrMode)
EmitIndirInstruction(0xFF, 0x4, ref addrMode);
}

public void EmitPUSH(Register reg)
{
if (reg >= Register.RAX && reg <= Register.R15)
{
Builder.EmitByte((byte)((byte)0x50 + (byte)((byte)reg & (byte)0x0F)));
}
}

public void EmitPUSH(sbyte imm8)
{
Builder.EmitByte(0x6A);
Expand Down Expand Up @@ -173,6 +196,11 @@ public void EmitPUSH(ISymbolNode node)
}
}

public void EmitPOP()
{
Builder.EmitByte(0x58);
}

public void EmitRET()
{
Builder.EmitByte(0xC3);
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 @@ -79,6 +79,7 @@ enum ReadyToRunSectionType
MethodIsGenericMap = 121, // Added in V9.0
EnclosingTypeMap = 122, // Added in V9.0
TypeGenericInfoMap = 123, // Added in V9.0
InterpreterMap = 124, // Added for prototyping only

//
// NativeAOT ReadyToRun sections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@ public enum ReadyToRunHelper

GetCurrentManagedThreadId = 0x112,

//Interpreter
InterpreterRoutine = 0x113,
InterpreterVirtualRoutine = 0x114,

// **********************************************************************************************
//
// These are not actually part of the R2R file format. We have them here because it's convenient.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
{
yield return baseEntry;
}

// This is for virtual calls
InterpreterImport _interpreterImport = new InterpreterImport();
InterpreterStub _interpreterStub = new InterpreterStub(_interpreterImport, /* virtual = */true);
factory.AddInterpreterMapping(this, _interpreterImport, _interpreterStub);
yield return new DependencyListEntry(_interpreterImport, "Unused reason 1");
yield return new DependencyListEntry(_interpreterStub, "Unused reason 2");
yield return new DependencyListEntry(factory.InterpreterMap, "Unused reason 3");

if (_useInstantiatingStub)
{
// Require compilation of the canonical version for instantiating stubs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
{
yield return entry;
}

// It is possible that an instance of DelayLoadMethodImport is constructed by never get into the graph
// So we must delay the construction and rooting of the InterpreterImport

// This is for static calls
InterpreterImport _interpreterImport = new InterpreterImport();
InterpreterStub _interpreterStub = new InterpreterStub(_interpreterImport, /* virtual = */false);
factory.AddInterpreterMapping(this, _interpreterImport, _interpreterStub);
yield return new DependencyListEntry(_interpreterImport, "Unused reason 1");
yield return new DependencyListEntry(_interpreterStub, "Unused reason 2");
yield return new DependencyListEntry(factory.InterpreterMap, "Unused reason 3");
if (_localMethod != null)
yield return new DependencyListEntry(_localMethod, "Local method import");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.JitInterface;
using Internal.Text;
using Internal.TypeSystem;
using Internal.ReadyToRunConstants;
using ILCompiler.DependencyAnalysisFramework;
using System.Collections.Generic;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
// An InterpreterImport simply a pointer sized variable that the
// interpreter stub can use to reference the InterpreterMethodInfo
public class InterpreterImport : ObjectNode, ISymbolDefinitionNode
{
public int _id;
public static int id = 1;

public InterpreterImport()
{
// TODO, andrewau, we need a mechanism to identify the call sites
// using a ID is not going to be deterministic
_id = id++;
}

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
return this._id - ((InterpreterImport)(other))._id;
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
builder.AddSymbol(this);
builder.EmitZeroPointer();
return builder.ToObjectData();
}

public int Offset { get; set; }

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
=> sb.Append(nameMangler.CompilationUnitPrefix).Append("InterpreterImport").Append(_id.ToString());

public override ObjectNodeSection GetSection(NodeFactory factory)
{
return ObjectNodeSection.DataSection;
}

public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
{
yield break;
}

protected override string GetName(NodeFactory context) => "InterpreterImport";

public override int ClassCode => 46709394;

public override bool IsShareable => false;

public override bool StaticDependenciesAreComputed => true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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 Internal.Text;
using System.Collections.Generic;
using System.Diagnostics;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
public class InterpreterMapNode : HeaderTableNode
{
public override int ClassCode => 25687179;

private List<ISymbolNode> leftItems = new List<ISymbolNode>();
private List<InterpreterStub> lastItems = new List<InterpreterStub>();
private List<InterpreterImport> rightItems = new List<InterpreterImport>();

public void AddMapping(ISymbolNode left, InterpreterImport right, InterpreterStub last)
{
// TODO, andrewau, this require proper locking and sorting for multithreaded compilation.
// correctness and determinism
leftItems.Add(left);
rightItems.Add(right);
lastItems.Add(last);
}

public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
{
sb.Append(nameMangler.CompilationUnitPrefix);
sb.Append("__InterpreterMap"u8);
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
builder.AddSymbol(this);
for (int i = 0; i < leftItems.Count; i++)
{
// This will emit the RVAs for these
builder.EmitReloc(leftItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
builder.EmitReloc(rightItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
builder.EmitReloc(lastItems[i], RelocType.IMAGE_REL_FILE_ABSOLUTE);
}
return builder.ToObjectData();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Internal.JitInterface;
using Internal.Text;
using Internal.TypeSystem;
using Internal.ReadyToRunConstants;
using ILCompiler.DependencyAnalysisFramework;
using System.Collections.Generic;

// TODO, andrewau, other architectures
using ILCompiler.DependencyAnalysis.X64;

namespace ILCompiler.DependencyAnalysis.ReadyToRun
{
// An InterpreterStub is a small trampoline that
// 1.) Copy the pointer to the pointer to the InterpreterMethodInfo into RAX
// 2.) Jump to the InterpreterRoutine
//
public class InterpreterStub : ObjectNode, ISymbolDefinitionNode
{
public InterpreterImport _interpreterImport;
public bool _virtual;

public InterpreterStub(InterpreterImport interpreterImport, bool isVirtual)
{
_interpreterImport = interpreterImport;
_virtual = isVirtual;
}

public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
return _interpreterImport._id - ((InterpreterStub)(other))._interpreterImport._id;
}

public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false)
{
X64Emitter x64Emitter = new X64Emitter(factory, relocsOnly);
x64Emitter.Builder.AddSymbol(this);
x64Emitter.EmitMOV(Register.RAX, _interpreterImport);
if (_virtual)
{
x64Emitter.EmitJMP(factory.InterpreterVirtualRoutineImport);
}
else
{
x64Emitter.EmitJMP(factory.InterpreterRoutineImport);
}
return x64Emitter.Builder.ToObjectData();
}

public int Offset { get; set; }

public void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
=> sb.Append(nameMangler.CompilationUnitPrefix).Append("InterpreterStub").Append(_interpreterImport._id.ToString());

public override ObjectNodeSection GetSection(NodeFactory factory)
{
return ObjectNodeSection.TextSection;
}

public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context)
{
yield break;
}

protected override string GetName(NodeFactory context) => "InterpreterStub";

public override int ClassCode => 95566084;

public override bool IsShareable => false;

public override bool StaticDependenciesAreComputed => true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,16 @@ public void GenerateHotColdMap(DependencyAnalyzerBase<NodeFactory> dependencyGra
dependencyGraph.AddRoot(HotColdMap, "HotColdMap is generated because there is cold code");
}
}

public void AddInterpreterMapping(ISymbolNode left, InterpreterImport right, InterpreterStub last)
{
if (InterpreterMap == null)
{
InterpreterMap = new InterpreterMapNode();
Header.Add(Internal.Runtime.ReadyToRunSectionType.InterpreterMap, InterpreterMap, InterpreterMap);
}
InterpreterMap.AddMapping(left, right, last);
}

public void SetMarkingComplete()
{
Expand Down Expand Up @@ -372,6 +382,8 @@ private void CreateNodeCaches()

public HotColdMapNode HotColdMap;

public InterpreterMapNode InterpreterMap;

public RuntimeFunctionsGCInfoNode RuntimeFunctionsGCInfo;

public DelayLoadMethodCallThunkNodeRange DelayLoadMethodCallThunks;
Expand All @@ -387,6 +399,10 @@ private void CreateNodeCaches()

public Import ModuleImport;

public Import InterpreterRoutineImport;

public Import InterpreterVirtualRoutineImport;

public ISymbolNode PersonalityRoutine;

public ISymbolNode FilterFuncletPersonalityRoutine;
Expand Down Expand Up @@ -803,6 +819,14 @@ public void AttachToDependencyGraph(DependencyAnalyzerBase<NodeFactory> graph, I
ReadyToRunHelper.Module));
graph.AddRoot(ModuleImport, "Module import is required by the R2R format spec");

InterpreterRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
ReadyToRunHelper.InterpreterRoutine));
graph.AddRoot(InterpreterRoutineImport, "This allow ready to run code to bail to interpreter");

InterpreterVirtualRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
ReadyToRunHelper.InterpreterVirtualRoutine));
graph.AddRoot(InterpreterVirtualRoutineImport, "This allow ready to run code to bail to interpreter");

if (Target.Architecture != TargetArchitecture.X86)
{
Import personalityRoutineImport = new Import(EagerImports, new ReadyToRunHelperSignature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,8 @@ internal ReadyToRunCodegenCompilation(
{
_computedFixedLayoutTypesUncached = IsLayoutFixedInCurrentVersionBubbleInternal;
_resilient = resilient;
_parallelism = parallelism;
// TODO, andrewau, until we fix the problem in InterpreterMapNode, this is required
_parallelism = 1;
_corInfoImpls = new CorInfoImpl[_parallelism];
_generateMapFile = generateMapFile;
_generateMapCsvFile = generateMapCsvFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\GCRefMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\GenericLookupSignature.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\ImportThunk.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterImport.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterMapNode.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\InterpreterStub.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DelegateCtorSignature.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\DevirtualizationManager.cs" />
<Compile Include="Compiler\DependencyAnalysis\ReadyToRun\FieldFixupSignature.cs" />
Expand Down
Loading
Loading