PageRenderTime 37ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/DLR_Main/Languages/Ruby/IronRuby.Tests/Runtime/InterpreterTests.cs

https://bitbucket.org/mdavid/dlr
C# | 1155 lines | 868 code | 163 blank | 124 comment | 37 complexity | 2a8f225b2b08dc39608b14e1a0829a9d MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. 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 Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System;
  21. using System.Collections.Generic;
  22. using System.IO;
  23. using System.Text;
  24. using Microsoft.Scripting.Generation;
  25. using Microsoft.Scripting.Utils;
  26. using System.Runtime.CompilerServices;
  27. using System.Threading;
  28. using System.Reflection;
  29. namespace IronRuby.Tests {
  30. using Ast = Expression;
  31. using AstUtils = Microsoft.Scripting.Ast.Utils;
  32. public partial class Tests {
  33. #region Tracing Helpers
  34. [ThreadStatic]
  35. public static List<object> _trace = new List<object>();
  36. public static void Trace(object value) {
  37. _trace.Add(value);
  38. }
  39. private Expression TraceCall(Expression arg) {
  40. return Ast.Call(null, typeof(Tests).GetMethod("Trace"), Ast.Convert(arg, typeof(object)));
  41. }
  42. private void RunTraceTest(Expression<Action> lambda, Action<Action> invoker, out object[] compiled, out object[] interpreted, out object[] sync) {
  43. if (invoker == null) {
  44. invoker = (a) => a();
  45. }
  46. invoker(lambda.Compile());
  47. compiled = _trace.ToArray();
  48. _trace.Clear();
  49. // force synchronous compilation:
  50. invoker(lambda.LightCompile(0));
  51. sync = _trace.ToArray();
  52. _trace.Clear();
  53. // force interpretation:
  54. invoker(lambda.LightCompile(Int32.MaxValue));
  55. interpreted = _trace.ToArray();
  56. _trace.Clear();
  57. }
  58. private void TraceTestLambda(Expression<Action> lambda, Type expectedException) {
  59. TraceTestLambda(lambda, (a) => {
  60. try {
  61. a();
  62. Assert(false, "Expected exception " + expectedException);
  63. } catch (Exception e) {
  64. Assert(e.GetType() == expectedException, "Expected exception " + expectedException);
  65. }
  66. });
  67. }
  68. private void TraceTestLambda(Expression<Action> lambda) {
  69. TraceTestLambda(lambda, (Action<Action>)null);
  70. }
  71. private void TraceTestLambda(Expression<Action> lambda, Action<Action> invoker) {
  72. object[] compiled, interpreted, sync;
  73. RunTraceTest(lambda, invoker, out compiled, out interpreted, out sync);
  74. Assert(compiled.ValueEquals(interpreted));
  75. Assert(compiled.ValueEquals(sync));
  76. }
  77. private void XTraceTestLambda(Expression<Action> lambda) {
  78. object[] compiled, interpreted, sync;
  79. RunTraceTest(lambda, null, out compiled, out interpreted, out sync);
  80. Console.WriteLine("-- compiled --");
  81. foreach (var obj in compiled) {
  82. Console.WriteLine(obj);
  83. }
  84. Console.WriteLine("-- interpreted --");
  85. foreach (var obj in interpreted) {
  86. Console.WriteLine(obj);
  87. }
  88. Console.WriteLine("-- sync --");
  89. foreach (var obj in sync) {
  90. Console.WriteLine(obj);
  91. }
  92. }
  93. #endregion
  94. [Options(NoRuntime = true)]
  95. public void Interpreter1A() {
  96. var m_AddValue = new Action<StrongBox<int>, int>(Interpreter1_AddValue).Method;
  97. var m_ThrowNSE = new Action(Interpreter1_ThrowNSE).Method;
  98. var m_f = new Func<int, int, int, int, int>(Interpreter1_f).Method;
  99. var m_g = new Func<int, int, int, int>(Interpreter1_g).Method;
  100. var value = new StrongBox<int>(0);
  101. LabelTarget label;
  102. int rc, ri;
  103. // value of try-catch:
  104. var l0 = Ast.Lambda<Func<int>>(
  105. Ast.TryCatch(Ast.Constant(1, typeof(int)), Ast.Catch(typeof(Exception), Ast.Constant(2, typeof(int))))
  106. );
  107. rc = l0.Compile()();
  108. ri = l0.LightCompile()();
  109. Assert(rc == ri);
  110. // cross-block goto in try-catch-finally:
  111. label = Ast.Label(typeof(int));
  112. var l1 = Ast.Lambda<Func<int>>(
  113. Ast.Label(label, Ast.TryCatchFinally(
  114. Ast.Goto(label, Ast.Constant(1), typeof(int)),
  115. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(1)),
  116. Ast.Catch(typeof(Exception), Ast.Constant(2, typeof(int)))
  117. )));
  118. value.Value = 0;
  119. rc = l1.Compile()();
  120. ri = l1.LightCompile()();
  121. Assert(value.Value == 11);
  122. Assert(rc == ri);
  123. // cross-block goto in try-catch-finally with an exception thrown and caught in finally:
  124. label = Ast.Label(typeof(int));
  125. var l2 = Ast.Lambda<Func<int>>(
  126. Ast.Label(label, Ast.TryCatchFinally(
  127. Ast.Goto(label, Ast.Constant(1), typeof(int)),
  128. Ast.Block(
  129. Ast.TryCatch(
  130. Ast.Call(null, m_ThrowNSE),
  131. Ast.Catch(typeof(NotSupportedException),
  132. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(1))
  133. )
  134. ),
  135. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(2))
  136. ),
  137. Ast.Catch(typeof(Exception), Ast.Constant(2, typeof(int)))
  138. )));
  139. value.Value = 0;
  140. rc = l2.Compile()();
  141. ri = l2.LightCompile()();
  142. Assert(value.Value == 1212);
  143. Assert(rc == ri);
  144. // executing fault and finally blocks for an exception coming from a method call:
  145. label = Ast.Label(typeof(int));
  146. var a = Ast.Lambda<Action>(
  147. Ast.TryCatch(
  148. Ast.TryFinally(// TODO: faults not supported yet: Ast.TryFault(
  149. Ast.TryFinally(
  150. Ast.Call(null, m_ThrowNSE),
  151. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(1))
  152. ),
  153. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(2))
  154. ),
  155. Ast.Catch(typeof(NotSupportedException),
  156. Ast.Call(null, m_AddValue, Ast.Constant(value), Ast.Constant(3))
  157. )
  158. )
  159. );
  160. value.Value = 0;
  161. a.Compile()();
  162. a.LightCompile()();
  163. Assert(value.Value == 123123);
  164. // try-catch with non-empty stack:
  165. var l3 = Ast.Lambda<Func<int>>(
  166. Ast.Call(null, m_f,
  167. Ast.Constant(1),
  168. Ast.Constant(2),
  169. Ast.TryCatch(
  170. Ast.Call(null, m_g,
  171. Ast.Constant(3),
  172. Ast.Constant(4),
  173. Ast.Throw(Ast.Constant(new Exception("!!!")), typeof(int))
  174. ),
  175. Ast.Catch(
  176. typeof(Exception),
  177. Ast.Constant(5)
  178. )
  179. ),
  180. Ast.Constant(7)
  181. )
  182. );
  183. rc = l3.Compile()();
  184. ri = l3.LightCompile()();
  185. Assert(rc == ri);
  186. // goto carrying a value needs to pop the value from the stack before executing finally
  187. // clauses to prevent stack overflow (the finally clause doesn't expect the value on the stack):
  188. var label3 = Ast.Label(typeof(int));
  189. var l4 = Ast.Lambda<Func<int>>(
  190. Ast.Label(label3,
  191. Ast.Block(
  192. Ast.TryFinally(
  193. Ast.Goto(label3, Ast.Constant(1), typeof(void)),
  194. Ast.Call(null, m_g, Ast.Constant(2), Ast.Constant(3), Ast.Constant(4))
  195. ),
  196. Ast.Constant(3)
  197. )
  198. )
  199. );
  200. rc = l4.Compile()();
  201. ri = l4.LightCompile()();
  202. Assert(rc == ri);
  203. // goto needs to pop unused values from the stack before it executes finally:
  204. var label4 = Ast.Label(typeof(int));
  205. var l5 = Ast.Lambda<Func<int>>(
  206. Ast.Label(label4,
  207. Ast.Block(
  208. Ast.TryFinally(
  209. Ast.Call(null, m_g, Ast.Constant(9), Ast.Constant(8), Ast.Goto(label4, Ast.Constant(1), typeof(int))),
  210. Ast.Call(null, m_f, Ast.Constant(2), Ast.Constant(3), Ast.Constant(4), Ast.Constant(5))
  211. ),
  212. Ast.Constant(3)
  213. )
  214. )
  215. );
  216. rc = l5.Compile()();
  217. ri = l5.LightCompile()();
  218. Assert(rc == ri);
  219. }
  220. public static void Interpreter1_AddValue(StrongBox<int> value, int d) {
  221. value.Value = value.Value * 10 + d;
  222. }
  223. public static void Interpreter1_ThrowNSE() {
  224. throw new NotSupportedException();
  225. }
  226. public static int Interpreter1_f(int a, int b, int c, int d) {
  227. return a * 1000 + b * 100 + c * 10 + d;
  228. }
  229. public static int Interpreter1_g(int a, int b, int c) {
  230. return 20;
  231. }
  232. [Options(NoRuntime = true)]
  233. public void Interpreter1B() {
  234. LabelTarget label = Ast.Label();
  235. // throw in a finally that is executed while jumping to a label cancels the jump:
  236. var l0 = Ast.Lambda<Action>(
  237. Ast.TryFinally(
  238. Ast.TryCatch(
  239. Ast.Block(
  240. Ast.TryFinally(
  241. Ast.TryFinally(
  242. Ast.Block(
  243. TraceCall(Ast.Constant(0)),
  244. Ast.Goto(label)
  245. ),
  246. // F2:
  247. Ast.Block(
  248. TraceCall(Ast.Constant(1)),
  249. Ast.Throw(Ast.Constant(new Exception("foo")))
  250. )
  251. ),
  252. // F1:
  253. TraceCall(Ast.Constant(2))
  254. ),
  255. // LABEL:
  256. Ast.Label(label),
  257. TraceCall(Ast.Constant(3))
  258. ),
  259. // CATCH:
  260. Ast.Catch(typeof(Exception),
  261. TraceCall(Ast.Constant(4))
  262. )
  263. ),
  264. // F0:
  265. TraceCall(Ast.Constant(5))
  266. )
  267. );
  268. TraceTestLambda(l0);
  269. // throw in a finally that is executed while jumping to a label cancels the jump:
  270. var l1 = Ast.Lambda<Action>(
  271. Ast.Block(
  272. Ast.TryFinally(
  273. Ast.TryCatch(
  274. Ast.Block(
  275. Ast.TryFinally(
  276. Ast.TryFinally(
  277. Ast.Block(
  278. TraceCall(Ast.Constant(0)),
  279. Ast.Goto(label)
  280. ),
  281. // F2:
  282. Ast.Block(
  283. TraceCall(Ast.Constant(1)),
  284. Ast.Throw(Ast.Constant(new Exception("foo")))
  285. )
  286. ),
  287. // F1:
  288. TraceCall(Ast.Constant(2))
  289. ),
  290. TraceCall(Ast.Constant(3))
  291. ),
  292. // CATCH:
  293. Ast.Catch(typeof(Exception),
  294. TraceCall(Ast.Constant(4))
  295. )
  296. ),
  297. // F0:
  298. TraceCall(Ast.Constant(5))
  299. ),
  300. Ast.Block(
  301. TraceCall(Ast.Constant(6)),
  302. // LABEL:
  303. Ast.Label(label),
  304. TraceCall(Ast.Constant(7))
  305. )
  306. )
  307. );
  308. TraceTestLambda(l1);
  309. // throw caught a try-catch in a finally that is executed while jumping to a label doesn't cancel the jump
  310. var l2 = Ast.Lambda<Action>(
  311. Ast.TryCatch(
  312. Ast.Block(
  313. Ast.TryFinally(
  314. Ast.TryFinally(
  315. Ast.Block(
  316. TraceCall(Ast.Constant(0)),
  317. Ast.Goto(label)
  318. ),
  319. Ast.Block(
  320. TraceCall(Ast.Constant(1)),
  321. Ast.TryCatch(
  322. Ast.Throw(Ast.Constant(new Exception("foo"))),
  323. Ast.Catch(typeof(Exception),
  324. TraceCall(Ast.Constant(2))
  325. )
  326. )
  327. )
  328. ),
  329. TraceCall(Ast.Constant(3))
  330. ),
  331. TraceCall(Ast.Constant(4)),
  332. Ast.Label(label),
  333. TraceCall(Ast.Constant(5))
  334. ),
  335. Ast.Catch(typeof(Exception),
  336. TraceCall(Ast.Constant(6))
  337. )
  338. )
  339. );
  340. TraceTestLambda(l2);
  341. }
  342. /// <summary>
  343. /// Faults.
  344. /// </summary>
  345. [Options(NoRuntime = true)]
  346. public void Interpreter1C() {
  347. var label1 = Ast.Label();
  348. var label2 = Ast.Label();
  349. var inner =
  350. Ast.TryFinally(
  351. Ast.TryCatch(
  352. Ast.TryFinally(
  353. Ast.Block(
  354. TraceCall(Ast.Constant(0)),
  355. Ast.Throw(Ast.Constant(new NotSupportedException("ex1")))
  356. ),
  357. TraceCall(Ast.Constant(1))
  358. ),
  359. Ast.Catch(typeof(Exception),
  360. Ast.Block(
  361. TraceCall(Ast.Constant(2)),
  362. Ast.Rethrow()
  363. )
  364. )
  365. ),
  366. TraceCall(Ast.Constant(3))
  367. );
  368. var l0 = Ast.Lambda<Action>(
  369. Ast.TryCatch(
  370. inner,
  371. Ast.Catch(typeof(Exception),
  372. TraceCall(Ast.Constant(4))
  373. )
  374. )
  375. );
  376. TraceTestLambda(l0);
  377. var l1 = Ast.Lambda<Action>(
  378. Ast.TryCatch(
  379. inner,
  380. Ast.Catch(typeof(InvalidOperationException),
  381. TraceCall(Ast.Constant(4))
  382. )
  383. )
  384. );
  385. TraceTestLambda(l1, typeof(NotSupportedException));
  386. var l2 = Ast.Lambda<Action>(
  387. inner
  388. );
  389. TraceTestLambda(l2, typeof(NotSupportedException));
  390. }
  391. /// <summary>
  392. /// Faults.
  393. /// </summary>
  394. [Options(NoRuntime = true)]
  395. public void Interpreter1D() {
  396. var l1 = Ast.Lambda<Action>(
  397. TraceCall(
  398. Ast.TryCatch(
  399. Ast.Call(null, new Func<int>(ThrowNSEReturnInt).Method),
  400. Ast.Catch(typeof(Exception),
  401. Ast.Block(
  402. Ast.Constant(2),
  403. Ast.Rethrow(typeof(int))
  404. )
  405. )
  406. )
  407. )
  408. );
  409. l1.LightCompile();
  410. }
  411. public static int ThrowNSEReturnInt() {
  412. throw new NotSupportedException();
  413. }
  414. /// <summary>
  415. /// Jump out of finally.
  416. /// </summary>
  417. [Options(NoRuntime = true)]
  418. public void Interpreter_JumpFromFinally1() {
  419. var label1 = Ast.Label();
  420. var label2 = Ast.Label();
  421. var l0 = Ast.Lambda<Action>(
  422. Ast.Block(
  423. Ast.TryFinally(
  424. Ast.Block(
  425. AstUtils.FinallyFlowControl(
  426. Ast.TryFinally(
  427. Ast.TryFinally(
  428. Ast.Block(
  429. TraceCall(Ast.Constant(0)),
  430. Ast.Goto(label1)
  431. ),
  432. // F2:
  433. Ast.Block(
  434. TraceCall(Ast.Constant(1)),
  435. Ast.Goto(label2)
  436. )
  437. ),
  438. // F1:
  439. TraceCall(Ast.Constant(2))
  440. )
  441. ),
  442. TraceCall(Ast.Constant(3)),
  443. // LABEL2:
  444. Ast.Label(label2),
  445. TraceCall(Ast.Constant(4))
  446. ),
  447. // F0:
  448. TraceCall(Ast.Constant(5))
  449. ),
  450. Ast.Block(
  451. TraceCall(Ast.Constant(6)),
  452. // LABEL1:
  453. Ast.Label(label1),
  454. TraceCall(Ast.Constant(7))
  455. )
  456. )
  457. );
  458. TraceTestLambda(l0);
  459. }
  460. /// <summary>
  461. /// Pending continuation override: jump from finally should cancel any pending jumps (gotos or throws) from try-block.
  462. /// </summary>
  463. [Options(NoRuntime = true)]
  464. public void Interpreter_JumpFromFinally2() {
  465. var label = Ast.Label();
  466. var l0 = Ast.Lambda<Action>(
  467. AstUtils.FinallyFlowControl(
  468. Ast.Block(
  469. Ast.TryFinally(
  470. Ast.Throw(Ast.Constant(new Exception("ex"))),
  471. Ast.Block(
  472. TraceCall(Ast.Constant(0)),
  473. Ast.Goto(label)
  474. )
  475. ),
  476. Ast.Label(label),
  477. TraceCall(Ast.Constant(1))
  478. )
  479. )
  480. );
  481. TraceTestLambda(l0);
  482. }
  483. [Options(NoRuntime = true)]
  484. public void Interpreter2() {
  485. Interpreter2_Test<Func<int>>(
  486. (var) => Ast.Lambda<Func<int>>(var),
  487. (c, i) => c() == i()
  488. );
  489. Interpreter2_Test<IRuntimeVariables>(
  490. (var) => Ast.RuntimeVariables(var),
  491. (c, i) => (int)c[0] == (int)i[0]
  492. );
  493. }
  494. private void Interpreter2_Test<TClosure>(Func<ParameterExpression, Expression> closure, Func<TClosure, TClosure, bool> comparer) {
  495. // value of try-catch:
  496. var closureVar = Ast.Parameter(typeof(int), "x");
  497. var indexVar = Ast.Parameter(typeof(int), "i");
  498. var limitVar = Ast.Parameter(typeof(int), "limit");
  499. var closuresVar = Ast.Parameter(typeof(TClosure[]), "closures");
  500. var returnLabel = Ast.Label(typeof(void));
  501. var l0 = Ast.Lambda<Action<int, int, TClosure[]>>(
  502. Ast.Label(returnLabel,
  503. Ast.Loop(
  504. Ast.IfThenElse(
  505. Ast.NotEqual(indexVar, limitVar),
  506. Ast.Block(new[] { closureVar },
  507. Ast.Assign(closureVar, indexVar),
  508. Ast.Assign(Ast.ArrayAccess(closuresVar, indexVar), closure(closureVar)),
  509. Ast.Assign(indexVar, Ast.Add(indexVar, Ast.Constant(1)))
  510. ),
  511. Ast.Return(returnLabel)
  512. )
  513. )
  514. ),
  515. new[] { indexVar, limitVar, closuresVar }
  516. );
  517. var fsc = new TClosure[2];
  518. l0.Compile()(0, 2, fsc);
  519. var fsi = new TClosure[2];
  520. l0.LightCompile()(0, 2, fsi);
  521. Assert(comparer(fsc[0], fsi[0]));
  522. Assert(comparer(fsc[1], fsi[1]));
  523. }
  524. /// <summary>
  525. /// ThreadAbortException handling.
  526. /// </summary>
  527. [Options(NoRuntime = true)]
  528. public void Interpreter3() {
  529. if (_driver.PartialTrust) return;
  530. var label = Ast.Label(typeof(void));
  531. foreach (var gotoLabel in new Expression[] { Ast.Goto(label), Ast.Empty() }) {
  532. var var_tracker = Ast.Parameter(typeof(List<object>));
  533. var var_abort1 = Ast.Parameter(typeof(ThreadAbortException));
  534. var var_e = Ast.Parameter(typeof(Exception));
  535. var var_abort2 = Ast.Parameter(typeof(ThreadAbortException));
  536. var m_Interpreter3_abort = new Action(Interpreter3_abort).Method;
  537. var m_Interpreter3_catchAbortThrowNSE = new Action<List<object>, ThreadAbortException>(Interpreter3_catchAbortThrowNSE).Method;
  538. var m_Interpreter3_catchE = new Action<List<object>, Exception>(Interpreter3_catchE).Method;
  539. var m_Interpreter3_unreachable = new Action<List<object>>(Interpreter3_unreachable).Method;
  540. var m_Interpreter3_catchAbort = new Action<List<object>, ThreadAbortException>(Interpreter3_catchAbort).Method;
  541. var l = Ast.Lambda<Action<List<object>>>(
  542. AstUtils.Try(
  543. AstUtils.Try(
  544. AstUtils.Try(
  545. Ast.Call(null, m_Interpreter3_abort)
  546. ).Catch(var_abort1,
  547. Ast.Call(null, m_Interpreter3_catchAbortThrowNSE, var_tracker, var_abort1)
  548. )
  549. ).Catch(var_e,
  550. Ast.Call(null, m_Interpreter3_catchE, var_tracker, var_e),
  551. gotoLabel
  552. ),
  553. Ast.Call(null, m_Interpreter3_unreachable, var_tracker),
  554. Ast.Label(label, Ast.Call(null, m_Interpreter3_unreachable, var_tracker))
  555. ).Catch(var_abort2,
  556. Ast.Call(null, m_Interpreter3_catchAbort, var_tracker, var_abort2)
  557. ),
  558. new[] { var_tracker }
  559. );
  560. var ctracker = new List<object>();
  561. var itracker = new List<object>();
  562. try {
  563. l.Compile()(ctracker);
  564. l.LightCompile()(itracker);
  565. } catch (ThreadAbortException) {
  566. Thread.ResetAbort();
  567. Assert(false);
  568. return;
  569. }
  570. foreach (var t in new[] { ctracker, itracker }) {
  571. Assert(t.Count == 10);
  572. Assert(t[0] as string == "1");
  573. Assert(t[1] is ThreadAbortException);
  574. Assert(t[2] as string == "stateInfo");
  575. Assert(t[3] as string == "2");
  576. Assert(t[4] is NotSupportedException);
  577. Assert((ThreadState)t[5] == ThreadState.AbortRequested);
  578. Assert(t[6] as string == "3");
  579. Assert(t[7] is ThreadAbortException);
  580. Assert(ReferenceEquals(t[8], t[2]));
  581. Assert((ThreadState)t[9] == ThreadState.AbortRequested);
  582. }
  583. }
  584. }
  585. public static void Interpreter3_abort() {
  586. Thread.CurrentThread.Abort("stateInfo");
  587. }
  588. public static void Interpreter3_catchAbortThrowNSE(List<object> tracker, ThreadAbortException e) {
  589. tracker.Add("1");
  590. tracker.Add(e);
  591. tracker.Add(e.ExceptionState);
  592. throw new NotSupportedException();
  593. }
  594. public static void Interpreter3_catchE(List<object> tracker, Exception e) {
  595. tracker.Add("2");
  596. tracker.Add(e);
  597. tracker.Add(Thread.CurrentThread.ThreadState);
  598. }
  599. public static void Interpreter3_unreachable(List<object> tracker) {
  600. tracker.Add("UNREACHABLE");
  601. }
  602. public static void Interpreter3_catchAbort(List<object> tracker, ThreadAbortException e) {
  603. tracker.Add("3");
  604. tracker.Add(e);
  605. tracker.Add(e.ExceptionState);
  606. tracker.Add(Thread.CurrentThread.ThreadState);
  607. Thread.ResetAbort();
  608. }
  609. public static void Interpreter4() {
  610. // TODO: figure out if this is specified behavior of thread abort:
  611. //var var_tracker = Ast.Parameter(typeof(List<object>));
  612. //var var_abort1 = Ast.Parameter(typeof(ThreadAbortException));
  613. //var var_abort2 = Ast.Parameter(typeof(ThreadAbortException));
  614. //var var_abort3 = Ast.Parameter(typeof(ThreadAbortException));
  615. //var var_abort4 = Ast.Parameter(typeof(ThreadAbortException));
  616. //var m_Interpreter4_abort = new Action(Interpreter4_abort).Method;
  617. //var m_Interpreter4_traceE = new Action<List<object>, ThreadAbortException>(Interpreter4_traceE).Method;
  618. //var m_Interpreter4_traceS = new Action<List<object>, string>(Interpreter4_traceS).Method;
  619. //var m_Interpreter4_reset = new Action<List<object>, ThreadAbortException>(Interpreter4_reset).Method;
  620. //var l = Ast.Lambda<Action<List<object>>>(
  621. // AstUtils.Try(
  622. // AstUtils.Try(
  623. // Ast.Call(null, m_Interpreter4_abort, Ast.Constant("r1"))
  624. // ).Catch(var_abort1,
  625. // Ast.Call(null, m_Interpreter4_traceE, var_tracker, var_abort1),
  626. // AstUtils.Try(
  627. // AstUtils.Try(
  628. // Ast.Call(null, m_Interpreter4_abort, Ast.Constant("r2"))
  629. // ).Catch(var_abort2,
  630. // Ast.Call(null, m_Interpreter4_traceE, var_tracker, var_abort2)
  631. // ),
  632. // Ast.Call(null, m_Interpreter4_traceS, var_tracker, Ast.Constant("1"))
  633. // ).Catch(var_abort3,
  634. // Ast.Call(null, m_Interpreter4_traceE, var_tracker, var_abort3)
  635. // ),
  636. // Ast.Call(null, m_Interpreter4_traceS, var_tracker, Ast.Constant("2"))
  637. // ),
  638. // Ast.Call(null, m_Interpreter4_traceS, var_tracker, Ast.Constant("2"))
  639. // ).Catch(var_abort4,
  640. // Ast.Call(null, m_Interpreter4_reset, var_tracker, var_abort4)
  641. // ),
  642. // new[] { var_tracker }
  643. //);
  644. //var ctracker = new List<object>();
  645. //var itracker = new List<object>();
  646. //try {
  647. // l.Compile()(ctracker);
  648. // //l.LightCompile()(itracker);
  649. //} catch (ThreadAbortException) {
  650. // Thread.ResetAbort();
  651. // Assert(false);
  652. // return;
  653. //}
  654. }
  655. public static void Interpreter4_abort(string value) {
  656. Thread.CurrentThread.Abort(value);
  657. }
  658. public static void Interpreter4_traceE(List<object> tracker, ThreadAbortException e) {
  659. tracker.Add(e.ExceptionState);
  660. }
  661. public static void Interpreter4_traceS(List<object> tracker, string s) {
  662. tracker.Add(s);
  663. }
  664. public static void Interpreter4_reset(List<object> tracker, ThreadAbortException e) {
  665. tracker.Add(e.ExceptionState);
  666. Thread.ResetAbort();
  667. tracker.Add(e.ExceptionState);
  668. }
  669. [Options(NoRuntime = true)]
  670. public void Interpreter5() {
  671. var strArray1 = new string[] { "foo" };
  672. var strArray2 = new string[1, 1];
  673. var strArray3 = new string[1, 1, 1];
  674. var strArray8 = new string[1, 1, 1, 1, 1, 1, 1, 1];
  675. strArray2[0, 0] = "foo";
  676. strArray3[0, 0, 0] = "foo";
  677. strArray8[0, 0, 0, 0, 0, 0, 0, 0] = "foo";
  678. // T[]::Get
  679. Assert("foo" == Ast.Lambda<Func<string>>(
  680. Ast.Call(Ast.Constant(strArray1), typeof(string[]).GetMethod("Get"), Ast.Constant(0))
  681. ).LightCompile()());
  682. // T[]::Set
  683. Ast.Lambda<Action>(
  684. Ast.Call(Ast.Constant(strArray1), typeof(string[]).GetMethod("Set"), Ast.Constant(0), Ast.Constant("bar"))
  685. ).LightCompile()();
  686. Assert(strArray1[0] == "bar");
  687. // T[,]::Get
  688. Assert("foo" == Ast.Lambda<Func<string>>(
  689. Ast.Call(Ast.Constant(strArray2), typeof(string[,]).GetMethod("Get"), Ast.Constant(0), Ast.Constant(0))
  690. ).LightCompile()());
  691. // T[,]::Set
  692. Ast.Lambda<Action>(
  693. Ast.Call(Ast.Constant(strArray2), typeof(string[,]).GetMethod("Set"), Ast.Constant(0), Ast.Constant(0), Ast.Constant("bar"))
  694. ).LightCompile()();
  695. Assert(strArray2[0, 0] == "bar");
  696. // T[,,]::Get
  697. Assert("foo" == Ast.Lambda<Func<string>>(
  698. Ast.Call(Ast.Constant(strArray3), typeof(string[, ,]).GetMethod("Get"), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0))
  699. ).LightCompile()());
  700. // T[,,]::Set
  701. Ast.Lambda<Action>(
  702. Ast.Call(Ast.Constant(strArray3), typeof(string[, ,]).GetMethod("Set"), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0), Ast.Constant("bar"))
  703. ).LightCompile()();
  704. Assert(strArray3[0, 0, 0] == "bar");
  705. // T[*]::Get
  706. Assert("foo" == Ast.Lambda<Func<string>>(
  707. Ast.Call(Ast.Constant(strArray8), typeof(string[, , , , , , ,]).GetMethod("Get"),
  708. Ast.Constant(0), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0),
  709. Ast.Constant(0), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0)
  710. )
  711. ).LightCompile()());
  712. // T[*]::Set
  713. Ast.Lambda<Action>(
  714. Ast.Call(Ast.Constant(strArray8), typeof(string[, , , , , , ,]).GetMethod("Set"),
  715. Ast.Constant(0), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0),
  716. Ast.Constant(0), Ast.Constant(0), Ast.Constant(0), Ast.Constant(0),
  717. Ast.Constant("bar")
  718. )
  719. ).LightCompile()();
  720. Assert(strArray8[0, 0, 0, 0, 0, 0, 0, 0] == "bar");
  721. }
  722. /// <summary>
  723. /// Variable shadowing.
  724. /// </summary>
  725. [Options(NoRuntime = true)]
  726. public void Interpreter6() {
  727. var i_var = Ast.Parameter(typeof(int), "i");
  728. var l1 = Ast.Lambda<Action>(
  729. Ast.Block(new[] { i_var },
  730. Ast.Assign(i_var, Ast.Constant(1)),
  731. TraceCall(i_var),
  732. Ast.Block(new[] { i_var },
  733. Ast.Assign(i_var, Ast.Constant(2)),
  734. TraceCall(i_var)
  735. ),
  736. Ast.Block(new[] { i_var },
  737. Ast.Assign(i_var, Ast.Constant(3)),
  738. TraceCall(i_var)
  739. ),
  740. TraceCall(i_var)
  741. )
  742. );
  743. //XTraceTestLambda(l1);
  744. var e_var = Ast.Parameter(typeof(Exception), "e");
  745. var ex1 = new Exception("ex1");
  746. var ex2 = new Exception("ex2");
  747. // each catch block actually defines e variable again shadowing the block's e variable.
  748. // Thus assignments within the catch block don't affect block's e variable.
  749. var l2 = Ast.Lambda<Action>(
  750. Ast.Block(new[] { e_var },
  751. Ast.TryCatch(Ast.Throw(Ast.Constant(ex1)), Ast.Catch(e_var, TraceCall(Ast.Property(e_var, "Message")))),
  752. TraceCall(e_var),
  753. Ast.TryCatch(Ast.Throw(Ast.Constant(ex2)), Ast.Catch(e_var, TraceCall(Ast.Property(e_var, "Message")))),
  754. TraceCall(e_var)
  755. )
  756. );
  757. l2.Compile()();
  758. //XTraceTestLambda(l2);
  759. var l3 = Ast.Lambda<Action>(
  760. Ast.Block(new[] { i_var },
  761. TraceCall(
  762. Ast.Invoke(
  763. Ast.Lambda<Func<int, int>>(Ast.Add(i_var, Ast.Constant(1)), new[] { i_var }),
  764. Ast.Constant(1)
  765. )
  766. )
  767. )
  768. );
  769. l3.Compile()();
  770. //XTraceTestLambda(l2);
  771. // TODO: add tests for loop compiler
  772. }
  773. [Options(NoRuntime = true)]
  774. public void InterpreterNumeric1() {
  775. Assert(Expression.Lambda<Func<short>>(
  776. Expression.Add(Expression.Constant((short)1), Expression.Constant((short)2))
  777. ).LightCompile()() == 3);
  778. Assert(Expression.Lambda<Func<int>>(
  779. Expression.Add(Expression.Constant((int)1), Expression.Constant((int)2))
  780. ).LightCompile()() == 3);
  781. Assert(Expression.Lambda<Func<short>>(
  782. Expression.AddChecked(Expression.Constant((short)1), Expression.Constant((short)2))
  783. ).LightCompile()() == 3);
  784. Assert(Expression.Lambda<Func<bool>>(
  785. Expression.LessThan(Expression.Constant((byte)1), Expression.Constant((byte)2))
  786. ).LightCompile()() == true);
  787. Assert(Expression.Lambda<Func<bool>>(
  788. Expression.Equal(Expression.Constant(true), Expression.Constant(false))
  789. ).LightCompile()() == false);
  790. object obj1 = 1;
  791. object obj2 = 1;
  792. Assert(Expression.Lambda<Func<bool>>(
  793. Expression.Equal(Expression.Constant(obj1, typeof(object)), Expression.Constant(obj2, typeof(object)))
  794. ).LightCompile()() == false);
  795. Assert(Expression.Lambda<Func<bool>>(
  796. Expression.Equal(Expression.Constant(1), Expression.Constant(1))
  797. ).LightCompile()() == true);
  798. }
  799. public class ClassWithMethods2 {
  800. private readonly string Str = "<this>";
  801. public static void SF0() { TestValues.Add("0"); }
  802. public static void SF1(string a) { TestValues.Add(a); }
  803. public static void SF2(string a, string b) { TestValues.Add(a + b); }
  804. public static void SF3(string a, string b, string c) { TestValues.Add(a + b + c); }
  805. public static void SF4(string a, string b, string c, string d) { TestValues.Add(a + b + c + d); }
  806. public static void SF5(string a, string b, string c, string d, string e) { TestValues.Add(a + b + c + d + e); }
  807. public static string SG0() { TestValues.Add("0"); return "G0"; }
  808. public static string SG1(string a) { TestValues.Add(a); return "G1"; }
  809. public static string SG2(string a, string b) { TestValues.Add(a + b); return "G2"; }
  810. public static string SG3(string a, string b, string c) { TestValues.Add(a + b + c); return "G3"; }
  811. public static string SG4(string a, string b, string c, string d) { TestValues.Add(a + b + c + d); return "G4"; }
  812. public static string SG5(string a, string b, string c, string d, string e) { TestValues.Add(a + b + c + d + e); return "G5"; }
  813. public void F0() { TestValues.Add(Str + "0"); }
  814. public void F1(string a) { TestValues.Add(Str + a); }
  815. public void F2(string a, string b) { TestValues.Add(Str + a + b); }
  816. public void F3(string a, string b, string c) { TestValues.Add(Str + a + b + c); }
  817. public void F4(string a, string b, string c, string d) { TestValues.Add(Str + a + b + c + d); }
  818. public void F5(string a, string b, string c, string d, string e) { TestValues.Add(Str + a + b + c + d + e); }
  819. public string G0() { TestValues.Add(Str + "0"); return "G0"; }
  820. public string G1(string a) { TestValues.Add(Str + a); return "G1"; }
  821. public string G2(string a, string b) { TestValues.Add(Str + a + b); return "G2"; }
  822. public string G3(string a, string b, string c) { TestValues.Add(Str + a + b + c); return "G3"; }
  823. public string G4(string a, string b, string c, string d) { TestValues.Add(Str + a + b + c + d); return "G4"; }
  824. public string G5(string a, string b, string c, string d, string e) { TestValues.Add(Str + a + b + c + d + e); return "G5"; }
  825. }
  826. private static MethodInfo GM2(string name) {
  827. return typeof(ClassWithMethods2).GetMethod(name);
  828. }
  829. [ThreadStatic]
  830. private static List<string> TestValues = new List<string>();
  831. [Options(NoRuntime = true)]
  832. public void InterpreterMethodCalls1() {
  833. var sf = Expression.Lambda<Action>(Ast.Block(
  834. Ast.Call(null, GM2("SF0")),
  835. Ast.Call(null, GM2("SF1"), Ast.Constant("1")),
  836. Ast.Call(null, GM2("SF2"), Ast.Constant("1"), Ast.Constant("2")),
  837. Ast.Call(null, GM2("SF3"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3")),
  838. Ast.Call(null, GM2("SF4"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4")),
  839. Ast.Call(null, GM2("SF5"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4"), Ast.Constant("5"))
  840. ));
  841. var sg = Expression.Lambda<Func<string[]>>(Ast.NewArrayInit(typeof(string),
  842. Ast.Call(null, GM2("SG0")),
  843. Ast.Call(null, GM2("SG1"), Ast.Constant("1")),
  844. Ast.Call(null, GM2("SG2"), Ast.Constant("1"), Ast.Constant("2")),
  845. Ast.Call(null, GM2("SG3"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3")),
  846. Ast.Call(null, GM2("SG4"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4")),
  847. Ast.Call(null, GM2("SG5"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4"), Ast.Constant("5"))
  848. ));
  849. var i = Expression.Constant(new ClassWithMethods2());
  850. var f = Expression.Lambda<Action>(Ast.Block(
  851. Ast.Call(i, GM2("F0")),
  852. Ast.Call(i, GM2("F1"), Ast.Constant("1")),
  853. Ast.Call(i, GM2("F2"), Ast.Constant("1"), Ast.Constant("2")),
  854. Ast.Call(i, GM2("F3"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3")),
  855. Ast.Call(i, GM2("F4"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4")),
  856. Ast.Call(i, GM2("F5"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4"), Ast.Constant("5"))
  857. ));
  858. var g = Expression.Lambda<Func<string[]>>(Ast.NewArrayInit(typeof(string),
  859. Ast.Call(i, GM2("G0")),
  860. Ast.Call(i, GM2("G1"), Ast.Constant("1")),
  861. Ast.Call(i, GM2("G2"), Ast.Constant("1"), Ast.Constant("2")),
  862. Ast.Call(i, GM2("G3"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3")),
  863. Ast.Call(i, GM2("G4"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4")),
  864. Ast.Call(i, GM2("G5"), Ast.Constant("1"), Ast.Constant("2"), Ast.Constant("3"), Ast.Constant("4"), Ast.Constant("5"))
  865. ));
  866. sf.Compile()();
  867. var c_sg_result = sg.Compile()();
  868. f.Compile()();
  869. var c_g_result = g.Compile()();
  870. string[] c_list = TestValues.ToArray();
  871. TestValues.Clear();
  872. sf.LightCompile()();
  873. var i_sg_result = sg.LightCompile()();
  874. f.LightCompile()();
  875. var i_g_result = g.LightCompile()();
  876. string[] i_list = TestValues.ToArray();
  877. TestValues.Clear();
  878. Assert(ArrayUtils.ValueEquals(c_sg_result, i_sg_result));
  879. Assert(ArrayUtils.ValueEquals(c_g_result, i_g_result));
  880. Assert(ArrayUtils.ValueEquals(c_list, i_list));
  881. }
  882. [Options(NoRuntime = true)]
  883. public void InterpreterLoops1() {
  884. ParameterExpression i_var = Ast.Parameter(typeof(int), "i");
  885. ParameterExpression s_var = Ast.Parameter(typeof(string), "s");
  886. ParameterExpression s2_var = Ast.Parameter(typeof(string), "s2");
  887. LabelTarget break2_label = Ast.Label();
  888. LabelTarget break1_label = Ast.Label();
  889. LabelTarget label1 = Ast.Label();
  890. var l = Expression.Lambda<Action>(
  891. Ast.Block(new[] { i_var },
  892. Ast.Assign(i_var, Ast.Constant(0)),
  893. Ast.Loop(
  894. Ast.Block(new[] { s2_var },
  895. Ast.Assign(s2_var, Ast.Constant("z")),
  896. Ast.Loop(
  897. Ast.Block(
  898. new[] { s_var },
  899. Ast.Assign(s_var, Ast.Constant("a")),
  900. Ast.IfThen(Ast.Equal(Expression.Assign(i_var, Ast.Add(i_var, Ast.Constant(1))), Ast.Constant(3)), Ast.Break(break2_label)),
  901. Ast.IfThen(Ast.Equal(i_var, Ast.Constant(5)), Ast.Break(label1)),
  902. TraceCall(s_var),
  903. TraceCall(s2_var)
  904. ),
  905. break2_label
  906. ),
  907. TraceCall(Ast.Constant("d"))
  908. )
  909. ),
  910. TraceCall(Ast.Constant("b")),
  911. Ast.Label(label1),
  912. TraceCall(Ast.Constant("c"))
  913. )
  914. );
  915. TraceTestLambda(l);
  916. }
  917. public static void MethodWithRef(ref int foo) {
  918. foo++;
  919. }
  920. [Options(NoRuntime = true)]
  921. public void InterpreterLoops2() {
  922. ParameterExpression i_var = Ast.Parameter(typeof(int), "i");
  923. ParameterExpression k_var = Ast.Parameter(typeof(int), "k");
  924. ParameterExpression j_var = Ast.Parameter(typeof(int), "j");
  925. ParameterExpression o_var = Ast.Parameter(typeof(object), "o");
  926. ParameterExpression d_var = Ast.Parameter(typeof(Func<int>), "d");
  927. LabelTarget label1 = Ast.Label();
  928. LabelTarget label2 = Ast.Label();
  929. var innerLambda = Ast.Lambda<Func<int>>(
  930. Ast.Block(new[] { k_var },
  931. Ast.Assign(k_var, Ast.Constant(0)),
  932. Ast.Loop(
  933. Ast.Block(
  934. Ast.IfThen(Ast.Equal(Ast.Assign(k_var, Ast.Add(k_var, Ast.Constant(1))), Ast.Constant(5)), Ast.Goto(label2)),
  935. Ast.Assign(j_var, Ast.Add(j_var, Ast.Constant(1)))
  936. )
  937. ),
  938. Ast.Label(label2),
  939. j_var
  940. )
  941. );
  942. var l = Expression.Lambda<Action>(
  943. Ast.Block(new[] { i_var, j_var, d_var },
  944. Ast.Assign(i_var, Ast.Constant(0)),
  945. Ast.Assign(j_var, Ast.Constant(-1)),
  946. // close over j:
  947. Ast.Assign(d_var, innerLambda),
  948. Ast.Loop(
  949. Ast.Block(
  950. Ast.IfThen(Ast.Equal(Ast.Assign(i_var, Ast.Add(i_var, Ast.Constant(1))), Ast.Constant(5)), Ast.Return(label1)),
  951. // this assignment must be to the closure Value not to the local j_var:
  952. Ast.Assign(j_var, i_var),
  953. TraceCall(Ast.Convert(Ast.Invoke(d_var), typeof(Object)))
  954. )
  955. ),
  956. Ast.Label(label1)
  957. )
  958. );
  959. TraceTestLambda(l);
  960. }
  961. /// <summary>
  962. /// Gotos with values jumping from the loop.
  963. /// </summary>
  964. [Options(NoRuntime = true)]
  965. public void InterpreterLoops3() {
  966. ParameterExpression i_var = Ast.Parameter(typeof(int), "i");
  967. LabelTarget label1 = Ast.Label(typeof(int));
  968. var l = Ast.Lambda<Action>(
  969. Ast.Block(new[] { i_var },
  970. Ast.Assign(i_var,
  971. Ast.Block(
  972. Ast.Loop(
  973. Ast.Goto(label1, Ast.Constant(123))
  974. ),
  975. Ast.Label(label1, Ast.Constant(5))
  976. )
  977. ),
  978. TraceCall(i_var)
  979. )
  980. );
  981. TraceTestLambda(l);
  982. }
  983. [Options(NoRuntime = true)]
  984. public void InterpreterLoops4() {
  985. ParameterExpression i_var = Ast.Parameter(typeof(int), "i");
  986. ParameterExpression j_var = Ast.Parameter(typeof(int), "j");
  987. ParameterExpression k_var = Ast.Parameter(typeof(int), "k");
  988. LabelTarget label1 = Ast.Label();
  989. var l = Ast.Lambda<Action>(
  990. Ast.Block(new[] { i_var },
  991. Ast.Loop(
  992. Ast.Block(new[]