PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full 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[

Large files files are truncated, but you can click here to view the full file