diff --git a/benchmarks/wasm/return.wat b/benchmarks/wasm/return.wat index f9609173..5bf59d17 100644 --- a/benchmarks/wasm/return.wat +++ b/benchmarks/wasm/return.wat @@ -1,13 +1,16 @@ (module (type (;0;) (func)) - (func (;0;) (type 0) - block ;; label = @1 + (type (;1;) (func (result i32))) + (func (type 1) + block + i32.const 42 return end - unreachable + i32.const 100 ) - (func (;1;) (type 0) + (func (type 0) call 0 + unreachable ) (start 1) -) \ No newline at end of file +) diff --git a/benchmarks/wasm/tribonacci.wat b/benchmarks/wasm/tribonacci.wat new file mode 100644 index 00000000..01a50848 --- /dev/null +++ b/benchmarks/wasm/tribonacci.wat @@ -0,0 +1,43 @@ +(module + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func (;0;) (type 0) (param i32) (result i32) + local.get 0 + if (result i32) ;; label = @1 + local.get 0 + i32.const 1 + i32.eq + if (result i32) ;; label = @2 + i32.const 1 + else + local.get 0 + i32.const 2 + i32.eq + if (result i32) ;; label = @3 + i32.const 1 + else + local.get 0 + i32.const 1 + i32.sub + call 0 + local.get 0 + i32.const 2 + i32.sub + call 0 + i32.add + local.get 0 + i32.const 3 + i32.sub + call 0 + i32.add + end + end + else + i32.const 0 + end) + (func (;1;) (type 1) (result i32) + i32.const 12 + call 0) + (start 1) + (memory (;0;) 0) + (export "memory" (memory 0))) diff --git a/benchmarks/wasm/tribonacci_ret.rs b/benchmarks/wasm/tribonacci_ret.rs new file mode 100644 index 00000000..ae576056 --- /dev/null +++ b/benchmarks/wasm/tribonacci_ret.rs @@ -0,0 +1,13 @@ +#[no_mangle] +#[inline(never)] +fn tribonacci(n: i32) -> i32 { + if n == 0 { 0 } + else if n == 1 { 1 } + else if n == 2 { 1 } + else { tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3) } +} + +#[no_mangle] +fn real_main() -> i32 { + tribonacci(12) +} diff --git a/benchmarks/wasm/tribonacci_ret.wat b/benchmarks/wasm/tribonacci_ret.wat new file mode 100644 index 00000000..88e70e23 --- /dev/null +++ b/benchmarks/wasm/tribonacci_ret.wat @@ -0,0 +1,68 @@ +(module $tribonacci.wat.temp + (type (;0;) (func (param i32) (result i32))) + (type (;1;) (func (result i32))) + (func $tribonacci (type 0) (param i32) (result i32) + (local i32 i32) + local.get 0 + i32.const 2 + i32.shl + i32.const 1048576 + i32.add + local.set 1 + i32.const 0 + local.set 2 + local.get 0 + local.set 0 + loop (result i32) ;; label = @1 + local.get 2 + local.set 2 + local.get 1 + local.set 1 + block ;; label = @2 + local.get 0 + local.tee 0 + i32.const 2 + i32.gt_u + br_if 0 (;@2;) + local.get 1 + i32.load + local.get 2 + i32.add + return + end + local.get 1 + i32.const -12 + i32.add + local.set 1 + local.get 0 + i32.const -1 + i32.add + call $tribonacci + local.get 0 + i32.const -2 + i32.add + call $tribonacci + i32.add + local.get 2 + i32.add + local.set 2 + local.get 0 + i32.const -3 + i32.add + local.set 0 + br 0 (;@1;) + end) + (func $real_main (type 1) (result i32) + i32.const 12 + call $tribonacci) + (table (;0;) 1 1 funcref) + (memory (;0;) 17) + (global $__stack_pointer (mut i32) (i32.const 1048576)) + (global (;1;) i32 (i32.const 1048588)) + (global (;2;) i32 (i32.const 1048592)) + (export "memory" (memory 0)) + (export "tribonacci" (func $tribonacci)) + (export "real_main" (func $real_main)) + (export "__data_end" (global 1)) + (export "__heap_base" (global 2)) + (data $.rodata (i32.const 1048576) "\00\00\00\00\01\00\00\00\01\00\00\00")) diff --git a/src/main/scala/wasm/MiniWasm.scala b/src/main/scala/wasm/MiniWasm.scala index b2789e2e..8efe0e12 100644 --- a/src/main/scala/wasm/MiniWasm.scala +++ b/src/main/scala/wasm/MiniWasm.scala @@ -7,6 +7,8 @@ import gensym.wasm.memory._ import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.HashMap +case class Trap() extends Exception + case class ModuleInstance( types: List[FuncType], funcs: HashMap[Int, WIR], @@ -259,7 +261,7 @@ object Evaluator { eval(rest, I32V(value) :: newStack, frame, kont, trail, ret) case Nop => eval(rest, stack, frame, kont, trail, ret) - case Unreachable => throw new RuntimeException("Unreachable") + case Unreachable => throw Trap() case Block(ty, inner) => val k: Cont[Ans] = (retStack) => eval(rest, retStack.take(ty.toList.size) ++ stack, frame, kont, trail, ret) @@ -302,7 +304,7 @@ object Evaluator { eval(rest, retStack.take(ty.out.size) ++ newStack, frame, kont, trail, ret) // We push newK on the trail since function creates a new block to escape // (more or less like `return`) - eval(body, List(), newFrame, newK, newK :: trail, ret+1) + eval(body, List(), newFrame, newK, List(newK), 0) case Call(f) if frame.module.funcs(f).isInstanceOf[Import] => frame.module.funcs(f) match { case Import("console", "log", _) => diff --git a/src/test/scala/genwasym/TestEval.scala b/src/test/scala/genwasym/TestEval.scala index f2d66b15..1c808fad 100644 --- a/src/test/scala/genwasym/TestEval.scala +++ b/src/test/scala/genwasym/TestEval.scala @@ -14,8 +14,6 @@ import collection.mutable.ArrayBuffer import org.scalatest.FunSuite class TestEval extends FunSuite { - - // Mostly testing the files generated form `benchmarks/wasm/test.rs` def testFile(filename: String, main: Option[String] = None, expected: Option[Int] = None) = { @@ -40,10 +38,19 @@ class TestEval extends FunSuite { test("fact") { testFile("./benchmarks/wasm/fact.wat", None, Some(120)) } test("loop") { testFile("./benchmarks/wasm/loop.wat", None, Some(10)) } test("even-odd") { testFile("./benchmarks/wasm/even_odd.wat", None, Some(1)) } - test("return") { testFile("./benchmarks/wasm/return.wat", None, None) } test("load") { testFile("./benchmarks/wasm/load.wat", None, Some(1)) } test("btree") { testFile("./benchmarks/wasm/btree/2o1u-unlabeled.wat") } test("fib") { testFile("./benchmarks/wasm/fib.wat", None, Some(144)) } + test("tribonacci") { testFile("./benchmarks/wasm/tribonacci.wat", None, Some(504)) } + + test("return") { + intercept[gensym.wasm.miniwasm.Trap] { + testFile("./benchmarks/wasm/return.wat", None, None) + } + } + + // FIXME: + //test("tribonacci-ret") { testFile("./benchmarks/wasm/tribonacci_ret.wat", None, Some(504)) } // TODO: add wasm spec tests? How to utilize wast files? }