Skip to content

Staged Miniwasm Interpreter #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 32 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
157aabf
try lms
butterunderflow Apr 22, 2025
a11a7ff
compose all parts
butterunderflow Apr 25, 2025
9408c85
Frame should be opaque
butterunderflow Apr 25, 2025
60c782b
function call
butterunderflow Apr 26, 2025
442d8d1
factor out getFuncType
butterunderflow Apr 26, 2025
ab679f3
fix: use restK when non-tail call
butterunderflow Apr 26, 2025
8ba8657
compile Block-like instructions(if-else, loop, block)
butterunderflow Apr 26, 2025
e2cc801
branching instructions
butterunderflow Apr 26, 2025
fa3d628
local set
butterunderflow Apr 27, 2025
d78a96b
operators
butterunderflow Apr 27, 2025
dac7e1c
global instructions
butterunderflow Apr 27, 2025
cc65f63
placeholder for mem instructions
butterunderflow Apr 27, 2025
cf3063a
scala code generation
butterunderflow Apr 27, 2025
80bfa68
some imported function
butterunderflow Apr 27, 2025
881eda4
polish
butterunderflow Apr 27, 2025
7a2bfd4
ci
butterunderflow Apr 27, 2025
294fcea
tweak
butterunderflow Apr 27, 2025
f450b5c
try some simplification
butterunderflow Apr 27, 2025
336eec5
improve runtime(the prelude)
butterunderflow Apr 27, 2025
6a666f3
some fixes
butterunderflow Apr 28, 2025
9947bec
fix: Frame creation is not optimizable
butterunderflow Apr 28, 2025
e7da823
demo br_table's attempts
butterunderflow Apr 29, 2025
2de28f5
fix: tail call
butterunderflow Apr 29, 2025
b5a69dc
fix global
ahuoguo Apr 29, 2025
de8f18e
fix: code generation for global.set
butterunderflow Apr 29, 2025
3bbd27e
brtable seems to work, but there is code duplication problem
Apr 29, 2025
a83eb06
effectful staged interpreter
butterunderflow May 4, 2025
b8a9aea
remove non-sense tests
butterunderflow May 4, 2025
b7b8786
scratch cpp backend
butterunderflow May 5, 2025
0a8339e
some tweaks
butterunderflow May 6, 2025
b4703c7
fix some of the nothing type
Kraks May 12, 2025
29acef0
manually supply the reflect's type arguments
butterunderflow May 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/scala.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ jobs:
sbt 'testOnly gensym.wasm.TestScriptRun'
sbt 'testOnly gensym.wasm.TestConcolic'
sbt 'testOnly gensym.wasm.TestDriver'
sbt 'testOnly gensym.wasm.TestStagedEval'
19 changes: 19 additions & 0 deletions benchmarks/wasm/global.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
(module
(type (;0;) (func (result i32)))
(type (;1;) (func))

(func (;0;) (type 0) (result i32)
i32.const 42
global.set 0
global.get 0
)
(func (;1;) (type 1)
call 0
;; should be 42
;; drop
)
(start 1)
(memory (;0;) 2)
(export "main" (func 1))
(global (;0;) (mut i32) (i32.const 0))
)
11 changes: 11 additions & 0 deletions benchmarks/wasm/staged/brtable.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(module $push-drop
(global (;0;) (mut i32) (i32.const 1048576))
(func (;0;) (type 1) (result i32)
i32.const 2
(block
(block
br_table 0 1 0
)
)
)
(start 0))
11 changes: 10 additions & 1 deletion src/main/scala/wasm/AST.scala
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,16 @@ case class RefType(kind: HeapType) extends ValueType

case class GlobalType(ty: ValueType, mut: Boolean) extends WasmType

abstract class BlockType extends WIR
abstract class BlockType extends WIR {
def funcType: FuncType =
this match {
case VarBlockType(_, None) =>
??? // TODO: fill this branch until we handle type index correctly
case VarBlockType(_, Some(tipe)) => tipe
case ValBlockType(Some(tipe)) => FuncType(List(), List(), List(tipe))
case ValBlockType(None) => FuncType(List(), List(), List())
}
}
case class VarBlockType(index: Int, tipe: Option[FuncType]) extends BlockType
case class ValBlockType(tipe: Option[ValueType]) extends BlockType;

Expand Down
13 changes: 2 additions & 11 deletions src/main/scala/wasm/ConcolicMiniWasm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,6 @@ object Primitives {
case NumType(F32Type) => F32V(rng.nextFloat())
case NumType(F64Type) => F64V(rng.nextDouble())
}

def getFuncType(ty: BlockType): FuncType =
ty match {
case VarBlockType(_, None) =>
??? // TODO: fill this branch until we handle type index correctly
case VarBlockType(_, Some(tipe)) => tipe
case ValBlockType(Some(tipe)) => FuncType(List(), List(), List(tipe))
case ValBlockType(None) => FuncType(List(), List(), List())
}
}

case class Frame(module: ModuleInstance, locals: ArrayBuffer[Value], symLocals: ArrayBuffer[SymVal])
Expand Down Expand Up @@ -383,15 +374,15 @@ case class Evaluator(module: ModuleInstance) {
eval(rest, concStack, symStack, frame, kont, trail)
case Unreachable => throw new RuntimeException("Unreachable")
case Block(ty, inner) =>
val funcTy = getFuncType(ty)
val funcTy = ty.funcType
val (inputSize, outputSize) = (funcTy.inps.size, funcTy.out.size)
val (inputs, restStack) = concStack.splitAt(inputSize)
val (symInputs, restSymStack) = symStack.splitAt(inputSize)
val restK: Cont = (retStack, retSymStack, tree) =>
eval(rest, retStack.take(outputSize) ++ restStack, retSymStack.take(outputSize) ++ restSymStack, frame, kont, trail)(tree)
eval(inner, inputs, symInputs, frame, restK, restK :: trail)
case Loop(ty, inner) =>
val funcTy = getFuncType(ty)
val funcTy = ty.funcType
val (inputSize, outputSize) = (funcTy.inps.size, funcTy.out.size)
val (inputs, restStack) = concStack.splitAt(inputSize)
val (symInputs, restSymStack) = symStack.splitAt(inputSize)
Expand Down
19 changes: 5 additions & 14 deletions src/main/scala/wasm/MiniWasm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,6 @@ object Primtives {
case VecType(kind) => ???
case RefType(kind) => RefNullV(kind)
}

def getFuncType(ty: BlockType): FuncType =
ty match {
case VarBlockType(_, None) =>
??? // TODO: fill this branch until we handle type index correctly
case VarBlockType(_, Some(tipe)) => tipe
case ValBlockType(Some(tipe)) => FuncType(List(), List(), List(tipe))
case ValBlockType(None) => FuncType(List(), List(), List())
}
}

case class Frame(locals: ArrayBuffer[Value])
Expand All @@ -264,8 +255,8 @@ case class Evaluator(module: ModuleInstance) {
val frameLocals = args ++ locals.map(zero(_))
val newFrame = Frame(ArrayBuffer(frameLocals: _*))
if (isTail)
// when tail call, share the continuation for returning with the callee
eval(body, List(), newFrame, kont, List(kont))
// when tail call, return to the caller's return continuation
eval(body, List(), newFrame, trail.last, List(trail.last))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for spotting this!

else {
val restK: Cont[Ans] = (retStack) =>
eval(rest, retStack.take(ty.out.size) ++ newStack, frame, kont, trail)
Expand Down Expand Up @@ -380,7 +371,7 @@ case class Evaluator(module: ModuleInstance) {
eval(rest, stack, frame, kont, trail)
case Unreachable => throw Trap()
case Block(ty, inner) =>
val funcTy = getFuncType(ty)
val funcTy = ty.funcType
val (inputs, restStack) = stack.splitAt(funcTy.inps.size)
val restK: Cont[Ans] = (retStack) =>
eval(rest, retStack.take(funcTy.out.size) ++ restStack, frame, kont, trail)
Expand All @@ -389,15 +380,15 @@ case class Evaluator(module: ModuleInstance) {
// 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 funcTy = getFuncType(ty)
val funcTy = ty.funcType
val (inputs, restStack) = stack.splitAt(funcTy.inps.size)
val restK: Cont[Ans] = (retStack) =>
eval(rest, retStack.take(funcTy.out.size) ++ restStack, frame, kont, trail)
def loop(retStack: Stack): Ans =
eval(inner, retStack.take(funcTy.inps.size), frame, restK, loop _ :: trail)
loop(inputs)
case If(ty, thn, els) =>
val funcTy = getFuncType(ty)
val funcTy = ty.funcType
val I32V(cond) :: newStack = stack
val inner = if (cond != 0) thn else els
val (inputs, restStack) = newStack.splitAt(funcTy.inps.size)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/wasm/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ class GSWasmVisitor extends WatParserBaseVisitor[WIR] {
else if (ctx.LOCAL_GET() != null) LocalGet(getVar(ctx.idx(0)).toInt)
else if (ctx.LOCAL_SET() != null) LocalSet(getVar(ctx.idx(0)).toInt)
else if (ctx.LOCAL_TEE() != null) LocalTee(getVar(ctx.idx(0)).toInt)
else if (ctx.GLOBAL_SET() != null) GlobalGet(getVar(ctx.idx(0)).toInt)
else if (ctx.GLOBAL_SET() != null) GlobalSet(getVar(ctx.idx(0)).toInt)
else if (ctx.GLOBAL_GET() != null) GlobalGet(getVar(ctx.idx(0)).toInt)
else if (ctx.load() != null) {
val ty = visitNumType(ctx.load.numType)
Expand Down
Loading