Skip to content

Commit

Permalink
Merge pull request #11 from bytecodealliance/cfallin/weval-h-and-smok…
Browse files Browse the repository at this point in the history
…etest

Fix weval.h, and add a smoketest.
  • Loading branch information
sunfishcode authored Oct 24, 2024
2 parents b9671a3 + 6929a00 commit 277fabf
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 17 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,26 @@ jobs:
- run: rustup default stable
- run: rustup component add rustfmt
- run: cargo fmt --all -- --check

smoke-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download and install wasi-sdk
run: |
cd /opt
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-linux.tar.gz
tar zxvf wasi-sdk-24.0-x86_64-linux.tar.gz
ln -s wasi-sdk-24.0-x86_64-linux wasi-sdk
- name: Download and install wasmtime
run: |
cd /opt
wget https://github.com/bytecodealliance/wasmtime/releases/download/v25.0.2/wasmtime-v25.0.2-x86_64-linux.tar.xz
tar Jxvf wasmtime-v25.0.2-x86_64-linux.tar.xz
ln -s `pwd`/wasmtime-v25.0.2-x86_64-linux/wasmtime /usr/local/bin/
- name: Build
run: cargo build --release
- name: Build and run base 'simple' test
run: make -C tests/simple run-base
- name: Build and run wevaled 'simple' test
run: make -C tests/simple run-wevaled
17 changes: 0 additions & 17 deletions include/weval.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ typedef void (*weval_func_t)();

typedef struct weval_req_t weval_req_t;
typedef struct weval_req_arg_t weval_req_arg_t;
typedef struct weval_lookup_entry_t weval_lookup_entry_t;
typedef struct weval_lookup_t weval_lookup_t;

/*
* A weval "request": a record of a generic function and arguments,
Expand Down Expand Up @@ -68,22 +66,8 @@ struct weval_req_arg_t {
} u;
};

/* Lookup table created by weval for pre-inserted wevaled function bodies */
struct weval_lookup_t {
weval_lookup_entry_t* entries;
uint32_t nentries;
};

struct weval_lookup_entry_t {
uint32_t func_id;
const uint8_t* argbuf;
uint32_t arglen;
weval_func_t specialized;
};

extern weval_req_t* weval_req_pending_head;
extern bool weval_is_wevaled;
extern weval_lookup_t weval_lookup_table;

#define WEVAL_DEFINE_GLOBALS() \
weval_req_t* weval_req_pending_head; \
Expand Down Expand Up @@ -472,7 +456,6 @@ weval_req_t* weval(impl::FuncPtr<Ret, Args...>* dest,
return nullptr;
}

req->func_id = func_id;
req->num_globals = num_globals;
req->func = (weval_func_t)generic;
req->arglen = writer.len;
Expand Down
2 changes: 2 additions & 0 deletions tests/simple/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.wasm
*.o
32 changes: 32 additions & 0 deletions tests/simple/Makefile
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

211 changes: 211 additions & 0 deletions tests/simple/simple.cpp
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);
}

0 comments on commit 277fabf

Please sign in to comment.