Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Private.Interpreter/src/Internal/Runtime')
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/CompilerHelpers/LibraryInitializer.cs17
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILImporter.Interpreter.cs501
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILInterpreter.cs46
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterCallInterceptor.cs72
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/InterpreterExecutionStrategy.cs22
-rw-r--r--src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/StackItem.cs105
6 files changed, 763 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..70b54d2a3
--- /dev/null
+++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILImporter.Interpreter.cs
@@ -0,0 +1,501 @@
+// 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 System.Diagnostics;
+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);
+ }
+
+ public StackItem PopWithValidation()
+ {
+ bool hasStackItem = _interpreter.EvaluationStack.TryPop(out StackItem stackItem);
+ if (!hasStackItem)
+ ThrowHelper.ThrowInvalidProgramException();
+
+ return stackItem;
+ }
+
+ 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()
+ {
+ _interpreter.EvaluationStack.Push(StackItem.FromObjectRef(null));
+ }
+
+ private void ImportReturn()
+ {
+ var returnType = _method.Signature.ReturnType;
+ if (returnType.IsVoid)
+ return;
+
+ StackItem stackItem = PopWithValidation();
+ TypeFlags category = returnType.Category;
+
+ switch (category)
+ {
+ case TypeFlags.Boolean:
+ _interpreter.SetReturnValue(stackItem.AsInt32() != 0);
+ break;
+ case TypeFlags.Char:
+ _interpreter.SetReturnValue((char)stackItem.AsInt32());
+ break;
+ case TypeFlags.SByte:
+ _interpreter.SetReturnValue((sbyte)stackItem.AsInt32());
+ break;
+ case TypeFlags.Byte:
+ _interpreter.SetReturnValue((byte)stackItem.AsInt32());
+ break;
+ case TypeFlags.Int16:
+ _interpreter.SetReturnValue((short)stackItem.AsInt32());
+ break;
+ case TypeFlags.UInt16:
+ _interpreter.SetReturnValue((ushort)stackItem.AsInt32());
+ break;
+ case TypeFlags.Int32:
+ case TypeFlags.UInt32:
+ _interpreter.SetReturnValue(stackItem.AsInt32());
+ break;
+ case TypeFlags.Int64:
+ case TypeFlags.UInt64:
+ _interpreter.SetReturnValue(stackItem.AsInt64());
+ break;
+ case TypeFlags.IntPtr:
+ case TypeFlags.UIntPtr:
+ _interpreter.SetReturnValue(stackItem.AsIntPtr());
+ break;
+ case TypeFlags.Single:
+ _interpreter.SetReturnValue((float)stackItem.AsDouble());
+ break;
+ case TypeFlags.Double:
+ _interpreter.SetReturnValue(stackItem.AsDouble());
+ break;
+ case TypeFlags.ValueType:
+ _interpreter.SetReturnValue(stackItem.AsValueType());
+ break;
+ case TypeFlags.Interface:
+ case TypeFlags.Class:
+ case TypeFlags.Array:
+ case TypeFlags.SzArray:
+ _interpreter.SetReturnValue(stackItem.AsObjectRef());
+ break;
+ case TypeFlags.Enum:
+ case TypeFlags.Nullable:
+ case TypeFlags.ByRef:
+ case TypeFlags.Pointer:
+ case TypeFlags.FunctionPointer:
+ case TypeFlags.GenericParameter:
+ default:
+ // TODO: Support more complex return types
+ break;
+ }
+ }
+
+ private void ImportLoadInt(long value, StackValueKind kind)
+ {
+ if (kind == StackValueKind.Int32)
+ _interpreter.EvaluationStack.Push(StackItem.FromInt32((int)value));
+ else if (kind == StackValueKind.Int64)
+ _interpreter.EvaluationStack.Push(StackItem.FromInt64(value));
+ }
+
+ private void ImportLoadFloat(double value)
+ {
+ _interpreter.EvaluationStack.Push(StackItem.FromDouble(value));
+ }
+
+ 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 token)
+ {
+ string str = (string)_methodIL.GetObject(token);
+ _interpreter.EvaluationStack.Push(StackItem.FromObjectRef(str));
+ }
+
+ 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..f5f947c74
--- /dev/null
+++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/ILInterpreter.cs
@@ -0,0 +1,46 @@
+// 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 => _stack;
+
+ public TypeSystemContext TypeSystemContext => _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..97578b61d
--- /dev/null
+++ b/src/System.Private.Interpreter/src/Internal/Runtime/Interpreter/StackItem.cs
@@ -0,0 +1,105 @@
+// 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 System.Diagnostics;
+using System.Runtime.InteropServices;
+using Internal.IL;
+using Internal.TypeSystem;
+
+namespace Internal.Runtime.Interpreter
+{
+ [StructLayout(LayoutKind.Explicit)]
+ internal unsafe struct StackItem
+ {
+ [FieldOffset(0)]
+ private StackValueKind _kind;
+
+ [FieldOffset(8)]
+ private int _int32;
+
+ [FieldOffset(8)]
+ private long _int64;
+
+ [FieldOffset(8)]
+ private IntPtr _nativeInt;
+
+ [FieldOffset(8)]
+ private double _double;
+
+ [FieldOffset(16)]
+ private ValueType _valueType;
+
+ [FieldOffset(16)]
+ private object _objref;
+
+ public StackValueKind Kind => _kind;
+
+ public static StackItem FromInt32(int int32)
+ {
+ return new StackItem { _int32 = int32, _kind = StackValueKind.Int32 };
+ }
+
+ public int AsInt32()
+ {
+ Debug.Assert(_kind == StackValueKind.Int32);
+ return _int32;
+ }
+
+ public static StackItem FromInt64(long int64)
+ {
+ return new StackItem { _int64 = int64, _kind = StackValueKind.Int64 };
+ }
+
+ public long AsInt64()
+ {
+ Debug.Assert(_kind == StackValueKind.Int64);
+ return _int64;
+ }
+
+ public static StackItem FromIntPtr(IntPtr nativeInt)
+ {
+ return new StackItem { _nativeInt = nativeInt, _kind = StackValueKind.NativeInt };
+ }
+
+ public IntPtr AsIntPtr()
+ {
+ Debug.Assert(_kind == StackValueKind.NativeInt);
+ return _nativeInt;
+ }
+
+ public static StackItem FromDouble(double d)
+ {
+ return new StackItem { _double = d, _kind = StackValueKind.Float };
+ }
+
+ public double AsDouble()
+ {
+ Debug.Assert(_kind == StackValueKind.Float);
+ return _double;
+ }
+
+ public static StackItem FromValueType(ValueType valueType)
+ {
+ return new StackItem { _valueType = valueType, _kind = StackValueKind.ValueType };
+ }
+
+ public ValueType AsValueType()
+ {
+ Debug.Assert(_kind == StackValueKind.ValueType);
+ return _valueType;
+ }
+
+ public static StackItem FromObjectRef(object obj)
+ {
+ return new StackItem { _objref = obj, _kind = StackValueKind.ObjRef };
+ }
+
+ public object AsObjectRef()
+ {
+ Debug.Assert(_kind == StackValueKind.ObjRef);
+ return _objref;
+ }
+ }
+}