/Microsoft.Scripting/Interpretation/Interpreter.cs
C# | 1634 lines | 1271 code | 271 blank | 92 comment | 433 complexity | 7c23130bf3795bc2de4b8c1335fc0cc2 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if CODEPLEX_40
- using System;
- #else
- using System; using Microsoft;
- #endif
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Diagnostics;
- #if CODEPLEX_40
- using System.Linq.Expressions;
- #else
- using Microsoft.Linq.Expressions;
- #endif
- using System.Reflection;
- using System.Runtime.CompilerServices;
- #if !CODEPLEX_40
- using Microsoft.Runtime.CompilerServices;
- #endif
-
- #if CODEPLEX_40
- using System.Dynamic;
- #else
- using Microsoft.Scripting;
- #endif
- using Microsoft.Scripting.Actions;
- using Microsoft.Scripting.Ast;
- using Microsoft.Scripting.Generation;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using AstUtils = Microsoft.Scripting.Ast.Utils;
-
- [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Scripting.Interpretation")]
-
- namespace Microsoft.Scripting.Interpretation {
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
- public static partial class Interpreter {
- #region Entry points
-
- public static object TopLevelExecute(InterpretedScriptCode scriptCode, params object[] args) {
- ContractUtils.RequiresNotNull(scriptCode, "scriptCode");
-
- var state = InterpreterState.Current.Update(
- (caller) => InterpreterState.CreateForTopLambda(scriptCode, scriptCode.Code, caller, args)
- );
-
- try {
- return DoExecute(state, scriptCode.Code);
- } finally {
- InterpreterState.Current.Value = state.Caller;
- }
- }
-
- internal static object Evaluate(InterpreterState state, Expression expression) {
- object result = Interpret(state, expression);
-
- if (result is ControlFlow) {
- throw new InvalidOperationException("Invalid expression");
- }
-
- return result;
- }
-
- internal static object ExecuteGenerator(InterpreterState state, Expression expression) {
- return Interpret(state, expression);
- }
-
- #endregion
-
- /// <summary>
- /// Evaluates expression and checks it for ControlFlow. If it is control flow, returns true,
- /// otherwise returns false.
- /// </summary>
- /// <param name="state"></param>
- /// <param name="node"></param>
- /// <param name="result">Result of the evaluation</param>
- /// <returns>true if control flow, false if not</returns>
- private static bool InterpretAndCheckFlow(InterpreterState state, Expression node, out object result) {
- result = Interpret(state, node);
-
- return result != ControlFlow.NextForYield && result is ControlFlow;
- }
-
- /// <summary>
- /// Evaluates an expression and checks to see if the ControlFlow is NextForYield. If it is then we are currently
- /// searching for the next yield and we need to execute any additional nodes in a larger compound node.
- /// </summary>
- private static bool InterpretAndCheckYield(InterpreterState state, Expression target, out object res) {
- res = Interpret(state, target);
- if (res != ControlFlow.NextForYield) {
- return true;
- }
- return false;
- }
-
- // Individual expressions and statements
-
- private static object InterpretConstantExpression(InterpreterState state, Expression expr) {
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- ConstantExpression node = (ConstantExpression)expr;
- return node.Value;
- }
-
- private static object InterpretConditionalExpression(InterpreterState state, Expression expr) {
- ConditionalExpression node = (ConditionalExpression)expr;
- object test;
-
- if (InterpretAndCheckFlow(state, node.Test, out test)) {
- return test;
- }
-
- if (test == ControlFlow.NextForYield || (bool)test) {
- if (InterpretAndCheckYield(state, node.IfTrue, out test)) {
- return test;
- }
- }
-
- return Interpret(state, node.IfFalse);
- }
-
- private static bool IsInputParameter(ParameterInfo pi) {
- return !pi.IsOut || (pi.Attributes & ParameterAttributes.In) != 0;
- }
-
- private static object InvokeMethod(InterpreterState state, MethodInfo method, object instance, params object[] parameters) {
- // TODO: Cache !!!
- ReflectedCaller _caller = null;
-
- if (_caller == null) {
- _caller = ReflectedCaller.Create(method);
- }
-
- try {
- if (instance == null) {
- return _caller.Invoke(parameters);
- } else {
- return _caller.InvokeInstance(instance, parameters);
- }
- } catch (Exception e) {
- // Give the language a chance to associate the interpreter stack trace with the exception.
- //
- // Note that this should be called for any exception caused by any Expression node
- // (for example, integer division by zero). For now, doing it for method calls
- // catches a large portion of the interesting cases (including calls into the language's library assembly).
- state.ScriptCode.LanguageContext.InterpretExceptionThrow(state, e, false);
- throw;
- }
- }
-
- private static object InterpretInvocationExpression(InterpreterState state, Expression expr) {
- InvocationExpression node = (InvocationExpression)expr;
-
- // TODO: this should have the same semantics of the compiler
- // in particular, it doesn't handle the case where the left hand
- // side returns a lambda that we need to interpret
- return InterpretMethodCallExpression(state, Expression.Call(node.Expression, node.Expression.Type.GetMethod("Invoke"), ArrayUtils.ToArray(node.Arguments)));
- }
-
- private static object InterpretIndexExpression(InterpreterState state, Expression expr) {
- var node = (IndexExpression)expr;
-
- if (node.Indexer != null) {
- return InterpretMethodCallExpression(
- state,
- Expression.Call(node.Object, node.Indexer.GetGetMethod(true), node.Arguments)
- );
- }
-
- if (node.Arguments.Count != 1) {
- var get = node.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance);
- return InterpretMethodCallExpression(
- state,
- Expression.Call(node.Object, get, node.Arguments)
- );
- }
-
- object array, index;
-
- if (InterpretAndCheckFlow(state, node.Object, out array)) {
- return array;
- }
- if (InterpretAndCheckFlow(state, node.Arguments[0], out index)) {
- return index;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- return ((Array)array).GetValue((int)index);
- }
-
- private static object InterpretMethodCallExpression(InterpreterState state, Expression expr) {
- MethodCallExpression methodCall = (MethodCallExpression)expr;
- return InterpretMethodCallExpression(state, expr, methodCall.Method, methodCall.Object, methodCall.Arguments);
- }
-
- private static object InterpretMethodCallExpression(InterpreterState state, Expression expr,
- MethodInfo method, Expression target, IList<Expression> arguments) {
-
- object instance = null;
- // Evaluate the instance first (if the method is non-static)
- if (!method.IsStatic) {
- if (InterpretAndCheckFlow(state, target, out instance)) {
- return instance;
- }
- }
-
- var parameterInfos = method.GetParameters();
-
- object[] parameters;
- if (!state.TryGetStackState(expr, out parameters)) {
- parameters = new object[parameterInfos.Length];
- }
-
- Debug.Assert(parameters.Length == parameterInfos.Length);
-
- int lastByRefParamIndex = -1;
- var paramAddrs = new EvaluationAddress[parameterInfos.Length];
- for (int i = 0; i < parameterInfos.Length; i++) {
- ParameterInfo info = parameterInfos[i];
-
- if (info.ParameterType.IsByRef) {
- lastByRefParamIndex = i;
- paramAddrs[i] = EvaluateAddress(state, arguments[i]);
-
- object value = paramAddrs[i].GetValue(state, !IsInputParameter(info));
- if (IsInputParameter(info)) {
- if (value != ControlFlow.NextForYield) {
- // implict cast?
- parameters[i] = Cast.Explicit(value, info.ParameterType.GetElementType());
- }
- }
- } else if (IsInputParameter(info)) {
- Expression arg = arguments[i];
- object argValue = null;
- if (arg != null) {
- if (InterpretAndCheckFlow(state, arg, out argValue)) {
- if (state.CurrentYield != null) {
- state.SaveStackState(expr, parameters);
- }
-
- return argValue;
- }
- }
-
- if (argValue != ControlFlow.NextForYield) {
- parameters[i] = argValue;
- }
- }
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- try {
- object res;
- try {
- // Call the method
- res = InvokeMethod(state, method, instance, parameters);
- } finally {
- // expose by-ref args
- for (int i = 0; i <= lastByRefParamIndex; i++) {
- if (parameterInfos[i].ParameterType.IsByRef) {
- paramAddrs[i].AssignValue(state, parameters[i]);
- }
- }
- }
-
- // back propagate instance on value types if the instance supports it.
- if (method.DeclaringType != null && method.DeclaringType.IsValueType && !method.IsStatic) {
- EvaluateAssign(state, target, instance);
- }
-
- return res;
- } catch (TargetInvocationException e) {
- // Unwrap the real (inner) exception and raise it
- throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
- }
- }
-
- private static object InterpretAndAlsoBinaryExpression(InterpreterState state, Expression expr) {
- BinaryExpression node = (BinaryExpression)expr;
- object ret;
- if (InterpretAndCheckFlow(state, node.Left, out ret)) {
- return ret;
- }
-
- if (ret == ControlFlow.NextForYield || (bool)ret) {
- return Interpret(state, node.Right);
- }
-
- return ret;
- }
-
- private static object InterpretOrElseBinaryExpression(InterpreterState state, Expression expr) {
- BinaryExpression node = (BinaryExpression)expr;
- object ret;
- if (InterpretAndCheckFlow(state, node.Left, out ret)) {
- return ret;
- }
-
- if (ret == ControlFlow.NextForYield || !(bool)ret) {
- return Interpret(state, node.Right);
- }
-
- return ret;
- }
-
- // TODO: support conversion lambda
- private static object InterpretCoalesceBinaryExpression(InterpreterState state, Expression expr) {
- BinaryExpression node = (BinaryExpression)expr;
-
- object ret;
- if (InterpretAndCheckFlow(state, node.Left, out ret)) {
- return ret;
- }
-
- if (ret == ControlFlow.NextForYield || ret == null) {
- return Interpret(state, node.Right);
- }
-
- return ret;
- }
-
- private static object InterpretReducibleExpression(InterpreterState state, Expression expr) {
- Debug.Assert(expr.CanReduce);
-
- //expr is an OpAssignement expression.
- //Reduce it before interpreting.
- return Interpret(state, expr.Reduce());
- }
-
- private static object InterpretBinaryExpression(InterpreterState state, Expression expr) {
- BinaryExpression node = (BinaryExpression)expr;
-
- object left, right;
-
- if (InterpretAndCheckFlow(state, node.Left, out left)) {
- return left;
- }
- if (InterpretAndCheckFlow(state, node.Right, out right)) {
- return right;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- if (node.Method != null) {
- return node.Method.Invoke(null, new object[] { left, right });
- } else {
- return EvaluateBinaryOperator(node.NodeType, left, right);
- }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
- private static object EvaluateBinaryOperator(ExpressionType nodeType, object l, object r) {
- switch (nodeType) {
- case ExpressionType.ArrayIndex:
- Array array = (Array)l;
- int index = (int)r;
- return array.GetValue(index);
-
- case ExpressionType.GreaterThan:
- return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) > 0);
- case ExpressionType.LessThan:
- return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) < 0);
- case ExpressionType.GreaterThanOrEqual:
- return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) >= 0);
- case ExpressionType.LessThanOrEqual:
- return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) <= 0);
- case ExpressionType.Equal:
- return ScriptingRuntimeHelpers.BooleanToObject(TestEquals(l, r));
-
- case ExpressionType.NotEqual:
- return ScriptingRuntimeHelpers.BooleanToObject(!TestEquals(l, r));
-
- case ExpressionType.Multiply:
- return EvalMultiply(l, r);
- case ExpressionType.Add:
- return EvalAdd(l, r);
- case ExpressionType.Subtract:
- return EvalSub(l, r);
- case ExpressionType.Divide:
- return EvalDiv(l, r);
- case ExpressionType.Modulo:
- return EvalMod(l, r);
- case ExpressionType.And:
- return EvalAnd(l, r);
- case ExpressionType.Or:
- return EvalOr(l, r);
- case ExpressionType.ExclusiveOr:
- return EvalXor(l, r);
- case ExpressionType.AddChecked:
- return EvalAddChecked(l, r);
- case ExpressionType.MultiplyChecked:
- return EvalMultiplyChecked(l, r);
- case ExpressionType.SubtractChecked:
- return EvalSubChecked(l, r);
- case ExpressionType.Power:
- return EvalPower(l, r);
-
- default:
- throw new NotImplementedException(nodeType.ToString());
- }
- }
-
- private static object EvalMultiply(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l * (int)r);
- if (l is uint) return (uint)l * (uint)r;
- if (l is short) return (short)((short)l * (short)r);
- if (l is ushort) return (ushort)((ushort)l * (ushort)r);
- if (l is long) return (long)l * (long)r;
- if (l is ulong) return (ulong)l * (ulong)r;
- if (l is float) return (float)l * (float)r;
- if (l is double) return (double)l * (double)r;
- throw new InvalidOperationException("multiply: {0} " + CompilerHelpers.GetType(l).Name);
- }
- private static object EvalMultiplyChecked(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l * (int)r));
- if (l is uint) return checked((uint)l * (uint)r);
- if (l is short) return checked((short)((short)l * (short)r));
- if (l is ushort) return checked((ushort)((ushort)l * (ushort)r));
- if (l is long) return checked((long)l * (long)r);
- if (l is ulong) return checked((ulong)l * (ulong)r);
- if (l is float) return checked((float)l * (float)r);
- if (l is double) return checked((double)l * (double)r);
- throw new InvalidOperationException("multiply: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalAdd(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l + (int)r);
- if (l is uint) return (uint)l + (uint)r;
- if (l is short) return (short)((short)l + (short)r);
- if (l is ushort) return (ushort)((ushort)l + (ushort)r);
- if (l is long) return (long)l + (long)r;
- if (l is ulong) return (ulong)l + (ulong)r;
- if (l is float) return (float)l + (float)r;
- if (l is double) return (double)l + (double)r;
- throw new InvalidOperationException("add: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalAddChecked(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l + (int)r));
- if (l is uint) return checked((uint)l + (uint)r);
- if (l is short) return checked((short)((short)l + (short)r));
- if (l is ushort) return checked((ushort)((ushort)l + (ushort)r));
- if (l is long) return checked((long)l + (long)r);
- if (l is ulong) return checked((ulong)l + (ulong)r);
- if (l is float) return checked((float)l + (float)r);
- if (l is double) return checked((double)l + (double)r);
- throw new InvalidOperationException("add: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalSub(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l - (int)r);
- if (l is uint) return (uint)l - (uint)r;
- if (l is short) return (short)((short)l - (short)r);
- if (l is ushort) return (ushort)((ushort)l - (ushort)r);
- if (l is long) return (long)l - (long)r;
- if (l is ulong) return (ulong)l - (ulong)r;
- if (l is float) return (float)l - (float)r;
- if (l is double) return (double)l - (double)r;
- throw new InvalidOperationException("sub: {0} " + CompilerHelpers.GetType(l).Name);
- }
- private static object EvalSubChecked(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l - (int)r));
- if (l is uint) return checked((uint)l - (uint)r);
- if (l is short) return checked((short)((short)l - (short)r));
- if (l is ushort) return checked((ushort)((ushort)l - (ushort)r));
- if (l is long) return checked((long)l - (long)r);
- if (l is ulong) return checked((ulong)l - (ulong)r);
- if (l is float) return checked((float)l - (float)r);
- if (l is double) return checked((double)l - (double)r);
- throw new InvalidOperationException("sub: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalMod(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l % (int)r);
- if (l is uint) return (uint)l % (uint)r;
- if (l is short) return (short)((short)l % (short)r);
- if (l is ushort) return (ushort)((ushort)l % (ushort)r);
- if (l is long) return (long)l % (long)r;
- if (l is ulong) return (ulong)l % (ulong)r;
- if (l is float) return (float)l % (float)r;
- if (l is double) return (double)l % (double)r;
- throw new InvalidOperationException("mod: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalDiv(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l / (int)r);
- if (l is uint) return (uint)l / (uint)r;
- if (l is short) return (short)((short)l / (short)r);
- if (l is ushort) return (ushort)((ushort)l / (ushort)r);
- if (l is long) return (long)l / (long)r;
- if (l is ulong) return (ulong)l / (ulong)r;
- if (l is float) return (float)l / (float)r;
- if (l is double) return (double)l / (double)r;
- throw new InvalidOperationException("div: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalAnd(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l & (int)r);
- if (l is uint) return (uint)l & (uint)r;
- if (l is short) return (short)((short)l & (short)r);
- if (l is ushort) return (ushort)((ushort)l & (ushort)r);
- if (l is long) return (long)l & (long)r;
- if (l is ulong) return (ulong)l & (ulong)r;
- throw new InvalidOperationException("and: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalOr(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l | (int)r);
- if (l is uint) return (uint)l | (uint)r;
- if (l is short) return (short)((short)l | (short)r);
- if (l is ushort) return (ushort)((ushort)l | (ushort)r);
- if (l is long) return (long)l | (long)r;
- if (l is ulong) return (ulong)l | (ulong)r;
- throw new InvalidOperationException("or: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalXor(object l, object r) {
- if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l ^ (int)r);
- if (l is uint) return (uint)l ^ (uint)r;
- if (l is short) return (short)((short)l ^ (short)r);
- if (l is ushort) return (ushort)((ushort)l ^ (ushort)r);
- if (l is long) return (long)l ^ (long)r;
- if (l is ulong) return (ulong)l ^ (ulong)r;
- throw new InvalidOperationException("xor: {0} " + CompilerHelpers.GetType(l).Name);
- }
-
- private static object EvalPower(object l, object r) {
- return System.Math.Pow((double)l, (double)r);
- }
-
- private static object EvalCoalesce(object l, object r) {
- return l ?? r;
- }
-
-
- private static bool TestEquals(object l, object r) {
- // We don't need to go through the same type checks as the emit case,
- // since we know we're always dealing with boxed objects.
-
- return Object.Equals(l, r);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
- private static object InterpretQuoteUnaryExpression(InterpreterState state, Expression expr) {
- // TODO: should we do all the fancy tree rewrite stuff here?
- return ((UnaryExpression)expr).Operand;
- }
-
- private static object InterpretUnboxUnaryExpression(InterpreterState state, Expression expr) {
- UnaryExpression node = (UnaryExpression)expr;
-
- object value;
- if (InterpretAndCheckFlow(state, node.Operand, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- if (value != null && node.Type == value.GetType()) {
- return value;
- }
-
- throw new InvalidCastException(string.Format("cannot unbox value to type '{0}'", node.Type));
- }
-
- private static object InterpretConvertUnaryExpression(InterpreterState state, Expression expr) {
- UnaryExpression node = (UnaryExpression)expr;
-
- if (node.Method != null) {
- return InterpretMethodCallExpression(state, expr, node.Method, null, new[] { node.Operand });
- }
-
- object value;
- if (InterpretAndCheckFlow(state, node.Operand, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- if (node.Type == typeof(void)) {
- return null;
- }
-
- // TODO: distinguish between Convert and ConvertChecked
- // TODO: semantics should match compiler
- return Cast.Explicit(value, node.Type);
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
- private static object InterpretUnaryExpression(InterpreterState state, Expression expr) {
- UnaryExpression node = (UnaryExpression)expr;
-
- object value;
- if (InterpretAndCheckFlow(state, node.Operand, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- switch (node.NodeType) {
- case ExpressionType.TypeAs:
- if (value != null && expr.Type.IsAssignableFrom(value.GetType())) {
- return value;
- } else {
- return null;
- }
-
- case ExpressionType.Not:
- if (value is bool) return (bool)value ? ScriptingRuntimeHelpers.False : ScriptingRuntimeHelpers.True;
- if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)~(int)value);
- if (value is long) return (long)~(long)value;
- if (value is short) return (short)~(short)value;
- if (value is uint) return (uint)~(uint)value;
- if (value is ulong) return (ulong)~(ulong)value;
- if (value is ushort) return (ushort)~(ushort)value;
- if (value is byte) return (byte)~(byte)value;
- if (value is sbyte) return (sbyte)~(sbyte)value;
- throw new InvalidOperationException("can't perform unary not on type " + CompilerHelpers.GetType(value).Name);
-
- case ExpressionType.Negate:
- if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)(-(int)value));
- if (value is long) return (long)(-(long)value);
- if (value is short) return (short)(-(short)value);
- if (value is float) return -(float)value;
- if (value is double) return -(double)value;
- throw new InvalidOperationException("can't negate type " + CompilerHelpers.GetType(value).Name);
-
- case ExpressionType.UnaryPlus:
- if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)+(int)value);
- if (value is long) return (long)+(long)value;
- if (value is short) return (short)+(short)value;
- if (value is uint) return (uint)+(uint)value;
- if (value is ulong) return (ulong)+(ulong)value;
- if (value is ushort) return (ushort)+(ushort)value;
- if (value is byte) return (byte)+(byte)value;
- if (value is sbyte) return (sbyte)+(sbyte)value;
- throw new InvalidOperationException("can't perform unary plus on type " + CompilerHelpers.GetType(value).Name);
-
- case ExpressionType.NegateChecked:
- if (value is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)(-(int)value)));
- if (value is long) return checked((long)(-(long)value));
- if (value is short) return checked((short)(-(short)value));
- if (value is float) return checked(-(float)value);
- if (value is double) return checked(-(double)value);
- throw new InvalidOperationException("can't negate type " + CompilerHelpers.GetType(value).Name);
-
- case ExpressionType.ArrayLength:
- System.Array arr = (System.Array)value;
- return arr.Length;
-
- default:
- throw new NotImplementedException();
- }
- }
-
- private static object InterpretRuntimeVariablesExpression(InterpreterState state, Expression expr) {
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- RuntimeVariablesExpression node = (RuntimeVariablesExpression)expr;
- return new InterpreterVariables(state, node);
- }
-
- private static object InterpretNewExpression(InterpreterState state, Expression expr) {
- NewExpression node = (NewExpression)expr;
-
- object[] args = new object[node.Arguments.Count];
- for (int i = 0; i < node.Arguments.Count; i++) {
- object argValue;
- if (InterpretAndCheckFlow(state, node.Arguments[i], out argValue)) {
- return argValue;
- }
- args[i] = argValue;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- try {
- return node.Constructor.Invoke(args);
- } catch (TargetInvocationException e) {
- throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
- }
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
- private static object InterpretListInitExpression(InterpreterState state, Expression expr) {
- throw new NotImplementedException("InterpretListInitExpression");
- }
-
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
- private static object InterpretMemberInitExpression(InterpreterState state, Expression expr) {
- throw new NotImplementedException("InterpretMemberInitExpression");
- }
-
- private static object InterpretTypeBinaryExpression(InterpreterState state, Expression expr) {
- TypeBinaryExpression node = (TypeBinaryExpression)expr;
-
- object value;
- if (InterpretAndCheckFlow(state, node.Expression, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- bool result;
- if (node.NodeType == ExpressionType.TypeEqual) {
- result = value != null && value.GetType() == node.TypeOperand;
- } else {
- result = node.TypeOperand.IsInstanceOfType(value);
- }
- return ScriptingRuntimeHelpers.BooleanToObject(result);
- }
-
- private static object InterpretDynamicExpression(InterpreterState state, Expression expr) {
- DynamicExpression node = (DynamicExpression)expr;
- var arguments = node.Arguments;
-
- object[] args;
- if (!state.TryGetStackState(node, out args)) {
- args = new object[arguments.Count];
- }
-
- for (int i = 0, n = arguments.Count; i < n; i++) {
- object argValue;
- if (InterpretAndCheckFlow(state, arguments[i], out argValue)) {
- if (state.CurrentYield != null) {
- state.SaveStackState(node, args);
- }
-
- return argValue;
- }
- if (argValue != ControlFlow.NextForYield) {
- args[i] = argValue;
- }
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- var metaAction = node.Binder as DynamicMetaObjectBinder;
- if (metaAction != null) {
- return InterpretMetaAction(state, metaAction, node, args);
- }
-
- PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.Site: Compiling non-meta-action");
- var callSiteInfo = GetCallSite(state, node);
- return callSiteInfo.CallerTarget(callSiteInfo.CallSite, args);
- }
-
- private const int SiteCompileThreshold = 2;
-
- private static object InterpretMetaAction(InterpreterState state, DynamicMetaObjectBinder action, DynamicExpression node, object[] argValues) {
- var callSites = state.LambdaState.ScriptCode.CallSites;
- CallSiteInfo callSiteInfo;
-
- // TODO: better locking
- lock (callSites) {
- if (!callSites.TryGetValue(node, out callSiteInfo)) {
- callSiteInfo = new CallSiteInfo();
- callSites.Add(node, callSiteInfo);
- }
- }
-
- callSiteInfo.Counter++;
- if (callSiteInfo.Counter > SiteCompileThreshold) {
- if (callSiteInfo.CallSite == null) {
- SetCallSite(callSiteInfo, node);
- }
-
- try {
- return callSiteInfo.CallerTarget(callSiteInfo.CallSite, argValues);
- } catch(Exception e) {
- state.ScriptCode.LanguageContext.InterpretExceptionThrow(state, e, false);
- throw;
- }
- }
-
- PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter: Interpreting meta-action");
-
- if (argValues.Length == 0) {
- throw new InvalidOperationException();
- }
-
- DynamicMetaObject[] args = DynamicMetaObject.EmptyMetaObjects;
- if (argValues.Length != 1) {
- args = new DynamicMetaObject[argValues.Length - 1];
- for (int i = 0; i < args.Length; i++) {
- args[i] = DynamicUtils.ObjectToMetaObject(
- argValues[i + 1],
- AstUtils.Constant(argValues[i + 1])
- );
- }
- }
-
- object result;
- ControlFlow flow;
- do {
- DynamicMetaObject binding = action.Bind(
- DynamicUtils.ObjectToMetaObject(
- argValues[0],
- AstUtils.Constant(argValues[0])
- ),
- args
- );
-
- if (binding == null) {
- throw new InvalidOperationException("Bind cannot return null.");
- }
-
- // restrictions ignored, they should be valid:
- AssertTrueRestrictions(state, binding);
-
- result = Interpret(state, binding.Expression);
- flow = result as ControlFlow;
-
- } while (flow != null && flow.Kind == ControlFlowKind.Goto && flow.Label == CallSiteBinder.UpdateLabel);
-
- return result;
- }
-
- [Conditional("DEBUG")]
- private static void AssertTrueRestrictions(InterpreterState state, DynamicMetaObject binding) {
- var test = binding.Restrictions.ToExpression();
- var result = Interpret(state, test);
- Debug.Assert(result is bool && (bool)result);
- }
-
- private static CallSiteInfo GetCallSite(InterpreterState state, DynamicExpression node) {
- CallSiteInfo callSiteInfo;
- var callSites = state.LambdaState.ScriptCode.CallSites;
-
- // TODO: better locking
- lock (callSites) {
- if (!callSites.TryGetValue(node, out callSiteInfo)) {
- callSiteInfo = new CallSiteInfo();
- SetCallSite(callSiteInfo, node);
- callSites.Add(node, callSiteInfo);
- }
- }
-
- return callSiteInfo;
- }
-
- // The ReflectiveCaller cache
- private static readonly Dictionary<ValueArray<Type>, ReflectedCaller> _executeSites = new Dictionary<ValueArray<Type>, ReflectedCaller>();
-
- private static void SetCallSite(CallSiteInfo info, DynamicExpression node) {
- var arguments = node.Arguments;
-
- // TODO: remove CodeContext special case
- if (arguments.Count > 0 && arguments[0].Type != typeof(CodeContext)) {
- switch (arguments.Count) {
- case 0:
- info.CallSite = CallSite<Func<CallSite, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target0);
- return;
-
- case 1:
- info.CallSite = CallSite<Func<CallSite, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target1);
- return;
-
- case 2:
- info.CallSite = CallSite<Func<CallSite, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target2);
- return;
-
- case 3:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target3);
- return;
-
- case 4:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target4);
- return;
-
- case 5:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target5);
- return;
-
- case 6:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target6);
- return;
-
- case 7:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target7);
- return;
-
- case 8:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target8);
- return;
-
- case 9:
- info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object, object>>.Create(node.Binder);
- info.CallerTarget = new MatchCallerTarget(MatchCaller.Target9);
- return;
- }
- }
-
- var callSite = CreateCallSite(node);
- info.CallSite = callSite;
- info.CallerTarget = MatchCaller.GetCaller((callSite.GetType().GetGenericArguments()[0]));
- }
-
- private static CallSite CreateCallSite(DynamicExpression node) {
- var arguments = node.Arguments;
-
- // non-optimized signatures:
- Type[] types = CompilerHelpers.GetSiteTypes(arguments, node.Type);
-
- int i = (arguments.Count > 0 && arguments[0].Type != typeof(CodeContext)) ? 1 : 0;
-
- for (; i < arguments.Count; i++) {
- if (!arguments[i].Type.IsByRef) {
- types[i] = typeof(object);
- }
- }
-
- ReflectedCaller rc;
- lock (_executeSites) {
- ValueArray<Type> array = new ValueArray<Type>(types);
- if (!_executeSites.TryGetValue(array, out rc)) {
- Type delegateType = DynamicSiteHelpers.MakeCallSiteDelegate(types);
- MethodInfo target = typeof(InterpreterHelpers).GetMethod("CreateSite").MakeGenericMethod(delegateType);
- _executeSites[array] = rc = ReflectedCaller.Create(target);
- }
- }
-
- return (CallSite)rc.Invoke(node.Binder);
- }
-
- private static object InterpretIndexAssignment(InterpreterState state, BinaryExpression node) {
- var index = (IndexExpression)node.Left;
-
- object instance, value;
- var args = new object[index.Arguments.Count];
-
- if (InterpretAndCheckFlow(state, index.Object, out instance)) {
- return instance;
- }
-
- for (int i = 0; i < index.Arguments.Count; i++) {
- object arg;
- if (InterpretAndCheckFlow(state, index.Arguments[i], out arg)) {
- return arg;
- }
- args[i] = arg;
- }
-
- if (InterpretAndCheckFlow(state, node.Right, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- if (index.Indexer != null) {
- // For indexed properties, just call the setter
- InvokeMethod(state, index.Indexer.GetSetMethod(true), instance, args);
- } else if (index.Arguments.Count != 1) {
- // Multidimensional arrays, call set
- var set = index.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance);
- InvokeMethod(state, set, instance, args);
- } else {
- ((Array)instance).SetValue(value, (int)args[0]);
- }
-
- return value;
- }
-
- private static object InterpretVariableAssignment(InterpreterState state, Expression expr) {
- var node = (BinaryExpression)expr;
- object value;
- if (InterpretAndCheckFlow(state, node.Right, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- EvaluateAssignVariable(state, node.Left, value);
- return value;
- }
-
- private static object InterpretAssignBinaryExpression(InterpreterState state, Expression expr) {
- var node = (BinaryExpression)expr;
- switch (node.Left.NodeType) {
- case ExpressionType.Index:
- return InterpretIndexAssignment(state, node);
- case ExpressionType.MemberAccess:
- return InterpretMemberAssignment(state, node);
- case ExpressionType.Parameter:
- case ExpressionType.Extension:
- return InterpretVariableAssignment(state, node);
- default:
- throw new InvalidOperationException("Invalid lvalue for assignment: " + node.Left.NodeType);
- }
- }
-
- private static object InterpretParameterExpression(InterpreterState state, Expression expr) {
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- return state.GetValue(expr);
- }
-
- private static object InterpretLambdaExpression(InterpreterState state, Expression expr) {
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- LambdaExpression node = (LambdaExpression)expr;
- return GetDelegateForInterpreter(state, node);
- }
-
- private static object InterpretMemberAssignment(InterpreterState state, BinaryExpression node) {
- var left = (MemberExpression)node.Left;
-
- object target = null, value;
- if (left.Expression != null) {
- if (InterpretAndCheckFlow(state, left.Expression, out target)) {
- return target;
- }
- }
- if (InterpretAndCheckFlow(state, node.Right, out value)) {
- return value;
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- switch (left.Member.MemberType) {
- case MemberTypes.Field:
- FieldInfo field = (FieldInfo)left.Member;
- field.SetValue(target, value);
- break;
- case MemberTypes.Property:
- PropertyInfo property = (PropertyInfo)left.Member;
- property.SetValue(target, value, null);
- break;
- default:
- Debug.Assert(false, "Invalid member type");
- break;
- }
- return value;
- }
-
- private static object InterpretMemberExpression(InterpreterState state, Expression expr) {
- MemberExpression node = (MemberExpression)expr;
-
- object self = null;
- if (node.Expression != null) {
- if (InterpretAndCheckFlow(state, node.Expression, out self)) {
- return self;
- }
- }
-
- if (state.CurrentYield != null) {
- return ControlFlow.NextForYield;
- }
-
- switch (node.Member.MemberType) {
- case MemberTypes.Field:
- FieldInfo field = (FieldInfo)node.Member;
- return field.GetValue(self);
- case MemberTypes.Property:
- PropertyInfo property = (PropertyInfo)node.Member;
- return property.GetValue(self, ArrayUtils.EmptyObjects);
- default:
- Debug.Assert(false, "Invalid member type");
- break;
- }
-
- throw new InvalidOperationException();
- }
-
- private static object InterpretNewArrayExpression(InterpreterState state, Expression expr) {
- NewArrayExpression node = (NewArrayExpression)expr;
- ConstructorInfo constructor;
-
- if (node.NodeType == ExpressionType.NewArrayBounds) {
- int rank = node.Type.GetArrayRank();
- Type[] types = new Type[rank];
- object[] bounds = new object[rank];
- for (int i = 0; i < rank; i++) {
- types[…
Large files files are truncated, but you can click here to view the full file