| File: System\Linq\Expressions\Interpreter\LocalAccess.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq.Expressions\src\System.Linq.Expressions.csproj (System.Linq.Expressions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Dynamic.Utils; using System.Reflection; using System.Runtime.CompilerServices; namespace System.Linq.Expressions.Interpreter { internal interface IBoxableInstruction { Instruction? BoxIfIndexMatches(int index); } internal abstract class LocalAccessInstruction : Instruction { internal readonly int _index; protected LocalAccessInstruction(int index) { _index = index; } public override string ToDebugString(int instructionIndex, object? cookie, Func<int, int> labelIndexer, IReadOnlyList<object>? objects) { return cookie == null ? InstructionName + "(" + _index + ")" : InstructionName + "(" + cookie + ": " + _index + ")"; } } #region Load internal sealed class LoadLocalInstruction : LocalAccessInstruction, IBoxableInstruction { internal LoadLocalInstruction(int index) : base(index) { } public override int ProducedStack => 1; public override string InstructionName => "LoadLocal"; public override int Run(InterpretedFrame frame) { frame.Data[frame.StackIndex++] = frame.Data[_index]; return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? InstructionList.LoadLocalBoxed(index) : null; } } internal sealed class LoadLocalBoxedInstruction : LocalAccessInstruction { internal LoadLocalBoxedInstruction(int index) : base(index) { } public override int ProducedStack => 1; public override string InstructionName => "LoadLocalBox"; public override int Run(InterpretedFrame frame) { var box = (IStrongBox)frame.Data[_index]!; frame.Data[frame.StackIndex++] = box.Value; return 1; } } internal sealed class LoadLocalFromClosureInstruction : LocalAccessInstruction { internal LoadLocalFromClosureInstruction(int index) : base(index) { } public override int ProducedStack => 1; public override string InstructionName => "LoadLocalClosure"; public override int Run(InterpretedFrame frame) { IStrongBox box = frame.Closure![_index]; frame.Data[frame.StackIndex++] = box.Value; return 1; } } internal sealed class LoadLocalFromClosureBoxedInstruction : LocalAccessInstruction { internal LoadLocalFromClosureBoxedInstruction(int index) : base(index) { } public override int ProducedStack => 1; public override string InstructionName => "LoadLocal"; public override int Run(InterpretedFrame frame) { IStrongBox box = frame.Closure![_index]; frame.Data[frame.StackIndex++] = box; return 1; } } #endregion #region Store, Assign internal sealed class AssignLocalInstruction : LocalAccessInstruction, IBoxableInstruction { internal AssignLocalInstruction(int index) : base(index) { } public override int ConsumedStack => 1; public override int ProducedStack => 1; public override string InstructionName => "AssignLocal"; public override int Run(InterpretedFrame frame) { frame.Data[_index] = frame.Peek(); return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? InstructionList.AssignLocalBoxed(index) : null; } } internal sealed class StoreLocalInstruction : LocalAccessInstruction, IBoxableInstruction { internal StoreLocalInstruction(int index) : base(index) { } public override int ConsumedStack => 1; public override string InstructionName => "StoreLocal"; public override int Run(InterpretedFrame frame) { frame.Data[_index] = frame.Pop(); return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? InstructionList.StoreLocalBoxed(index) : null; } } internal sealed class AssignLocalBoxedInstruction : LocalAccessInstruction { internal AssignLocalBoxedInstruction(int index) : base(index) { } public override int ConsumedStack => 1; public override int ProducedStack => 1; public override string InstructionName => "AssignLocalBox"; public override int Run(InterpretedFrame frame) { var box = (IStrongBox)frame.Data[_index]!; box.Value = frame.Peek(); return 1; } } internal sealed class StoreLocalBoxedInstruction : LocalAccessInstruction { internal StoreLocalBoxedInstruction(int index) : base(index) { } public override int ConsumedStack => 1; public override string InstructionName => "StoreLocalBox"; public override int Run(InterpretedFrame frame) { var box = (IStrongBox)frame.Data[_index]!; box.Value = frame.Data[--frame.StackIndex]; return 1; } } internal sealed class AssignLocalToClosureInstruction : LocalAccessInstruction { internal AssignLocalToClosureInstruction(int index) : base(index) { } public override int ConsumedStack => 1; public override int ProducedStack => 1; public override string InstructionName => "AssignLocalClosure"; public override int Run(InterpretedFrame frame) { IStrongBox box = frame.Closure![_index]; box.Value = frame.Peek(); return 1; } } internal sealed class ValueTypeCopyInstruction : Instruction { public static readonly ValueTypeCopyInstruction Instruction = new ValueTypeCopyInstruction(); public override int ConsumedStack => 1; public override int ProducedStack => 1; public override string InstructionName => "ValueTypeCopy"; public override int Run(InterpretedFrame frame) { object? o = frame.Pop(); frame.Push(o == null ? o : RuntimeHelpers.GetObjectValue(o)); return 1; } } #endregion #region Initialize internal abstract class InitializeLocalInstruction : LocalAccessInstruction { internal InitializeLocalInstruction(int index) : base(index) { } internal sealed class Reference : InitializeLocalInstruction, IBoxableInstruction { internal Reference(int index) : base(index) { } public override int Run(InterpretedFrame frame) { frame.Data[_index] = null; return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? InstructionList.InitImmutableRefBox(index) : null; } public override string InstructionName => "InitRef"; } internal sealed class ImmutableValue : InitializeLocalInstruction, IBoxableInstruction { private readonly object _defaultValue; internal ImmutableValue(int index, object defaultValue) : base(index) { Debug.Assert(defaultValue != null); _defaultValue = defaultValue; } public override int Run(InterpretedFrame frame) { frame.Data[_index] = _defaultValue; return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? new ImmutableBox(index, _defaultValue) : null; } public override string InstructionName => "InitImmutableValue"; } internal sealed class ImmutableBox : InitializeLocalInstruction { // immutable value: private readonly object _defaultValue; internal ImmutableBox(int index, object defaultValue) : base(index) { _defaultValue = defaultValue; } public override int Run(InterpretedFrame frame) { frame.Data[_index] = new StrongBox<object>(_defaultValue); return 1; } public override string InstructionName => "InitImmutableBox"; } internal sealed class ImmutableRefBox : InitializeLocalInstruction { // immutable value: internal ImmutableRefBox(int index) : base(index) { } public override int Run(InterpretedFrame frame) { frame.Data[_index] = new StrongBox<object>(); return 1; } public override string InstructionName => "InitImmutableBox"; } internal sealed class ParameterBox : InitializeLocalInstruction { public ParameterBox(int index) : base(index) { } public override int Run(InterpretedFrame frame) { frame.Data[_index] = new StrongBox<object?>(frame.Data[_index]); return 1; } public override string InstructionName => "InitParameterBox"; } internal sealed class Parameter : InitializeLocalInstruction, IBoxableInstruction { internal Parameter(int index) : base(index) { } public override int Run(InterpretedFrame frame) { // nop return 1; } public Instruction? BoxIfIndexMatches(int index) { if (index == _index) { return InstructionList.ParameterBox(index); } return null; } public override string InstructionName => "InitParameter"; } internal sealed class MutableValue : InitializeLocalInstruction, IBoxableInstruction { private readonly Type _type; internal MutableValue(int index, Type type) : base(index) { Debug.Assert(type.IsValueType, "MutableValue only supports value types."); _type = type; } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2077:UnrecognizedReflectionPattern", Justification = "_type is a ValueType. You can always get an uninitialized ValueType.")] public override int Run(InterpretedFrame frame) { try { frame.Data[_index] = _type.IsNullableType() ? Activator.CreateInstance(_type) : RuntimeHelpers.GetUninitializedObject(_type); } catch (TargetInvocationException e) { ExceptionHelpers.UnwrapAndRethrow(e); throw ContractUtils.Unreachable; } return 1; } public Instruction? BoxIfIndexMatches(int index) { return (index == _index) ? new MutableBox(index, _type) : null; } public override string InstructionName => "InitMutableValue"; } internal sealed class MutableBox : InitializeLocalInstruction { private readonly Type _type; internal MutableBox(int index, Type type) : base(index) { Debug.Assert(type.IsValueType, "MutableBox only supports value types."); _type = type; } [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2077:UnrecognizedReflectionPattern", Justification = "_type is a ValueType. You can always get an uninitialized ValueType.")] public override int Run(InterpretedFrame frame) { object? value; try { value = _type.IsNullableType() ? Activator.CreateInstance(_type) : RuntimeHelpers.GetUninitializedObject(_type); } catch (TargetInvocationException e) { ExceptionHelpers.UnwrapAndRethrow(e); throw ContractUtils.Unreachable; } frame.Data[_index] = new StrongBox<object?>(value); return 1; } public override string InstructionName => "InitMutableBox"; } } #endregion #region RuntimeVariables internal sealed class RuntimeVariablesInstruction : Instruction { private readonly int _count; public RuntimeVariablesInstruction(int count) { _count = count; } public override int ProducedStack => 1; public override int ConsumedStack => _count; public override string InstructionName => "GetRuntimeVariables"; public override int Run(InterpretedFrame frame) { var ret = new IStrongBox[_count]; for (int i = ret.Length - 1; i >= 0; i--) { ret[i] = (IStrongBox)frame.Pop()!; } frame.Push(RuntimeVariables.Create(ret)); return 1; } } #endregion }