PageRenderTime 79ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting/Interpreter/LightCompiler.cs

https://bitbucket.org/stefanrusek/xronos
C# | 1343 lines | 1070 code | 217 blank | 56 comment | 300 complexity | 1fc0e8dab6c76341482b96e8c94e8146 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;
  21. using System.Collections.Generic;
  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 Microsoft.Scripting.Utils;
  30. using AstUtils = Microsoft.Scripting.Ast.Utils;
  31. namespace Microsoft.Scripting.Interpreter {
  32. public class ExceptionHandler {
  33. public Type ExceptionType;
  34. public int StartIndex, EndIndex;
  35. public int JumpToIndex, EndHandlerIndex;
  36. public bool PushException;
  37. public bool IsFault { get { return ExceptionType == null; } }
  38. public bool Matches(Type exceptionType, int index) {
  39. if (index >= StartIndex && index < EndIndex) {
  40. if (ExceptionType == null || ExceptionType.IsAssignableFrom(exceptionType)) {
  41. return true;
  42. }
  43. }
  44. return false;
  45. }
  46. public bool IsBetterThan(ExceptionHandler other) {
  47. if (other == null) return true;
  48. if (StartIndex == other.StartIndex && EndIndex == other.EndIndex) {
  49. return JumpToIndex < other.JumpToIndex;
  50. }
  51. if (StartIndex > other.StartIndex) {
  52. Debug.Assert(EndIndex <= other.EndIndex);
  53. return true;
  54. } else if (EndIndex < other.EndIndex) {
  55. Debug.Assert(StartIndex == other.StartIndex);
  56. return true;
  57. } else {
  58. return false;
  59. }
  60. }
  61. }
  62. public class DebugInfo {
  63. public int StartLine, EndLine;
  64. public int Index;
  65. public string FileName;
  66. public bool IsClear;
  67. private static readonly DebugInfoComparer _debugComparer = new DebugInfoComparer();
  68. private class DebugInfoComparer : IComparer<DebugInfo> {
  69. //We allow comparison between int and DebugInfo here
  70. int IComparer<DebugInfo>.Compare(DebugInfo d1, DebugInfo d2) {
  71. if (d1.Index > d2.Index) return 1;
  72. else if (d1.Index == d2.Index) return 0;
  73. else return -1;
  74. }
  75. }
  76. public static DebugInfo GetMatchingDebugInfo(DebugInfo[] debugInfos, int index) {
  77. //Create a faked DebugInfo to do the search
  78. DebugInfo d = new DebugInfo { Index = index };
  79. //to find the closest debug info before the current index
  80. int i = Array.BinarySearch<DebugInfo>(debugInfos, d, _debugComparer);
  81. if (i < 0) {
  82. //~i is the index for the first bigger element
  83. //if there is no bigger element, ~i is the length of the array
  84. i = ~i;
  85. if (i == 0) {
  86. return null;
  87. }
  88. //return the last one that is smaller
  89. i = i - 1;
  90. }
  91. return debugInfos[i];
  92. }
  93. }
  94. public class LightCompiler {
  95. private static readonly MethodInfo _RunMethod = typeof(Interpreter).GetMethod("Run");
  96. private static readonly MethodInfo _GetCurrentMethod = typeof(MethodBase).GetMethod("GetCurrentMethod");
  97. private List<Instruction> _instructions = new List<Instruction>();
  98. private int _maxStackDepth = 0;
  99. private int _currentStackDepth = 0;
  100. private List<ParameterExpression> _locals = new List<ParameterExpression>();
  101. private List<bool> _localIsBoxed = new List<bool>();
  102. private List<ParameterExpression> _closureVariables = new List<ParameterExpression>();
  103. private List<ExceptionHandler> _handlers = new List<ExceptionHandler>();
  104. private List<DebugInfo> _debugInfos = new List<DebugInfo>();
  105. private Dictionary<LabelTarget, Label> _labels = new Dictionary<LabelTarget, Label>();
  106. private Stack<ParameterExpression> _exceptionForRethrowStack = new Stack<ParameterExpression>();
  107. private Stack<FinallyLabels> _finallyLabels = new Stack<FinallyLabels>();
  108. private LightCompiler _parent;
  109. internal LightCompiler() {}
  110. private LightCompiler(LightCompiler parent) : this() {
  111. this._parent = parent;
  112. }
  113. internal Interpreter CompileTop(LambdaExpression node) {
  114. foreach (var p in node.Parameters) {
  115. this.AddVariable(p);
  116. }
  117. this.Compile(node.Body);
  118. return this.MakeInterpreter(node);
  119. }
  120. private Interpreter MakeInterpreter(LambdaExpression lambda) {
  121. var handlers = _handlers.ToArray();
  122. var debugInfos = _debugInfos.ToArray();
  123. return new Interpreter(lambda, _localIsBoxed.ToArray(), _maxStackDepth, _instructions.ToArray(), handlers, debugInfos);
  124. }
  125. class FinallyLabels {
  126. public Label startOfFinally;
  127. public Dictionary<Label, List<OffsetInstruction>> labels =
  128. new Dictionary<Label, List<OffsetInstruction>>();
  129. public Dictionary<Label, bool> labelHasValue = new Dictionary<Label, bool>();
  130. public FinallyLabels(Label startOfFinally) {
  131. this.startOfFinally = startOfFinally;
  132. }
  133. public void AddBranch(OffsetInstruction instruction, Label label, bool hasValue) {
  134. List<OffsetInstruction> branches;
  135. if (!labels.TryGetValue(label, out branches)) {
  136. branches = new List<OffsetInstruction>();
  137. labels[label] = branches;
  138. labelHasValue[label] = hasValue;
  139. }
  140. Debug.Assert(labelHasValue[label] == hasValue);
  141. branches.Add(instruction);
  142. }
  143. }
  144. class Label {
  145. public int _index;
  146. private LightCompiler _compiler;
  147. public int _expectedStackSize = -1;
  148. private List<OffsetInstruction> _offsetInstructions = new List<OffsetInstruction>();
  149. public Label(LightCompiler compiler) {
  150. this._compiler = compiler;
  151. this._index = -1;
  152. }
  153. public void NoteStackSize() {
  154. int stackSize = _compiler._currentStackDepth;
  155. if (_expectedStackSize == -1) _expectedStackSize = stackSize;
  156. Debug.Assert(_expectedStackSize == stackSize);
  157. }
  158. public void Mark() {
  159. if (_expectedStackSize != -1) {
  160. Debug.Assert(_compiler._currentStackDepth == -1 || _compiler._currentStackDepth == _expectedStackSize);
  161. _compiler._currentStackDepth = _expectedStackSize;
  162. } else {
  163. _expectedStackSize = _compiler._currentStackDepth;
  164. }
  165. this._index = _compiler._instructions.Count;
  166. foreach (var oi in _offsetInstructions) {
  167. SetOffset(oi);
  168. }
  169. }
  170. public void RemoveBinding(OffsetInstruction instruction) {
  171. this._offsetInstructions.Remove(instruction);
  172. }
  173. public void SetOffset(OffsetInstruction instruction) {
  174. //TODO some work here to verify expectedStackSize
  175. if (_index == -1) {
  176. this._offsetInstructions.Add(instruction);
  177. } else {
  178. int index = _compiler._instructions.IndexOf(instruction);
  179. int offset = _index - index;
  180. instruction.SetOffset(offset);
  181. }
  182. }
  183. }
  184. private Label MakeLabel() {
  185. return new Label(this);
  186. }
  187. private Label ReferenceLabel(LabelTarget target) {
  188. Label ret;
  189. if (!_labels.TryGetValue(target, out ret)) {
  190. ret = MakeLabel();
  191. _labels[target] = ret;
  192. }
  193. return ret;
  194. }
  195. private ExceptionHandler AddHandler(Type exceptionType, ParameterExpression exceptionParameter, int start, int end) {
  196. var handler = new ExceptionHandler() {
  197. ExceptionType = exceptionType, PushException = exceptionParameter != null,
  198. StartIndex = start, EndIndex = end,
  199. JumpToIndex = _instructions.Count };
  200. _handlers.Add(handler);
  201. return handler;
  202. }
  203. private BranchInstruction AddBranch(Label label) {
  204. var branch = new BranchInstruction();
  205. AddBranch(branch, label);
  206. _currentStackDepth = -1; // always clear the stack after an unconditional branch
  207. return branch;
  208. }
  209. private void AddBranch(OffsetInstruction instruction, Label label) {
  210. if (_currentStackDepth == -1) {
  211. return; // this code is unreachable
  212. }
  213. AddInstruction(instruction);
  214. label.NoteStackSize();
  215. label.SetOffset(instruction);
  216. }
  217. public void AddInstruction(Instruction instruction) {
  218. //Debug.Assert(_currentStackDepth >= 0); // checks that the stack is valid
  219. if (_currentStackDepth == -1) {
  220. return; // this code is unreachable
  221. }
  222. _instructions.Add(instruction);
  223. _currentStackDepth -= instruction.ConsumedStack;
  224. Debug.Assert(_currentStackDepth >= 0); // checks that there's enough room to pop
  225. _currentStackDepth += instruction.ProducedStack;
  226. if (_currentStackDepth > _maxStackDepth) _maxStackDepth = _currentStackDepth;
  227. }
  228. public void PushConstant(object value) {
  229. AddInstruction(new PushInstruction(value));
  230. }
  231. private void CompileConstantExpression(Expression expr) {
  232. var node = (ConstantExpression)expr;
  233. PushConstant(node.Value);
  234. }
  235. private void CompileDefaultExpression(Expression expr) {
  236. if (_currentStackDepth == -1) {
  237. // HEURISTIC this means this is unreachable code and not needed to be compiled
  238. return;
  239. }
  240. var node = (DefaultExpression)expr;
  241. if (node.Type != typeof(void)) {
  242. object value;
  243. if (node.Type.IsValueType) {
  244. value = Activator.CreateInstance(node.Type);
  245. } else {
  246. value = null;
  247. }
  248. PushConstant(value);
  249. }
  250. }
  251. private bool IsBoxed(int index) {
  252. return _localIsBoxed[index];
  253. }
  254. private void SwitchToBoxed(int index) {
  255. for (int i = 0; i < _instructions.Count; i++) {
  256. var instruction = _instructions[i] as IBoxableInstruction;
  257. if (instruction != null) {
  258. var newInstruction = instruction.BoxIfIndexMatches(index);
  259. if (newInstruction != null) {
  260. _instructions[i] = newInstruction;
  261. }
  262. }
  263. }
  264. }
  265. private void EnsureAvailableForClosure(ParameterExpression expr) {
  266. int index = _locals.IndexOf(expr);
  267. if (index != -1) {
  268. if (!_localIsBoxed[index]) {
  269. _localIsBoxed[index] = true;
  270. SwitchToBoxed(index);
  271. }
  272. return;
  273. }
  274. if (!_closureVariables.Contains(expr)) {
  275. Debug.Assert(_parent != null);
  276. _parent.EnsureAvailableForClosure(expr);
  277. _closureVariables.Add(expr);
  278. }
  279. }
  280. private Instruction GetVariable(ParameterExpression expr) {
  281. int index = _locals.IndexOf(expr);
  282. if (index != -1) {
  283. if (_localIsBoxed[index]) {
  284. return new GetBoxedLocalInstruction(index);
  285. } else {
  286. return new GetLocalInstruction(index);
  287. }
  288. }
  289. this.EnsureAvailableForClosure(expr);
  290. index = _closureVariables.IndexOf(expr);
  291. Debug.Assert(index != -1);
  292. return new GetClosureInstruction(index);
  293. }
  294. private Instruction GetBoxedVariable(ParameterExpression expr) {
  295. int index = _locals.IndexOf(expr);
  296. if (index != -1) {
  297. Debug.Assert(_localIsBoxed[index]);
  298. return new GetLocalInstruction(index);
  299. }
  300. this.EnsureAvailableForClosure(expr);
  301. index = _closureVariables.IndexOf(expr);
  302. Debug.Assert(index != -1);
  303. return new GetBoxedClosureInstruction(index);
  304. }
  305. private void SetVariable(ParameterExpression expr, bool isVoid) {
  306. int index = _locals.IndexOf(expr);
  307. if (index != -1) {
  308. if (_localIsBoxed[index]) {
  309. if (isVoid) AddInstruction(new SetBoxedLocalVoidInstruction(index));
  310. else AddInstruction(new SetBoxedLocalInstruction(index));
  311. } else {
  312. if (isVoid) AddInstruction(new SetLocalVoidInstruction(index));
  313. else AddInstruction(new SetLocalInstruction(index));
  314. }
  315. return;
  316. }
  317. this.EnsureAvailableForClosure(expr);
  318. index = _closureVariables.IndexOf(expr);
  319. Debug.Assert(index != -1);
  320. AddInstruction(new SetClosureInstruction(index));
  321. if (isVoid) AddInstruction(PopInstruction.Instance);
  322. }
  323. private int AddVariable(ParameterExpression expr) {
  324. int index = _locals.Count;
  325. _locals.Add(expr);
  326. _localIsBoxed.Add(false);
  327. return index;
  328. }
  329. private void CompileParameterExpression(Expression expr) {
  330. var node = (ParameterExpression)expr;
  331. AddInstruction(GetVariable(node));
  332. }
  333. private void CompileBlockExpression(Expression expr, bool asVoid) {
  334. var node = (BlockExpression)expr;
  335. // TODO: pop these off a stack when exiting
  336. // TODO: basic flow analysis so we don't have to initialize all
  337. // variables.
  338. foreach (var local in node.Variables) {
  339. int index = this.AddVariable(local);
  340. object value = GetDefaultOfType(local.Type);
  341. if (value != null) {
  342. this.AddInstruction(new PushInstruction(value));
  343. this.AddInstruction(new SetLocalVoidInstruction(index));
  344. }
  345. }
  346. for (int i = 0; i < node.Expressions.Count - 1; i++) {
  347. this.CompileAsVoid(node.Expressions[i]);
  348. }
  349. var lastExpression = node.Expressions[node.Expressions.Count - 1];
  350. if (asVoid) {
  351. this.CompileAsVoid(lastExpression);
  352. } else {
  353. this.Compile(lastExpression, asVoid);
  354. }
  355. }
  356. private static object GetDefaultOfType(Type type) {
  357. if (!type.IsValueType) {
  358. return null;
  359. } else if (type == typeof(int)) {
  360. return 0;
  361. } else if (type == typeof(bool)) {
  362. return false;
  363. }
  364. return Activator.CreateInstance(type);
  365. }
  366. private void CompileIndexAssignment(BinaryExpression node, bool asVoid) {
  367. throw new NotImplementedException();
  368. }
  369. private void CompileMemberAssignment(BinaryExpression node, bool asVoid) {
  370. var member = (MemberExpression)node.Left;
  371. PropertyInfo pi = member.Member as PropertyInfo;
  372. if (pi != null) {
  373. var method = pi.GetSetMethod();
  374. this.Compile(member.Expression);
  375. this.Compile(node.Right);
  376. int index = 0;
  377. if (!asVoid) {
  378. index = AddVariable(Expression.Parameter(node.Right.Type, null));
  379. AddInstruction(new SetLocalInstruction(index));
  380. // TODO: free the variable when it goes out of scope
  381. }
  382. AddInstruction(new CallInstruction(method));
  383. if (!asVoid) {
  384. AddInstruction(new GetLocalInstruction(index));
  385. }
  386. return;
  387. }
  388. FieldInfo fi = member.Member as FieldInfo;
  389. if (fi != null) {
  390. this.Compile(member.Expression);
  391. this.Compile(node.Right);
  392. int index = 0;
  393. if (!asVoid) {
  394. index = AddVariable(Expression.Parameter(node.Right.Type, null));
  395. AddInstruction(new SetLocalInstruction(index));
  396. // TODO: free the variable when it goes out of scope
  397. }
  398. AddInstruction(new FieldAssignInstruction(fi));
  399. if (!asVoid) {
  400. AddInstruction(new GetLocalInstruction(index));
  401. }
  402. return;
  403. }
  404. throw new NotImplementedException();
  405. }
  406. private void CompileVariableAssignment(BinaryExpression node, bool asVoid) {
  407. this.Compile(node.Right);
  408. var target = (ParameterExpression)node.Left;
  409. SetVariable(target, asVoid);
  410. }
  411. private void CompileAssignBinaryExpression(Expression expr, bool asVoid) {
  412. var node = (BinaryExpression)expr;
  413. switch (node.Left.NodeType) {
  414. case ExpressionType.Index:
  415. CompileIndexAssignment(node, asVoid); break;
  416. case ExpressionType.MemberAccess:
  417. CompileMemberAssignment(node, asVoid); break;
  418. case ExpressionType.Parameter:
  419. case ExpressionType.Extension:
  420. CompileVariableAssignment(node, asVoid); break;
  421. default:
  422. throw new InvalidOperationException("Invalid lvalue for assignment: " + node.Left.NodeType);
  423. }
  424. }
  425. private void CompileBinaryExpression(Expression expr) {
  426. var node = (BinaryExpression)expr;
  427. if (node.Method != null) {
  428. this.Compile(node.Left);
  429. this.Compile(node.Right);
  430. AddInstruction(new CallInstruction(node.Method));
  431. } else {
  432. switch (node.NodeType) {
  433. case ExpressionType.ArrayIndex:
  434. CompileArrayIndex(node.Left, node.Right);
  435. return;
  436. case ExpressionType.Equal:
  437. CompileEqual(node.Left, node.Right);
  438. return;
  439. case ExpressionType.NotEqual:
  440. CompileNotEqual(node.Left, node.Right);
  441. return;
  442. default:
  443. throw new NotImplementedException();
  444. }
  445. }
  446. }
  447. private void CompileEqual(Expression left, Expression right) {
  448. if (left.Type == typeof(bool) && right.Type == typeof(bool)) {
  449. this.Compile(left);
  450. this.Compile(right);
  451. AddInstruction(EqualBoolInstruction.Instance);
  452. } else if (left.Type == typeof(int) && right.Type == typeof(int)) {
  453. this.Compile(left);
  454. this.Compile(right);
  455. AddInstruction(EqualIntInstruction.Instance);
  456. } else {
  457. throw new NotImplementedException();
  458. }
  459. }
  460. private void CompileNotEqual(Expression left, Expression right) {
  461. if (left.Type == typeof(int) && right.Type == typeof(int)) {
  462. this.Compile(left);
  463. this.Compile(right);
  464. AddInstruction(NotEqualIntInstruction.Instance);
  465. } else if (!left.Type.IsValueType) {
  466. this.Compile(left);
  467. this.Compile(right);
  468. AddInstruction(NotEqualObjectInstruction.Instance);
  469. } else {
  470. throw new NotImplementedException();
  471. }
  472. }
  473. private void CompileArrayIndex(Expression array, Expression index) {
  474. Type elemType = array.Type.GetElementType();
  475. if ((elemType.IsClass || elemType.IsInterface) && index.Type == typeof(int)) {
  476. this.Compile(array);
  477. this.Compile(index);
  478. AddInstruction(ArrayIndexInstruction<object>.Instance);
  479. } else {
  480. throw new NotImplementedException();
  481. }
  482. }
  483. private void CompileIndexExpression(Expression expr) {
  484. var node = (IndexExpression)expr;
  485. if (node.Object.Type.IsArray && node.Arguments.Count == 1) {
  486. CompileArrayIndex(node.Object, node.Arguments[0]);
  487. return;
  488. }
  489. throw new System.NotImplementedException();
  490. }
  491. private void CompileConvertUnaryExpression(Expression expr) {
  492. var node = (UnaryExpression)expr;
  493. // TODO: check the logic on this, but we think we can ignore conversions in this boxed world
  494. Compile(node.Operand);
  495. if (node.Method != null) {
  496. // We should be able to ignore Int32ToObject
  497. if (node.Method != Runtime.ScriptingRuntimeHelpers.Int32ToObjectMethod) {
  498. AddInstruction(new CallInstruction(node.Method));
  499. }
  500. }
  501. }
  502. private void CompileNotExpression(UnaryExpression node) {
  503. if (node.Operand.Type == typeof(bool)) {
  504. this.Compile(node.Operand);
  505. AddInstruction(NotInstruction.Instance);
  506. } else {
  507. throw new NotImplementedException();
  508. }
  509. }
  510. private void CompileUnaryExpression(Expression expr) {
  511. var node = (UnaryExpression)expr;
  512. if (node.Method != null) {
  513. this.Compile(node.Operand);
  514. AddInstruction(new CallInstruction(node.Method));
  515. } else {
  516. switch (node.NodeType) {
  517. case ExpressionType.Not:
  518. CompileNotExpression(node);
  519. return;
  520. default:
  521. throw new NotImplementedException();
  522. }
  523. }
  524. }
  525. private void CompileAndAlsoBinaryExpression(Expression expr) {
  526. var node = (BinaryExpression)expr;
  527. if (node.Left.Type == typeof(bool)) {
  528. this.Compile(node.Left);
  529. var elseLabel = MakeLabel();
  530. var endLabel = MakeLabel();
  531. AddBranch(new BranchFalseInstruction(), elseLabel);
  532. this.Compile(node.Right);
  533. AddBranch(endLabel);
  534. elseLabel.Mark();
  535. PushConstant(false);
  536. endLabel.Mark();
  537. return;
  538. }
  539. throw new System.NotImplementedException();
  540. }
  541. private void CompileConditionalExpression(Expression expr, bool asVoid) {
  542. var node = (ConditionalExpression)expr;
  543. this.Compile(node.Test);
  544. if (node.IfTrue == AstUtils.Empty()) {
  545. var endOfFalse = MakeLabel();
  546. AddBranch(new BranchTrueInstruction(), endOfFalse);
  547. this.Compile(node.IfFalse, asVoid);
  548. endOfFalse.Mark();
  549. } else {
  550. var endOfTrue = MakeLabel();
  551. AddBranch(new BranchFalseInstruction(), endOfTrue);
  552. this.Compile(node.IfTrue, asVoid);
  553. if (node.IfFalse != AstUtils.Empty()) {
  554. var endOfFalse = MakeLabel();
  555. AddBranch(endOfFalse);
  556. endOfTrue.Mark();
  557. this.Compile(node.IfFalse, asVoid);
  558. endOfFalse.Mark();
  559. } else {
  560. endOfTrue.Mark();
  561. }
  562. }
  563. }
  564. private void CompileLoopExpression(Expression expr) {
  565. var node = (LoopExpression)expr;
  566. var continueLabel = node.ContinueLabel == null ?
  567. MakeLabel() : ReferenceLabel(node.ContinueLabel);
  568. continueLabel.Mark();
  569. this.Compile(node.Body);
  570. if (node.Body.Type != typeof(void)) {
  571. AddInstruction(PopInstruction.Instance);
  572. }
  573. AddBranch(continueLabel);
  574. if (node.BreakLabel != null) {
  575. ReferenceLabel(node.BreakLabel).Mark();
  576. }
  577. }
  578. private void CompileSwitchExpression(Expression expr) {
  579. var node = (SwitchExpression)expr;
  580. // Currently only supports int test values, with no method
  581. if (node.SwitchValue.Type != typeof(int) || node.Comparison != null) {
  582. throw new NotImplementedException();
  583. }
  584. // Test values must be constant
  585. if (!node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression))) {
  586. throw new NotImplementedException();
  587. }
  588. this.Compile(node.SwitchValue);
  589. int start = _instructions.Count;
  590. var switchInstruction = new SwitchInstruction();
  591. AddInstruction(switchInstruction);
  592. var end = MakeLabel();
  593. int switchStack = _currentStackDepth;
  594. for (int i = 0, n = node.Cases.Count; i < n; i++) {
  595. var clause = node.Cases[i];
  596. _currentStackDepth = switchStack;
  597. int offset = _instructions.Count - start;
  598. foreach (ConstantExpression testValue in clause.TestValues) {
  599. switchInstruction.AddCase((int)testValue.Value, offset);
  600. }
  601. this.Compile(clause.Body);
  602. // Last case doesn't need branch
  603. if (node.DefaultBody != null || i < n - 1) {
  604. AddBranch(end);
  605. }
  606. Debug.Assert(_currentStackDepth == -1 || _currentStackDepth == switchStack);
  607. }
  608. switchInstruction.AddDefault(_instructions.Count - start);
  609. if (node.DefaultBody != null) {
  610. _currentStackDepth = switchStack;
  611. this.Compile(node.DefaultBody);
  612. }
  613. if (node.Type != typeof(void)) {
  614. Debug.Assert(_currentStackDepth == -1 || _currentStackDepth == switchStack + 1);
  615. _currentStackDepth = switchStack + 1;
  616. } else {
  617. Debug.Assert(_currentStackDepth == -1 || _currentStackDepth == switchStack);
  618. _currentStackDepth = switchStack;
  619. }
  620. end.Mark();
  621. }
  622. private void CompileLabelExpression(Expression expr) {
  623. var node = (LabelExpression)expr;
  624. if (node.DefaultValue != null) {
  625. this.Compile(node.DefaultValue);
  626. }
  627. ReferenceLabel(node.Target).Mark();
  628. }
  629. private void CompileGotoExpression(Expression expr) {
  630. var node = (GotoExpression)expr;
  631. //int finalStackDepth = _currentStackDepth;
  632. if (node.Value != null) {
  633. this.Compile(node.Value);
  634. }
  635. var label = ReferenceLabel(node.Target);
  636. var branch = AddBranch(label);
  637. // goto is the only node that can break out of a finally
  638. // so we do this here instead of in the AddBranch method
  639. if (_finallyLabels.Count > 0) {
  640. var labels = _finallyLabels.Peek();
  641. labels.AddBranch(branch, label, node.Value != null);
  642. }
  643. //_currentStackDepth = finalStackDepth;
  644. }
  645. private void CompileThrowUnaryExpression(Expression expr, bool asVoid) {
  646. Debug.Assert(asVoid);
  647. var node = (UnaryExpression)expr;
  648. if (node.Operand == null) {
  649. AddInstruction(GetVariable(_exceptionForRethrowStack.Peek()));
  650. AddInstruction(RethrowInstruction.Instance);
  651. } else {
  652. this.Compile(node.Operand);
  653. AddInstruction(ThrowInstruction.Instance);
  654. }
  655. //TODO _currentStackDepth = -1;
  656. }
  657. //TODO this needs to also check that there are no jumps outside of expr (including returns)
  658. private bool EndsWithRethrow(Expression expr) {
  659. if (expr.NodeType == ExpressionType.Throw) {
  660. var node = (UnaryExpression)expr;
  661. return node.Operand == null;
  662. }
  663. BlockExpression block = expr as BlockExpression;
  664. if (block != null) {
  665. return EndsWithRethrow(block.Expressions[block.Expressions.Count - 1]);
  666. }
  667. return false;
  668. }
  669. private void CompileWithoutRethrow(Expression expr) {
  670. if (expr.NodeType == ExpressionType.Throw) {
  671. var throwNode = (UnaryExpression)expr;
  672. Debug.Assert(throwNode.Operand == null);
  673. _currentStackDepth = -1;
  674. return;
  675. }
  676. BlockExpression node = (BlockExpression)expr;
  677. foreach (var local in node.Variables) {
  678. this.AddVariable(local);
  679. }
  680. for (int i = 0; i < node.Expressions.Count - 1; i++) {
  681. this.Compile(node.Expressions[i]);
  682. if (node.Expressions[i].Type != typeof(void)) {
  683. AddInstruction(PopInstruction.Instance);
  684. }
  685. }
  686. CompileWithoutRethrow(node.Expressions[node.Expressions.Count - 1]);
  687. }
  688. private void CompileTryExpression(Expression expr) {
  689. var node = (TryExpression)expr;
  690. if (node.Fault != null) {
  691. throw new NotImplementedException();
  692. }
  693. // See if the handler is a no-op, in which case we ignore the whole
  694. // try expression.
  695. if (node.Finally == null && node.Handlers.Count == 1) {
  696. var block = node.Handlers[0].Body as BlockExpression;
  697. if (block != null && block.Expressions.Count == 2) {
  698. var skip = block.Expressions[0] as Ast.SkipInterpretExpression;
  699. if (skip != null && EndsWithRethrow(block)) {
  700. new ParameterVisitor(this).Visit(skip);
  701. Compile(node.Body);
  702. return;
  703. }
  704. }
  705. }
  706. Label startOfFinally = MakeLabel();
  707. if (node.Finally != null) {
  708. _finallyLabels.Push(new FinallyLabels(startOfFinally));
  709. }
  710. int startingStack = _currentStackDepth;
  711. int start = _instructions.Count;
  712. this.Compile(node.Body);
  713. int end = _instructions.Count;
  714. if (_currentStackDepth != -1) {
  715. AddBranch(startOfFinally);
  716. }
  717. if (node.Finally == null && node.Handlers.Count == 1) {
  718. var handler = node.Handlers[0];
  719. if (handler.Filter == null && handler.Test == typeof(Exception) && handler.Variable == null) {
  720. if (EndsWithRethrow(handler.Body)) {
  721. var fault = this.AddHandler(null, null, start, end);
  722. _currentStackDepth = startingStack;
  723. CompileWithoutRethrow(handler.Body);
  724. fault.EndHandlerIndex = this._instructions.Count;
  725. startOfFinally.Mark();
  726. return;
  727. }
  728. }
  729. }
  730. foreach (var handler in node.Handlers) {
  731. if (handler.Filter != null) throw new NotImplementedException();
  732. var parameter = handler.Variable;
  733. // TODO we should only create one of these if needed for a rethrow
  734. if (parameter == null) {
  735. parameter = Expression.Parameter(handler.Test, "currentException");
  736. }
  737. // TODO: free the variable when it goes out of scope
  738. AddVariable(parameter);
  739. this.AddHandler(handler.Test, parameter, start, end);
  740. _exceptionForRethrowStack.Push(parameter);
  741. _currentStackDepth = System.Math.Max(startingStack + 1, 1);
  742. SetVariable(parameter, true);
  743. this.Compile(handler.Body);
  744. //TODO pop this scoped variable that we no longer need
  745. //PopVariable(parameter);
  746. _exceptionForRethrowStack.Pop();
  747. AddBranch(startOfFinally);
  748. }
  749. if (node.Finally != null) {
  750. var myLabels = _finallyLabels.Pop();
  751. var myNewTargets = new List<Label>();
  752. int finallyStart = _instructions.Count;
  753. ParameterExpression finallyStateVar = null;
  754. ParameterExpression finallyStackValue = null;
  755. foreach (var kv in myLabels.labels) {
  756. var label = kv.Key;
  757. if (label._index == -1 || label._index < start || label._index > finallyStart) {
  758. myNewTargets.Add(label);
  759. var currentLabel = MakeLabel();
  760. _currentStackDepth = -1;
  761. currentLabel._expectedStackSize = label._expectedStackSize;
  762. currentLabel.Mark();
  763. foreach (var branch in kv.Value) {
  764. currentLabel.SetOffset(branch);
  765. label.RemoveBinding(branch);
  766. }
  767. if (finallyStateVar == null) {
  768. finallyStateVar = Expression.Parameter(typeof(int), "finallyBranch");
  769. AddVariable(finallyStateVar);
  770. finallyStackValue = Expression.Parameter(typeof(object), "stackValue");
  771. AddVariable(finallyStackValue);
  772. }
  773. if (myLabels.labelHasValue[label]) {
  774. SetVariable(finallyStackValue, true);
  775. }
  776. PushConstant(myNewTargets.Count-1);
  777. SetVariable(finallyStateVar, true);
  778. AddBranch(startOfFinally);
  779. }
  780. }
  781. _currentStackDepth = startingStack + ((node.Body.Type == typeof(void)) ? 0 : 1);
  782. startOfFinally.Mark();
  783. var faultHandler = this.AddHandler(null, null, start, end);
  784. this.Compile(node.Finally);
  785. if (node.Finally.Type != typeof(void)) {
  786. AddInstruction(PopInstruction.Instance);
  787. }
  788. faultHandler.EndHandlerIndex = _instructions.Count;
  789. if (finallyStateVar != null) {
  790. // we can make this much more efficient in the future
  791. var si = new SwitchInstruction();
  792. AddInstruction(GetVariable(finallyStateVar));
  793. int switchIndex = _instructions.Count;
  794. AddInstruction(si);
  795. int switchStack = _currentStackDepth;
  796. for (int i = 0; i < myNewTargets.Count; i++) {
  797. _currentStackDepth = switchStack;
  798. si.AddCase(i, _instructions.Count-switchIndex);
  799. if (myLabels.labelHasValue[myNewTargets[i]]) {
  800. AddInstruction(GetVariable(finallyStackValue));
  801. }
  802. var branchInstruction = AddBranch(myNewTargets[i]);
  803. if (_finallyLabels.Count > 0) {
  804. var labels = _finallyLabels.Peek();
  805. labels.AddBranch(branchInstruction, myNewTargets[i], myLabels.labelHasValue[myNewTargets[i]]);
  806. }
  807. }
  808. si.AddDefault(_instructions.Count - switchIndex);
  809. _currentStackDepth = switchStack; // we might exit totally normally!
  810. }
  811. } else {
  812. startOfFinally.Mark();
  813. }
  814. }
  815. private void CompileDynamicExpression(Expression expr) {
  816. var node = (DynamicExpression)expr;
  817. foreach (var arg in node.Arguments) {
  818. this.Compile(arg);
  819. }
  820. AddInstruction(DynamicInstructions.MakeInstruction(node.DelegateType, node.Binder));
  821. }
  822. private void CompileMethodCallExpression(Expression expr) {
  823. var node = (MethodCallExpression)expr;
  824. if (node.Method == _GetCurrentMethod && node.Object == null && node.Arguments.Count == 0) {
  825. // If we call GetCurrentMethod, it will expose details of the
  826. // interpreter's CallInstruction. Instead, we use
  827. // Interpreter.Run, which logically represents the running
  828. // method, and will appear in the stack trace of an exception.
  829. AddInstruction(new PushInstruction(_RunMethod));
  830. return;
  831. }
  832. //TODO support pass by reference and lots of other fancy stuff
  833. if (!node.Method.IsStatic) {
  834. this.Compile(node.Object);
  835. }
  836. foreach (var arg in node.Arguments) {
  837. this.Compile(arg);
  838. }
  839. AddInstruction(new CallInstruction(node.Method));
  840. }
  841. private void CompileNewExpression(Expression expr) {
  842. var node = (NewExpression)expr;
  843. foreach (var arg in node.Arguments) {
  844. this.Compile(arg);
  845. }
  846. AddInstruction(new NewInstruction(node.Constructor));
  847. }
  848. private void CompileMemberExpression(Expression expr) {
  849. var node = (MemberExpression)expr;
  850. var member = node.Member;
  851. FieldInfo fi = member as FieldInfo;
  852. if (fi != null) {
  853. if (fi.IsLiteral) {
  854. PushConstant(fi.GetRawConstantValue());
  855. } else if (fi.IsStatic) {
  856. if (fi.IsInitOnly) {
  857. object value = fi.GetValue(null);
  858. PushConstant(value);
  859. } else {
  860. AddInstruction(new StaticFieldAccessInstruction(fi));
  861. }
  862. } else {
  863. Compile(node.Expression);
  864. AddInstruction(new FieldAccessInstruction(fi));
  865. }
  866. return;
  867. }
  868. PropertyInfo pi = member as PropertyInfo;
  869. if (pi != null) {
  870. var method = pi.GetGetMethod();
  871. if (node.Expression != null) {
  872. this.Compile(node.Expression);
  873. }
  874. AddInstruction(new CallInstruction(method));
  875. return;
  876. }
  877. throw new System.NotImplementedException();
  878. }
  879. private void CompileNewArrayExpression(Expression expr) {
  880. var node = (NewArrayExpression)expr;
  881. foreach (var arg in node.Expressions) {
  882. this.Compile(arg);
  883. }
  884. Type elementType = node.Type.GetElementType();
  885. int count = node.Expressions.Count;
  886. if (node.NodeType == ExpressionType.NewArrayInit) {
  887. AddInstruction(new NewArrayInitInstruction(elementType, count));
  888. } else if (node.NodeType == ExpressionType.NewArrayBounds) {
  889. if (count == 1) {
  890. AddInstruction(new NewArrayBoundsInstruction1(elementType));
  891. } else {
  892. AddInstruction(new NewArrayBoundsInstructionN(elementType, count));
  893. }
  894. } else {
  895. throw new System.NotImplementedException();
  896. }
  897. }
  898. class ParameterVisitor : ExpressionVisitor {
  899. private readonly LightCompiler _compiler;
  900. public ParameterVisitor(LightCompiler compiler) {
  901. _compiler = compiler;
  902. }
  903. protected override Expression VisitParameter(ParameterExpression node) {
  904. _compiler.GetVariable(node);
  905. return node;
  906. }
  907. protected override Expression VisitLambda<T>(Expression<T> node) {
  908. return node;
  909. }
  910. }
  911. private void CompileExtensionExpression(Expression expr) {
  912. var instructionProvider = expr as IInstructionProvider;
  913. if (instructionProvider != null) {
  914. AddInstruction(instructionProvider.GetInstruction(this));
  915. // we need to walk the reduced expression in case it has any closure
  916. // variables that we'd need to track when we actually turn around and
  917. // compile it
  918. if (expr.CanReduce) {
  919. new ParameterVisitor(this).Visit(expr.Reduce());
  920. }
  921. return;
  922. }
  923. var skip = expr as Ast.SkipInterpretExpression;
  924. if (skip != null) {
  925. new ParameterVisitor(this).Visit(skip);
  926. return;
  927. }
  928. var node = expr as Microsoft.Scripting.Ast.SymbolConstantExpression;
  929. if (node != null) {
  930. PushConstant(node.Value);
  931. return;
  932. }
  933. if (expr.CanReduce) {
  934. Compile(expr.Reduce());
  935. } else {
  936. throw new System.NotImplementedException();
  937. }
  938. }
  939. private void CompileDebugInfoExpression(Expression expr) {
  940. var node = (DebugInfoExpression)expr;
  941. int start = _instructions.Count;
  942. var info = new DebugInfo()
  943. {
  944. Index = start,
  945. FileName = node.Document.FileName,
  946. StartLine = node.StartLine,
  947. EndLine = node.EndLine,
  948. IsClear = node.IsClear
  949. };
  950. _debugInfos.Add(info);
  951. }
  952. private void CompileRuntimeVariablesExpression(Expression expr) {
  953. // Generates IRuntimeVariables for all requested variables
  954. var node = (RuntimeVariablesExpression)expr;
  955. foreach (var variable in node.Variables) {
  956. this.EnsureAvailableForClosure(variable);
  957. AddInstruction(GetBoxedVariable(variable));
  958. }
  959. AddInstruction(new RuntimeVariablesInstruction(node.Variables.Count));
  960. }
  961. private void CompileLambdaExpression(Expression expr) {
  962. var node = (LambdaExpression)expr;
  963. var compiler = new LightCompiler(this);
  964. var interpreter = compiler.CompileTop(node);
  965. int[] closureBoxes = new int[compiler._closureVariables.Count];
  966. for (int i = 0; i < closureBoxes.Length; i++) {
  967. var closureVar = compiler._closureVariables[i];
  968. AddInstruction(GetBoxedVariable(closureVar));
  969. }
  970. AddInstruction(new CreateDelegateInstruction(new LightDelegateCreator(interpreter, node, compiler._closureVariables)));
  971. }
  972. private void CompileCoalesceBinaryExpression(Expression expr) {
  973. throw new System.NotImplementedException();
  974. }
  975. private void CompileInvocationExpression(Expression expr) {
  976. throw new System.NotImplementedException();
  977. }
  978. private void CompileListInitExpression(Expression expr) {
  979. throw new System.NotImplementedException();
  980. }
  981. private void CompileMemberInitExpression(Expression expr) {
  982. throw new System.NotImplementedException();
  983. }
  984. private void CompileOrElseBinaryExpression(Expression expr) {
  985. throw new System.NotImplementedException();
  986. }
  987. private void CompileQuoteUnaryExpression(Expression expr) {
  988. throw new System.NotImplementedException();
  989. }
  990. private void CompileUnboxUnaryExpression(Expression expr) {
  991. throw new System.NotImplementedException();
  992. }
  993. private void CompileTypeBinaryExpression(Expression expr) {
  994. throw new System.NotImplementedException();
  995. }
  996. private void CompileReducibleExpression(Expression expr) {
  997. throw new System.NotImplementedException();
  998. }
  999. internal void Compile(Expression expr, bool asVoid) {
  1000. if (asVoid) {
  1001. CompileAsVoid(expr);
  1002. } else {
  1003. Compile(expr);
  1004. }
  1005. }
  1006. internal void CompileAsVoid(Expression expr) {
  1007. switch (expr.NodeType) {
  1008. case ExpressionType.Assign:
  1009. CompileAssignBinaryExpression(expr, true);
  1010. break;
  1011. case ExpressionType.Block:
  1012. CompileBlockExpression(expr, true);
  1013. break;
  1014. case ExpressionType.Throw:
  1015. CompileThrowUnaryExpression(expr, true);
  1016. break;
  1017. case ExpressionType.Constant:
  1018. case ExpressionType.Default:
  1019. case ExpressionType.Parameter:
  1020. // no-op
  1021. break;
  1022. default:
  1023. Compile(expr);
  1024. if (expr.Type != typeof(void)) {
  1025. AddInstruction(PopInstruction.Instance);
  1026. }
  1027. break;
  1028. }
  1029. }
  1030. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
  1031. public void Compile(Expression expr) {
  1032. int startingStackDepth = this._currentStackDepth;
  1033. switch (expr.NodeType) {
  1034. case ExpressionType.Add: CompileBinaryExpression(expr); break;
  1035. case ExpressionType.AddChecked: CompileBinaryExpression(expr); break;
  1036. case ExpressionType.And: CompileBinaryExpression(expr); break;
  1037. case ExpressionType.AndAlso: CompileAndAlsoBinaryExpression(expr); break;
  1038. case ExpressionType.ArrayLength: CompileUnaryExpression(expr); break;
  1039. case ExpressionType.ArrayIndex: CompileBinaryExpression(expr); break;
  1040. case ExpressionType.Call: CompileMethodCallExpression(expr); break;
  1041. case ExpressionType.Coalesce: CompileCoalesceBinaryExpression(expr); break;
  1042. case ExpressionType.Conditional: CompileConditionalExpression(expr, expr.Type == typeof(void)); break;
  1043. case ExpressionType.Constant: CompileConstantExpression(expr); break;
  1044. case ExpressionType.Convert: CompileConvertUnaryExpression(expr); break;
  1045. case ExpressionType.ConvertChecked: CompileConvertUnaryExpression(expr); break;
  1046. case ExpressionType.Divide: CompileBinaryExpression(expr); break;
  1047. case ExpressionType.Equal: CompileBinaryExpression(expr); break;
  1048. case ExpressionType.ExclusiveOr: CompileBinaryExpression(expr); break;
  1049. case ExpressionType.GreaterThan: CompileBinaryExpression(expr); break;
  1050. case ExpressionType.GreaterThanOrEqual: CompileBinaryExpression(expr); break;
  1051. case ExpressionType.Invoke: CompileInvocationExpression(expr); break;
  1052. case ExpressionType.Lambda: Comp

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