PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Microsoft.Scripting/Interpretation/Interpreter.cs

https://bitbucket.org/stefanrusek/xronos
C# | 1634 lines | 1271 code | 271 blank | 92 comment | 433 complexity | 7c23130bf3795bc2de4b8c1335fc0cc2 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if CODEPLEX_40
  16. using System;
  17. #else
  18. using System; using Microsoft;
  19. #endif
  20. using System.Collections.Generic;
  21. using System.Collections.ObjectModel;
  22. using System.Diagnostics;
  23. #if CODEPLEX_40
  24. using System.Linq.Expressions;
  25. #else
  26. using Microsoft.Linq.Expressions;
  27. #endif
  28. using System.Reflection;
  29. using System.Runtime.CompilerServices;
  30. #if !CODEPLEX_40
  31. using Microsoft.Runtime.CompilerServices;
  32. #endif
  33. #if CODEPLEX_40
  34. using System.Dynamic;
  35. #else
  36. using Microsoft.Scripting;
  37. #endif
  38. using Microsoft.Scripting.Actions;
  39. using Microsoft.Scripting.Ast;
  40. using Microsoft.Scripting.Generation;
  41. using Microsoft.Scripting.Runtime;
  42. using Microsoft.Scripting.Utils;
  43. using AstUtils = Microsoft.Scripting.Ast.Utils;
  44. [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Microsoft.Scripting.Interpretation")]
  45. namespace Microsoft.Scripting.Interpretation {
  46. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
  47. public static partial class Interpreter {
  48. #region Entry points
  49. public static object TopLevelExecute(InterpretedScriptCode scriptCode, params object[] args) {
  50. ContractUtils.RequiresNotNull(scriptCode, "scriptCode");
  51. var state = InterpreterState.Current.Update(
  52. (caller) => InterpreterState.CreateForTopLambda(scriptCode, scriptCode.Code, caller, args)
  53. );
  54. try {
  55. return DoExecute(state, scriptCode.Code);
  56. } finally {
  57. InterpreterState.Current.Value = state.Caller;
  58. }
  59. }
  60. internal static object Evaluate(InterpreterState state, Expression expression) {
  61. object result = Interpret(state, expression);
  62. if (result is ControlFlow) {
  63. throw new InvalidOperationException("Invalid expression");
  64. }
  65. return result;
  66. }
  67. internal static object ExecuteGenerator(InterpreterState state, Expression expression) {
  68. return Interpret(state, expression);
  69. }
  70. #endregion
  71. /// <summary>
  72. /// Evaluates expression and checks it for ControlFlow. If it is control flow, returns true,
  73. /// otherwise returns false.
  74. /// </summary>
  75. /// <param name="state"></param>
  76. /// <param name="node"></param>
  77. /// <param name="result">Result of the evaluation</param>
  78. /// <returns>true if control flow, false if not</returns>
  79. private static bool InterpretAndCheckFlow(InterpreterState state, Expression node, out object result) {
  80. result = Interpret(state, node);
  81. return result != ControlFlow.NextForYield && result is ControlFlow;
  82. }
  83. /// <summary>
  84. /// Evaluates an expression and checks to see if the ControlFlow is NextForYield. If it is then we are currently
  85. /// searching for the next yield and we need to execute any additional nodes in a larger compound node.
  86. /// </summary>
  87. private static bool InterpretAndCheckYield(InterpreterState state, Expression target, out object res) {
  88. res = Interpret(state, target);
  89. if (res != ControlFlow.NextForYield) {
  90. return true;
  91. }
  92. return false;
  93. }
  94. // Individual expressions and statements
  95. private static object InterpretConstantExpression(InterpreterState state, Expression expr) {
  96. if (state.CurrentYield != null) {
  97. return ControlFlow.NextForYield;
  98. }
  99. ConstantExpression node = (ConstantExpression)expr;
  100. return node.Value;
  101. }
  102. private static object InterpretConditionalExpression(InterpreterState state, Expression expr) {
  103. ConditionalExpression node = (ConditionalExpression)expr;
  104. object test;
  105. if (InterpretAndCheckFlow(state, node.Test, out test)) {
  106. return test;
  107. }
  108. if (test == ControlFlow.NextForYield || (bool)test) {
  109. if (InterpretAndCheckYield(state, node.IfTrue, out test)) {
  110. return test;
  111. }
  112. }
  113. return Interpret(state, node.IfFalse);
  114. }
  115. private static bool IsInputParameter(ParameterInfo pi) {
  116. return !pi.IsOut || (pi.Attributes & ParameterAttributes.In) != 0;
  117. }
  118. private static object InvokeMethod(InterpreterState state, MethodInfo method, object instance, params object[] parameters) {
  119. // TODO: Cache !!!
  120. ReflectedCaller _caller = null;
  121. if (_caller == null) {
  122. _caller = ReflectedCaller.Create(method);
  123. }
  124. try {
  125. if (instance == null) {
  126. return _caller.Invoke(parameters);
  127. } else {
  128. return _caller.InvokeInstance(instance, parameters);
  129. }
  130. } catch (Exception e) {
  131. // Give the language a chance to associate the interpreter stack trace with the exception.
  132. //
  133. // Note that this should be called for any exception caused by any Expression node
  134. // (for example, integer division by zero). For now, doing it for method calls
  135. // catches a large portion of the interesting cases (including calls into the language's library assembly).
  136. state.ScriptCode.LanguageContext.InterpretExceptionThrow(state, e, false);
  137. throw;
  138. }
  139. }
  140. private static object InterpretInvocationExpression(InterpreterState state, Expression expr) {
  141. InvocationExpression node = (InvocationExpression)expr;
  142. // TODO: this should have the same semantics of the compiler
  143. // in particular, it doesn't handle the case where the left hand
  144. // side returns a lambda that we need to interpret
  145. return InterpretMethodCallExpression(state, Expression.Call(node.Expression, node.Expression.Type.GetMethod("Invoke"), ArrayUtils.ToArray(node.Arguments)));
  146. }
  147. private static object InterpretIndexExpression(InterpreterState state, Expression expr) {
  148. var node = (IndexExpression)expr;
  149. if (node.Indexer != null) {
  150. return InterpretMethodCallExpression(
  151. state,
  152. Expression.Call(node.Object, node.Indexer.GetGetMethod(true), node.Arguments)
  153. );
  154. }
  155. if (node.Arguments.Count != 1) {
  156. var get = node.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance);
  157. return InterpretMethodCallExpression(
  158. state,
  159. Expression.Call(node.Object, get, node.Arguments)
  160. );
  161. }
  162. object array, index;
  163. if (InterpretAndCheckFlow(state, node.Object, out array)) {
  164. return array;
  165. }
  166. if (InterpretAndCheckFlow(state, node.Arguments[0], out index)) {
  167. return index;
  168. }
  169. if (state.CurrentYield != null) {
  170. return ControlFlow.NextForYield;
  171. }
  172. return ((Array)array).GetValue((int)index);
  173. }
  174. private static object InterpretMethodCallExpression(InterpreterState state, Expression expr) {
  175. MethodCallExpression methodCall = (MethodCallExpression)expr;
  176. return InterpretMethodCallExpression(state, expr, methodCall.Method, methodCall.Object, methodCall.Arguments);
  177. }
  178. private static object InterpretMethodCallExpression(InterpreterState state, Expression expr,
  179. MethodInfo method, Expression target, IList<Expression> arguments) {
  180. object instance = null;
  181. // Evaluate the instance first (if the method is non-static)
  182. if (!method.IsStatic) {
  183. if (InterpretAndCheckFlow(state, target, out instance)) {
  184. return instance;
  185. }
  186. }
  187. var parameterInfos = method.GetParameters();
  188. object[] parameters;
  189. if (!state.TryGetStackState(expr, out parameters)) {
  190. parameters = new object[parameterInfos.Length];
  191. }
  192. Debug.Assert(parameters.Length == parameterInfos.Length);
  193. int lastByRefParamIndex = -1;
  194. var paramAddrs = new EvaluationAddress[parameterInfos.Length];
  195. for (int i = 0; i < parameterInfos.Length; i++) {
  196. ParameterInfo info = parameterInfos[i];
  197. if (info.ParameterType.IsByRef) {
  198. lastByRefParamIndex = i;
  199. paramAddrs[i] = EvaluateAddress(state, arguments[i]);
  200. object value = paramAddrs[i].GetValue(state, !IsInputParameter(info));
  201. if (IsInputParameter(info)) {
  202. if (value != ControlFlow.NextForYield) {
  203. // implict cast?
  204. parameters[i] = Cast.Explicit(value, info.ParameterType.GetElementType());
  205. }
  206. }
  207. } else if (IsInputParameter(info)) {
  208. Expression arg = arguments[i];
  209. object argValue = null;
  210. if (arg != null) {
  211. if (InterpretAndCheckFlow(state, arg, out argValue)) {
  212. if (state.CurrentYield != null) {
  213. state.SaveStackState(expr, parameters);
  214. }
  215. return argValue;
  216. }
  217. }
  218. if (argValue != ControlFlow.NextForYield) {
  219. parameters[i] = argValue;
  220. }
  221. }
  222. }
  223. if (state.CurrentYield != null) {
  224. return ControlFlow.NextForYield;
  225. }
  226. try {
  227. object res;
  228. try {
  229. // Call the method
  230. res = InvokeMethod(state, method, instance, parameters);
  231. } finally {
  232. // expose by-ref args
  233. for (int i = 0; i <= lastByRefParamIndex; i++) {
  234. if (parameterInfos[i].ParameterType.IsByRef) {
  235. paramAddrs[i].AssignValue(state, parameters[i]);
  236. }
  237. }
  238. }
  239. // back propagate instance on value types if the instance supports it.
  240. if (method.DeclaringType != null && method.DeclaringType.IsValueType && !method.IsStatic) {
  241. EvaluateAssign(state, target, instance);
  242. }
  243. return res;
  244. } catch (TargetInvocationException e) {
  245. // Unwrap the real (inner) exception and raise it
  246. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  247. }
  248. }
  249. private static object InterpretAndAlsoBinaryExpression(InterpreterState state, Expression expr) {
  250. BinaryExpression node = (BinaryExpression)expr;
  251. object ret;
  252. if (InterpretAndCheckFlow(state, node.Left, out ret)) {
  253. return ret;
  254. }
  255. if (ret == ControlFlow.NextForYield || (bool)ret) {
  256. return Interpret(state, node.Right);
  257. }
  258. return ret;
  259. }
  260. private static object InterpretOrElseBinaryExpression(InterpreterState state, Expression expr) {
  261. BinaryExpression node = (BinaryExpression)expr;
  262. object ret;
  263. if (InterpretAndCheckFlow(state, node.Left, out ret)) {
  264. return ret;
  265. }
  266. if (ret == ControlFlow.NextForYield || !(bool)ret) {
  267. return Interpret(state, node.Right);
  268. }
  269. return ret;
  270. }
  271. // TODO: support conversion lambda
  272. private static object InterpretCoalesceBinaryExpression(InterpreterState state, Expression expr) {
  273. BinaryExpression node = (BinaryExpression)expr;
  274. object ret;
  275. if (InterpretAndCheckFlow(state, node.Left, out ret)) {
  276. return ret;
  277. }
  278. if (ret == ControlFlow.NextForYield || ret == null) {
  279. return Interpret(state, node.Right);
  280. }
  281. return ret;
  282. }
  283. private static object InterpretReducibleExpression(InterpreterState state, Expression expr) {
  284. Debug.Assert(expr.CanReduce);
  285. //expr is an OpAssignement expression.
  286. //Reduce it before interpreting.
  287. return Interpret(state, expr.Reduce());
  288. }
  289. private static object InterpretBinaryExpression(InterpreterState state, Expression expr) {
  290. BinaryExpression node = (BinaryExpression)expr;
  291. object left, right;
  292. if (InterpretAndCheckFlow(state, node.Left, out left)) {
  293. return left;
  294. }
  295. if (InterpretAndCheckFlow(state, node.Right, out right)) {
  296. return right;
  297. }
  298. if (state.CurrentYield != null) {
  299. return ControlFlow.NextForYield;
  300. }
  301. if (node.Method != null) {
  302. return node.Method.Invoke(null, new object[] { left, right });
  303. } else {
  304. return EvaluateBinaryOperator(node.NodeType, left, right);
  305. }
  306. }
  307. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]
  308. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  309. private static object EvaluateBinaryOperator(ExpressionType nodeType, object l, object r) {
  310. switch (nodeType) {
  311. case ExpressionType.ArrayIndex:
  312. Array array = (Array)l;
  313. int index = (int)r;
  314. return array.GetValue(index);
  315. case ExpressionType.GreaterThan:
  316. return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) > 0);
  317. case ExpressionType.LessThan:
  318. return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) < 0);
  319. case ExpressionType.GreaterThanOrEqual:
  320. return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) >= 0);
  321. case ExpressionType.LessThanOrEqual:
  322. return ScriptingRuntimeHelpers.BooleanToObject(((IComparable)l).CompareTo(r) <= 0);
  323. case ExpressionType.Equal:
  324. return ScriptingRuntimeHelpers.BooleanToObject(TestEquals(l, r));
  325. case ExpressionType.NotEqual:
  326. return ScriptingRuntimeHelpers.BooleanToObject(!TestEquals(l, r));
  327. case ExpressionType.Multiply:
  328. return EvalMultiply(l, r);
  329. case ExpressionType.Add:
  330. return EvalAdd(l, r);
  331. case ExpressionType.Subtract:
  332. return EvalSub(l, r);
  333. case ExpressionType.Divide:
  334. return EvalDiv(l, r);
  335. case ExpressionType.Modulo:
  336. return EvalMod(l, r);
  337. case ExpressionType.And:
  338. return EvalAnd(l, r);
  339. case ExpressionType.Or:
  340. return EvalOr(l, r);
  341. case ExpressionType.ExclusiveOr:
  342. return EvalXor(l, r);
  343. case ExpressionType.AddChecked:
  344. return EvalAddChecked(l, r);
  345. case ExpressionType.MultiplyChecked:
  346. return EvalMultiplyChecked(l, r);
  347. case ExpressionType.SubtractChecked:
  348. return EvalSubChecked(l, r);
  349. case ExpressionType.Power:
  350. return EvalPower(l, r);
  351. default:
  352. throw new NotImplementedException(nodeType.ToString());
  353. }
  354. }
  355. private static object EvalMultiply(object l, object r) {
  356. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l * (int)r);
  357. if (l is uint) return (uint)l * (uint)r;
  358. if (l is short) return (short)((short)l * (short)r);
  359. if (l is ushort) return (ushort)((ushort)l * (ushort)r);
  360. if (l is long) return (long)l * (long)r;
  361. if (l is ulong) return (ulong)l * (ulong)r;
  362. if (l is float) return (float)l * (float)r;
  363. if (l is double) return (double)l * (double)r;
  364. throw new InvalidOperationException("multiply: {0} " + CompilerHelpers.GetType(l).Name);
  365. }
  366. private static object EvalMultiplyChecked(object l, object r) {
  367. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l * (int)r));
  368. if (l is uint) return checked((uint)l * (uint)r);
  369. if (l is short) return checked((short)((short)l * (short)r));
  370. if (l is ushort) return checked((ushort)((ushort)l * (ushort)r));
  371. if (l is long) return checked((long)l * (long)r);
  372. if (l is ulong) return checked((ulong)l * (ulong)r);
  373. if (l is float) return checked((float)l * (float)r);
  374. if (l is double) return checked((double)l * (double)r);
  375. throw new InvalidOperationException("multiply: {0} " + CompilerHelpers.GetType(l).Name);
  376. }
  377. private static object EvalAdd(object l, object r) {
  378. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l + (int)r);
  379. if (l is uint) return (uint)l + (uint)r;
  380. if (l is short) return (short)((short)l + (short)r);
  381. if (l is ushort) return (ushort)((ushort)l + (ushort)r);
  382. if (l is long) return (long)l + (long)r;
  383. if (l is ulong) return (ulong)l + (ulong)r;
  384. if (l is float) return (float)l + (float)r;
  385. if (l is double) return (double)l + (double)r;
  386. throw new InvalidOperationException("add: {0} " + CompilerHelpers.GetType(l).Name);
  387. }
  388. private static object EvalAddChecked(object l, object r) {
  389. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l + (int)r));
  390. if (l is uint) return checked((uint)l + (uint)r);
  391. if (l is short) return checked((short)((short)l + (short)r));
  392. if (l is ushort) return checked((ushort)((ushort)l + (ushort)r));
  393. if (l is long) return checked((long)l + (long)r);
  394. if (l is ulong) return checked((ulong)l + (ulong)r);
  395. if (l is float) return checked((float)l + (float)r);
  396. if (l is double) return checked((double)l + (double)r);
  397. throw new InvalidOperationException("add: {0} " + CompilerHelpers.GetType(l).Name);
  398. }
  399. private static object EvalSub(object l, object r) {
  400. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l - (int)r);
  401. if (l is uint) return (uint)l - (uint)r;
  402. if (l is short) return (short)((short)l - (short)r);
  403. if (l is ushort) return (ushort)((ushort)l - (ushort)r);
  404. if (l is long) return (long)l - (long)r;
  405. if (l is ulong) return (ulong)l - (ulong)r;
  406. if (l is float) return (float)l - (float)r;
  407. if (l is double) return (double)l - (double)r;
  408. throw new InvalidOperationException("sub: {0} " + CompilerHelpers.GetType(l).Name);
  409. }
  410. private static object EvalSubChecked(object l, object r) {
  411. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)l - (int)r));
  412. if (l is uint) return checked((uint)l - (uint)r);
  413. if (l is short) return checked((short)((short)l - (short)r));
  414. if (l is ushort) return checked((ushort)((ushort)l - (ushort)r));
  415. if (l is long) return checked((long)l - (long)r);
  416. if (l is ulong) return checked((ulong)l - (ulong)r);
  417. if (l is float) return checked((float)l - (float)r);
  418. if (l is double) return checked((double)l - (double)r);
  419. throw new InvalidOperationException("sub: {0} " + CompilerHelpers.GetType(l).Name);
  420. }
  421. private static object EvalMod(object l, object r) {
  422. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l % (int)r);
  423. if (l is uint) return (uint)l % (uint)r;
  424. if (l is short) return (short)((short)l % (short)r);
  425. if (l is ushort) return (ushort)((ushort)l % (ushort)r);
  426. if (l is long) return (long)l % (long)r;
  427. if (l is ulong) return (ulong)l % (ulong)r;
  428. if (l is float) return (float)l % (float)r;
  429. if (l is double) return (double)l % (double)r;
  430. throw new InvalidOperationException("mod: {0} " + CompilerHelpers.GetType(l).Name);
  431. }
  432. private static object EvalDiv(object l, object r) {
  433. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l / (int)r);
  434. if (l is uint) return (uint)l / (uint)r;
  435. if (l is short) return (short)((short)l / (short)r);
  436. if (l is ushort) return (ushort)((ushort)l / (ushort)r);
  437. if (l is long) return (long)l / (long)r;
  438. if (l is ulong) return (ulong)l / (ulong)r;
  439. if (l is float) return (float)l / (float)r;
  440. if (l is double) return (double)l / (double)r;
  441. throw new InvalidOperationException("div: {0} " + CompilerHelpers.GetType(l).Name);
  442. }
  443. private static object EvalAnd(object l, object r) {
  444. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l & (int)r);
  445. if (l is uint) return (uint)l & (uint)r;
  446. if (l is short) return (short)((short)l & (short)r);
  447. if (l is ushort) return (ushort)((ushort)l & (ushort)r);
  448. if (l is long) return (long)l & (long)r;
  449. if (l is ulong) return (ulong)l & (ulong)r;
  450. throw new InvalidOperationException("and: {0} " + CompilerHelpers.GetType(l).Name);
  451. }
  452. private static object EvalOr(object l, object r) {
  453. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l | (int)r);
  454. if (l is uint) return (uint)l | (uint)r;
  455. if (l is short) return (short)((short)l | (short)r);
  456. if (l is ushort) return (ushort)((ushort)l | (ushort)r);
  457. if (l is long) return (long)l | (long)r;
  458. if (l is ulong) return (ulong)l | (ulong)r;
  459. throw new InvalidOperationException("or: {0} " + CompilerHelpers.GetType(l).Name);
  460. }
  461. private static object EvalXor(object l, object r) {
  462. if (l is int) return ScriptingRuntimeHelpers.Int32ToObject((int)l ^ (int)r);
  463. if (l is uint) return (uint)l ^ (uint)r;
  464. if (l is short) return (short)((short)l ^ (short)r);
  465. if (l is ushort) return (ushort)((ushort)l ^ (ushort)r);
  466. if (l is long) return (long)l ^ (long)r;
  467. if (l is ulong) return (ulong)l ^ (ulong)r;
  468. throw new InvalidOperationException("xor: {0} " + CompilerHelpers.GetType(l).Name);
  469. }
  470. private static object EvalPower(object l, object r) {
  471. return System.Math.Pow((double)l, (double)r);
  472. }
  473. private static object EvalCoalesce(object l, object r) {
  474. return l ?? r;
  475. }
  476. private static bool TestEquals(object l, object r) {
  477. // We don't need to go through the same type checks as the emit case,
  478. // since we know we're always dealing with boxed objects.
  479. return Object.Equals(l, r);
  480. }
  481. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  482. private static object InterpretQuoteUnaryExpression(InterpreterState state, Expression expr) {
  483. // TODO: should we do all the fancy tree rewrite stuff here?
  484. return ((UnaryExpression)expr).Operand;
  485. }
  486. private static object InterpretUnboxUnaryExpression(InterpreterState state, Expression expr) {
  487. UnaryExpression node = (UnaryExpression)expr;
  488. object value;
  489. if (InterpretAndCheckFlow(state, node.Operand, out value)) {
  490. return value;
  491. }
  492. if (state.CurrentYield != null) {
  493. return ControlFlow.NextForYield;
  494. }
  495. if (value != null && node.Type == value.GetType()) {
  496. return value;
  497. }
  498. throw new InvalidCastException(string.Format("cannot unbox value to type '{0}'", node.Type));
  499. }
  500. private static object InterpretConvertUnaryExpression(InterpreterState state, Expression expr) {
  501. UnaryExpression node = (UnaryExpression)expr;
  502. if (node.Method != null) {
  503. return InterpretMethodCallExpression(state, expr, node.Method, null, new[] { node.Operand });
  504. }
  505. object value;
  506. if (InterpretAndCheckFlow(state, node.Operand, out value)) {
  507. return value;
  508. }
  509. if (state.CurrentYield != null) {
  510. return ControlFlow.NextForYield;
  511. }
  512. if (node.Type == typeof(void)) {
  513. return null;
  514. }
  515. // TODO: distinguish between Convert and ConvertChecked
  516. // TODO: semantics should match compiler
  517. return Cast.Explicit(value, node.Type);
  518. }
  519. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  520. private static object InterpretUnaryExpression(InterpreterState state, Expression expr) {
  521. UnaryExpression node = (UnaryExpression)expr;
  522. object value;
  523. if (InterpretAndCheckFlow(state, node.Operand, out value)) {
  524. return value;
  525. }
  526. if (state.CurrentYield != null) {
  527. return ControlFlow.NextForYield;
  528. }
  529. switch (node.NodeType) {
  530. case ExpressionType.TypeAs:
  531. if (value != null && expr.Type.IsAssignableFrom(value.GetType())) {
  532. return value;
  533. } else {
  534. return null;
  535. }
  536. case ExpressionType.Not:
  537. if (value is bool) return (bool)value ? ScriptingRuntimeHelpers.False : ScriptingRuntimeHelpers.True;
  538. if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)~(int)value);
  539. if (value is long) return (long)~(long)value;
  540. if (value is short) return (short)~(short)value;
  541. if (value is uint) return (uint)~(uint)value;
  542. if (value is ulong) return (ulong)~(ulong)value;
  543. if (value is ushort) return (ushort)~(ushort)value;
  544. if (value is byte) return (byte)~(byte)value;
  545. if (value is sbyte) return (sbyte)~(sbyte)value;
  546. throw new InvalidOperationException("can't perform unary not on type " + CompilerHelpers.GetType(value).Name);
  547. case ExpressionType.Negate:
  548. if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)(-(int)value));
  549. if (value is long) return (long)(-(long)value);
  550. if (value is short) return (short)(-(short)value);
  551. if (value is float) return -(float)value;
  552. if (value is double) return -(double)value;
  553. throw new InvalidOperationException("can't negate type " + CompilerHelpers.GetType(value).Name);
  554. case ExpressionType.UnaryPlus:
  555. if (value is int) return ScriptingRuntimeHelpers.Int32ToObject((int)+(int)value);
  556. if (value is long) return (long)+(long)value;
  557. if (value is short) return (short)+(short)value;
  558. if (value is uint) return (uint)+(uint)value;
  559. if (value is ulong) return (ulong)+(ulong)value;
  560. if (value is ushort) return (ushort)+(ushort)value;
  561. if (value is byte) return (byte)+(byte)value;
  562. if (value is sbyte) return (sbyte)+(sbyte)value;
  563. throw new InvalidOperationException("can't perform unary plus on type " + CompilerHelpers.GetType(value).Name);
  564. case ExpressionType.NegateChecked:
  565. if (value is int) return ScriptingRuntimeHelpers.Int32ToObject(checked((int)(-(int)value)));
  566. if (value is long) return checked((long)(-(long)value));
  567. if (value is short) return checked((short)(-(short)value));
  568. if (value is float) return checked(-(float)value);
  569. if (value is double) return checked(-(double)value);
  570. throw new InvalidOperationException("can't negate type " + CompilerHelpers.GetType(value).Name);
  571. case ExpressionType.ArrayLength:
  572. System.Array arr = (System.Array)value;
  573. return arr.Length;
  574. default:
  575. throw new NotImplementedException();
  576. }
  577. }
  578. private static object InterpretRuntimeVariablesExpression(InterpreterState state, Expression expr) {
  579. if (state.CurrentYield != null) {
  580. return ControlFlow.NextForYield;
  581. }
  582. RuntimeVariablesExpression node = (RuntimeVariablesExpression)expr;
  583. return new InterpreterVariables(state, node);
  584. }
  585. private static object InterpretNewExpression(InterpreterState state, Expression expr) {
  586. NewExpression node = (NewExpression)expr;
  587. object[] args = new object[node.Arguments.Count];
  588. for (int i = 0; i < node.Arguments.Count; i++) {
  589. object argValue;
  590. if (InterpretAndCheckFlow(state, node.Arguments[i], out argValue)) {
  591. return argValue;
  592. }
  593. args[i] = argValue;
  594. }
  595. if (state.CurrentYield != null) {
  596. return ControlFlow.NextForYield;
  597. }
  598. try {
  599. return node.Constructor.Invoke(args);
  600. } catch (TargetInvocationException e) {
  601. throw ExceptionHelpers.UpdateForRethrow(e.InnerException);
  602. }
  603. }
  604. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  605. private static object InterpretListInitExpression(InterpreterState state, Expression expr) {
  606. throw new NotImplementedException("InterpretListInitExpression");
  607. }
  608. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")]
  609. private static object InterpretMemberInitExpression(InterpreterState state, Expression expr) {
  610. throw new NotImplementedException("InterpretMemberInitExpression");
  611. }
  612. private static object InterpretTypeBinaryExpression(InterpreterState state, Expression expr) {
  613. TypeBinaryExpression node = (TypeBinaryExpression)expr;
  614. object value;
  615. if (InterpretAndCheckFlow(state, node.Expression, out value)) {
  616. return value;
  617. }
  618. if (state.CurrentYield != null) {
  619. return ControlFlow.NextForYield;
  620. }
  621. bool result;
  622. if (node.NodeType == ExpressionType.TypeEqual) {
  623. result = value != null && value.GetType() == node.TypeOperand;
  624. } else {
  625. result = node.TypeOperand.IsInstanceOfType(value);
  626. }
  627. return ScriptingRuntimeHelpers.BooleanToObject(result);
  628. }
  629. private static object InterpretDynamicExpression(InterpreterState state, Expression expr) {
  630. DynamicExpression node = (DynamicExpression)expr;
  631. var arguments = node.Arguments;
  632. object[] args;
  633. if (!state.TryGetStackState(node, out args)) {
  634. args = new object[arguments.Count];
  635. }
  636. for (int i = 0, n = arguments.Count; i < n; i++) {
  637. object argValue;
  638. if (InterpretAndCheckFlow(state, arguments[i], out argValue)) {
  639. if (state.CurrentYield != null) {
  640. state.SaveStackState(node, args);
  641. }
  642. return argValue;
  643. }
  644. if (argValue != ControlFlow.NextForYield) {
  645. args[i] = argValue;
  646. }
  647. }
  648. if (state.CurrentYield != null) {
  649. return ControlFlow.NextForYield;
  650. }
  651. var metaAction = node.Binder as DynamicMetaObjectBinder;
  652. if (metaAction != null) {
  653. return InterpretMetaAction(state, metaAction, node, args);
  654. }
  655. PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter.Site: Compiling non-meta-action");
  656. var callSiteInfo = GetCallSite(state, node);
  657. return callSiteInfo.CallerTarget(callSiteInfo.CallSite, args);
  658. }
  659. private const int SiteCompileThreshold = 2;
  660. private static object InterpretMetaAction(InterpreterState state, DynamicMetaObjectBinder action, DynamicExpression node, object[] argValues) {
  661. var callSites = state.LambdaState.ScriptCode.CallSites;
  662. CallSiteInfo callSiteInfo;
  663. // TODO: better locking
  664. lock (callSites) {
  665. if (!callSites.TryGetValue(node, out callSiteInfo)) {
  666. callSiteInfo = new CallSiteInfo();
  667. callSites.Add(node, callSiteInfo);
  668. }
  669. }
  670. callSiteInfo.Counter++;
  671. if (callSiteInfo.Counter > SiteCompileThreshold) {
  672. if (callSiteInfo.CallSite == null) {
  673. SetCallSite(callSiteInfo, node);
  674. }
  675. try {
  676. return callSiteInfo.CallerTarget(callSiteInfo.CallSite, argValues);
  677. } catch(Exception e) {
  678. state.ScriptCode.LanguageContext.InterpretExceptionThrow(state, e, false);
  679. throw;
  680. }
  681. }
  682. PerfTrack.NoteEvent(PerfTrack.Categories.Count, "Interpreter: Interpreting meta-action");
  683. if (argValues.Length == 0) {
  684. throw new InvalidOperationException();
  685. }
  686. DynamicMetaObject[] args = DynamicMetaObject.EmptyMetaObjects;
  687. if (argValues.Length != 1) {
  688. args = new DynamicMetaObject[argValues.Length - 1];
  689. for (int i = 0; i < args.Length; i++) {
  690. args[i] = DynamicUtils.ObjectToMetaObject(
  691. argValues[i + 1],
  692. AstUtils.Constant(argValues[i + 1])
  693. );
  694. }
  695. }
  696. object result;
  697. ControlFlow flow;
  698. do {
  699. DynamicMetaObject binding = action.Bind(
  700. DynamicUtils.ObjectToMetaObject(
  701. argValues[0],
  702. AstUtils.Constant(argValues[0])
  703. ),
  704. args
  705. );
  706. if (binding == null) {
  707. throw new InvalidOperationException("Bind cannot return null.");
  708. }
  709. // restrictions ignored, they should be valid:
  710. AssertTrueRestrictions(state, binding);
  711. result = Interpret(state, binding.Expression);
  712. flow = result as ControlFlow;
  713. } while (flow != null && flow.Kind == ControlFlowKind.Goto && flow.Label == CallSiteBinder.UpdateLabel);
  714. return result;
  715. }
  716. [Conditional("DEBUG")]
  717. private static void AssertTrueRestrictions(InterpreterState state, DynamicMetaObject binding) {
  718. var test = binding.Restrictions.ToExpression();
  719. var result = Interpret(state, test);
  720. Debug.Assert(result is bool && (bool)result);
  721. }
  722. private static CallSiteInfo GetCallSite(InterpreterState state, DynamicExpression node) {
  723. CallSiteInfo callSiteInfo;
  724. var callSites = state.LambdaState.ScriptCode.CallSites;
  725. // TODO: better locking
  726. lock (callSites) {
  727. if (!callSites.TryGetValue(node, out callSiteInfo)) {
  728. callSiteInfo = new CallSiteInfo();
  729. SetCallSite(callSiteInfo, node);
  730. callSites.Add(node, callSiteInfo);
  731. }
  732. }
  733. return callSiteInfo;
  734. }
  735. // The ReflectiveCaller cache
  736. private static readonly Dictionary<ValueArray<Type>, ReflectedCaller> _executeSites = new Dictionary<ValueArray<Type>, ReflectedCaller>();
  737. private static void SetCallSite(CallSiteInfo info, DynamicExpression node) {
  738. var arguments = node.Arguments;
  739. // TODO: remove CodeContext special case
  740. if (arguments.Count > 0 && arguments[0].Type != typeof(CodeContext)) {
  741. switch (arguments.Count) {
  742. case 0:
  743. info.CallSite = CallSite<Func<CallSite, object>>.Create(node.Binder);
  744. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target0);
  745. return;
  746. case 1:
  747. info.CallSite = CallSite<Func<CallSite, object, object>>.Create(node.Binder);
  748. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target1);
  749. return;
  750. case 2:
  751. info.CallSite = CallSite<Func<CallSite, object, object, object>>.Create(node.Binder);
  752. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target2);
  753. return;
  754. case 3:
  755. info.CallSite = CallSite<Func<CallSite, object, object, object, object>>.Create(node.Binder);
  756. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target3);
  757. return;
  758. case 4:
  759. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object>>.Create(node.Binder);
  760. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target4);
  761. return;
  762. case 5:
  763. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object>>.Create(node.Binder);
  764. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target5);
  765. return;
  766. case 6:
  767. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object>>.Create(node.Binder);
  768. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target6);
  769. return;
  770. case 7:
  771. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object>>.Create(node.Binder);
  772. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target7);
  773. return;
  774. case 8:
  775. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object>>.Create(node.Binder);
  776. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target8);
  777. return;
  778. case 9:
  779. info.CallSite = CallSite<Func<CallSite, object, object, object, object, object, object, object, object, object, object>>.Create(node.Binder);
  780. info.CallerTarget = new MatchCallerTarget(MatchCaller.Target9);
  781. return;
  782. }
  783. }
  784. var callSite = CreateCallSite(node);
  785. info.CallSite = callSite;
  786. info.CallerTarget = MatchCaller.GetCaller((callSite.GetType().GetGenericArguments()[0]));
  787. }
  788. private static CallSite CreateCallSite(DynamicExpression node) {
  789. var arguments = node.Arguments;
  790. // non-optimized signatures:
  791. Type[] types = CompilerHelpers.GetSiteTypes(arguments, node.Type);
  792. int i = (arguments.Count > 0 && arguments[0].Type != typeof(CodeContext)) ? 1 : 0;
  793. for (; i < arguments.Count; i++) {
  794. if (!arguments[i].Type.IsByRef) {
  795. types[i] = typeof(object);
  796. }
  797. }
  798. ReflectedCaller rc;
  799. lock (_executeSites) {
  800. ValueArray<Type> array = new ValueArray<Type>(types);
  801. if (!_executeSites.TryGetValue(array, out rc)) {
  802. Type delegateType = DynamicSiteHelpers.MakeCallSiteDelegate(types);
  803. MethodInfo target = typeof(InterpreterHelpers).GetMethod("CreateSite").MakeGenericMethod(delegateType);
  804. _executeSites[array] = rc = ReflectedCaller.Create(target);
  805. }
  806. }
  807. return (CallSite)rc.Invoke(node.Binder);
  808. }
  809. private static object InterpretIndexAssignment(InterpreterState state, BinaryExpression node) {
  810. var index = (IndexExpression)node.Left;
  811. object instance, value;
  812. var args = new object[index.Arguments.Count];
  813. if (InterpretAndCheckFlow(state, index.Object, out instance)) {
  814. return instance;
  815. }
  816. for (int i = 0; i < index.Arguments.Count; i++) {
  817. object arg;
  818. if (InterpretAndCheckFlow(state, index.Arguments[i], out arg)) {
  819. return arg;
  820. }
  821. args[i] = arg;
  822. }
  823. if (InterpretAndCheckFlow(state, node.Right, out value)) {
  824. return value;
  825. }
  826. if (state.CurrentYield != null) {
  827. return ControlFlow.NextForYield;
  828. }
  829. if (index.Indexer != null) {
  830. // For indexed properties, just call the setter
  831. InvokeMethod(state, index.Indexer.GetSetMethod(true), instance, args);
  832. } else if (index.Arguments.Count != 1) {
  833. // Multidimensional arrays, call set
  834. var set = index.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance);
  835. InvokeMethod(state, set, instance, args);
  836. } else {
  837. ((Array)instance).SetValue(value, (int)args[0]);
  838. }
  839. return value;
  840. }
  841. private static object InterpretVariableAssignment(InterpreterState state, Expression expr) {
  842. var node = (BinaryExpression)expr;
  843. object value;
  844. if (InterpretAndCheckFlow(state, node.Right, out value)) {
  845. return value;
  846. }
  847. if (state.CurrentYield != null) {
  848. return ControlFlow.NextForYield;
  849. }
  850. EvaluateAssignVariable(state, node.Left, value);
  851. return value;
  852. }
  853. private static object InterpretAssignBinaryExpression(InterpreterState state, Expression expr) {
  854. var node = (BinaryExpression)expr;
  855. switch (node.Left.NodeType) {
  856. case ExpressionType.Index:
  857. return InterpretIndexAssignment(state, node);
  858. case ExpressionType.MemberAccess:
  859. return InterpretMemberAssignment(state, node);
  860. case ExpressionType.Parameter:
  861. case ExpressionType.Extension:
  862. return InterpretVariableAssignment(state, node);
  863. default:
  864. throw new InvalidOperationException("Invalid lvalue for assignment: " + node.Left.NodeType);
  865. }
  866. }
  867. private static object InterpretParameterExpression(InterpreterState state, Expression expr) {
  868. if (state.CurrentYield != null) {
  869. return ControlFlow.NextForYield;
  870. }
  871. return state.GetValue(expr);
  872. }
  873. private static object InterpretLambdaExpression(InterpreterState state, Expression expr) {
  874. if (state.CurrentYield != null) {
  875. return ControlFlow.NextForYield;
  876. }
  877. LambdaExpression node = (LambdaExpression)expr;
  878. return GetDelegateForInterpreter(state, node);
  879. }
  880. private static object InterpretMemberAssignment(InterpreterState state, BinaryExpression node) {
  881. var left = (MemberExpression)node.Left;
  882. object target = null, value;
  883. if (left.Expression != null) {
  884. if (InterpretAndCheckFlow(state, left.Expression, out target)) {
  885. return target;
  886. }
  887. }
  888. if (InterpretAndCheckFlow(state, node.Right, out value)) {
  889. return value;
  890. }
  891. if (state.CurrentYield != null) {
  892. return ControlFlow.NextForYield;
  893. }
  894. switch (left.Member.MemberType) {
  895. case MemberTypes.Field:
  896. FieldInfo field = (FieldInfo)left.Member;
  897. field.SetValue(target, value);
  898. break;
  899. case MemberTypes.Property:
  900. PropertyInfo property = (PropertyInfo)left.Member;
  901. property.SetValue(target, value, null);
  902. break;
  903. default:
  904. Debug.Assert(false, "Invalid member type");
  905. break;
  906. }
  907. return value;
  908. }
  909. private static object InterpretMemberExpression(InterpreterState state, Expression expr) {
  910. MemberExpression node = (MemberExpression)expr;
  911. object self = null;
  912. if (node.Expression != null) {
  913. if (InterpretAndCheckFlow(state, node.Expression, out self)) {
  914. return self;
  915. }
  916. }
  917. if (state.CurrentYield != null) {
  918. return ControlFlow.NextForYield;
  919. }
  920. switch (node.Member.MemberType) {
  921. case MemberTypes.Field:
  922. FieldInfo field = (FieldInfo)node.Member;
  923. return field.GetValue(self);
  924. case MemberTypes.Property:
  925. PropertyInfo property = (PropertyInfo)node.Member;
  926. return property.GetValue(self, ArrayUtils.EmptyObjects);
  927. default:
  928. Debug.Assert(false, "Invalid member type");
  929. break;
  930. }
  931. throw new InvalidOperationException();
  932. }
  933. private static object InterpretNewArrayExpression(InterpreterState state, Expression expr) {
  934. NewArrayExpression node = (NewArrayExpression)expr;
  935. ConstructorInfo constructor;
  936. if (node.NodeType == ExpressionType.NewArrayBounds) {
  937. int rank = node.Type.GetArrayRank();
  938. Type[] types = new Type[rank];
  939. object[] bounds = new object[rank];
  940. for (int i = 0; i < rank; i++) {
  941. types[i] = typeof(int);
  942. object value;
  943. if (InterpretAndCheckFlow(state, node.Expressions[i], out value)) {
  944. return value;
  945. }
  946. bounds[i] = value;
  947. }
  948. if (state.CurrentYield != null) {
  949. return ControlFlow.NextForYield;
  950. }
  951. constructor = expr.Type.GetConstructor(types);
  952. return constructor.Invoke(bounds);
  953. } else {
  954. // this must be ExpressionType.NewArrayInit
  955. object[] values;
  956. if (!state.TryGetStackState(node, out values)) {
  957. values = new object[node.Expressions.Count];
  958. }
  959. for (int i = 0; i < node.Expressions.Count; i++) {
  960. object value;
  961. if (InterpretAndCheckFlow(state, node.Expressions[i], out value)) {
  962. if (state.CurrentYield != null) {
  963. // yield w/ expressions on the stack, we need to save the currently
  964. // evaluated nodes for when we come back.
  965. state.SaveStackState(node, values);
  966. }
  967. return value;
  968. }
  969. if (value != ControlFlow.NextForYield) {
  970. values[i] = value;
  971. }
  972. }
  973. if (state.CurrentYield != null) {
  974. // we were just walking looking for yields, this has no result.
  975. return ControlFlow.NextForYield;
  976. }
  977. if (node.Type != typeof(object[])) {
  978. constructor = expr.Type.GetConstructor(new Type[] { typeof(int) });
  979. Array contents = (Array)constructor.Invoke(new object[] { node.Expressions.Count });
  980. // value arrays cannot be cast to object arrays
  981. for (int i = 0; i < node.Expressions.Count; i++) {
  982. contents.SetValue(values[i], i);
  983. }
  984. return contents;
  985. }
  986. return values;
  987. }
  988. }
  989. private static object InterpretGotoExpression(InterpreterState state, Expression expr) {
  990. if (state.CurrentYield != null) {
  991. return ControlFlow.NextForYield;
  992. }
  993. var node = (GotoExpression)expr;
  994. object value = null;
  995. if (node.Value != null) {
  996. value = Interpret(state, node.Value);
  997. ControlFlow cf = value as ControlFlow;
  998. if (cf != null) {
  999. // propagate
  1000. return cf;
  1001. }
  1002. }
  1003. return ControlFlow.Goto(node.Target, value);
  1004. }
  1005. private static object InterpretDefaultExpression(InterpreterState state, Expression expr) {
  1006. if (state.CurrentYield != null) {
  1007. return ControlFlow.NextForYield;
  1008. }
  1009. Type type = expr.Type;
  1010. if (type == typeof(void)) {
  1011. return ControlFlow.NextStatement;
  1012. } else if (type.IsValueType) {
  1013. return Activator.CreateInstance(type);
  1014. } else {
  1015. return null;
  1016. }
  1017. }
  1018. /// <summary>
  1019. /// Labeled statement makes break/continue go to the end of the contained expression.
  1020. /// </summary>
  1021. private static object InterpretLabelExpression(InterpreterState state, Expression expr) {
  1022. LabelExpression node = (LabelExpression)expr;
  1023. object res = ControlFlow.NextStatement;
  1024. if (node.DefaultValue != null) {
  1025. res = Interpret(state, node.DefaultValue);
  1026. var cf = res as ControlFlow;
  1027. if (cf != null && cf.Kind == ControlFlowKind.Goto && cf.Label == node.Target) {
  1028. res = cf.Value;
  1029. }
  1030. }
  1031. return res;
  1032. }
  1033. private static object InterpretLoopExpression(InterpreterState state, Expression expr) {
  1034. LoopExpression node = (LoopExpression)expr;
  1035. for (; ; ) {
  1036. ControlFlow cf;
  1037. object body = Interpret(state, node.Body);
  1038. if ((cf = body as ControlFlow) != null) {
  1039. if (cf.Kind == ControlFlowKind.Goto) {
  1040. if (cf.Label == node.BreakLabel) {
  1041. // Break out of the loop and execute next statement outside
  1042. return ControlFlow.NextStatement;
  1043. } else if (cf.Label != node.ContinueLabel) {
  1044. return cf;
  1045. }
  1046. } else if (cf.Kind == ControlFlowKind.Yield) {
  1047. return body;
  1048. }
  1049. }
  1050. }
  1051. }
  1052. private static object InterpretDebugInfoExpression(InterpreterState state, Expression expr) {
  1053. var node = (DebugInfoExpression)expr;
  1054. if (state.CurrentYield == null && !node.IsClear) {
  1055. //We may want to set CurrentLocation to None when the DebugInfo is a clearance,
  1056. //the current code keeps the previous behavior.
  1057. // Note: setting index to 0 because we don't have one available
  1058. // Index should be removed from SourceLocation
  1059. state.CurrentLocation = new SourceLocation(0, node.StartLine, node.StartColumn);
  1060. }
  1061. return null;
  1062. }
  1063. private static object InterpretBlockExpression(InterpreterState state, Expression expr) {
  1064. BlockExpression node = (BlockExpression)expr;
  1065. InterpreterState child = state;
  1066. if (node.Variables.Count > 0) {
  1067. // restore scope if we yielded
  1068. if (!state.TryGetStackState(node, out child)) {
  1069. // otherwise, create a new nested scope
  1070. child = state.CreateForScope(node);
  1071. }
  1072. }
  1073. try {
  1074. var expressions = node.Expressions;
  1075. int count = expressions.Count;
  1076. if (count > 0) {
  1077. int current = 0;
  1078. for (; ; ) {
  1079. object val = null;
  1080. Expression ce = expressions[current];
  1081. if (InterpretAndCheckFlow(child, ce, out val)) {
  1082. // Control flow
  1083. if (val != ControlFlow.NextStatement) {
  1084. ControlFlow cf = (ControlFlow)val;
  1085. if (cf.Kind == ControlFlowKind.Goto) {
  1086. // Is the goto within the block?
  1087. for (int target = 0; target < count; target++) {
  1088. LabelExpression le = expressions[target] as LabelExpression;
  1089. if (le != null && le.Target == cf.Label) {
  1090. // Reset to execute the code from after the label
  1091. // We are going to the label and since label is at the end of the
  1092. // expression, set to target and we'll advance below.
  1093. current = target;
  1094. val = null;
  1095. goto Next;
  1096. }
  1097. }
  1098. }
  1099. return cf;
  1100. }
  1101. }
  1102. Next:
  1103. // Next expression
  1104. current++;
  1105. // Last expression?
  1106. if (current >= count) {
  1107. return node.Type != typeof(void) ? val : ControlFlow.NextStatement;
  1108. }
  1109. }
  1110. }
  1111. } finally {
  1112. if (node.Variables.Count > 0) {
  1113. if (state.CurrentYield != null) {
  1114. // save scope if yielding so we can restore it
  1115. state.SaveStackState(node, child);
  1116. }
  1117. }
  1118. }
  1119. return ControlFlow.NextStatement;
  1120. }
  1121. private static object InterpretSwitchExpression(InterpreterState state, Expression expr) {
  1122. throw new NotSupportedException("switch not supported by old interpreter");
  1123. }
  1124. #region Exceptions
  1125. [ThreadStatic]
  1126. private static List<Exception> _evalExceptions;
  1127. private static void PopEvalException() {
  1128. _evalExceptions.RemoveAt(_evalExceptions.Count - 1);
  1129. if (_evalExceptions.Count == 0) _evalExceptions = null;
  1130. }
  1131. private static void PushEvalException(Exception exc) {
  1132. if (_evalExceptions == null) _evalExceptions = new List<Exception>();
  1133. _evalExceptions.Add(exc);
  1134. }
  1135. private static Exception LastEvalException {
  1136. get {
  1137. if (_evalExceptions == null || _evalExceptions.Count == 0) {
  1138. throw new InvalidOperationException("rethrow outside of catch block");
  1139. }
  1140. return _evalExceptions[_evalExceptions.Count - 1];
  1141. }
  1142. }
  1143. private static object InterpretThrowUnaryExpression(InterpreterState state, Expression expr) {
  1144. UnaryExpression node = (UnaryExpression)expr;
  1145. Exception ex;
  1146. if (node.Operand == null) {
  1147. ex = LastEvalException;
  1148. } else {
  1149. object exception;
  1150. if (InterpretAndCheckFlow(state, node.Operand, out exception)) {
  1151. return exception;
  1152. }
  1153. ex = (Exception)exception;
  1154. }
  1155. if (state.CurrentYield != null) {
  1156. return ControlFlow.NextForYield;
  1157. }
  1158. state.LambdaState.ScriptCode.LanguageContext.InterpretExceptionThrow(state, ex, true);
  1159. throw ex;
  1160. }
  1161. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  1162. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2219:DoNotRaiseExceptionsInExceptionClauses")]
  1163. private static object InterpretTryExpression(InterpreterState state, Expression expr) {
  1164. // TODO: Yield aware
  1165. TryExpression node = (TryExpression)expr;
  1166. bool rethrow = false, catchFaulted = false;
  1167. Exception savedExc = null;
  1168. object ret = ControlFlow.NextStatement;
  1169. try {
  1170. if (!InterpretAndCheckFlow(state, node.Body, out ret)) {
  1171. ret = ControlFlow.NextStatement;
  1172. }
  1173. } catch (Exception exc) {
  1174. rethrow = true;
  1175. savedExc = exc;
  1176. if (node.Handlers != null) {
  1177. PushEvalException(exc);
  1178. try {
  1179. ret = ControlFlowKind.NextStatement;
  1180. foreach (CatchBlock handler in node.Handlers) {
  1181. if (handler.Test.IsInstanceOfType(exc)) {
  1182. if (handler.Variable != null) {
  1183. EvaluateAssignVariable(state, handler.Variable, exc);
  1184. }
  1185. if (handler.Filter != null) {
  1186. object filterResult;
  1187. if (InterpretAndCheckFlow(state, handler.Filter, out filterResult)) {
  1188. ret = filterResult;
  1189. break;
  1190. } else if (!((bool)filterResult)) {
  1191. // handler doesn't apply, check next handler.
  1192. continue;
  1193. }
  1194. }
  1195. rethrow = false;
  1196. catchFaulted = true;
  1197. object body;
  1198. if (InterpretAndCheckFlow(state, handler.Body, out body)) {
  1199. ret = body;
  1200. }
  1201. catchFaulted = false;
  1202. break;
  1203. }
  1204. }
  1205. } finally {
  1206. PopEvalException();
  1207. }
  1208. }
  1209. } finally {
  1210. if (node.Finally != null || ((rethrow || catchFaulted) && node.Fault != null)) {
  1211. Expression faultOrFinally = node.Finally ?? node.Fault;
  1212. object result;
  1213. if (InterpretAndCheckFlow(state, faultOrFinally, out result) &&
  1214. result != ControlFlow.NextStatement) {
  1215. ret = result;
  1216. rethrow = false;
  1217. }
  1218. }
  1219. if (rethrow) {
  1220. throw ExceptionHelpers.UpdateForRethrow(savedExc);
  1221. }
  1222. }
  1223. return ret;
  1224. }
  1225. private static object InterpretYieldExpression(InterpreterState state, YieldExpression node) {
  1226. // Yield break
  1227. if (node.Value == null) {
  1228. return ControlFlow.YieldBreak;
  1229. }
  1230. if (state.CurrentYield == node) {
  1231. // we've just advanced past the current yield, start executing code again.
  1232. state.CurrentYield = null;
  1233. return ControlFlow.NextStatement;
  1234. }
  1235. object res;
  1236. if (InterpretAndCheckFlow(state, node.Value, out res) && res != ControlFlow.NextStatement) {
  1237. // yield contains flow control.
  1238. return res;
  1239. }
  1240. if (state.CurrentYield == null) {
  1241. // we are the yield, we just ran our code, and now we
  1242. // need to return the result.
  1243. state.CurrentYield = node;
  1244. return ControlFlow.YieldReturn(res);
  1245. }
  1246. return ControlFlow.NextForYield;
  1247. }
  1248. private static object InterpretGeneratorExpression(InterpreterState state, GeneratorExpression generator) {
  1249. // Fast path for object
  1250. if (generator.Target.Type == typeof(object)) {
  1251. return InterpretGenerator<object>(state, generator);
  1252. }
  1253. // TODO: slow path
  1254. return ReflectedCaller.Create(
  1255. typeof(Interpreter).GetMethod(
  1256. "InterpretGenerator", BindingFlags.NonPublic | BindingFlags.Static
  1257. ).MakeGenericMethod(generator.Target.Type)
  1258. ).Invoke(state, generator);
  1259. }
  1260. private static object InterpretGenerator<T>(InterpreterState state, GeneratorExpression generator) {
  1261. var caller = InterpreterState.Current.Value;
  1262. if (generator.IsEnumerable) {
  1263. return new GeneratorEnumerable<T>(
  1264. () => new GeneratorInvoker(generator, state.CreateForGenerator(caller)).Invoke
  1265. );
  1266. } else {
  1267. return new GeneratorEnumerator<T>(
  1268. new GeneratorInvoker(generator, state.CreateForGenerator(caller)).Invoke
  1269. );
  1270. }
  1271. }
  1272. private static object InterpretExtensionExpression(InterpreterState state, Expression expr) {
  1273. var ffc = expr as FinallyFlowControlExpression;
  1274. if (ffc != null) {
  1275. return Interpret(state, ffc.Body);
  1276. }
  1277. var yield = expr as YieldExpression;
  1278. if (yield != null) {
  1279. return InterpretYieldExpression(state, yield);
  1280. }
  1281. var generator = expr as GeneratorExpression;
  1282. if (generator != null) {
  1283. return InterpretGeneratorExpression(state, generator);
  1284. }
  1285. return Interpret(state, expr.ReduceExtensions());
  1286. }
  1287. #endregion
  1288. internal static object EvaluateAssign(InterpreterState state, Expression node, object value) {
  1289. switch (node.NodeType) {
  1290. case ExpressionType.Parameter:
  1291. case ExpressionType.Extension:
  1292. return EvaluateAssignVariable(state, node, value);
  1293. // TODO: this is wierd, why are we supporting assign to assignment?
  1294. case ExpressionType.Assign:
  1295. return EvaluateAssignVariable(state, ((BinaryExpression)node).Left, value);
  1296. case ExpressionType.MemberAccess:
  1297. return EvaluateAssign(state, (MemberExpression)node, value);
  1298. default:
  1299. return value;
  1300. }
  1301. }
  1302. private static object EvaluateAssignVariable(InterpreterState state, Expression var, object value) {
  1303. if (state.CurrentYield != null) {
  1304. return ControlFlow.NextForYield;
  1305. }
  1306. state.SetValue(var, value);
  1307. return value;
  1308. }
  1309. private static object EvaluateAssign(InterpreterState state, MemberExpression node, object value) {
  1310. object self = null;
  1311. if (InterpretAndCheckFlow(state, node.Expression, out self)) {
  1312. return self;
  1313. }
  1314. if (state.CurrentYield != null) {
  1315. return ControlFlow.NextForYield;
  1316. }
  1317. switch (node.Member.MemberType) {
  1318. case MemberTypes.Field:
  1319. FieldInfo field = (FieldInfo)node.Member;
  1320. field.SetValue(self, value);
  1321. return value;
  1322. case MemberTypes.Property:
  1323. PropertyInfo property = (PropertyInfo)node.Member;
  1324. property.SetValue(self, value, ArrayUtils.EmptyObjects);
  1325. return value;
  1326. default:
  1327. Debug.Assert(false, "Invalid member type");
  1328. break;
  1329. }
  1330. throw new InvalidOperationException();
  1331. }
  1332. private static EvaluationAddress EvaluateAddress(InterpreterState state, Expression node) {
  1333. switch (node.NodeType) {
  1334. case ExpressionType.Parameter:
  1335. return new VariableAddress(node);
  1336. case ExpressionType.Block:
  1337. return EvaluateAddress(state, (BlockExpression)node);
  1338. case ExpressionType.Conditional:
  1339. return EvaluateAddress(state, (ConditionalExpression)node);
  1340. default:
  1341. return new EvaluationAddress(node);
  1342. }
  1343. }
  1344. private static EvaluationAddress EvaluateAddress(InterpreterState state, BlockExpression node) {
  1345. if (node.Type == typeof(void)) {
  1346. throw new NotSupportedException("Address of block without value");
  1347. }
  1348. List<EvaluationAddress> addresses = new List<EvaluationAddress>();
  1349. foreach (Expression current in node.Expressions) {
  1350. addresses.Add(EvaluateAddress(state, current));
  1351. }
  1352. return new CommaAddress(node, addresses);
  1353. }
  1354. private static EvaluationAddress EvaluateAddress(InterpreterState state, ConditionalExpression node) {
  1355. object test = (bool)Interpret(state, node.Test);
  1356. if ((bool)test) {
  1357. return EvaluateAddress(state, node.IfTrue);
  1358. } else {
  1359. return EvaluateAddress(state, node.IfFalse);
  1360. }
  1361. }
  1362. }
  1363. }