-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from bytecodealliance/cfallin/weval-h-and-smok…
…etest Fix weval.h, and add a smoketest.
- Loading branch information
Showing
5 changed files
with
268 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*.wasm | ||
*.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
NAME := simple | ||
|
||
CC := /opt/wasi-sdk/bin/clang | ||
CXX := /opt/wasi-sdk/bin/clang++ | ||
CFLAGS := -I../../include -O2 -g | ||
CXXFLAGS := $(CFLAGS) -std=c++17 | ||
WEVAL := ../../target/release/weval | ||
|
||
.PHONY: all | ||
all: $(NAME).wasm $(NAME)-wevaled.wasm | ||
|
||
$(NAME).wasm: $(NAME).o | ||
$(CXX) $(CXXFLAGS) -o $@ $^ | ||
|
||
$(NAME)-wevaled.wasm: $(NAME).wasm | ||
$(WEVAL) weval -w -i $^ -o $@ | ||
|
||
$(NAME).o: $(NAME).cpp ../../include/weval.h | ||
$(CXX) $(CXXFLAGS) -c -o $@ $< | ||
|
||
.PHONY: clean | ||
clean: | ||
rm -f $(NAME).wasm $(NAME)-wevaled.wasm *.o | ||
|
||
.PHONY: run-base | ||
run-base: $(NAME).wasm | ||
wasmtime run --preload weval=../../lib/weval-stubs.wat $(NAME).wasm | ||
|
||
.PHONY: run-wevaled | ||
run-wevaled: $(NAME)-wevaled.wasm | ||
wasmtime run $(NAME)-wevaled.wasm | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
#include <weval.h> | ||
#include <wizer.h> | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <assert.h> | ||
|
||
WIZER_DEFAULT_INIT(); | ||
WEVAL_DEFINE_GLOBALS(); | ||
|
||
enum Opcode { | ||
PushConst, | ||
Drop, | ||
Dup, | ||
GetLocal, | ||
SetLocal, | ||
Add, | ||
Sub, | ||
Print, | ||
Goto, | ||
GotoIf, | ||
Exit, | ||
}; | ||
|
||
struct Inst { | ||
Opcode opcode; | ||
uint32_t imm; | ||
|
||
explicit Inst(Opcode opcode_) : opcode(opcode_), imm(0) {} | ||
Inst(Opcode opcode_, uint32_t imm_) : opcode(opcode_), imm(imm_) {} | ||
}; | ||
|
||
#define OPSTACK_SIZE 32 | ||
#define LOCAL_SIZE 32 | ||
|
||
struct State { | ||
uint32_t opstack[OPSTACK_SIZE]; | ||
uint32_t locals[LOCAL_SIZE]; | ||
}; | ||
|
||
template<bool Specialized> | ||
uint32_t Interpret(const Inst* insts, uint32_t ninsts, State* state) { | ||
uint32_t pc = 0; | ||
uint32_t steps = 0; | ||
uint32_t* opstack = state->opstack; | ||
uint32_t* locals = state->locals; | ||
int sp = 0; | ||
|
||
if (Specialized) { | ||
weval::push_context(pc); | ||
} | ||
while (true) { | ||
steps++; | ||
const Inst* inst = &insts[pc]; | ||
pc++; | ||
if (Specialized) { | ||
weval::update_context(pc); | ||
} | ||
switch (inst->opcode) { | ||
case PushConst: | ||
if (sp + 1 > OPSTACK_SIZE) { | ||
return 0; | ||
} | ||
opstack[sp++] = inst->imm; | ||
break; | ||
case Drop: | ||
if (sp == 0) { | ||
return 0; | ||
} | ||
sp--; | ||
break; | ||
case Dup: | ||
if (sp + 1 > OPSTACK_SIZE) { | ||
return 0; | ||
} | ||
if (sp == 0) { | ||
return 0; | ||
} | ||
opstack[sp] = opstack[sp - 1]; | ||
sp++; | ||
break; | ||
case GetLocal: | ||
if (sp + 1 > OPSTACK_SIZE) { | ||
return 0; | ||
} | ||
if (inst->imm >= LOCAL_SIZE) { | ||
return 0; | ||
} | ||
opstack[sp++] = locals[inst->imm]; | ||
break; | ||
case SetLocal: | ||
if (sp == 0) { | ||
return 0; | ||
} | ||
if (inst->imm >= LOCAL_SIZE) { | ||
return 0; | ||
} | ||
locals[inst->imm] = opstack[--sp]; | ||
break; | ||
case Add: | ||
if (sp < 2) { | ||
return 0; | ||
} | ||
opstack[sp - 2] += opstack[sp - 1]; | ||
sp--; | ||
break; | ||
case Sub: | ||
if (sp < 2) { | ||
return 0; | ||
} | ||
opstack[sp - 2] -= opstack[sp - 1]; | ||
sp--; | ||
break; | ||
case Print: | ||
if (sp == 0) { | ||
return 0; | ||
} | ||
printf("%u\n", opstack[--sp]); | ||
break; | ||
case Goto: | ||
if (inst->imm >= ninsts) { | ||
return 0; | ||
} | ||
pc = inst->imm; | ||
if (Specialized) { | ||
weval::update_context(pc); | ||
} | ||
break; | ||
case GotoIf: | ||
if (sp == 0) { | ||
return 0; | ||
} | ||
if (inst->imm >= ninsts) { | ||
return 0; | ||
} | ||
sp--; | ||
if (opstack[sp] != 0) { | ||
pc = inst->imm; | ||
if (Specialized) { | ||
weval::update_context(pc); | ||
} | ||
continue; | ||
} | ||
break; | ||
case Exit: | ||
goto out; | ||
} | ||
} | ||
out: | ||
if (Specialized) { | ||
weval::pop_context(); | ||
} | ||
|
||
printf("Exiting after %d steps at PC %d.\n", steps, pc); | ||
return steps; | ||
} | ||
|
||
static const uint32_t kIters = 10000000; | ||
Inst prog[] = { | ||
Inst(PushConst, 0), | ||
Inst(Dup), | ||
Inst(PushConst, kIters), | ||
Inst(Sub), | ||
Inst(GotoIf, 6), | ||
Inst(Exit), | ||
Inst(PushConst, 1), | ||
Inst(Add), | ||
Inst(Goto, 1), | ||
}; | ||
static const uint32_t kExpectedSteps = 7*kIters + 6; | ||
|
||
typedef uint32_t (*InterpretFunc)(const Inst* insts, uint32_t ninsts, State* state); | ||
|
||
WEVAL_DEFINE_TARGET(1, Interpret<true>); | ||
|
||
struct Func { | ||
const Inst* insts; | ||
uint32_t ninsts; | ||
InterpretFunc specialized; | ||
|
||
Func(const Inst* insts_, uint32_t ninsts_) | ||
: insts(insts_), ninsts(ninsts_), specialized(nullptr) { | ||
printf("ctor: ptr %p\n", &specialized); | ||
auto* req = weval::weval( | ||
&specialized, | ||
&Interpret<true>, | ||
1, | ||
0, | ||
weval::SpecializeMemory<const Inst*>(insts, ninsts * sizeof(Inst)), | ||
weval::Specialize(ninsts), | ||
weval::Runtime<State*>()); | ||
assert(req); | ||
} | ||
|
||
uint32_t invoke(State* state) { | ||
printf("Inspecting func ptr at: %p -> %p (size %lu)\n", &specialized, specialized, sizeof(specialized)); | ||
if (specialized) { | ||
printf("Calling specialized function: %p\n", specialized); | ||
return specialized(insts, ninsts, state); | ||
} | ||
return Interpret<false>(insts, ninsts, state); | ||
} | ||
}; | ||
|
||
Func prog_func(prog, sizeof(prog)/sizeof(Inst)); | ||
|
||
int main(int argc, char** argv) { | ||
State* state = (State*)calloc(sizeof(State), 1); | ||
uint32_t steps = prog_func.invoke(state); | ||
assert(kExpectedSteps == steps); | ||
fflush(stdout); | ||
} |