diff options
author | Toni Solarin-Sodara <toni.edward@outlook.com> | 2018-08-14 19:50:42 +0300 |
---|---|---|
committer | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2018-08-14 19:50:42 +0300 |
commit | c214863ad3e4da15fb3b56fa9c82ef359fee55fe (patch) | |
tree | 576cbddfcd403739018cc219b4593735ac0d3ff1 /src/System.Private.Interpreter | |
parent | d55ebfd33d4d45afbdf1a3adedc32a839c5a4a69 (diff) |
Preliminary Interpreter Support (#6182)
Diffstat (limited to 'src/System.Private.Interpreter')
7 files changed, 711 insertions, 0 deletions
diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs b/src/System.Private.Interpreter/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs new file mode 100644 index 000000000..82c5b1299 --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs @@ -0,0 +1,17 @@ +// 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.Runtime.Interpreter; +using Internal.Runtime.TypeLoader; + +namespace Internal.Runtime.CompilerHelpers +{ + public class LibraryInitializer + { + public static void InitializeLibrary() + { + MethodExecutionStrategy.GlobalExecutionStrategy = new InterpreterExecutionStrategy(); + } + } +} diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILImporter.Interpreter.cs b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILImporter.Interpreter.cs new file mode 100644 index 000000000..a86ef2d67 --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILImporter.Interpreter.cs @@ -0,0 +1,447 @@ +// 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 Internal.Runtime.Interpreter; +using Internal.TypeSystem; + +namespace Internal.IL +{ + partial class ILImporter + { + private class BasicBlock + { + // Common fields + public enum ImportState : byte + { + Unmarked, + IsPending + } + + public BasicBlock Next; + + public int StartOffset; + public ImportState State = ImportState.Unmarked; + + public bool TryStart; + public bool FilterStart; + public bool HandlerStart; + } + + private class ExceptionRegion + { + public ILExceptionRegion ILRegion; + } + + private readonly byte[] _ilBytes; + private readonly MethodDesc _method; + private readonly MethodIL _methodIL; + private readonly ILInterpreter _interpreter; + private ExceptionRegion[] _exceptionRegions; + + public ILImporter(ILInterpreter interpreter, MethodDesc method, MethodIL methodIL) + { + _ilBytes = methodIL.GetILBytes(); + _method = method; + _methodIL = methodIL; + _interpreter = interpreter; + + var ilExceptionRegions = methodIL.GetExceptionRegions(); + _exceptionRegions = new ExceptionRegion[methodIL.GetExceptionRegions().Length]; + for (int i = 0; i < ilExceptionRegions.Length; i++) + { + _exceptionRegions[i] = new ExceptionRegion() { ILRegion = ilExceptionRegions[i] }; + } + } + + public void Interpret() + { + FindBasicBlocks(); + ImportBasicBlocks(); + } + + private void MarkInstructionBoundary() { } + + private void StartImportingInstruction() { } + + private void EndImportingInstruction() { } + + private void StartImportingBasicBlock(BasicBlock basicBlock) { } + + private void EndImportingBasicBlock(BasicBlock basicBlock) { } + + private void ReportInvalidBranchTarget(int targetOffset) + { + ThrowHelper.ThrowInvalidProgramException(); + } + + private void ReportFallthroughAtEndOfMethod() + { + ThrowHelper.ThrowInvalidProgramException(); + } + + private void ReportMethodEndInsideInstruction() + { + ThrowHelper.ThrowInvalidProgramException(); + } + + private void ReportInvalidInstruction(ILOpcode opcode) + { + ThrowHelper.ThrowInvalidProgramException(); + } + + private TypeDesc ResolveTypeToken(int token) + { + return (TypeDesc)_methodIL.GetObject(token); + } + + private TypeDesc GetWellKnownType(WellKnownType wellKnownType) + { + return _interpreter.TypeSystemContext.GetWellKnownType(wellKnownType); + } + + private void ImportNop() + { + // Do nothing! + } + + private void ImportBreak() + { + throw new NotImplementedException(); + } + + private void ImportLoadVar(int index, bool argument) + { + throw new NotImplementedException(); + } + + private void ImportStoreVar(int index, bool argument) + { + throw new NotImplementedException(); + } + + private void ImportAddressOfVar(int index, bool argument) + { + throw new NotImplementedException(); + } + + private void ImportDup() + { + throw new NotImplementedException(); + } + + private void ImportPop() + { + throw new NotImplementedException(); + } + + private void ImportCalli(int token) + { + throw new NotImplementedException(); + } + + private void ImportLoadNull() + { + throw new NotImplementedException(); + } + + private void ImportReturn() + { + bool hasReturnValue = _interpreter.EvaluationStack.TryPop(out StackItem stackItem); + if (!hasReturnValue) + return; + + switch (stackItem.Kind) + { + case StackValueKind.Int32: + _interpreter.SetReturnValue(((Int32StackItem)stackItem).Value); + break; + case StackValueKind.Int64: + _interpreter.SetReturnValue(((Int64StackItem)stackItem).Value); + break; + case StackValueKind.Unknown: + case StackValueKind.NativeInt: + case StackValueKind.Float: + case StackValueKind.ByRef: + case StackValueKind.ObjRef: + case StackValueKind.ValueType: + default: + break; + } + } + + private void ImportLoadInt(long value, StackValueKind kind) + { + if (kind == StackValueKind.Int32) + _interpreter.EvaluationStack.Push(new Int32StackItem((int)value)); + else if (kind == StackValueKind.Int64) + _interpreter.EvaluationStack.Push(new Int64StackItem(value)); + } + + private void ImportLoadFloat(double value) + { + throw new NotImplementedException(); + } + + private void ImportShiftOperation(ILOpcode opcode) + { + throw new NotImplementedException(); + } + + private void ImportCompareOperation(ILOpcode opcode) + { + throw new NotImplementedException(); + } + + private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool unsigned) + { + throw new NotImplementedException(); + } + + private void ImportUnaryOperation(ILOpcode opCode) + { + throw new NotImplementedException(); + } + + private void ImportCpOpj(int token) + { + throw new NotImplementedException(); + } + + private void ImportCkFinite() + { + throw new NotImplementedException(); + } + + private void ImportLocalAlloc() + { + throw new NotImplementedException(); + } + + private void ImportEndFilter() + { + throw new NotImplementedException(); + } + + private void ImportCpBlk() + { + throw new NotImplementedException(); + } + + private void ImportInitBlk() + { + throw new NotImplementedException(); + } + + private void ImportRethrow() + { + throw new NotImplementedException(); + } + + private void ImportSizeOf(int token) + { + throw new NotImplementedException(); + } + + private void ImportUnalignedPrefix(byte alignment) + { + throw new NotImplementedException(); + } + + private void ImportVolatilePrefix() + { + throw new NotImplementedException(); + } + + private void ImportTailPrefix() + { + throw new NotImplementedException(); + } + + private void ImportNoPrefix(byte mask) + { + throw new NotImplementedException(); + } + + private void ImportThrow() + { + throw new NotImplementedException(); + } + + private void ImportInitObj(int token) + { + throw new NotImplementedException(); + } + + private void ImportLoadLength() + { + throw new NotImplementedException(); + } + + private void ImportEndFinally() + { + throw new NotImplementedException(); + } + + private void ImportFallthrough(BasicBlock nextBasicBlock) + { + throw new NotImplementedException(); + } + + private void ImportReadOnlyPrefix() + { + throw new NotImplementedException(); + } + + private void ImportRefAnyType() + { + throw new NotImplementedException(); + } + + private void ImportConstrainedPrefix(int v) + { + throw new NotImplementedException(); + } + + private void ImportLdFtn(int v, ILOpcode opCode) + { + throw new NotImplementedException(); + } + + private void ImportArgList() + { + throw new NotImplementedException(); + } + + private void ImportLeave(BasicBlock basicBlock) + { + throw new NotImplementedException(); + } + + private void ImportLdToken(int v) + { + throw new NotImplementedException(); + } + + private void ImportMkRefAny(int v) + { + throw new NotImplementedException(); + } + + private void ImportRefAnyVal(int v) + { + throw new NotImplementedException(); + } + + private void ImportAddressOfElement(int v) + { + throw new NotImplementedException(); + } + + private void ImportNewArray(int v) + { + throw new NotImplementedException(); + } + + private void ImportBox(int v) + { + throw new NotImplementedException(); + } + + private void ImportStoreField(int v1, bool v2) + { + throw new NotImplementedException(); + } + + private void ImportAddressOfField(int v1, bool v2) + { + throw new NotImplementedException(); + } + + private void ImportLoadField(int v1, bool v2) + { + throw new NotImplementedException(); + } + + private void ImportUnbox(int v, ILOpcode opCode) + { + throw new NotImplementedException(); + } + + private void ImportCasting(ILOpcode opCode, int v) + { + throw new NotImplementedException(); + } + + private void ImportLoadString(int v) + { + throw new NotImplementedException(); + } + + private void ImportBinaryOperation(ILOpcode opCode) + { + throw new NotImplementedException(); + } + + private void ImportSwitchJump(int jmpBase, int[] jmpDelta, BasicBlock basicBlock) + { + throw new NotImplementedException(); + } + + private void ImportBranch(ILOpcode iLOpcode, BasicBlock basicBlock1, BasicBlock basicBlock2) + { + throw new NotImplementedException(); + } + + private void ImportCall(ILOpcode opCode, int v) + { + throw new NotImplementedException(); + } + + private void ImportJmp(int v) + { + throw new NotImplementedException(); + } + + private void ImportLoadIndirect(int token) + { + ImportLoadIndirect(ResolveTypeToken(token)); + } + + private void ImportLoadIndirect(TypeDesc type) + { + throw new NotImplementedException(); + } + + private void ImportStoreIndirect(int token) + { + ImportStoreIndirect(ResolveTypeToken(token)); + } + + private void ImportStoreIndirect(TypeDesc type) + { + throw new NotImplementedException(); + } + + private void ImportLoadElement(int token) + { + ImportLoadElement(ResolveTypeToken(token)); + } + + private void ImportLoadElement(TypeDesc elementType) + { + throw new NotImplementedException(); + } + + private void ImportStoreElement(int token) + { + ImportStoreElement(ResolveTypeToken(token)); + } + + private void ImportStoreElement(TypeDesc elementType) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILInterpreter.cs b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILInterpreter.cs new file mode 100644 index 000000000..d78611ec9 --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILInterpreter.cs @@ -0,0 +1,58 @@ +// 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.Collections.Generic; + +using Internal.IL; +using Internal.Runtime.CallInterceptor; +using Internal.TypeSystem; + +namespace Internal.Runtime.Interpreter +{ + internal unsafe class ILInterpreter + { + private readonly MethodDesc _method; + private readonly MethodIL _methodIL; + private readonly TypeSystemContext _context; + private readonly LowLevelStack<StackItem> _stack; + + private CallInterceptorArgs _callInterceptorArgs; + + public LowLevelStack<StackItem> EvaluationStack + { + get + { + return _stack; + } + } + + public TypeSystemContext TypeSystemContext + { + get + { + return _context; + } + } + + public ILInterpreter(TypeSystemContext context, MethodDesc method, MethodIL methodIL) + { + _context = context; + _method = method; + _methodIL = methodIL; + _stack = new LowLevelStack<StackItem>(); + } + + public void InterpretMethod(ref CallInterceptorArgs callInterceptorArgs) + { + _callInterceptorArgs = callInterceptorArgs; + ILImporter importer = new ILImporter(this, _method, _methodIL); + importer.Interpret(); + } + + public void SetReturnValue<T>(T value) + { + _callInterceptorArgs.ArgumentsAndReturnValue.SetVar<T>(0, value); + } + } +} diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterCallInterceptor.cs b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterCallInterceptor.cs new file mode 100644 index 000000000..3703d213b --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterCallInterceptor.cs @@ -0,0 +1,72 @@ +// 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.IL; +using Internal.Runtime.CallConverter; +using Internal.Runtime.CallInterceptor; +using Internal.TypeSystem; +using Internal.TypeSystem.Ecma; + +namespace Internal.Runtime.Interpreter +{ + public class InterpreterCallInterceptor : CallInterceptor.CallInterceptor + { + private readonly MethodDesc _method; + private readonly MethodIL _methodIL; + private readonly TypeSystemContext _context; + + public InterpreterCallInterceptor(TypeSystemContext context, MethodDesc method) : base(false) + { + _context = context; + _method = method; + _methodIL = EcmaMethodIL.Create(method as EcmaMethod); + } + + public override LocalVariableType[] ArgumentAndReturnTypes + { + get + { + LocalVariableType[] localVariableTypes = new LocalVariableType[_method.Signature.Length + 1]; + localVariableTypes[0] = new LocalVariableType(_method.Signature.ReturnType.RuntimeTypeHandle, false, _method.Signature.ReturnType.IsByRef); + for (int i = 0; i < _method.Signature.Length; i++) + { + var argument = _method.Signature[i]; + localVariableTypes[i + 1] = new LocalVariableType(argument.RuntimeTypeHandle, false, argument.IsByRef); + } + + return localVariableTypes; + } + } + + public override CallingConvention CallingConvention + { + get + { + return _method.Signature.IsStatic ? CallingConvention.ManagedStatic : CallingConvention.ManagedInstance; + } + } + + public override LocalVariableType[] LocalVariableTypes + { + get + { + LocalVariableDefinition[] locals = _methodIL.GetLocals(); + LocalVariableType[] localVariableTypes = new LocalVariableType[locals.Length]; + for (int i = 0; i < locals.Length; i++) + { + var variable = locals[i]; + localVariableTypes[i] = new LocalVariableType(variable.Type.RuntimeTypeHandle, variable.IsPinned, variable.Type.IsByRef); + } + + return localVariableTypes; + } + } + + public override void ThunkExecute(ref CallInterceptorArgs callInterceptorArgs) + { + ILInterpreter interpreter = new ILInterpreter(_context, _method, _methodIL); + interpreter.InterpretMethod(ref callInterceptorArgs); + } + } +} diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterExecutionStrategy.cs b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterExecutionStrategy.cs new file mode 100644 index 000000000..7fa3a5742 --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterExecutionStrategy.cs @@ -0,0 +1,22 @@ +// 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 Internal.Runtime.TypeLoader; +using Internal.TypeSystem; + +namespace Internal.Runtime.Interpreter +{ + public class InterpreterExecutionStrategy : MethodExecutionStrategy + { + public override IntPtr OnEntryPoint(MethodEntrypointPtr methodEntrypointPtr, IntPtr callerArgumentsInfo) + { + var context = TypeSystemContextFactory.Create(); + MethodDesc method = methodEntrypointPtr.MethodIdentifier.ToMethodDesc(context); + InterpreterCallInterceptor callInterceptor = new InterpreterCallInterceptor(context, method); + return callInterceptor.GetThunkAddress(); + } + } +} diff --git a/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/StackItem.cs b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/StackItem.cs new file mode 100644 index 000000000..b35b8bb05 --- /dev/null +++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/StackItem.cs @@ -0,0 +1,60 @@ +// 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 Internal.IL; + +namespace Internal.Runtime.Interpreter +{ + internal abstract class StackItem + { + public StackValueKind Kind { get; set; } + } + + internal class StackItem<T> : StackItem + { + public T Value { get; } + + public StackItem(T value, StackValueKind kind) + { + Value = value; + Kind = kind; + } + } + + internal class Int32StackItem : StackItem<int> + { + public Int32StackItem(int value) : base(value, StackValueKind.Int32) + { + } + } + + internal class Int64StackItem : StackItem<long> + { + public Int64StackItem(long value) : base(value, StackValueKind.Int64) + { + } + } + + internal class FloatStackItem : StackItem<double> + { + public FloatStackItem(double value) : base(value, StackValueKind.Float) + { + } + } + + internal class ValueTypeStackItem : StackItem<ValueType> + { + public ValueTypeStackItem(ValueType value) : base(value, StackValueKind.ValueType) + { + } + } + + internal class ObjectRefStackItem : StackItem<Object> + { + public ObjectRefStackItem(Object value) : base(value, StackValueKind.ObjRef) + { + } + } +} diff --git a/src/System.Private.Interpreter/src/System.Private.Interpreter.csproj b/src/System.Private.Interpreter/src/System.Private.Interpreter.csproj new file mode 100644 index 000000000..3808516a4 --- /dev/null +++ b/src/System.Private.Interpreter/src/System.Private.Interpreter.csproj @@ -0,0 +1,35 @@ +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <AssemblyName>System.Private.Interpreter</AssemblyName> + <AssemblyVersion>4.0.0.0</AssemblyVersion> + <OutputType>Library</OutputType> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <ItemGroup Condition="'$(IsProjectNLibrary)' != 'true'"> + <ProjectReference Include="..\..\AotPackageReference\AotPackageReference.depproj"> + <ReferenceOutputAssembly>false</ReferenceOutputAssembly> + <SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties> + </ProjectReference> + <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Runtime.Extensions.dll" /> + <ReferencePath Include="$(AotPackageReferencePath)\System.Private.Reflection.Metadata.Ecma335.dll" /> + <ProjectReference Include="..\..\System.Private.CoreLib\src\System.Private.CoreLib.csproj" /> + <ProjectReference Include="..\..\System.Private.Reflection.Metadata\src\System.Private.Reflection.Metadata.csproj" /> + <ProjectReference Include="..\..\System.Private.TypeLoader\src\System.Private.TypeLoader.Experimental.csproj" /> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\Common\src\TypeSystem\IL\EcmaMethodIL.cs" /> + <Compile Include="..\..\Common\src\TypeSystem\IL\ILImporter.cs" /> + <Compile Include="..\..\Common\src\System\Collections\Generic\LowLevelStack.cs" /> + <Compile Include="Internal\Runtime\CompilerHelpers\LibraryInitializer.cs" /> + <Compile Include="Internal\Runtime\Interpreter\StackItem.cs" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Internal\Runtime\Interpreter\ILImporter.Interpreter.cs" /> + <Compile Include="Internal\Runtime\Interpreter\ILInterpreter.cs" /> + <Compile Include="Internal\Runtime\Interpreter\InterpreterCallInterceptor.cs" /> + <Compile Include="Internal\Runtime\Interpreter\InterpreterExecutionStrategy.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file |