Skip to content

Commit 277fabf

Browse files
authored
Merge pull request #11 from bytecodealliance/cfallin/weval-h-and-smoketest
Fix weval.h, and add a smoketest.
2 parents b9671a3 + 6929a00 commit 277fabf

File tree

5 files changed

+268
-17
lines changed

5 files changed

+268
-17
lines changed

.github/workflows/ci.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,26 @@ jobs:
2828
- run: rustup default stable
2929
- run: rustup component add rustfmt
3030
- run: cargo fmt --all -- --check
31+
32+
smoke-test:
33+
runs-on: ubuntu-latest
34+
steps:
35+
- uses: actions/checkout@v4
36+
- name: Download and install wasi-sdk
37+
run: |
38+
cd /opt
39+
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-linux.tar.gz
40+
tar zxvf wasi-sdk-24.0-x86_64-linux.tar.gz
41+
ln -s wasi-sdk-24.0-x86_64-linux wasi-sdk
42+
- name: Download and install wasmtime
43+
run: |
44+
cd /opt
45+
wget https://github.com/bytecodealliance/wasmtime/releases/download/v25.0.2/wasmtime-v25.0.2-x86_64-linux.tar.xz
46+
tar Jxvf wasmtime-v25.0.2-x86_64-linux.tar.xz
47+
ln -s `pwd`/wasmtime-v25.0.2-x86_64-linux/wasmtime /usr/local/bin/
48+
- name: Build
49+
run: cargo build --release
50+
- name: Build and run base 'simple' test
51+
run: make -C tests/simple run-base
52+
- name: Build and run wevaled 'simple' test
53+
run: make -C tests/simple run-wevaled

include/weval.h

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ typedef void (*weval_func_t)();
1212

1313
typedef struct weval_req_t weval_req_t;
1414
typedef struct weval_req_arg_t weval_req_arg_t;
15-
typedef struct weval_lookup_entry_t weval_lookup_entry_t;
16-
typedef struct weval_lookup_t weval_lookup_t;
1715

1816
/*
1917
* A weval "request": a record of a generic function and arguments,
@@ -68,22 +66,8 @@ struct weval_req_arg_t {
6866
} u;
6967
};
7068

71-
/* Lookup table created by weval for pre-inserted wevaled function bodies */
72-
struct weval_lookup_t {
73-
weval_lookup_entry_t* entries;
74-
uint32_t nentries;
75-
};
76-
77-
struct weval_lookup_entry_t {
78-
uint32_t func_id;
79-
const uint8_t* argbuf;
80-
uint32_t arglen;
81-
weval_func_t specialized;
82-
};
83-
8469
extern weval_req_t* weval_req_pending_head;
8570
extern bool weval_is_wevaled;
86-
extern weval_lookup_t weval_lookup_table;
8771

8872
#define WEVAL_DEFINE_GLOBALS() \
8973
weval_req_t* weval_req_pending_head; \
@@ -472,7 +456,6 @@ weval_req_t* weval(impl::FuncPtr<Ret, Args...>* dest,
472456
return nullptr;
473457
}
474458

475-
req->func_id = func_id;
476459
req->num_globals = num_globals;
477460
req->func = (weval_func_t)generic;
478461
req->arglen = writer.len;

tests/simple/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.wasm
2+
*.o

tests/simple/Makefile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
NAME := simple
2+
3+
CC := /opt/wasi-sdk/bin/clang
4+
CXX := /opt/wasi-sdk/bin/clang++
5+
CFLAGS := -I../../include -O2 -g
6+
CXXFLAGS := $(CFLAGS) -std=c++17
7+
WEVAL := ../../target/release/weval
8+
9+
.PHONY: all
10+
all: $(NAME).wasm $(NAME)-wevaled.wasm
11+
12+
$(NAME).wasm: $(NAME).o
13+
$(CXX) $(CXXFLAGS) -o $@ $^
14+
15+
$(NAME)-wevaled.wasm: $(NAME).wasm
16+
$(WEVAL) weval -w -i $^ -o $@
17+
18+
$(NAME).o: $(NAME).cpp ../../include/weval.h
19+
$(CXX) $(CXXFLAGS) -c -o $@ $<
20+
21+
.PHONY: clean
22+
clean:
23+
rm -f $(NAME).wasm $(NAME)-wevaled.wasm *.o
24+
25+
.PHONY: run-base
26+
run-base: $(NAME).wasm
27+
wasmtime run --preload weval=../../lib/weval-stubs.wat $(NAME).wasm
28+
29+
.PHONY: run-wevaled
30+
run-wevaled: $(NAME)-wevaled.wasm
31+
wasmtime run $(NAME)-wevaled.wasm
32+

tests/simple/simple.cpp

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#include <weval.h>
2+
#include <wizer.h>
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
#include <assert.h>
6+
7+
WIZER_DEFAULT_INIT();
8+
WEVAL_DEFINE_GLOBALS();
9+
10+
enum Opcode {
11+
PushConst,
12+
Drop,
13+
Dup,
14+
GetLocal,
15+
SetLocal,
16+
Add,
17+
Sub,
18+
Print,
19+
Goto,
20+
GotoIf,
21+
Exit,
22+
};
23+
24+
struct Inst {
25+
Opcode opcode;
26+
uint32_t imm;
27+
28+
explicit Inst(Opcode opcode_) : opcode(opcode_), imm(0) {}
29+
Inst(Opcode opcode_, uint32_t imm_) : opcode(opcode_), imm(imm_) {}
30+
};
31+
32+
#define OPSTACK_SIZE 32
33+
#define LOCAL_SIZE 32
34+
35+
struct State {
36+
uint32_t opstack[OPSTACK_SIZE];
37+
uint32_t locals[LOCAL_SIZE];
38+
};
39+
40+
template<bool Specialized>
41+
uint32_t Interpret(const Inst* insts, uint32_t ninsts, State* state) {
42+
uint32_t pc = 0;
43+
uint32_t steps = 0;
44+
uint32_t* opstack = state->opstack;
45+
uint32_t* locals = state->locals;
46+
int sp = 0;
47+
48+
if (Specialized) {
49+
weval::push_context(pc);
50+
}
51+
while (true) {
52+
steps++;
53+
const Inst* inst = &insts[pc];
54+
pc++;
55+
if (Specialized) {
56+
weval::update_context(pc);
57+
}
58+
switch (inst->opcode) {
59+
case PushConst:
60+
if (sp + 1 > OPSTACK_SIZE) {
61+
return 0;
62+
}
63+
opstack[sp++] = inst->imm;
64+
break;
65+
case Drop:
66+
if (sp == 0) {
67+
return 0;
68+
}
69+
sp--;
70+
break;
71+
case Dup:
72+
if (sp + 1 > OPSTACK_SIZE) {
73+
return 0;
74+
}
75+
if (sp == 0) {
76+
return 0;
77+
}
78+
opstack[sp] = opstack[sp - 1];
79+
sp++;
80+
break;
81+
case GetLocal:
82+
if (sp + 1 > OPSTACK_SIZE) {
83+
return 0;
84+
}
85+
if (inst->imm >= LOCAL_SIZE) {
86+
return 0;
87+
}
88+
opstack[sp++] = locals[inst->imm];
89+
break;
90+
case SetLocal:
91+
if (sp == 0) {
92+
return 0;
93+
}
94+
if (inst->imm >= LOCAL_SIZE) {
95+
return 0;
96+
}
97+
locals[inst->imm] = opstack[--sp];
98+
break;
99+
case Add:
100+
if (sp < 2) {
101+
return 0;
102+
}
103+
opstack[sp - 2] += opstack[sp - 1];
104+
sp--;
105+
break;
106+
case Sub:
107+
if (sp < 2) {
108+
return 0;
109+
}
110+
opstack[sp - 2] -= opstack[sp - 1];
111+
sp--;
112+
break;
113+
case Print:
114+
if (sp == 0) {
115+
return 0;
116+
}
117+
printf("%u\n", opstack[--sp]);
118+
break;
119+
case Goto:
120+
if (inst->imm >= ninsts) {
121+
return 0;
122+
}
123+
pc = inst->imm;
124+
if (Specialized) {
125+
weval::update_context(pc);
126+
}
127+
break;
128+
case GotoIf:
129+
if (sp == 0) {
130+
return 0;
131+
}
132+
if (inst->imm >= ninsts) {
133+
return 0;
134+
}
135+
sp--;
136+
if (opstack[sp] != 0) {
137+
pc = inst->imm;
138+
if (Specialized) {
139+
weval::update_context(pc);
140+
}
141+
continue;
142+
}
143+
break;
144+
case Exit:
145+
goto out;
146+
}
147+
}
148+
out:
149+
if (Specialized) {
150+
weval::pop_context();
151+
}
152+
153+
printf("Exiting after %d steps at PC %d.\n", steps, pc);
154+
return steps;
155+
}
156+
157+
static const uint32_t kIters = 10000000;
158+
Inst prog[] = {
159+
Inst(PushConst, 0),
160+
Inst(Dup),
161+
Inst(PushConst, kIters),
162+
Inst(Sub),
163+
Inst(GotoIf, 6),
164+
Inst(Exit),
165+
Inst(PushConst, 1),
166+
Inst(Add),
167+
Inst(Goto, 1),
168+
};
169+
static const uint32_t kExpectedSteps = 7*kIters + 6;
170+
171+
typedef uint32_t (*InterpretFunc)(const Inst* insts, uint32_t ninsts, State* state);
172+
173+
WEVAL_DEFINE_TARGET(1, Interpret<true>);
174+
175+
struct Func {
176+
const Inst* insts;
177+
uint32_t ninsts;
178+
InterpretFunc specialized;
179+
180+
Func(const Inst* insts_, uint32_t ninsts_)
181+
: insts(insts_), ninsts(ninsts_), specialized(nullptr) {
182+
printf("ctor: ptr %p\n", &specialized);
183+
auto* req = weval::weval(
184+
&specialized,
185+
&Interpret<true>,
186+
1,
187+
0,
188+
weval::SpecializeMemory<const Inst*>(insts, ninsts * sizeof(Inst)),
189+
weval::Specialize(ninsts),
190+
weval::Runtime<State*>());
191+
assert(req);
192+
}
193+
194+
uint32_t invoke(State* state) {
195+
printf("Inspecting func ptr at: %p -> %p (size %lu)\n", &specialized, specialized, sizeof(specialized));
196+
if (specialized) {
197+
printf("Calling specialized function: %p\n", specialized);
198+
return specialized(insts, ninsts, state);
199+
}
200+
return Interpret<false>(insts, ninsts, state);
201+
}
202+
};
203+
204+
Func prog_func(prog, sizeof(prog)/sizeof(Inst));
205+
206+
int main(int argc, char** argv) {
207+
State* state = (State*)calloc(sizeof(State), 1);
208+
uint32_t steps = prog_func.invoke(state);
209+
assert(kExpectedSteps == steps);
210+
fflush(stdout);
211+
}

0 commit comments

Comments
 (0)