Skip to content

Commit

Permalink
evalTop runs exported function now
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuoguo committed Oct 14, 2024
1 parent 59151e6 commit 7cf04ea
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 49 deletions.
4 changes: 2 additions & 2 deletions benchmarks/wasm/ack.wat
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "ack" (func $ack))
(export "real_main" (func $real_main))
(export "ack" (func 0))
(export "real_main" (func 1))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))
4 changes: 2 additions & 2 deletions benchmarks/wasm/pow.wat
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
(global (;1;) i32 (i32.const 1048576))
(global (;2;) i32 (i32.const 1048576))
(export "memory" (memory 0))
(export "power" (func $power))
(export "real_main" (func $real_main))
(export "power" (func 0))
(export "real_main" (func 1))
(export "__data_end" (global 1))
(export "__heap_base" (global 2)))
1 change: 0 additions & 1 deletion benchmarks/wasm/return.wat
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@
call 0
unreachable
)
;; (start 1)
(export "$real_main" (func 1))
)
17 changes: 12 additions & 5 deletions grammar/gen-wat-parser.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
#! /usr/bin/env bash
#
ANTLR4=antlr-4.13.0-complete.jar
ANTLR4=antlr-4.13.2-complete.jar

java20 -jar $ANTLR4 WatLexer.g4
java20 -jar $ANTLR4 -visitor WatParser.g4
java -jar $ANTLR4 WatLexer.g4
java -jar $ANTLR4 -visitor WatParser.g4

DST=../src/main/java/wasm/
echo "Copy WAT parsers into $DST"

for file in "WatLexer.java" "WatParserBaseVisitor.java" "WatParserListener.java" "WatParserBaseListener.java" "WatParser.java" "WatParserVisitor.java"
do
sed -i "1ipackage gensym.wasm;$line" $file
cp $file $DST/$file
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' $'1i\\\npackage gensym.wasm;\n' $file
else
sed -i "1ipackage gensym.wasm;$line" $file
fi
cp $file "$DST/$file"
rm $file
done

rm *.tokens *.interp
102 changes: 77 additions & 25 deletions src/main/scala/wasm/MiniWasm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ case class ModuleInstance(
funcs: HashMap[Int, WIR],
memory: List[RTMemory] = List(RTMemory()),
globals: List[RTGlobal] = List(),
exports: List[Export] = List()
)

object Primtives {
Expand Down Expand Up @@ -202,7 +203,12 @@ object Evaluator {
frame.locals(i) = value
eval(rest, stack, frame, kont, trail, ret)
case GlobalGet(i) =>
eval(rest, frame.module.globals(i).value :: stack, frame, kont, trail, ret)
eval(rest,
frame.module.globals(i).value :: stack,
frame,
kont,
trail,
ret)
case GlobalSet(i) =>
val value :: newStack = stack
frame.module.globals(i).ty match {
Expand All @@ -213,14 +219,21 @@ object Evaluator {
}
eval(rest, newStack, frame, kont, trail, ret)
case MemorySize =>
eval(rest, I32V(frame.module.memory.head.size) :: stack, frame, kont, trail, ret)
eval(rest,
I32V(frame.module.memory.head.size) :: stack,
frame,
kont,
trail,
ret)
case MemoryGrow =>
val I32V(delta) :: newStack = stack
val mem = frame.module.memory.head
val oldSize = mem.size
mem.grow(delta) match {
case Some(e) => eval(rest, I32V(-1) :: newStack, frame, kont, trail, ret)
case _ => eval(rest, I32V(oldSize) :: newStack, frame, kont, trail, ret)
case Some(e) =>
eval(rest, I32V(-1) :: newStack, frame, kont, trail, ret)
case _ =>
eval(rest, I32V(oldSize) :: newStack, frame, kont, trail, ret)
}
case MemoryFill =>
val I32V(value) :: I32V(offset) :: I32V(size) :: newStack = stack
Expand Down Expand Up @@ -264,25 +277,41 @@ object Evaluator {
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)
eval(rest,
retStack.take(ty.toList.size) ++ stack,
frame,
kont,
trail,
ret)
// TODO: block can take inputs too
eval(inner, List(), frame, k, k :: trail, ret+1)
eval(inner, List(), frame, k, k :: trail, ret + 1)
case Loop(ty, inner) =>
// We construct two continuations, one for the break (to the begining of the loop),
// and one for fall-through to the next instruction following the syntactic structure
// of the program.
val restK: Cont[Ans] = (retStack) => eval(rest, retStack.take(ty.toList.size) ++ stack, frame, kont, trail, ret)
val restK: Cont[Ans] = (retStack) =>
eval(rest,
retStack.take(ty.toList.size) ++ stack,
frame,
kont,
trail,
ret)
def loop(stack: List[Value]): Ans = {
val k: Cont[Ans] = (retStack) => loop(retStack.take(ty.toList.size))
eval(inner, stack, frame, restK, k :: trail, ret+1)
eval(inner, stack, frame, restK, k :: trail, ret + 1)
}
loop(List())
case If(ty, thn, els) =>
val I32V(cond) :: newStack = stack
val inner = if (cond != 0) thn else els
val k: Cont[Ans] = (retStack) =>
eval(rest, retStack.take(ty.toList.size) ++ newStack, frame, kont, trail, ret)
eval(inner, List(), frame, k, k :: trail, ret+1)
eval(rest,
retStack.take(ty.toList.size) ++ newStack,
frame,
kont,
trail,
ret)
eval(inner, List(), frame, k, k :: trail, ret + 1)
case Br(label) =>
trail(label)(stack)
case BrIf(label) =>
Expand All @@ -301,7 +330,12 @@ object Evaluator {
val frameLocals = args ++ locals.map(_ => I32V(0)) // GW: always I32? or depending on their types?
val newFrame = Frame(frame.module, ArrayBuffer(frameLocals: _*))
val newK: Cont[Ans] = (retStack) =>
eval(rest, retStack.take(ty.out.size) ++ newStack, frame, kont, trail, ret)
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, List(newK), 0)
Expand All @@ -322,23 +356,36 @@ object Evaluator {

// If `main` is given, then we use that function as the entry point of the program;
// otherwise, we look up the top-level `start` instruction to locate the entry point.
def evalTop[Ans](module: Module, halt: Cont[Ans], main: Option[String] = None): Ans = {
def evalTop[Ans](module: Module,
halt: Cont[Ans],
main: Option[String] = None): Ans = {
val instrs = main match {
case Some(_) => module.definitions.flatMap({
case FuncDef(`main`, FuncBodyDef(_, _, _, body)) =>
case Some(func_name) =>
module.definitions.flatMap({
case Export(`func_name`, ExportFunc(fid)) =>
println(s"Entering function $main")
body
module.funcEnv(fid) match {
case FuncDef(_, FuncBodyDef(_, _, _, body)) => body
case _ =>
throw new Exception("Entry function has no concrete body")
}
case _ => List()
})
case None => module.definitions.flatMap({
case Start(id) => module.funcEnv(id) match {
case FuncDef(_, FuncBodyDef(_, _, _, body)) =>
case None =>
module.definitions.flatMap({
case Start(id) =>
println(s"Entering unnamed function $id")
body
case _ => throw new Exception("Start function has no concrete definition")
}
case _ => List()
})
module.funcEnv(id) match {
case FuncDef(_, FuncBodyDef(_, _, _, body)) => body
case _ =>
throw new Exception("Entry function has no concrete body")
}
case _ => List()
})
}

if (instrs.isEmpty) {
println("Warning: nothing is executed")
}

val types = List()
Expand All @@ -354,7 +401,7 @@ object Evaluator {
(e.head) match {
case Const(c) => RTGlobal(ty, c)
// Q: What is the default behavior if case in non-exhaustive
case _ => ???
case _ => ???
}
})
.toList
Expand All @@ -369,7 +416,12 @@ object Evaluator {

val moduleInst = ModuleInstance(types, module.funcEnv, memory, globals)

Evaluator.eval(instrs, List(), Frame(moduleInst, ArrayBuffer(I32V(0))), halt, List(halt), 0)
Evaluator.eval(instrs,
List(),
Frame(moduleInst, ArrayBuffer(I32V(0))),
halt,
List(halt),
0)
}

def evalTop(m: Module): Unit = evalTop(m, stack => ())
Expand Down
17 changes: 13 additions & 4 deletions src/main/scala/wasm/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -567,16 +567,25 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
Global(name, field)
}

override def visitExport(ctx: ExportContext): WIR = {
val name = ctx.name
override def visitExport_(ctx: Export_Context): WIR = {
val name: String = ctx.name.getText.substring(1).dropRight(1)
val desc = visitExportDesc(ctx.exportDesc).asInstanceOf[ExportDesc]
Export(name, desc)
}

override def visitExportDesc(ctx: ExportDescContext): WIR = {
val fid = ctx.idx
val id = if (ctx.idx.VAR() != null) {
println(s"Warning: we don't support labeling yet")
throw new RuntimeException("Unsupported")
} else {
getVar(ctx.idx()).toInt
}
if (ctx.FUNC != null) ExportFunc(id)
else if (ctx.TABLE != null) ExportTable(id)
else if (ctx.MEMORY != null) ExportMemory(id)
else if (ctx.GLOBAL != null) ExportGlobal(id)
else error

ExportFunc(getVar(fid).toInt)
}

}
Expand Down
20 changes: 10 additions & 10 deletions src/test/scala/genwasym/TestEval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ class TestEval extends FunSuite {
// TODO: the power test can be used to test the stack
// For now: 2^10 works, 2^100 results in 0 (TODO: why?),
// and 2^1000 results in a stack overflow
// test("ack") { testFile("./benchmarks/wasm/ack.wat", Some("$real_main"), Some(7)) }
// test("power") { testFile("./benchmarks/wasm/pow.wat", Some("$real_main"), Some(1024)) }
// test("start") { testFile("./benchmarks/wasm/start.wat") }
// 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("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("ack") { testFile("./benchmarks/wasm/ack.wat", Some("real_main"), Some(7)) }
test("power") { testFile("./benchmarks/wasm/pow.wat", Some("real_main"), Some(1024)) }
test("start") { testFile("./benchmarks/wasm/start.wat") }
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("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] {
Expand Down

0 comments on commit 7cf04ea

Please sign in to comment.