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

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

http://github.com/IronLanguages/main
C# | 1210 lines | 913 code | 173 blank | 124 comment | 39 complexity | ee4f825a1033a25f9afcd91e425ec1d9 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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

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