authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-11-27 19:55:12-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-06 12:15:04-07:00
log12633467747de2349f7cc0f5068e9749801476b0
treec2a3ebb484d8293b93bb282e1ea137e930ff0acd
parenta63305bc5018afe538255218542e1d0af0393f01

use zig-wasm2c for bootstrapping


8 files changed, 4202 insertions(+), 4581 deletions(-)

CMakeLists.txt+37-14
......@@ -179,8 +179,8 @@ set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std")
179179set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
180180set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
181181
182set(STAGE1_SOURCES
183 "${CMAKE_SOURCE_DIR}/stage1/zig1.c"
182set(ZIG_WASM2C_SOURCES
183 "${CMAKE_SOURCE_DIR}/stage1/wasm2c.c"
184184 "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/huf_decompress.c"
185185 "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_ddict.c"
186186 "${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress.c"
......@@ -709,30 +709,53 @@ target_link_libraries(zigcpp LINK_PUBLIC
709709)
710710
711711if(MSVC)
712 set(ZIG1_COMPILE_FLAGS "/std:c99")
713 set(ZIG2_COMPILE_FLAGS "/std:c99")
712 set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2")
713 set(ZIG1_COMPILE_FLAGS "/std:c99 /Os")
714 set(ZIG2_COMPILE_FLAGS "/std:c99 /O0")
714715 set(ZIG2_LINK_FLAGS "/STACK:16777216")
715716else()
717 set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
716718 set(ZIG1_COMPILE_FLAGS "-std=c99")
717719 set(ZIG2_COMPILE_FLAGS "-std=c99")
718720 set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000")
719721endif()
720722
721add_executable(zig1 ${STAGE1_SOURCES})
722set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS})
723string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}-${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_TRIPLE)
724set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst")
725set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c")
726set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c")
727set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c")
728
729add_executable(zig-wasm2c ${ZIG_WASM2C_SOURCES})
730set_target_properties(zig-wasm2c PROPERTIES COMPILE_FLAGS ${ZIG_WASM2C_COMPILE_FLAGS})
731target_include_directories(zig-wasm2c PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib")
732target_compile_definitions(zig-wasm2c PRIVATE ZSTD_DISABLE_ASM)
733
734add_custom_command(
735 OUTPUT "${ZIG1_C_SOURCE}"
736 COMMAND zig-wasm2c "${ZIG1_WASM_SOURCE}" "${ZIG1_C_SOURCE}"
737 DEPENDS zig-wasm2c "${ZIG1_WASM_SOURCE}"
738 COMMENT STATUS "Converting ${ZIG1_WASM_SOURCE} to ${ZIG1_C_SOURCE}"
739 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
740)
741
742add_executable(zig1 ${ZIG1_C_SOURCE} "${CMAKE_SOURCE_DIR}/stage1/wasi.c")
743set_target_properties(zig1 PROPERTIES
744 COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}
745 LINK_FLAGS ${ZIG2_LINK_FLAGS})
723746target_link_libraries(zig1 LINK_PUBLIC m)
724747target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib")
725748target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM)
726749
727set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c")
728750set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst")
729751set(BUILD_ZIG2_ARGS
730752 "${CMAKE_SOURCE_DIR}/lib"
731 "${CMAKE_BINARY_DIR}"
732 zig2
733 "${ZIG1_WASM_ZST_SOURCE}"
734753 build-exe src/main.zig -ofmt=c -lc
735754 -OReleaseSmall
755 --name zig2 -femit-bin="${ZIG2_C_SOURCE}"
756 --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end
757 -target "${HOST_TARGET_TRIPLE}"
758 --color on
736759)
737760
738761add_custom_command(
......@@ -743,14 +766,14 @@ add_custom_command(
743766 WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
744767)
745768
746set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c")
747769set(BUILD_COMPILER_RT_ARGS
748770 "${CMAKE_SOURCE_DIR}/lib"
749 "${CMAKE_BINARY_DIR}"
750 compiler_rt
751 "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst"
752771 build-obj lib/compiler_rt.zig -ofmt=c
753772 -OReleaseSmall
773 --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}"
774 --pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end
775 -target "${HOST_TARGET_TRIPLE}"
776 --color on
754777)
755778
756779add_custom_command(
stage1/FuncGen.h created+164
......@@ -0,0 +1,164 @@
1#ifndef FUNC_GEN_H
2#define FUNC_GEN_H
3
4#include "panic.h"
5#include "wasm.h"
6
7#include <inttypes.h>
8#include <stdbool.h>
9#include <stdint.h>
10#include <stdio.h>
11#include <string.h>
12
13struct Block {
14 uint32_t type;
15 uint32_t label;
16 uint32_t stack_i;
17};
18
19struct FuncGen {
20 int8_t *type;
21 uint32_t *stack;
22 struct Block *block;
23 uint32_t type_i;
24 uint32_t stack_i;
25 uint32_t block_i;
26 uint32_t type_len;
27 uint32_t stack_len;
28 uint32_t block_len;
29};
30
31static void FuncGen_init(struct FuncGen *self) {
32 memset(self, 0, sizeof(struct FuncGen));
33}
34
35static void FuncGen_reset(struct FuncGen *self) {
36 self->type_i = 0;
37 self->stack_i = 0;
38 self->block_i = 0;
39}
40
41static void FuncGen_free(struct FuncGen *self) {
42 free(self->block);
43 free(self->stack);
44 free(self->type);
45}
46
47static void FuncGen_outdent(struct FuncGen *self, FILE *out) {
48 for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out);
49}
50
51static void FuncGen_indent(struct FuncGen *self, FILE *out) {
52 FuncGen_outdent(self, out);
53 fputs(" ", out);
54}
55
56static void FuncGen_cont(struct FuncGen *self, FILE *out) {
57 FuncGen_indent(self, out);
58 fputs(" ", out);
59}
60
61static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) {
62 if (self->type_i == self->type_len) {
63 self->type_len += 10;
64 self->type_len *= 2;
65 self->type = realloc(self->type, sizeof(int8_t) * self->type_len);
66 if (self->type == NULL) panic("out of memory");
67 }
68 uint32_t local_i = self->type_i;
69 self->type[local_i] = type;
70 self->type_i += 1;
71 return local_i;
72}
73
74static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
75 uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type);
76 fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i);
77 return local_i;
78}
79
80static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
81 return self->type[local_idx];
82}
83
84static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
85 if (self->stack_i == self->stack_len) {
86 self->stack_len += 10;
87 self->stack_len *= 2;
88 self->stack = realloc(self->stack, sizeof(uint32_t) * self->stack_len);
89 if (self->stack == NULL) panic("out of memory");
90 }
91 FuncGen_indent(self, out);
92 fputs("const ", out);
93 self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type);
94 self->stack_i += 1;
95 fputs(" = ", out);
96}
97
98static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx) {
99 return self->stack[self->stack_i - 1 - stack_idx];
100}
101
102static uint32_t FuncGen_stackPop(struct FuncGen *self) {
103 self->stack_i -= 1;
104 return self->stack[self->stack_i];
105}
106
107static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) {
108 FuncGen_indent(self, out);
109 fprintf(out, "goto l%" PRIu32 ";\n", label);
110 FuncGen_outdent(self, out);
111 fprintf(out, "l%" PRIu32 ":;\n", label);
112}
113
114static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode kind, int64_t type) {
115 if (self->block_i == self->block_len) {
116 self->block_len += 10;
117 self->block_len *= 2;
118 self->block = realloc(self->block, sizeof(struct Block) * self->block_len);
119 if (self->block == NULL) panic("out of memory");
120 }
121 uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
122 FuncGen_indent(self, out);
123 if (kind == WasmOpcode_if) fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(self));
124 fputs("{\n", out);
125 self->block[self->block_i].type = type < 0 ? ~type : type;
126 self->block[self->block_i].label = label;
127 self->block[self->block_i].stack_i = self->stack_i;
128 self->block_i += 1;
129 if (kind == WasmOpcode_loop) FuncGen_label(self, out, label);
130}
131
132static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) {
133 int8_t kind = self->type[self->block[self->block_i - 1 - label_idx].label];
134 return (enum WasmOpcode)(kind < 0 ? ~kind : kind);
135}
136
137static int64_t FuncGen_blockType(const struct FuncGen *self, uint32_t label_idx) {
138 struct Block *block = &self->block[self->block_i - 1 - label_idx];
139 return self->type[block->label] < 0 ? ~(int64_t)block->type : (int64_t)block->type;
140}
141
142static uint32_t FuncGen_blockLabel(const struct FuncGen *self, uint32_t label_idx) {
143 return self->block[self->block_i - 1 - label_idx].label;
144}
145
146static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) {
147 enum WasmOpcode kind = FuncGen_blockKind(self, 0);
148 uint32_t label = FuncGen_blockLabel(self, 0);
149 if (kind != WasmOpcode_loop) FuncGen_label(self, out, label);
150 self->block_i -= 1;
151 FuncGen_indent(self, out);
152 fputs("}\n", out);
153 if (self->stack_i != self->block[self->block_i].stack_i) {
154 FuncGen_indent(self, out);
155 fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i);
156 }
157 self->stack_i = self->block[self->block_i].stack_i;
158}
159
160static bool FuncGen_done(const struct FuncGen *self) {
161 return self->block_i == 0;
162}
163
164#endif /* FUNC_GEN_H */
stage1/InputStream.h created+241
......@@ -0,0 +1,241 @@
1#ifndef INPUT_STREAM_H
2#define INPUT_STREAM_H
3
4#include "panic.h"
5#include "wasm.h"
6
7#include <zstd.h>
8
9#include <assert.h>
10#include <stdbool.h>
11#include <stdint.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16struct InputStream {
17 FILE *stream;
18 ZSTD_DStream *ds;
19 ZSTD_outBuffer out;
20 ZSTD_inBuffer in;
21 size_t pos;
22};
23
24static void InputStream_open(struct InputStream *self, const char *path) {
25 self->stream = fopen(path, "rb");
26 if (self->stream == NULL) panic("unable to open input file");
27 self->ds = ZSTD_createDStream();
28 if (self->ds == NULL) panic("unable to create zstd context");
29 size_t in_size = ZSTD_initDStream(self->ds);
30 if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size));
31 self->out.size = ZSTD_DStreamOutSize();
32 self->out.dst = malloc(self->out.size + ZSTD_DStreamInSize());
33 if (self->out.dst == NULL) panic("unable to allocate input buffers");
34 self->out.pos = 0;
35 self->in.src = (const char *)self->out.dst + self->out.size;
36 self->in.size = fread((void *)self->in.src, 1, in_size, self->stream);
37 self->in.pos = 0;
38 self->pos = 0;
39}
40
41static void InputStream_close(struct InputStream *self) {
42 free(self->out.dst);
43 ZSTD_freeDStream(self->ds);
44 fclose(self->stream);
45}
46
47static bool InputStream_atEnd(struct InputStream *self) {
48 while (self->pos >= self->out.pos) {
49 self->out.pos = 0;
50 self->pos = 0;
51 size_t in_size = ZSTD_decompressStream(self->ds, &self->out, &self->in);
52 if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size));
53 if (self->in.pos >= self->in.size) {
54 size_t max_in_size = ZSTD_DStreamInSize();
55 if (in_size > max_in_size) in_size = max_in_size;
56 self->in.size = fread((void *)self->in.src, 1, in_size, self->stream);
57 self->in.pos = 0;
58 if (self->in.pos >= self->in.size) return true;
59 }
60 }
61 return false;
62}
63
64static uint8_t InputStream_readByte(struct InputStream *self) {
65 if (InputStream_atEnd(self)) panic("unexpected end of input stream");
66 uint8_t value = ((uint8_t *)self->out.dst)[self->pos];
67 self->pos += 1;
68 return value;
69}
70
71static uint32_t InputStream_readLittle_u32(struct InputStream *self) {
72 uint32_t value = 0;
73 value |= (uint32_t)InputStream_readByte(self) << 0;
74 value |= (uint32_t)InputStream_readByte(self) << 8;
75 value |= (uint32_t)InputStream_readByte(self) << 16;
76 value |= (uint32_t)InputStream_readByte(self) << 24;
77 return value;
78}
79
80static uint64_t InputStream_readLittle_u64(struct InputStream *self) {
81 uint64_t value = 0;
82 value |= (uint64_t)InputStream_readByte(self) << 0;
83 value |= (uint64_t)InputStream_readByte(self) << 8;
84 value |= (uint64_t)InputStream_readByte(self) << 16;
85 value |= (uint64_t)InputStream_readByte(self) << 24;
86 value |= (uint64_t)InputStream_readByte(self) << 32;
87 value |= (uint64_t)InputStream_readByte(self) << 40;
88 value |= (uint64_t)InputStream_readByte(self) << 48;
89 value |= (uint64_t)InputStream_readByte(self) << 56;
90 return value;
91}
92
93static float InputStream_readLittle_f32(struct InputStream *self) {
94 uint32_t value = InputStream_readLittle_u32(self);
95 float result;
96 memcpy(&result, &value, sizeof(result));
97 return result;
98}
99
100static double InputStream_readLittle_f64(struct InputStream *self) {
101 uint64_t value = InputStream_readLittle_u64(self);
102 double result;
103 memcpy(&result, &value, sizeof(result));
104 return result;
105}
106
107static uint32_t InputStream_readLeb128_u32(struct InputStream *self) {
108 uint32_t value = 0;
109 uint8_t shift = 0;
110 uint8_t byte;
111 do {
112 byte = InputStream_readByte(self);
113 assert(shift < 32);
114 value |= (uint32_t)(byte & 0x7F) << shift;
115 shift += 7;
116 } while (byte & 0x80);
117 return value;
118}
119
120static int32_t InputStream_readLeb128_i32(struct InputStream *self) {
121 uint32_t value = 0;
122 uint8_t shift = 0;
123 uint8_t byte;
124 do {
125 byte = InputStream_readByte(self);
126 assert(shift < 64);
127 value |= (uint32_t)(byte & 0x7F) << shift;
128 shift += 7;
129 } while (byte & 0x80);
130 if (shift < 32) {
131 uint32_t mask = -((uint32_t)1 << shift);
132 if (byte & 0x40) value |= mask; else value &= ~mask;
133 }
134 return (int32_t)value;
135}
136
137static int64_t InputStream_readLeb128_u64(struct InputStream *self) {
138 uint64_t value = 0;
139 uint8_t shift = 0;
140 uint8_t byte;
141 do {
142 byte = InputStream_readByte(self);
143 assert(shift < 64);
144 value |= (uint64_t)(byte & 0x7F) << shift;
145 shift += 7;
146 } while (byte & 0x80);
147 return value;
148}
149
150static int64_t InputStream_readLeb128_i64(struct InputStream *self) {
151 uint64_t value = 0;
152 uint8_t shift = 0;
153 uint8_t byte;
154 do {
155 byte = InputStream_readByte(self);
156 assert(shift < 64);
157 value |= (uint64_t)(byte & 0x7F) << shift;
158 shift += 7;
159 } while (byte & 0x80);
160 if (shift < 64) {
161 uint64_t mask = -((uint64_t)1 << shift);
162 if (byte & 0x40) value |= mask; else value &= ~mask;
163 }
164 return (int64_t)value;
165}
166
167static char *InputStream_readName(struct InputStream *self) {
168 uint32_t len = InputStream_readLeb128_u32(self);
169 char *name = malloc(len + 1);
170 if (name == NULL) panic("out of memory");
171 for (uint32_t i = 0; i < len; ) {
172 if (InputStream_atEnd(self)) panic("unexpected end of input stream");
173 size_t remaining = self->out.pos - self->pos;
174 if (remaining > len - i) remaining = len - i;
175 memcpy(&name[i], &((char *)self->out.dst)[self->pos], remaining);
176 i += remaining;
177 self->pos += remaining;
178 }
179 name[len] = '\0';
180 return name;
181}
182
183static void InputStream_skipBytes(struct InputStream *self, size_t len) {
184 for (size_t i = 0; i < len; ) {
185 if (InputStream_atEnd(self)) panic("unexpected end of input stream");
186 size_t remaining = self->out.pos - self->pos;
187 if (remaining > len - i) remaining = len - i;
188 i += remaining;
189 self->pos += remaining;
190 }
191}
192
193static uint32_t InputStream_skipToSection(struct InputStream *self, uint8_t expected_id) {
194 while (true) {
195 uint8_t id = InputStream_readByte(self);
196 uint32_t size = InputStream_readLeb128_u32(self);
197 if (id == expected_id) return size;
198 InputStream_skipBytes(self, size);
199 }
200}
201
202struct ResultType {
203 uint32_t len;
204 int8_t types[1];
205};
206static struct ResultType *InputStream_readResultType(struct InputStream *self) {
207 uint32_t len = InputStream_readLeb128_u32(self);
208 struct ResultType *result_type = malloc(offsetof(struct ResultType, types) + sizeof(int8_t) * len);
209 if (result_type == NULL) panic("out of memory");
210 result_type->len = len;
211 for (uint32_t i = 0; i < len; i += 1) {
212 int64_t val_type = InputStream_readLeb128_i64(self);
213 switch (val_type) {
214 case WasmValType_i32: case WasmValType_i64:
215 case WasmValType_f32: case WasmValType_f64:
216 break;
217
218 default: panic("unsupported valtype");
219 }
220 result_type->types[i] = val_type;
221 }
222 return result_type;
223}
224
225struct Limits {
226 uint32_t min;
227 uint32_t max;
228};
229static struct Limits InputStream_readLimits(struct InputStream *self) {
230 struct Limits limits;
231 uint8_t kind = InputStream_readByte(self);
232 limits.min = InputStream_readLeb128_u32(self);
233 switch (kind) {
234 case 0x00: limits.max = UINT32_MAX; break;
235 case 0x01: limits.max = InputStream_readLeb128_u32(self); break;
236 default: panic("unsupported limit kind");
237 }
238 return limits;
239}
240
241#endif /* INPUT_STREAM_H */
stage1/panic.h created+12
......@@ -0,0 +1,12 @@
1#ifndef PANIC_H
2#define PANIC_H
3
4#include <stdio.h>
5#include <stdlib.h>
6
7static void panic(const char *reason) {
8 fprintf(stderr, "%s\n", reason);
9 abort();
10}
11
12#endif /* PANIC_H */
stage1/wasi.c created+948
......@@ -0,0 +1,948 @@
1#include <stdbool.h>
2#include <stdint.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <time.h>
7
8#include "panic.h"
9
10#define LOG_TRACE 0
11
12enum wasi_errno {
13 wasi_errno_success = 0,
14 wasi_errno_2big = 1,
15 wasi_errno_acces = 2,
16 wasi_errno_addrinuse = 3,
17 wasi_errno_addrnotavail = 4,
18 wasi_errno_afnosupport = 5,
19 wasi_errno_again = 6,
20 wasi_errno_already = 7,
21 wasi_errno_badf = 8,
22 wasi_errno_badmsg = 9,
23 wasi_errno_busy = 10,
24 wasi_errno_canceled = 11,
25 wasi_errno_child = 12,
26 wasi_errno_connaborted = 13,
27 wasi_errno_connrefused = 14,
28 wasi_errno_connreset = 15,
29 wasi_errno_deadlk = 16,
30 wasi_errno_destaddrreq = 17,
31 wasi_errno_dom = 18,
32 wasi_errno_dquot = 19,
33 wasi_errno_exist = 20,
34 wasi_errno_fault = 21,
35 wasi_errno_fbig = 22,
36 wasi_errno_hostunreach = 23,
37 wasi_errno_idrm = 24,
38 wasi_errno_ilseq = 25,
39 wasi_errno_inprogress = 26,
40 wasi_errno_intr = 27,
41 wasi_errno_inval = 28,
42 wasi_errno_io = 29,
43 wasi_errno_isconn = 30,
44 wasi_errno_isdir = 31,
45 wasi_errno_loop = 32,
46 wasi_errno_mfile = 33,
47 wasi_errno_mlink = 34,
48 wasi_errno_msgsize = 35,
49 wasi_errno_multihop = 36,
50 wasi_errno_nametoolong = 37,
51 wasi_errno_netdown = 38,
52 wasi_errno_netreset = 39,
53 wasi_errno_netunreach = 40,
54 wasi_errno_nfile = 41,
55 wasi_errno_nobufs = 42,
56 wasi_errno_nodev = 43,
57 wasi_errno_noent = 44,
58 wasi_errno_noexec = 45,
59 wasi_errno_nolck = 46,
60 wasi_errno_nolink = 47,
61 wasi_errno_nomem = 48,
62 wasi_errno_nomsg = 49,
63 wasi_errno_noprotoopt = 50,
64 wasi_errno_nospc = 51,
65 wasi_errno_nosys = 52,
66 wasi_errno_notconn = 53,
67 wasi_errno_notdir = 54,
68 wasi_errno_notempty = 55,
69 wasi_errno_notrecoverable = 56,
70 wasi_errno_notsock = 57,
71 wasi_errno_opnotsupp = 58,
72 wasi_errno_notty = 59,
73 wasi_errno_nxio = 60,
74 wasi_errno_overflow = 61,
75 wasi_errno_ownerdead = 62,
76 wasi_errno_perm = 63,
77 wasi_errno_pipe = 64,
78 wasi_errno_proto = 65,
79 wasi_errno_protonosupport = 66,
80 wasi_errno_prototype = 67,
81 wasi_errno_range = 68,
82 wasi_errno_rofs = 69,
83 wasi_errno_spipe = 70,
84 wasi_errno_srch = 71,
85 wasi_errno_stale = 72,
86 wasi_errno_timedout = 73,
87 wasi_errno_txtbsy = 74,
88 wasi_errno_xdev = 75,
89 wasi_errno_notcapable = 76,
90};
91
92enum wasi_oflags {
93 wasi_oflags_creat = 1 << 0,
94 wasi_oflags_directory = 1 << 1,
95 wasi_oflags_excl = 1 << 2,
96 wasi_oflags_trunc = 1 << 3,
97};
98
99enum wasi_rights {
100 wasi_rights_fd_datasync = 1ull << 0,
101 wasi_rights_fd_read = 1ull << 1,
102 wasi_rights_fd_seek = 1ull << 2,
103 wasi_rights_fd_fdstat_set_flags = 1ull << 3,
104 wasi_rights_fd_sync = 1ull << 4,
105 wasi_rights_fd_tell = 1ull << 5,
106 wasi_rights_fd_write = 1ull << 6,
107 wasi_rights_fd_advise = 1ull << 7,
108 wasi_rights_fd_allocate = 1ull << 8,
109 wasi_rights_path_create_directory = 1ull << 9,
110 wasi_rights_path_create_file = 1ull << 10,
111 wasi_rights_path_link_source = 1ull << 11,
112 wasi_rights_path_link_target = 1ull << 12,
113 wasi_rights_path_open = 1ull << 13,
114 wasi_rights_fd_readdir = 1ull << 14,
115 wasi_rights_path_readlink = 1ull << 15,
116 wasi_rights_path_rename_source = 1ull << 16,
117 wasi_rights_path_rename_target = 1ull << 17,
118 wasi_rights_path_filestat_get = 1ull << 18,
119 wasi_rights_path_filestat_set_size = 1ull << 19,
120 wasi_rights_path_filestat_set_times = 1ull << 20,
121 wasi_rights_fd_filestat_get = 1ull << 21,
122 wasi_rights_fd_filestat_set_size = 1ull << 22,
123 wasi_rights_fd_filestat_set_times = 1ull << 23,
124 wasi_rights_path_symlink = 1ull << 24,
125 wasi_rights_path_remove_directory = 1ull << 25,
126 wasi_rights_path_unlink_file = 1ull << 26,
127 wasi_rights_poll_fd_readwrite = 1ull << 27,
128 wasi_rights_sock_shutdown = 1ull << 28,
129 wasi_rights_sock_accept = 1ull << 29,
130};
131
132enum wasi_clockid {
133 wasi_clockid_realtime = 0,
134 wasi_clockid_monotonic = 1,
135 wasi_clockid_process_cputime_id = 2,
136 wasi_clockid_thread_cputime_id = 3,
137};
138
139enum wasi_filetype {
140 wasi_filetype_unknown = 0,
141 wasi_filetype_block_device = 1,
142 wasi_filetype_character_device = 2,
143 wasi_filetype_directory = 3,
144 wasi_filetype_regular_file = 4,
145 wasi_filetype_socket_dgram = 5,
146 wasi_filetype_socket_stream = 6,
147 wasi_filetype_symbolic_link = 7,
148};
149
150enum wasi_fdflags {
151 wasi_fdflags_append = 1 << 0,
152 wasi_fdflags_dsync = 1 << 1,
153 wasi_fdflags_nonblock = 1 << 2,
154 wasi_fdflags_rsync = 1 << 3,
155 wasi_fdflags_sync = 1 << 4,
156};
157
158struct wasi_filestat {
159 uint64_t dev;
160 uint64_t ino;
161 uint64_t filetype;
162 uint64_t nlink;
163 uint64_t size;
164 uint64_t atim;
165 uint64_t mtim;
166 uint64_t ctim;
167};
168
169struct wasi_fdstat {
170 uint16_t fs_filetype;
171 uint16_t fs_flags;
172 uint32_t padding;
173 uint64_t fs_rights_inheriting;
174};
175
176struct wasi_ciovec {
177 uint32_t ptr;
178 uint32_t len;
179};
180
181extern uint8_t **const wasm_memory;
182extern void wasm__start(void);
183
184static int global_argc;
185static char **global_argv;
186
187static uint32_t de_len;
188struct DirEntry {
189 enum wasi_filetype filetype;
190 time_t atim;
191 time_t mtim;
192 time_t ctim;
193 char *guest_path;
194 char *host_path;
195} *des;
196
197static uint32_t fd_len;
198static struct FileDescriptor {
199 uint32_t de;
200 FILE *stream;
201} *fds;
202
203static void *dupe(const void *data, size_t len) {
204 void *copy = malloc(len);
205 if (copy == NULL) panic("out of memory");
206 memcpy(copy, data, len);
207 return copy;
208}
209
210int main(int argc, char **argv) {
211 if (argc < 2) {
212 fprintf(stderr, "usage: %s <zig-lib-path> <args...>\n", argv[0]);
213 return 1;
214 }
215
216 global_argc = argc;
217 global_argv = argv;
218
219 time_t now = time(NULL);
220 srand((unsigned)now);
221
222 de_len = 4;
223 des = calloc(de_len, sizeof(struct DirEntry));
224 if (des == NULL) panic("out of memory");
225
226 des[0].filetype = wasi_filetype_character_device;
227
228 des[1].filetype = wasi_filetype_directory;
229 des[1].guest_path = dupe(".", sizeof("."));
230 des[1].host_path = dupe(".", sizeof("."));
231
232 des[2].filetype = wasi_filetype_directory;
233 des[2].guest_path = dupe("/cache", sizeof("/cache"));
234 des[2].atim = now;
235 des[2].mtim = now;
236 des[2].ctim = now;
237
238 des[3].filetype = wasi_filetype_directory;
239 des[3].guest_path = dupe("/lib", sizeof("/lib"));
240 des[3].host_path = dupe(argv[1], strlen(argv[1]));
241
242 fd_len = 6;
243 fds = calloc(sizeof(struct FileDescriptor), fd_len);
244 if (fds == NULL) panic("out of memory");
245 fds[0].stream = stdin;
246 fds[1].stream = stdout;
247 fds[2].stream = stderr;
248 fds[3].de = 1;
249 fds[4].de = 2;
250 fds[5].de = 3;
251
252 wasm__start();
253}
254
255static enum wasi_errno DirEntry_create(uint32_t dir_fd, const char *path, uint32_t path_len, enum wasi_filetype filetype, time_t tim, uint32_t *res_de) {
256 if (path[0] != '/') {
257 if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
258 if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
259 }
260
261 struct DirEntry *new_des = realloc(des, (de_len + 1) * sizeof(struct DirEntry));
262 if (new_des == NULL) return wasi_errno_nomem;
263 des = new_des;
264
265 struct DirEntry *de = &des[de_len];
266 de->filetype = filetype;
267 de->atim = tim;
268 de->mtim = tim;
269 de->ctim = tim;
270 if (path[0] == '/') {
271 de->guest_path = malloc(path_len + 1);
272 if (de->guest_path == NULL) return wasi_errno_nomem;
273 memcpy(&de->guest_path[0], path, path_len);
274 de->guest_path[path_len] = '\0';
275
276 de->host_path = malloc(path_len + 1);
277 if (de->host_path == NULL) return wasi_errno_nomem;
278 memcpy(&de->host_path[0], path, path_len);
279 de->host_path[path_len] = '\0';
280 } else {
281 const struct DirEntry *dir_de = &des[fds[dir_fd].de];
282 if (dir_de->guest_path != NULL) {
283 size_t dir_guest_path_len = strlen(dir_de->guest_path);
284 de->guest_path = malloc(dir_guest_path_len + 1 + path_len + 1);
285 if (de->guest_path == NULL) return wasi_errno_nomem;
286 memcpy(&de->guest_path[0], dir_de->guest_path, dir_guest_path_len);
287 de->guest_path[dir_guest_path_len] = '/';
288 memcpy(&de->guest_path[dir_guest_path_len + 1], path, path_len);
289 de->guest_path[dir_guest_path_len + 1 + path_len] = '\0';
290 } else de->guest_path = NULL;
291
292 if (dir_de->host_path != NULL) {
293 size_t dir_host_path_len = strlen(dir_de->host_path);
294 de->host_path = malloc(dir_host_path_len + 1 + path_len + 1);
295 if (de->host_path == NULL) { free(de->guest_path); return wasi_errno_nomem; }
296 memcpy(&de->host_path[0], dir_de->host_path, dir_host_path_len);
297 de->host_path[dir_host_path_len] = '/';
298 memcpy(&de->host_path[dir_host_path_len + 1], path, path_len);
299 de->host_path[dir_host_path_len + 1 + path_len] = '\0';
300 } else de->host_path = NULL;
301 }
302
303 if (res_de != NULL) *res_de = de_len;
304 de_len += 1;
305 return wasi_errno_success;
306}
307
308static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) {
309 (void)flags;
310 if (path[0] == '/') {
311 for (uint32_t de = 0; de < de_len; de += 1) {
312 if (des[de].guest_path == NULL) continue;
313 if (memcmp(&des[de].guest_path[0], path, path_len) != 0) continue;
314 if (des[de].guest_path[path_len] != '\0') continue;
315 if (res_de != NULL) *res_de = de;
316 return wasi_errno_success;
317 }
318 } else {
319 if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
320 const struct DirEntry *dir_de = &des[fds[dir_fd].de];
321 if (dir_de->filetype != wasi_filetype_directory) return wasi_errno_notdir;
322
323 size_t dir_guest_path_len = strlen(dir_de->guest_path);
324 for (uint32_t de = 0; de < de_len; de += 1) {
325 if (des[de].guest_path == NULL) continue;
326 if (memcmp(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len) != 0) continue;
327 if (des[de].guest_path[dir_guest_path_len] != '/') continue;
328 if (memcmp(&des[de].guest_path[dir_guest_path_len + 1], path, path_len) != 0) continue;
329 if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue;
330 if (res_de != NULL) *res_de = de;
331 return wasi_errno_success;
332 }
333 }
334 return wasi_errno_noent;
335}
336
337static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) {
338 res_filestat->dev = 0;
339 res_filestat->ino = de;
340 res_filestat->filetype = des[de].filetype;
341 res_filestat->nlink = 1;
342 res_filestat->size = 0;
343 res_filestat->atim = des[de].atim * UINT64_C(1000000000);
344 res_filestat->mtim = des[de].mtim * UINT64_C(1000000000);
345 res_filestat->ctim = des[de].ctim * UINT64_C(1000000000);
346}
347
348static void DirEntry_unlink(uint32_t de) {
349 free(des[de].guest_path);
350 des[de].guest_path = NULL;
351 free(des[de].host_path);
352 des[de].host_path = NULL;
353}
354
355uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv_buf_size) {
356 uint8_t *const m = *wasm_memory;
357 uint32_t *argv_size_ptr = (uint32_t *)&m[argv_size];
358 uint32_t *argv_buf_size_ptr = (uint32_t *)&m[argv_buf_size];
359#if LOG_TRACE
360 fprintf(stderr, "wasi_snapshot_preview1_args_sizes_get()\n");
361#endif
362
363 int c_argc = global_argc;
364 char **c_argv = global_argv;
365 uint32_t size = 0;
366 for (int i = 0; i < c_argc; i += 1) {
367 if (i == 1) continue;
368 size += strlen(c_argv[i]) + 1;
369 }
370 *argv_size_ptr = c_argc - 1;
371 *argv_buf_size_ptr = size;
372 return wasi_errno_success;
373}
374
375uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) {
376 uint8_t *const m = *wasm_memory;
377 uint32_t *argv_ptr = (uint32_t *)&m[argv];
378 char *argv_buf_ptr = (char *)&m[argv_buf];
379#if LOG_TRACE
380 fprintf(stderr, "wasi_snapshot_preview1_args_get()\n");
381#endif
382
383 int c_argc = global_argc;
384 char **c_argv = global_argv;
385 uint32_t dst_i = 0;
386 uint32_t argv_buf_i = 0;
387 for (int src_i = 0; src_i < c_argc; src_i += 1) {
388 if (src_i == 1) continue;
389 argv_ptr[dst_i] = argv_buf + argv_buf_i;
390 dst_i += 1;
391 strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]);
392 argv_buf_i += strlen(c_argv[src_i]) + 1;
393 }
394 return wasi_errno_success;
395}
396
397uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat) {
398 uint8_t *const m = *wasm_memory;
399 uint32_t *res_prestat_ptr = (uint32_t *)&m[res_prestat];
400#if LOG_TRACE
401 fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_get(%u)\n", fd);
402#endif
403
404 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
405
406 res_prestat_ptr[0] = 0;
407 res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path);
408 return wasi_errno_success;
409}
410
411uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path, uint32_t path_len) {
412 uint8_t *const m = *wasm_memory;
413 char *path_ptr = (char *)&m[path];
414#if LOG_TRACE
415 fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_dir_name(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
416#endif
417
418 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
419 strncpy(path_ptr, des[fds[fd].de].guest_path, path_len);
420 return wasi_errno_success;
421}
422
423void wasi_snapshot_preview1_proc_exit(uint32_t rval) {
424#if LOG_TRACE
425 fprintf(stderr, "wasi_snapshot_preview1_proc_exit(%u)\n", rval);
426#endif
427
428 exit(rval);
429}
430
431uint32_t wasi_snapshot_preview1_fd_close(uint32_t fd) {
432#if LOG_TRACE
433 fprintf(stderr, "wasi_snapshot_preview1_fd_close(%u)\n", fd);
434#endif
435
436 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
437 if (fds[fd].stream != NULL) fclose(fds[fd].stream);
438
439 fds[fd].de = ~0;
440 fds[fd].stream = NULL;
441 return wasi_errno_success;
442}
443
444uint32_t wasi_snapshot_preview1_path_create_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
445 uint8_t *const m = *wasm_memory;
446 const char *path_ptr = (const char *)&m[path];
447#if LOG_TRACE
448 fprintf(stderr, "wasi_snapshot_preview1_path_create_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
449#endif
450
451 enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, NULL);
452 switch (lookup_errno) {
453 case wasi_errno_success: return wasi_errno_exist;
454 case wasi_errno_noent: break;
455 default: return lookup_errno;
456 }
457 return DirEntry_create(fd, path_ptr, path_len, wasi_filetype_directory, time(NULL), NULL);
458}
459
460uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
461 uint8_t *const m = *wasm_memory;
462 struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
463 uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
464#if LOG_TRACE
465 fprintf(stderr, "wasi_snapshot_preview1_fd_read(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
466#endif
467
468 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
469 switch (des[fds[fd].de].filetype) {
470 case wasi_filetype_character_device: break;
471 case wasi_filetype_regular_file: break;
472 case wasi_filetype_directory: return wasi_errno_inval;
473 default: panic("unimplemented");
474 }
475
476 size_t size = 0;
477 for (uint32_t i = 0; i < iovs_len; i += 1) {
478 size_t read_size = 0;
479 if (fds[fd].stream != NULL)
480 read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
481 else
482 panic("unimplemented");
483 size += read_size;
484 if (read_size < iovs_ptr[i].len) break;
485 }
486
487 if (size > 0) des[fds[fd].de].atim = time(NULL);
488 *res_size_ptr = size;
489 return wasi_errno_success;
490}
491
492uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filestat) {
493 uint8_t *const m = *wasm_memory;
494 struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
495#if LOG_TRACE
496 fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_get(%u)\n", fd);
497#endif
498
499 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
500 DirEntry_filestat(fds[fd].de, res_filestat_ptr);
501 if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_success;
502 if (fds[fd].stream == NULL) return wasi_errno_success;
503 fpos_t pos;
504 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
505 if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
506 long size = ftell(fds[fd].stream);
507 if (size < 0) return wasi_errno_io;
508 res_filestat_ptr->size = size;
509 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
510 return wasi_errno_success;
511}
512
513uint32_t wasi_snapshot_preview1_path_rename(uint32_t fd, uint32_t old_path, uint32_t old_path_len, uint32_t new_fd, uint32_t new_path, uint32_t new_path_len) {
514 uint8_t *const m = *wasm_memory;
515 const char *old_path_ptr = (const char *)&m[old_path];
516 const char *new_path_ptr = (const char *)&m[new_path];
517#if LOG_TRACE
518 fprintf(stderr, "wasi_snapshot_preview1_path_rename(%u, \"%.*s\", %u, \"%.*s\")\n", fd, (int)old_path_len, old_path_ptr, new_fd, (int)new_path_len, new_path_ptr);
519#endif
520
521 uint32_t old_de;
522 enum wasi_errno old_lookup_errno = DirEntry_lookup(fd, 0, old_path_ptr, old_path_len, &old_de);
523 if (old_lookup_errno != wasi_errno_success) return old_lookup_errno;
524 DirEntry_unlink(old_de);
525
526 uint32_t de;
527 enum wasi_errno new_lookup_errno = DirEntry_lookup(new_fd, 0, new_path_ptr, new_path_len, &de);
528 switch (new_lookup_errno) {
529 case wasi_errno_success: DirEntry_unlink(de); break;
530 case wasi_errno_noent: break;
531 default: return new_lookup_errno;
532 }
533
534 uint32_t new_de;
535 enum wasi_errno create_errno =
536 DirEntry_create(new_fd, new_path_ptr, new_path_len, des[old_de].filetype, 0, &new_de);
537 if (create_errno != wasi_errno_success) return create_errno;
538 des[new_de].atim = des[old_de].atim;
539 des[new_de].mtim = des[old_de].mtim;
540 des[new_de].ctim = time(NULL);
541 return wasi_errno_success;
542}
543
544uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) {
545#if LOG_TRACE
546 fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_size(%u, %llu)\n", fd, (unsigned long long)size);
547#endif
548
549 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
550 if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_inval;
551
552 if (fds[fd].stream == NULL) return wasi_errno_success;
553 fpos_t pos;
554 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
555 if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
556 long old_size = ftell(fds[fd].stream);
557 if (old_size < 0) return wasi_errno_io;
558 if (size > (unsigned long)old_size) {
559 if (fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io;
560 fputc(0, fds[fd].stream);
561 } else if (size < (unsigned long)old_size) panic("unimplemented");
562 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
563 return wasi_errno_success;
564}
565
566uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
567 uint8_t *const m = *wasm_memory;
568 struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
569 uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
570#if LOG_TRACE
571 fprintf(stderr, "wasi_snapshot_preview1_fd_pwrite(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
572#endif
573
574 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
575 switch (des[fds[fd].de].filetype) {
576 case wasi_filetype_character_device: break;
577 case wasi_filetype_regular_file: break;
578 case wasi_filetype_directory: return wasi_errno_inval;
579 default: panic("unimplemented");
580 }
581
582 fpos_t pos;
583 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
584 if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
585
586 size_t size = 0;
587 for (uint32_t i = 0; i < iovs_len; i += 1) {
588 size_t written_size = 0;
589 if (fds[fd].stream != NULL)
590 written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
591 else
592 written_size = iovs_ptr[i].len;
593 size += written_size;
594 if (written_size < iovs_ptr[i].len) break;
595 }
596
597 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
598
599 if (size > 0) {
600 time_t now = time(NULL);
601 des[fds[fd].de].atim = now;
602 des[fds[fd].de].mtim = now;
603 }
604 *res_size_ptr = size;
605 return wasi_errno_success;
606}
607
608uint32_t wasi_snapshot_preview1_random_get(uint32_t buf, uint32_t buf_len) {
609 uint8_t *const m = *wasm_memory;
610 uint8_t *buf_ptr = (uint8_t *)&m[buf];
611#if LOG_TRACE
612 fprintf(stderr, "wasi_snapshot_preview1_random_get(%u)\n", buf_len);
613#endif
614
615 for (uint32_t i = 0; i < buf_len; i += 1) buf_ptr[i] = (uint8_t)rand();
616 return wasi_errno_success;
617}
618
619uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) {
620 (void)fd;
621 (void)atim;
622 (void)mtim;
623 (void)fst_flags;
624#if LOG_TRACE
625 fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_times(%u, %llu, %llu, 0x%X)\n", fd, (unsigned long long)atim, (unsigned long long)mtim, fst_flags);
626#endif
627
628 panic("unimplemented");
629 return wasi_errno_success;
630}
631
632uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_t environ_buf_size) {
633 (void)environ_size;
634 (void)environ_buf_size;
635#if LOG_TRACE
636 fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n");
637#endif
638
639 panic("unimplemented");
640 return wasi_errno_success;
641}
642
643uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_buf) {
644 (void)environ;
645 (void)environ_buf;
646#if LOG_TRACE
647 fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n");
648#endif
649
650 panic("unimplemented");
651 return wasi_errno_success;
652}
653
654uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, uint32_t path, uint32_t path_len, uint32_t res_filestat) {
655 uint8_t *const m = *wasm_memory;
656 const char *path_ptr = (const char *)&m[path];
657 struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
658#if LOG_TRACE
659 fprintf(stderr, "wasi_snapshot_preview1_path_filestat_get(%u, 0x%X, \"%.*s\")\n", fd, flags, (int)path_len, path_ptr);
660#endif
661
662 uint32_t de;
663 enum wasi_errno lookup_errno = DirEntry_lookup(fd, flags, path_ptr, path_len, &de);
664 if (lookup_errno != wasi_errno_success) return lookup_errno;
665 DirEntry_filestat(de, res_filestat_ptr);
666 if (des[de].filetype == wasi_filetype_regular_file && des[de].host_path != NULL) {
667 FILE *stream = fopen(des[de].host_path, "rb");
668 if (stream != NULL) {
669 if (fseek(stream, 0, SEEK_END) >= 0) {
670 long size = ftell(stream);
671 if (size >= 0) res_filestat_ptr->size = size;
672 }
673 fclose(stream);
674 }
675 }
676 return wasi_errno_success;
677}
678
679uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat) {
680 (void)fd;
681 (void)res_fdstat;
682#if LOG_TRACE
683 fprintf(stderr, "wasi_snapshot_preview1_fd_fdstat_get(%u)\n", fd);
684#endif
685
686 panic("unimplemented");
687 return wasi_errno_success;
688}
689
690uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t buf_len, uint64_t cookie, uint32_t res_size) {
691 (void)fd;
692 (void)buf;
693 (void)buf_len;
694 (void)cookie;
695 (void)res_size;
696#if LOG_TRACE
697 fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie);
698#endif
699
700 panic("unimplemented");
701 return wasi_errno_success;
702}
703
704uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
705 uint8_t *const m = *wasm_memory;
706 struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
707 uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
708#if LOG_TRACE
709 fprintf(stderr, "wasi_snapshot_preview1_fd_write(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
710#endif
711
712 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
713 switch (des[fds[fd].de].filetype) {
714 case wasi_filetype_character_device: break;
715 case wasi_filetype_regular_file: break;
716 case wasi_filetype_directory: return wasi_errno_inval;
717 default: panic("unimplemented");
718 }
719
720 size_t size = 0;
721 for (uint32_t i = 0; i < iovs_len; i += 1) {
722 size_t written_size = 0;
723 if (fds[fd].stream != NULL)
724 written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
725 else
726 written_size = iovs_ptr[i].len;
727 size += written_size;
728 if (written_size < iovs_ptr[i].len) break;
729 }
730
731 if (size > 0) {
732 time_t now = time(NULL);
733 des[fds[fd].de].atim = now;
734 des[fds[fd].de].mtim = now;
735 }
736 *res_size_ptr = size;
737 return wasi_errno_success;
738}
739
740uint32_t wasi_snapshot_preview1_path_open(uint32_t fd, uint32_t dirflags, uint32_t path, uint32_t path_len, uint32_t oflags, uint64_t fs_rights_base, uint64_t fs_rights_inheriting, uint32_t fdflags, uint32_t res_fd) {
741 uint8_t *const m = *wasm_memory;
742 const char *path_ptr = (const char *)&m[path];
743 (void)fs_rights_inheriting;
744 uint32_t *res_fd_ptr = (uint32_t *)&m[res_fd];
745#if LOG_TRACE
746 fprintf(stderr, "wasi_snapshot_preview1_path_open(%u, 0x%X, \"%.*s\", 0x%X, 0x%llX, 0x%llX, 0x%X)\n", fd, dirflags, (int)path_len, path_ptr, oflags, (unsigned long long)fs_rights_base, (unsigned long long)fs_rights_inheriting, fdflags);
747#endif
748
749 bool creat = (oflags & wasi_oflags_creat) != 0;
750 bool directory = (oflags & wasi_oflags_directory) != 0;
751 bool excl = (oflags & wasi_oflags_excl) != 0;
752 bool trunc = (oflags & wasi_oflags_trunc) != 0;
753 bool append = (fdflags & wasi_fdflags_append) != 0;
754
755 uint32_t de;
756 enum wasi_errno lookup_errno = DirEntry_lookup(fd, dirflags, path_ptr, path_len, &de);
757 if (lookup_errno == wasi_errno_success) {
758 if (directory && des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
759
760 struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
761 if (new_fds == NULL) return wasi_errno_nomem;
762 fds = new_fds;
763
764 fds[fd_len].de = de;
765 switch (des[de].filetype) {
766 case wasi_filetype_directory: fds[fd_len].stream = NULL; break;
767 default: panic("unimplemented");
768 }
769
770#if LOG_TRACE
771 fprintf(stderr, "fd = %u\n", fd_len);
772#endif
773 *res_fd_ptr = fd_len;
774 fd_len += 1;
775 }
776 if (lookup_errno != wasi_errno_noent) return lookup_errno;
777
778 struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
779 if (new_fds == NULL) return wasi_errno_nomem;
780 fds = new_fds;
781
782 enum wasi_filetype filetype = directory ? wasi_filetype_directory : wasi_filetype_regular_file;
783 enum wasi_errno create_errno = DirEntry_create(fd, path_ptr, path_len, filetype, 0, &de);
784 if (create_errno != wasi_errno_success) return create_errno;
785 FILE *stream;
786 if (!directory) {
787 if (des[de].host_path == NULL) {
788 if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
789 time_t now = time(NULL);
790 des[de].atim = now;
791 des[de].mtim = now;
792 des[de].ctim = now;
793 stream = NULL;
794 } else {
795 if (oflags != (append ? wasi_oflags_creat : wasi_oflags_creat | wasi_oflags_trunc)) {
796 char mode[] = "rb+";
797 if ((fs_rights_base & wasi_rights_fd_write) == 0) mode[2] = '\0';
798 stream = fopen(des[de].host_path, mode);
799 if (stream != NULL) {
800 if (append || excl || trunc) fclose(stream);
801 if (excl) {
802 DirEntry_unlink(de);
803 de_len -= 1;
804 return wasi_errno_exist;
805 }
806 } else if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
807 }
808 if (append || trunc || stream == NULL) {
809 char mode[] = "wb+";
810 if ((fs_rights_base & wasi_rights_fd_read) == 0) mode[2] = '\0';
811 if (trunc || !append) {
812 stream = fopen(des[de].host_path, mode);
813 if (append && stream != NULL) fclose(stream);
814 }
815 if (append) {
816 mode[0] = 'a';
817 stream = fopen(des[de].host_path, mode);
818 }
819 }
820 if (stream == NULL) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_isdir; }
821 }
822 } else stream = NULL;
823
824#if LOG_TRACE
825 fprintf(stderr, "fd = %u\n", fd_len);
826#endif
827 fds[fd_len].de = de;
828 fds[fd_len].stream = stream;
829 *res_fd_ptr = fd_len;
830 fd_len += 1;
831 return wasi_errno_success;
832}
833
834uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision, uint32_t res_timestamp) {
835 uint8_t *const m = *wasm_memory;
836 (void)precision;
837 uint64_t *res_timestamp_ptr = (uint64_t *)&m[res_timestamp];
838#if LOG_TRACE
839 fprintf(stderr, "wasi_snapshot_preview1_clock_time_get(%u, %llu)\n", id, (unsigned long long)precision);
840#endif
841
842 switch (id) {
843 case wasi_clockid_realtime:
844 *res_timestamp_ptr = time(NULL) * UINT64_C(1000000000);
845 break;
846 case wasi_clockid_monotonic:
847 case wasi_clockid_process_cputime_id:
848 case wasi_clockid_thread_cputime_id:
849 *res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC);
850 break;
851 default: return wasi_errno_inval;
852 }
853 return wasi_errno_success;
854}
855
856uint32_t wasi_snapshot_preview1_path_remove_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
857 uint8_t *const m = *wasm_memory;
858 const char *path_ptr = (const char *)&m[path];
859#if LOG_TRACE
860 fprintf(stderr, "wasi_snapshot_preview1_path_remove_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
861#endif
862
863 uint32_t de;
864 enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
865 if (lookup_errno != wasi_errno_success) return lookup_errno;
866 if (des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
867 DirEntry_unlink(de);
868 return wasi_errno_success;
869}
870
871uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uint32_t path_len) {
872 uint8_t *const m = *wasm_memory;
873 const char *path_ptr = (const char *)&m[path];
874#if LOG_TRACE
875 fprintf(stderr, "wasi_snapshot_preview1_path_unlink_file(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
876#endif
877
878 uint32_t de;
879 enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
880 if (lookup_errno != wasi_errno_success) return lookup_errno;
881 if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir;
882 if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented");
883 DirEntry_unlink(de);
884 return wasi_errno_success;
885}
886
887uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
888 uint8_t *const m = *wasm_memory;
889 struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
890 uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
891#if LOG_TRACE
892 fprintf(stderr, "wasi_snapshot_preview1_fd_pread(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
893#endif
894
895 if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
896 switch (des[fds[fd].de].filetype) {
897 case wasi_filetype_character_device: break;
898 case wasi_filetype_regular_file: break;
899 case wasi_filetype_directory: return wasi_errno_inval;
900 default: panic("unimplemented");
901 }
902
903 fpos_t pos;
904 if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
905 if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
906
907 size_t size = 0;
908 for (uint32_t i = 0; i < iovs_len; i += 1) {
909 size_t read_size = 0;
910 if (fds[fd].stream != NULL)
911 read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
912 else
913 panic("unimplemented");
914 size += read_size;
915 if (read_size < iovs_ptr[i].len) break;
916 }
917
918 if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
919
920 if (size > 0) des[fds[fd].de].atim = time(NULL);
921 *res_size_ptr = size;
922 return wasi_errno_success;
923}
924
925uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t nsubscriptions, uint32_t res_nevents) {
926 (void)in;
927 (void)out;
928 (void)nsubscriptions;
929 (void)res_nevents;
930#if LOG_TRACE
931 fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions);
932#endif
933
934 panic("unimplemented");
935 return wasi_errno_success;
936}
937
938
939void wasi_snapshot_preview1_debug(uint32_t string, uint64_t x) {
940 uint8_t *const m = *wasm_memory;
941 const char *string_ptr = (const char *)&m[string];
942#if LOG_TRACE
943 fprintf(stderr, "wasi_snapshot_preview1_debug(\"%s\", %llu, 0x%llX)\n", string_ptr, (unsigned long long)x, (unsigned long long)x);
944#endif
945
946 (void)string_ptr;
947 (void)x;
948}
stage1/wasm.h created+280
......@@ -0,0 +1,280 @@
1#ifndef WASM_H
2#define WASM_H
3
4#include "panic.h"
5
6enum WasmSectionId {
7 WasmSectionId_type = 1,
8 WasmSectionId_import = 2,
9 WasmSectionId_func = 3,
10 WasmSectionId_table = 4,
11 WasmSectionId_mem = 5,
12 WasmSectionId_global = 6,
13 WasmSectionId_export = 7,
14 WasmSectionId_start = 8,
15 WasmSectionId_elem = 9,
16 WasmSectionId_code = 10,
17 WasmSectionId_data = 11,
18 WasmSectionId_datacount = 12,
19};
20
21enum WasmValType {
22 WasmValType_i32 = -0x01,
23 WasmValType_i64 = -0x02,
24 WasmValType_f32 = -0x03,
25 WasmValType_f64 = -0x04,
26 WasmValType_v128 = -0x05,
27 WasmValType_funcref = -0x10,
28 WasmValType_externref = -0x11,
29 WasmValType_empty = -0x40,
30};
31static const char *WasmValType_toC(enum WasmValType val_type) {
32 switch (val_type) {
33 case WasmValType_i32: return "uint32_t";
34 case WasmValType_i64: return "uint64_t";
35 case WasmValType_f32: return "float";
36 case WasmValType_f64: return "double";
37 case WasmValType_v128: panic("vector types are unsupported");
38 case WasmValType_funcref: return "void (*)(void)";
39 case WasmValType_externref: return "void *";
40 default: panic("unsupported value type");
41 }
42 return NULL;
43}
44
45enum WasmMut {
46 WasmMut_const = 0x00,
47 WasmMut_var = 0x01,
48};
49static const char *WasmMut_toC(enum WasmMut val_type) {
50 switch (val_type) {
51 case WasmMut_const: return "const ";
52 case WasmMut_var: return "";
53 default: panic("unsupported mut");
54 }
55}
56
57enum WasmOpcode {
58 WasmOpcode_unreachable = 0x00,
59 WasmOpcode_nop = 0x01,
60 WasmOpcode_block = 0x02,
61 WasmOpcode_loop = 0x03,
62 WasmOpcode_if = 0x04,
63 WasmOpcode_else = 0x05,
64 WasmOpcode_end = 0x0B,
65 WasmOpcode_br = 0x0C,
66 WasmOpcode_br_if = 0x0D,
67 WasmOpcode_br_table = 0x0E,
68 WasmOpcode_return = 0x0F,
69 WasmOpcode_call = 0x10,
70 WasmOpcode_call_indirect = 0x11,
71
72 WasmOpcode_drop = 0x1A,
73 WasmOpcode_select = 0x1B,
74 WasmOpcode_select_t = 0x1C,
75
76 WasmOpcode_local_get = 0x20,
77 WasmOpcode_local_set = 0x21,
78 WasmOpcode_local_tee = 0x22,
79 WasmOpcode_global_get = 0x23,
80 WasmOpcode_global_set = 0x24,
81
82 WasmOpcode_table_get = 0x25,
83 WasmOpcode_table_set = 0x26,
84
85 WasmOpcode_i32_load = 0x28,
86 WasmOpcode_i64_load = 0x29,
87 WasmOpcode_f32_load = 0x2A,
88 WasmOpcode_f64_load = 0x2B,
89 WasmOpcode_i32_load8_s = 0x2C,
90 WasmOpcode_i32_load8_u = 0x2D,
91 WasmOpcode_i32_load16_s = 0x2E,
92 WasmOpcode_i32_load16_u = 0x2F,
93 WasmOpcode_i64_load8_s = 0x30,
94 WasmOpcode_i64_load8_u = 0x31,
95 WasmOpcode_i64_load16_s = 0x32,
96 WasmOpcode_i64_load16_u = 0x33,
97 WasmOpcode_i64_load32_s = 0x34,
98 WasmOpcode_i64_load32_u = 0x35,
99 WasmOpcode_i32_store = 0x36,
100 WasmOpcode_i64_store = 0x37,
101 WasmOpcode_f32_store = 0x38,
102 WasmOpcode_f64_store = 0x39,
103 WasmOpcode_i32_store8 = 0x3A,
104 WasmOpcode_i32_store16 = 0x3B,
105 WasmOpcode_i64_store8 = 0x3C,
106 WasmOpcode_i64_store16 = 0x3D,
107 WasmOpcode_i64_store32 = 0x3E,
108 WasmOpcode_memory_size = 0x3F,
109 WasmOpcode_memory_grow = 0x40,
110
111 WasmOpcode_i32_const = 0x41,
112 WasmOpcode_i64_const = 0x42,
113 WasmOpcode_f32_const = 0x43,
114 WasmOpcode_f64_const = 0x44,
115
116 WasmOpcode_i32_eqz = 0x45,
117 WasmOpcode_i32_eq = 0x46,
118 WasmOpcode_i32_ne = 0x47,
119 WasmOpcode_i32_lt_s = 0x48,
120 WasmOpcode_i32_lt_u = 0x49,
121 WasmOpcode_i32_gt_s = 0x4A,
122 WasmOpcode_i32_gt_u = 0x4B,
123 WasmOpcode_i32_le_s = 0x4C,
124 WasmOpcode_i32_le_u = 0x4D,
125 WasmOpcode_i32_ge_s = 0x4E,
126 WasmOpcode_i32_ge_u = 0x4F,
127
128 WasmOpcode_i64_eqz = 0x50,
129 WasmOpcode_i64_eq = 0x51,
130 WasmOpcode_i64_ne = 0x52,
131 WasmOpcode_i64_lt_s = 0x53,
132 WasmOpcode_i64_lt_u = 0x54,
133 WasmOpcode_i64_gt_s = 0x55,
134 WasmOpcode_i64_gt_u = 0x56,
135 WasmOpcode_i64_le_s = 0x57,
136 WasmOpcode_i64_le_u = 0x58,
137 WasmOpcode_i64_ge_s = 0x59,
138 WasmOpcode_i64_ge_u = 0x5A,
139
140 WasmOpcode_f32_eq = 0x5B,
141 WasmOpcode_f32_ne = 0x5C,
142 WasmOpcode_f32_lt = 0x5D,
143 WasmOpcode_f32_gt = 0x5E,
144 WasmOpcode_f32_le = 0x5F,
145 WasmOpcode_f32_ge = 0x60,
146
147 WasmOpcode_f64_eq = 0x61,
148 WasmOpcode_f64_ne = 0x62,
149 WasmOpcode_f64_lt = 0x63,
150 WasmOpcode_f64_gt = 0x64,
151 WasmOpcode_f64_le = 0x65,
152 WasmOpcode_f64_ge = 0x66,
153
154 WasmOpcode_i32_clz = 0x67,
155 WasmOpcode_i32_ctz = 0x68,
156 WasmOpcode_i32_popcnt = 0x69,
157 WasmOpcode_i32_add = 0x6A,
158 WasmOpcode_i32_sub = 0x6B,
159 WasmOpcode_i32_mul = 0x6C,
160 WasmOpcode_i32_div_s = 0x6D,
161 WasmOpcode_i32_div_u = 0x6E,
162 WasmOpcode_i32_rem_s = 0x6F,
163 WasmOpcode_i32_rem_u = 0x70,
164 WasmOpcode_i32_and = 0x71,
165 WasmOpcode_i32_or = 0x72,
166 WasmOpcode_i32_xor = 0x73,
167 WasmOpcode_i32_shl = 0x74,
168 WasmOpcode_i32_shr_s = 0x75,
169 WasmOpcode_i32_shr_u = 0x76,
170 WasmOpcode_i32_rotl = 0x77,
171 WasmOpcode_i32_rotr = 0x78,
172
173 WasmOpcode_i64_clz = 0x79,
174 WasmOpcode_i64_ctz = 0x7A,
175 WasmOpcode_i64_popcnt = 0x7B,
176 WasmOpcode_i64_add = 0x7C,
177 WasmOpcode_i64_sub = 0x7D,
178 WasmOpcode_i64_mul = 0x7E,
179 WasmOpcode_i64_div_s = 0x7F,
180 WasmOpcode_i64_div_u = 0x80,
181 WasmOpcode_i64_rem_s = 0x81,
182 WasmOpcode_i64_rem_u = 0x82,
183 WasmOpcode_i64_and = 0x83,
184 WasmOpcode_i64_or = 0x84,
185 WasmOpcode_i64_xor = 0x85,
186 WasmOpcode_i64_shl = 0x86,
187 WasmOpcode_i64_shr_s = 0x87,
188 WasmOpcode_i64_shr_u = 0x88,
189 WasmOpcode_i64_rotl = 0x89,
190 WasmOpcode_i64_rotr = 0x8A,
191
192 WasmOpcode_f32_abs = 0x8B,
193 WasmOpcode_f32_neg = 0x8C,
194 WasmOpcode_f32_ceil = 0x8D,
195 WasmOpcode_f32_floor = 0x8E,
196 WasmOpcode_f32_trunc = 0x8F,
197 WasmOpcode_f32_nearest = 0x90,
198 WasmOpcode_f32_sqrt = 0x91,
199 WasmOpcode_f32_add = 0x92,
200 WasmOpcode_f32_sub = 0x93,
201 WasmOpcode_f32_mul = 0x94,
202 WasmOpcode_f32_div = 0x95,
203 WasmOpcode_f32_min = 0x96,
204 WasmOpcode_f32_max = 0x97,
205 WasmOpcode_f32_copysign = 0x98,
206
207 WasmOpcode_f64_abs = 0x99,
208 WasmOpcode_f64_neg = 0x9A,
209 WasmOpcode_f64_ceil = 0x9B,
210 WasmOpcode_f64_floor = 0x9C,
211 WasmOpcode_f64_trunc = 0x9D,
212 WasmOpcode_f64_nearest = 0x9E,
213 WasmOpcode_f64_sqrt = 0x9F,
214 WasmOpcode_f64_add = 0xA0,
215 WasmOpcode_f64_sub = 0xA1,
216 WasmOpcode_f64_mul = 0xA2,
217 WasmOpcode_f64_div = 0xA3,
218 WasmOpcode_f64_min = 0xA4,
219 WasmOpcode_f64_max = 0xA5,
220 WasmOpcode_f64_copysign = 0xA6,
221
222 WasmOpcode_i32_wrap_i64 = 0xA7,
223 WasmOpcode_i32_trunc_f32_s = 0xA8,
224 WasmOpcode_i32_trunc_f32_u = 0xA9,
225 WasmOpcode_i32_trunc_f64_s = 0xAA,
226 WasmOpcode_i32_trunc_f64_u = 0xAB,
227 WasmOpcode_i64_extend_i32_s = 0xAC,
228 WasmOpcode_i64_extend_i32_u = 0xAD,
229 WasmOpcode_i64_trunc_f32_s = 0xAE,
230 WasmOpcode_i64_trunc_f32_u = 0xAF,
231 WasmOpcode_i64_trunc_f64_s = 0xB0,
232 WasmOpcode_i64_trunc_f64_u = 0xB1,
233 WasmOpcode_f32_convert_i32_s = 0xB2,
234 WasmOpcode_f32_convert_i32_u = 0xB3,
235 WasmOpcode_f32_convert_i64_s = 0xB4,
236 WasmOpcode_f32_convert_i64_u = 0xB5,
237 WasmOpcode_f32_demote_f64 = 0xB6,
238 WasmOpcode_f64_convert_i32_s = 0xB7,
239 WasmOpcode_f64_convert_i32_u = 0xB8,
240 WasmOpcode_f64_convert_i64_s = 0xB9,
241 WasmOpcode_f64_convert_i64_u = 0xBA,
242 WasmOpcode_f64_promote_f32 = 0xBB,
243 WasmOpcode_i32_reinterpret_f32 = 0xBC,
244 WasmOpcode_i64_reinterpret_f64 = 0xBD,
245 WasmOpcode_f32_reinterpret_i32 = 0xBE,
246 WasmOpcode_f64_reinterpret_i64 = 0xBF,
247
248 WasmOpcode_i32_extend8_s = 0xC0,
249 WasmOpcode_i32_extend16_s = 0xC1,
250 WasmOpcode_i64_extend8_s = 0xC2,
251 WasmOpcode_i64_extend16_s = 0xC3,
252 WasmOpcode_i64_extend32_s = 0xC4,
253
254 WasmOpcode_prefixed = 0xFC,
255};
256
257enum WasmPrefixedOpcode {
258 WasmPrefixedOpcode_i32_trunc_sat_f32_s = 0,
259 WasmPrefixedOpcode_i32_trunc_sat_f32_u = 1,
260 WasmPrefixedOpcode_i32_trunc_sat_f64_s = 2,
261 WasmPrefixedOpcode_i32_trunc_sat_f64_u = 3,
262 WasmPrefixedOpcode_i64_trunc_sat_f32_s = 4,
263 WasmPrefixedOpcode_i64_trunc_sat_f32_u = 5,
264 WasmPrefixedOpcode_i64_trunc_sat_f64_s = 6,
265 WasmPrefixedOpcode_i64_trunc_sat_f64_u = 7,
266
267 WasmPrefixedOpcode_memory_init = 8,
268 WasmPrefixedOpcode_data_drop = 9,
269 WasmPrefixedOpcode_memory_copy = 10,
270 WasmPrefixedOpcode_memory_fill = 11,
271
272 WasmPrefixedOpcode_table_init = 12,
273 WasmPrefixedOpcode_elem_drop = 13,
274 WasmPrefixedOpcode_table_copy = 14,
275 WasmPrefixedOpcode_table_grow = 15,
276 WasmPrefixedOpcode_table_size = 16,
277 WasmPrefixedOpcode_table_fill = 17,
278};
279
280#endif /* WASM_H */
stage1/wasm2c.c created+2520
......@@ -0,0 +1,2520 @@
1#include "FuncGen.h"
2#include "InputStream.h"
3#include "panic.h"
4#include "wasm.h"
5
6#include <inttypes.h>
7#include <limits.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12
13struct FuncType {
14 const struct ResultType *param;
15 const struct ResultType *result;
16};
17static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) {
18 if (block_type >= 0) return &types[block_type];
19
20 static const struct ResultType none = { 0, { 0 }};
21 static const struct ResultType i32 = { 1, { WasmValType_i32 } };
22 static const struct ResultType i64 = { 1, { WasmValType_i64 } };
23 static const struct ResultType f32 = { 1, { WasmValType_f32 } };
24 static const struct ResultType f64 = { 1, { WasmValType_f64 } };
25
26 static const struct FuncType none_i32 = { &none, &i32 };
27 static const struct FuncType none_i64 = { &none, &i64 };
28 static const struct FuncType none_f32 = { &none, &f32 };
29 static const struct FuncType none_f64 = { &none, &f64 };
30 static const struct FuncType none_none = { &none, &none };
31
32 switch (block_type) {
33 case WasmValType_i32: return &none_i32;
34 case WasmValType_i64: return &none_i64;
35 case WasmValType_f32: return &none_f32;
36 case WasmValType_f64: return &none_f64;
37 case WasmValType_empty: return &none_none;
38 default: panic("unsupported block type");
39 }
40 return NULL;
41}
42
43static uint32_t evalExpr(struct InputStream *in) {
44 uint32_t value;
45 while (true) {
46 switch (InputStream_readByte(in)) {
47 case WasmOpcode_end: return value;
48
49 case WasmOpcode_i32_const:
50 value = (uint32_t)InputStream_readLeb128_i32(in);
51 break;
52
53 default: panic("unsupported expr opcode");
54 }
55 }
56}
57
58static void renderExpr(FILE *out, struct InputStream *in) {
59 while (true) {
60 switch (InputStream_readByte(in)) {
61 case WasmOpcode_end: return;
62
63 case WasmOpcode_i32_const: {
64 uint32_t value = (uint32_t)InputStream_readLeb128_i32(in);
65 fprintf(out, "UINT32_C(0x%" PRIX32 ")", value);
66 break;
67 }
68
69 default: panic("unsupported expr opcode");
70 }
71 }
72}
73
74int main(int argc, char **argv) {
75 if (argc != 3) {
76 fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]);
77 return 1;
78 }
79
80 const char *mod = "wasm";
81 bool isBigEndian = false; // TODO
82
83 struct InputStream in;
84 InputStream_open(&in, argv[1]);
85
86 if (InputStream_readByte(&in) != '\0' ||
87 InputStream_readByte(&in) != 'a' ||
88 InputStream_readByte(&in) != 's' ||
89 InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file");
90 if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version");
91
92 FILE *out = fopen(argv[2], "w");
93 if (out == NULL) panic("unable to open output file");
94 fputs("#include <math.h>\n"
95 "#include <stdint.h>\n"
96 "#include <stdlib.h>\n"
97 "#include <string.h>\n"
98 "\n"
99 "static uint32_t i32_reinterpret_f32(const float src) {\n"
100 " uint32_t dst;\n"
101 " memcpy(&dst, &src, sizeof(dst));\n"
102 " return dst;\n"
103 "}\n"
104 "static uint64_t i64_reinterpret_f64(const double src) {\n"
105 " uint64_t dst;\n"
106 " memcpy(&dst, &src, sizeof(dst));\n"
107 " return dst;\n"
108 "}\n"
109 "static float f32_reinterpret_i32(const uint32_t src) {\n"
110 " float dst;\n"
111 " memcpy(&dst, &src, sizeof(dst));\n"
112 " return dst;\n"
113 "}\n"
114 "static double f64_reinterpret_i64(const uint64_t src) {\n"
115 " double dst;\n"
116 " memcpy(&dst, &src, sizeof(dst));\n"
117 " return dst;\n"
118 "}\n"
119 "\n"
120 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t n) {\n"
121 " uint32_t r = *p;\n"
122 " uint32_t new_p = r + n;\n"
123 " uint8_t *new_m = realloc(*m, new_p << 16);\n"
124 " if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n"
125 " memset(&new_m[r << 16], 0, n << 16);\n"
126 " *m = new_m;\n"
127 " *p = new_p;\n"
128 " return r;\n"
129 "}\n"
130 "\n"
131 "static int inited;\n"
132 "static void init_elem(void);\n"
133 "static void init_data(void);\n"
134 "static void init(void) {\n"
135 " if (inited != 0) return;\n"
136 " init_elem();\n"
137 " init_data();\n"
138 " inited = 1;\n"
139 "}\n"
140 "\n", out);
141
142 struct FuncType *types;
143 uint32_t max_param_len = 0;
144 (void)InputStream_skipToSection(&in, WasmSectionId_type);
145 {
146 uint32_t len = InputStream_readLeb128_u32(&in);
147 types = malloc(sizeof(struct FuncType) * len);
148 if (types == NULL) panic("out of memory");
149 for (uint32_t i = 0; i < len; i += 1) {
150 if (InputStream_readByte(&in) != 0x60) panic("expected functype");
151 types[i].param = InputStream_readResultType(&in);
152 if (types[i].param->len > max_param_len) max_param_len = types[i].param->len;
153 types[i].result = InputStream_readResultType(&in);
154 }
155 }
156
157 struct Import {
158 const char *mod;
159 const char *name;
160 uint32_t type_idx;
161 } *imports;
162 (void)InputStream_skipToSection(&in, WasmSectionId_import);
163 uint32_t imports_len = InputStream_readLeb128_u32(&in);
164 {
165 imports = malloc(sizeof(struct Import) * imports_len);
166 if (imports == NULL) panic("out of memory");
167 for (uint32_t i = 0; i < imports_len; i += 1) {
168 imports[i].mod = InputStream_readName(&in);
169 imports[i].name = InputStream_readName(&in);
170 switch (InputStream_readByte(&in)) {
171 case 0x00: { // func
172 imports[i].type_idx = InputStream_readLeb128_u32(&in);
173 const struct FuncType *func_type = &types[imports[i].type_idx];
174 switch (func_type->result->len) {
175 case 0: fputs("void", out); break;
176 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
177 default: panic("multiple function returns not supported");
178 }
179 fprintf(out, " %s_%s(", imports[i].mod, imports[i].name);
180 if (func_type->param->len == 0) fputs("void", out);
181 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
182 if (param_i > 0) fputs(", ", out);
183 fputs(WasmValType_toC(func_type->param->types[param_i]), out);
184 }
185 fputs(");\n", out);
186 break;
187 }
188
189 case 0x01: // table
190 case 0x02: // mem
191 case 0x03: // global
192 default:
193 panic("unsupported import type");
194 }
195 }
196 fputc('\n', out);
197 }
198
199 struct Func {
200 uint32_t type_idx;
201 } *funcs;
202 (void)InputStream_skipToSection(&in, WasmSectionId_func);
203 {
204 uint32_t len = InputStream_readLeb128_u32(&in);
205 funcs = malloc(sizeof(struct Func) * len);
206 if (funcs == NULL) panic("out of memory");
207 for (uint32_t i = 0; i < len; i += 1) {
208 funcs[i].type_idx = InputStream_readLeb128_u32(&in);
209 const struct FuncType *func_type = &types[funcs[i].type_idx];
210 fputs("static ", out);
211 switch (func_type->result->len) {
212 case 0: fputs("void", out); break;
213 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
214 default: panic("multiple function returns not supported");
215 }
216 fprintf(out, " f%" PRIu32 "(", i);
217 if (func_type->param->len == 0) fputs("void", out);
218 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
219 if (param_i > 0) fputs(", ", out);
220 fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i]));
221 }
222 fputs(");\n", out);
223 }
224 fputc('\n', out);
225 }
226
227 struct Table {
228 int8_t type;
229 struct Limits limits;
230 } *tables;
231 (void)InputStream_skipToSection(&in, WasmSectionId_table);
232 {
233 uint32_t len = InputStream_readLeb128_u32(&in);
234 tables = malloc(sizeof(struct Table) * len);
235 if (tables == NULL) panic("out of memory");
236 for (uint32_t i = 0; i < len; i += 1) {
237 int64_t ref_type = InputStream_readLeb128_i64(&in);
238 switch (ref_type) {
239 case WasmValType_funcref:
240 break;
241
242 default: panic("unsupported reftype");
243 }
244 tables[i].type = ref_type;
245 tables[i].limits = InputStream_readLimits(&in);
246 if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported");
247 fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n",
248 i, tables[i].limits.min);
249 }
250 fputc('\n', out);
251 }
252
253 struct Mem {
254 struct Limits limits;
255 } *mems;
256 (void)InputStream_skipToSection(&in, WasmSectionId_mem);
257 uint32_t mems_len = InputStream_readLeb128_u32(&in);
258 {
259 mems = malloc(sizeof(struct Mem) * mems_len);
260 if (mems == NULL) panic("out of memory");
261 for (uint32_t i = 0; i < mems_len; i += 1) {
262 mems[i].limits = InputStream_readLimits(&in);
263 fprintf(out, "static uint8_t *m%" PRIu32 ";\n"
264 "static uint32_t p%" PRIu32 ";\n", i, i);
265 }
266 fputc('\n', out);
267 }
268
269 struct Global {
270 bool mut;
271 int8_t val_type;
272 } *globals;
273 (void)InputStream_skipToSection(&in, WasmSectionId_global);
274 {
275 uint32_t len = InputStream_readLeb128_u32(&in);
276 globals = malloc(sizeof(struct Global) * len);
277 if (globals == NULL) panic("out of memory");
278 for (uint32_t i = 0; i < len; i += 1) {
279 int64_t val_type = InputStream_readLeb128_i64(&in);
280 enum WasmMut mut = InputStream_readByte(&in);
281 fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i);
282 renderExpr(out, &in);
283 fputs(";\n", out);
284 globals[i].mut = mut;
285 globals[i].val_type = val_type;
286 }
287 fputc('\n', out);
288 }
289
290 (void)InputStream_skipToSection(&in, WasmSectionId_export);
291 {
292 uint32_t len = InputStream_readLeb128_u32(&in);
293 for (uint32_t i = 0; i < len; i += 1) {
294 char *name = InputStream_readName(&in);
295 uint8_t kind = InputStream_readByte(&in);
296 uint32_t idx = InputStream_readLeb128_u32(&in);
297 switch (kind) {
298 case 0x00: {
299 if (idx < imports_len) panic("can't export an import");
300 const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx];
301 switch (func_type->result->len) {
302 case 0: fputs("void", out); break;
303 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
304 default: panic("multiple function returns not supported");
305 }
306 fprintf(out, " %s_%s(", mod, name);
307 if (func_type->param->len == 0) fputs("void", out);
308 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
309 if (param_i > 0) fputs(", ", out);
310 fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i);
311 }
312 fprintf(out,
313 ") {\n"
314 " init();\n"
315 " %sf%" PRIu32 "(",
316 func_type->result->len > 0 ? "return " : "", idx - imports_len);
317 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
318 if (param_i > 0) fputs(", ", out);
319 fprintf(out, "l%" PRIu32, param_i);
320 }
321 fputs(");\n}\n", out);
322 break;
323 }
324
325 case 0x02:
326 fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx);
327 break;
328
329 default: panic("unsupported export kind");
330 }
331 free(name);
332 }
333 fputc('\n', out);
334 }
335
336 (void)InputStream_skipToSection(&in, WasmSectionId_elem);
337 {
338 uint32_t table_i = 0;
339 uint32_t len = InputStream_readLeb128_u32(&in);
340 fputs("static void init_elem(void) {\n", out);
341 for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
342 uint32_t table_idx = 0;
343 uint32_t elem_type = InputStream_readLeb128_u32(&in);
344 if (elem_type != 0x00) panic("unsupported elem type");
345 uint32_t offset = evalExpr(&in);
346 uint32_t segment_len = InputStream_readLeb128_u32(&in);
347 for (uint32_t i = 0; i < segment_len; i += 1) {
348 uint32_t func_id = InputStream_readLeb128_u32(&in);
349 fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&",
350 table_idx, offset + i);
351 if (func_id < imports_len)
352 fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
353 else
354 fprintf(out, "f%" PRIu32, func_id - imports_len);
355 fputs(";\n", out);
356 }
357 }
358 fputs("}\n\n", out);
359 }
360
361 (void)InputStream_skipToSection(&in, WasmSectionId_code);
362 {
363 struct FuncGen fg;
364 FuncGen_init(&fg);
365 bool *param_used = malloc(sizeof(bool) * max_param_len);
366 uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len);
367
368 uint32_t len = InputStream_readLeb128_u32(&in);
369 for (uint32_t func_i = 0; func_i < len; func_i += 1) {
370 FuncGen_reset(&fg);
371
372 uint32_t code_len = InputStream_readLeb128_u32(&in);
373 const struct FuncType *func_type = &types[funcs[func_i].type_idx];
374 fputs("static ", out);
375 switch (func_type->result->len) {
376 case 0: fputs("void", out); break;
377 case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
378 default: panic("multiple function returns not supported");
379 }
380 fprintf(out, " f%" PRIu32 "(", func_i);
381 if (func_type->param->len == 0) fputs("void", out);
382 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
383 param_used[param_i] = false;
384 int8_t param_type = func_type->param->types[param_i];
385 if (param_i > 0) fputs(", ", out);
386 FuncGen_localDeclare(&fg, out, param_type);
387 }
388 fputs(") {\n", out);
389
390 for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in);
391 local_sets_remaining > 0; local_sets_remaining -= 1) {
392 uint32_t local_set_len = InputStream_readLeb128_u32(&in);
393 int64_t val_type = InputStream_readLeb128_i64(&in);
394 for (; local_set_len > 0; local_set_len -= 1) {
395 FuncGen_indent(&fg, out);
396 FuncGen_localDeclare(&fg, out, val_type);
397 fputs(" = 0;\n", out);
398 }
399 }
400
401 uint32_t unreachable_depth = 0;
402 for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
403 result_i -= 1;
404 FuncGen_indent(&fg, out);
405 (void)FuncGen_localDeclare(&fg, out,
406 func_type->result->types[result_i]);
407 fputs(";\n", out);
408 }
409 FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx);
410 while (!FuncGen_done(&fg)) {
411 //static const char *mnemonics[] = {
412 // [WasmOpcode_unreachable] = "unreachable",
413 // [WasmOpcode_nop] = "nop",
414 // [WasmOpcode_block] = "block",
415 // [WasmOpcode_loop] = "loop",
416 // [WasmOpcode_if] = "if",
417 // [WasmOpcode_else] = "else",
418 // [WasmOpcode_end] = "end",
419 // [WasmOpcode_br] = "br",
420 // [WasmOpcode_br_if] = "br_if",
421 // [WasmOpcode_br_table] = "br_table",
422 // [WasmOpcode_return] = "return",
423 // [WasmOpcode_call] = "call",
424 // [WasmOpcode_call_indirect] = "call_indirect",
425 //
426 // [WasmOpcode_drop] = "drop",
427 // [WasmOpcode_select] = "select",
428 // [WasmOpcode_select_t] = "select t",
429 //
430 // [WasmOpcode_local_get] = "local.get",
431 // [WasmOpcode_local_set] = "local.set",
432 // [WasmOpcode_local_tee] = "local.tee",
433 // [WasmOpcode_global_get] = "global.get",
434 // [WasmOpcode_global_set] = "global.set",
435 // [WasmOpcode_table_get] = "table.get",
436 // [WasmOpcode_table_set] = "table.set",
437 //
438 // [WasmOpcode_i32_load] = "i32.load",
439 // [WasmOpcode_i64_load] = "i64.load",
440 // [WasmOpcode_f32_load] = "f32.load",
441 // [WasmOpcode_f64_load] = "f64.load",
442 // [WasmOpcode_i32_load8_s] = "i32.load8_s",
443 // [WasmOpcode_i32_load8_u] = "i32.load8_u",
444 // [WasmOpcode_i32_load16_s] = "i32.load16_s",
445 // [WasmOpcode_i32_load16_u] = "i32.load16_u",
446 // [WasmOpcode_i64_load8_s] = "i64.load8_s",
447 // [WasmOpcode_i64_load8_u] = "i64.load8_u",
448 // [WasmOpcode_i64_load16_s] = "i64.load16_s",
449 // [WasmOpcode_i64_load16_u] = "i64.load16_u",
450 // [WasmOpcode_i64_load32_s] = "i64.load32_s",
451 // [WasmOpcode_i64_load32_u] = "i64.load32_u",
452 // [WasmOpcode_i32_store] = "i32.store",
453 // [WasmOpcode_i64_store] = "i64.store",
454 // [WasmOpcode_f32_store] = "f32.store",
455 // [WasmOpcode_f64_store] = "f64.store",
456 // [WasmOpcode_i32_store8] = "i32.store8",
457 // [WasmOpcode_i32_store16] = "i32.store16",
458 // [WasmOpcode_i64_store8] = "i64.store8",
459 // [WasmOpcode_i64_store16] = "i64.store16",
460 // [WasmOpcode_i64_store32] = "i64.store32",
461 // [WasmOpcode_memory_size] = "memory.size",
462 // [WasmOpcode_memory_grow] = "memory.grow",
463 //
464 // [WasmOpcode_i32_const] = "i32.const",
465 // [WasmOpcode_i64_const] = "i64.const",
466 // [WasmOpcode_f32_const] = "f32.const",
467 // [WasmOpcode_f64_const] = "f64.const",
468 //
469 // [WasmOpcode_i32_eqz] = "i32.eqz",
470 // [WasmOpcode_i32_eq] = "i32.eq",
471 // [WasmOpcode_i32_ne] = "i32.ne",
472 // [WasmOpcode_i32_lt_s] = "i32.lt_s",
473 // [WasmOpcode_i32_lt_u] = "i32.lt_u",
474 // [WasmOpcode_i32_gt_s] = "i32.gt_s",
475 // [WasmOpcode_i32_gt_u] = "i32.gt_u",
476 // [WasmOpcode_i32_le_s] = "i32.le_s",
477 // [WasmOpcode_i32_le_u] = "i32.le_u",
478 // [WasmOpcode_i32_ge_s] = "i32.ge_s",
479 // [WasmOpcode_i32_ge_u] = "i32.ge_u",
480 //
481 // [WasmOpcode_i64_eqz] = "i64.eqz",
482 // [WasmOpcode_i64_eq] = "i64.eq",
483 // [WasmOpcode_i64_ne] = "i64.ne",
484 // [WasmOpcode_i64_lt_s] = "i64.lt_s",
485 // [WasmOpcode_i64_lt_u] = "i64.lt_u",
486 // [WasmOpcode_i64_gt_s] = "i64.gt_s",
487 // [WasmOpcode_i64_gt_u] = "i64.gt_u",
488 // [WasmOpcode_i64_le_s] = "i64.le_s",
489 // [WasmOpcode_i64_le_u] = "i64.le_u",
490 // [WasmOpcode_i64_ge_s] = "i64.ge_s",
491 // [WasmOpcode_i64_ge_u] = "i64.ge_u",
492 //
493 // [WasmOpcode_f32_eq] = "f32.eq",
494 // [WasmOpcode_f32_ne] = "f32.ne",
495 // [WasmOpcode_f32_lt] = "f32.lt",
496 // [WasmOpcode_f32_gt] = "f32.gt",
497 // [WasmOpcode_f32_le] = "f32.le",
498 // [WasmOpcode_f32_ge] = "f32.ge",
499 //
500 // [WasmOpcode_f64_eq] = "f64.eq",
501 // [WasmOpcode_f64_ne] = "f64.ne",
502 // [WasmOpcode_f64_lt] = "f64.lt",
503 // [WasmOpcode_f64_gt] = "f64.gt",
504 // [WasmOpcode_f64_le] = "f64.le",
505 // [WasmOpcode_f64_ge] = "f64.ge",
506 //
507 // [WasmOpcode_i32_clz] = "i32.clz",
508 // [WasmOpcode_i32_ctz] = "i32.ctz",
509 // [WasmOpcode_i32_popcnt] = "i32.popcnt",
510 // [WasmOpcode_i32_add] = "i32.add",
511 // [WasmOpcode_i32_sub] = "i32.sub",
512 // [WasmOpcode_i32_mul] = "i32.mul",
513 // [WasmOpcode_i32_div_s] = "i32.div_s",
514 // [WasmOpcode_i32_div_u] = "i32.div_u",
515 // [WasmOpcode_i32_rem_s] = "i32.rem_s",
516 // [WasmOpcode_i32_rem_u] = "i32.rem_u",
517 // [WasmOpcode_i32_and] = "i32.and",
518 // [WasmOpcode_i32_or] = "i32.or",
519 // [WasmOpcode_i32_xor] = "i32.xor",
520 // [WasmOpcode_i32_shl] = "i32.shl",
521 // [WasmOpcode_i32_shr_s] = "i32.shr_s",
522 // [WasmOpcode_i32_shr_u] = "i32.shr_u",
523 // [WasmOpcode_i32_rotl] = "i32.rotl",
524 // [WasmOpcode_i32_rotr] = "i32.rotr",
525 //
526 // [WasmOpcode_i64_clz] = "i64.clz",
527 // [WasmOpcode_i64_ctz] = "i64.ctz",
528 // [WasmOpcode_i64_popcnt] = "i64.popcnt",
529 // [WasmOpcode_i64_add] = "i64.add",
530 // [WasmOpcode_i64_sub] = "i64.sub",
531 // [WasmOpcode_i64_mul] = "i64.mul",
532 // [WasmOpcode_i64_div_s] = "i64.div_s",
533 // [WasmOpcode_i64_div_u] = "i64.div_u",
534 // [WasmOpcode_i64_rem_s] = "i64.rem_s",
535 // [WasmOpcode_i64_rem_u] = "i64.rem_u",
536 // [WasmOpcode_i64_and] = "i64.and",
537 // [WasmOpcode_i64_or] = "i64.or",
538 // [WasmOpcode_i64_xor] = "i64.xor",
539 // [WasmOpcode_i64_shl] = "i64.shl",
540 // [WasmOpcode_i64_shr_s] = "i64.shr_s",
541 // [WasmOpcode_i64_shr_u] = "i64.shr_u",
542 // [WasmOpcode_i64_rotl] = "i64.rotl",
543 // [WasmOpcode_i64_rotr] = "i64.rotr",
544 //
545 // [WasmOpcode_f32_abs] = "f32.abs",
546 // [WasmOpcode_f32_neg] = "f32.neg",
547 // [WasmOpcode_f32_ceil] = "f32.ceil",
548 // [WasmOpcode_f32_floor] = "f32.floor",
549 // [WasmOpcode_f32_trunc] = "f32.trunc",
550 // [WasmOpcode_f32_nearest] = "f32.nearest",
551 // [WasmOpcode_f32_sqrt] = "f32.sqrt",
552 // [WasmOpcode_f32_add] = "f32.add",
553 // [WasmOpcode_f32_sub] = "f32.sub",
554 // [WasmOpcode_f32_mul] = "f32.mul",
555 // [WasmOpcode_f32_div] = "f32.div",
556 // [WasmOpcode_f32_min] = "f32.min",
557 // [WasmOpcode_f32_max] = "f32.max",
558 // [WasmOpcode_f32_copysign] = "f32.copysign",
559 //
560 // [WasmOpcode_f64_abs] = "f64.abs",
561 // [WasmOpcode_f64_neg] = "f64.neg",
562 // [WasmOpcode_f64_ceil] = "f64.ceil",
563 // [WasmOpcode_f64_floor] = "f64.floor",
564 // [WasmOpcode_f64_trunc] = "f64.trunc",
565 // [WasmOpcode_f64_nearest] = "f64.nearest",
566 // [WasmOpcode_f64_sqrt] = "f64.sqrt",
567 // [WasmOpcode_f64_add] = "f64.add",
568 // [WasmOpcode_f64_sub] = "f64.sub",
569 // [WasmOpcode_f64_mul] = "f64.mul",
570 // [WasmOpcode_f64_div] = "f64.div",
571 // [WasmOpcode_f64_min] = "f64.min",
572 // [WasmOpcode_f64_max] = "f64.max",
573 // [WasmOpcode_f64_copysign] = "f64.copysign",
574 //
575 // [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64",
576 // [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s",
577 // [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u",
578 // [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s",
579 // [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u",
580 // [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s",
581 // [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u",
582 // [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s",
583 // [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u",
584 // [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s",
585 // [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u",
586 // [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s",
587 // [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u",
588 // [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s",
589 // [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u",
590 // [WasmOpcode_f32_demote_f64] = "f32.demote_f64",
591 // [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s",
592 // [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u",
593 // [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s",
594 // [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u",
595 // [WasmOpcode_f64_promote_f32] = "f64.promote_f32",
596 // [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32",
597 // [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64",
598 // [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32",
599 // [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64",
600 //
601 // [WasmOpcode_i32_extend8_s] = "i32.extend8_s",
602 // [WasmOpcode_i32_extend16_s] = "i32.extend16_s",
603 // [WasmOpcode_i64_extend8_s] = "i64.extend8_s",
604 // [WasmOpcode_i64_extend16_s] = "i64.extend16_s",
605 // [WasmOpcode_i64_extend32_s] = "i64.extend32_s",
606 //
607 // [WasmOpcode_prefixed] = "prefixed",
608 //};
609 uint8_t opcode = InputStream_readByte(&in);
610 //FuncGen_indent(&fg, out);
611 //fprintf(out, "// %2u: ", fg.stack_i);
612 //if (mnemonics[opcode])
613 // fprintf(out, "%s\n", mnemonics[opcode]);
614 //else
615 // fprintf(out, "%02hhX\n", opcode);
616 //fflush(out); // DEBUG
617 switch (opcode) {
618 case WasmOpcode_unreachable:
619 if (unreachable_depth == 0) {
620 FuncGen_indent(&fg, out);
621 fprintf(out, "abort();\n");
622 unreachable_depth += 1;
623 }
624 break;
625 case WasmOpcode_nop:
626 break;
627 case WasmOpcode_block:
628 case WasmOpcode_loop:
629 case WasmOpcode_if: {
630 int64_t block_type = InputStream_readLeb128_i64(&in);
631 if (unreachable_depth == 0) {
632 const struct FuncType *func_type = FuncType_blockType(types, block_type);
633 for (uint32_t param_i = func_type->param->len; param_i > 0; ) {
634 param_i -= 1;
635 FuncGen_indent(&fg, out);
636 param_stash[param_i] =
637 FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]);
638 fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
639 }
640 for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
641 result_i -= 1;
642 FuncGen_indent(&fg, out);
643 (void)FuncGen_localDeclare(&fg, out,
644 func_type->result->types[result_i]);
645 fputs(";\n", out);
646 }
647 FuncGen_blockBegin(&fg, out, opcode, block_type);
648 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
649 FuncGen_stackPush(&fg, out, func_type->param->types[param_i]);
650 fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]);
651 }
652 } else unreachable_depth += 1;
653 break;
654 }
655 case WasmOpcode_else:
656 case WasmOpcode_end:
657 if (unreachable_depth <= 1) {
658 const struct ResultType *result_type =
659 FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
660 uint32_t label = FuncGen_blockLabel(&fg, 0);
661 if (unreachable_depth == 0) {
662 const struct ResultType *result_type =
663 FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
664 for (uint32_t result_i = result_type->len; result_i > 0; ) {
665 result_i -= 1;
666 FuncGen_indent(&fg, out);
667 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
668 label - result_type->len + result_i, FuncGen_stackPop(&fg));
669 }
670 } else unreachable_depth -= 1;
671 switch (opcode) {
672 case WasmOpcode_else:
673 FuncGen_outdent(&fg, out);
674 fputs("} else {\n", out);
675 break;
676 case WasmOpcode_end:
677 FuncGen_blockEnd(&fg, out);
678 for (uint32_t result_i = 0; result_i < result_type->len;
679 result_i += 1) {
680 FuncGen_stackPush(&fg, out, result_type->types[result_i]);
681 fprintf(out, "l%" PRIu32 ";\n",
682 label - result_type->len + result_i);
683 }
684 break;
685 }
686 } else if (opcode == WasmOpcode_end) unreachable_depth -= 1;
687 break;
688 case WasmOpcode_br:
689 case WasmOpcode_br_if: {
690 uint32_t label_idx = InputStream_readLeb128_u32(&in);
691 if (unreachable_depth == 0) {
692 enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx);
693 const struct FuncType *func_type =
694 FuncType_blockType(types, FuncGen_blockType(&fg, label_idx));
695 uint32_t label = FuncGen_blockLabel(&fg, label_idx);
696
697 FuncGen_indent(&fg, out);
698 if (opcode == WasmOpcode_br_if)
699 fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(&fg));
700 fputs("{\n", out);
701 const struct ResultType *label_type;
702 uint32_t lhs;
703 switch (kind) {
704 case WasmOpcode_loop:
705 label_type = func_type->param;
706 lhs = label - func_type->result->len - func_type->param->len;
707 break;
708 default:
709 label_type = func_type->result;
710 lhs = label - func_type->result->len;
711 break;
712 }
713 for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) {
714 uint32_t rhs;
715 switch (opcode) {
716 case WasmOpcode_br:
717 rhs = FuncGen_stackPop(&fg);
718 break;
719 case WasmOpcode_br_if:
720 rhs = FuncGen_stackAt(&fg, stack_i);
721 break;
722 default: panic("unexpected opcode");
723 }
724 FuncGen_cont(&fg, out);
725 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs);
726 lhs += 1;
727 }
728 FuncGen_cont(&fg, out);
729 fprintf(out, "goto l%" PRIu32 ";\n", label);
730 FuncGen_indent(&fg, out);
731 fprintf(out, "}\n");
732 if (opcode == WasmOpcode_br) unreachable_depth += 1;
733 }
734 break;
735 }
736 case WasmOpcode_br_table: {
737 if (unreachable_depth == 0) {
738 FuncGen_indent(&fg, out);
739 fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
740 }
741 uint32_t label_len = InputStream_readLeb128_u32(&in);
742 for (uint32_t i = 0; i < label_len; i += 1) {
743 uint32_t label = InputStream_readLeb128_u32(&in);
744 if (unreachable_depth == 0) {
745 FuncGen_indent(&fg, out);
746 fprintf(out, "case %u: goto l%" PRIu32 ";\n",
747 i, FuncGen_blockLabel(&fg, label));
748 }
749 }
750 uint32_t label = InputStream_readLeb128_u32(&in);
751 if (unreachable_depth == 0) {
752 FuncGen_indent(&fg, out);
753 fprintf(out, "default: goto l%" PRIu32 ";\n",
754 FuncGen_blockLabel(&fg, label));
755 FuncGen_indent(&fg, out);
756 fputs("}\n", out);
757 unreachable_depth += 1;
758 }
759 break;
760 }
761 case WasmOpcode_return:
762 if (unreachable_depth == 0) {
763 FuncGen_indent(&fg, out);
764 fputs("return", out);
765 switch (func_type->result->len) {
766 case 0: break;
767 case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break;
768 default: panic("multiple function returns not supported");
769 }
770 fputs(";\n", out);
771 unreachable_depth += 1;
772 }
773 break;
774 case WasmOpcode_call:
775 case WasmOpcode_call_indirect: {
776 uint32_t func_id;
777 uint32_t type_idx;
778 uint32_t table_idx;
779 switch (opcode) {
780 case WasmOpcode_call:
781 func_id = InputStream_readLeb128_u32(&in);
782 if (func_id < imports_len)
783 type_idx = imports[func_id].type_idx;
784 else
785 type_idx = funcs[func_id - imports_len].type_idx;
786 break;
787 case WasmOpcode_call_indirect:
788 type_idx = InputStream_readLeb128_u32(&in);
789 table_idx = InputStream_readLeb128_u32(&in);
790 func_id = FuncGen_stackPop(&fg);
791 break;
792 }
793 if (unreachable_depth == 0) {
794 const struct FuncType *callee_func_type = &types[type_idx];
795 for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) {
796 param_i -= 1;
797 param_stash[param_i] = FuncGen_stackPop(&fg);
798 }
799 switch (callee_func_type->result->len) {
800 case 0: FuncGen_indent(&fg, out); break;
801 case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break;
802 default: panic("multiple function returns not supported");
803 }
804 switch (opcode) {
805 case WasmOpcode_call:
806 if (func_id < imports_len)
807 fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
808 else
809 fprintf(out, "f%" PRIu32, func_id - imports_len);
810 break;
811 case WasmOpcode_call_indirect:
812 fputs("(*(", out);
813 switch (callee_func_type->result->len) {
814 case 0: fputs("void", out); break;
815 case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break;
816 default: panic("multiple function returns not supported");
817 }
818 fputs(" (*)(", out);
819 if (callee_func_type->param->len == 0) fputs("void", out);
820 for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) {
821 if (param_i > 0) fputs(", ", out);
822 fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out);
823 }
824 fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id);
825 break;
826 }
827 fputc('(', out);
828 for (uint32_t param_i = 0; param_i < callee_func_type->param->len;
829 param_i += 1) {
830 if (param_i > 0) fputs(", ", out);
831 fprintf(out, "l%" PRIu32, param_stash[param_i]);
832 }
833 fputs(");\n", out);
834 }
835 break;
836 }
837
838 case WasmOpcode_drop:
839 if (unreachable_depth == 0) {
840 FuncGen_indent(&fg, out);
841 fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
842 }
843 break;
844 case WasmOpcode_select:
845 if (unreachable_depth == 0) {
846 uint32_t cond = FuncGen_stackPop(&fg);
847 uint32_t rhs = FuncGen_stackPop(&fg);
848 uint32_t lhs = FuncGen_stackPop(&fg);
849 FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, lhs));
850 fprintf(out, "l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
851 cond, lhs, rhs);
852 }
853 break;
854
855 case WasmOpcode_local_get: {
856 uint32_t local_idx = InputStream_readLeb128_u32(&in);
857 if (unreachable_depth == 0) {
858 if (local_idx < func_type->param->len) param_used[local_idx] = true;
859 FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx));
860 fprintf(out, "l%" PRIu32 ";\n", local_idx);
861 }
862 break;
863 }
864 case WasmOpcode_local_set: {
865 uint32_t local_idx = InputStream_readLeb128_u32(&in);
866 if (unreachable_depth == 0) {
867 if (local_idx < func_type->param->len) param_used[local_idx] = true;
868 FuncGen_indent(&fg, out);
869 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
870 local_idx, FuncGen_stackPop(&fg));
871 }
872 break;
873 }
874 case WasmOpcode_local_tee: {
875 uint32_t local_idx = InputStream_readLeb128_u32(&in);
876 if (unreachable_depth == 0) {
877 if (local_idx < func_type->param->len) param_used[local_idx] = true;
878 FuncGen_indent(&fg, out);
879 fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
880 local_idx, FuncGen_stackAt(&fg, 0));
881 }
882 break;
883 }
884
885 case WasmOpcode_global_get: {
886 uint32_t global_idx = InputStream_readLeb128_u32(&in);
887 if (unreachable_depth == 0) {
888 FuncGen_stackPush(&fg, out, globals[global_idx].val_type);
889 fprintf(out, "g%" PRIu32 ";\n", global_idx);
890 }
891 break;
892 }
893 case WasmOpcode_global_set: {
894 uint32_t global_idx = InputStream_readLeb128_u32(&in);
895 if (unreachable_depth == 0) {
896 FuncGen_indent(&fg, out);
897 fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n",
898 global_idx, FuncGen_stackPop(&fg));
899 }
900 break;
901 }
902
903 case WasmOpcode_table_get:
904 case WasmOpcode_table_set:
905 (void)InputStream_readLeb128_u32(&in);
906 if (unreachable_depth == 0) panic("unimplemented opcode");
907 break;
908
909 case WasmOpcode_i32_load: {
910 uint32_t align = InputStream_readLeb128_u32(&in);
911 uint32_t offset = InputStream_readLeb128_u32(&in);
912 if (unreachable_depth == 0) {
913 uint32_t base = FuncGen_stackPop(&fg);
914 FuncGen_stackPush(&fg, out, WasmValType_i32);
915 if (align < 2 || isBigEndian) {
916 fseek(out, -1, SEEK_CUR);
917 fputc('\n', out);
918 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
919 if (byte_i > 0) fputs(" |\n", out);
920 FuncGen_cont(&fg, out);
921 fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
922 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
923 }
924 } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32
925 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
926 fputs(";\n", out);
927 }
928 break;
929 }
930 case WasmOpcode_i64_load: {
931 uint32_t align = InputStream_readLeb128_u32(&in);
932 uint32_t offset = InputStream_readLeb128_u32(&in);
933 if (unreachable_depth == 0) {
934 uint32_t base = FuncGen_stackPop(&fg);
935 FuncGen_stackPush(&fg, out, WasmValType_i64);
936 if (align < 3 || isBigEndian) {
937 fseek(out, -1, SEEK_CUR);
938 fputc('\n', out);
939 for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
940 if (byte_i > 0) fputs(" |\n", out);
941 FuncGen_cont(&fg, out);
942 fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
943 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
944 }
945 } else fprintf(out, "*(const uint64_t *)&m%" PRIu32 "[l%" PRIu32
946 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
947 fputs(";\n", out);
948 }
949 break;
950 }
951 case WasmOpcode_f32_load: {
952 uint32_t align = InputStream_readLeb128_u32(&in);
953 uint32_t offset = InputStream_readLeb128_u32(&in);
954 if (unreachable_depth == 0) {
955 uint32_t base = FuncGen_stackPop(&fg);
956 FuncGen_stackPush(&fg, out, WasmValType_f32);
957 if (align < 2 || isBigEndian) {
958 fputs("f32_reinterpret_i32(\n", out);
959 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
960 if (byte_i > 0) fputs(" |\n", out);
961 FuncGen_cont(&fg, out);
962 fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
963 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
964 }
965 fputc(')', out);
966 } else fprintf(out, "*(const float *)&m%" PRIu32 "[l%" PRIu32
967 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
968 fputs(";\n", out);
969 }
970 break;
971 }
972 case WasmOpcode_f64_load: {
973 uint32_t align = InputStream_readLeb128_u32(&in);
974 uint32_t offset = InputStream_readLeb128_u32(&in);
975 if (unreachable_depth == 0) {
976 uint32_t base = FuncGen_stackPop(&fg);
977 FuncGen_stackPush(&fg, out, WasmValType_f64);
978 if (align < 3 || isBigEndian) {
979 fputs("f64_reinterpret_i64(\n", out);
980 for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
981 if (byte_i > 0) fputs(" |\n", out);
982 FuncGen_cont(&fg, out);
983 fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
984 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
985 }
986 fputc(')', out);
987 } else fprintf(out, "*(const double *)&m%" PRIu32 "[l%" PRIu32
988 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
989 fputs(";\n", out);
990 }
991 break;
992 }
993 case WasmOpcode_i32_load8_s: {
994 (void)InputStream_readLeb128_u32(&in);
995 uint32_t offset = InputStream_readLeb128_u32(&in);
996 if (unreachable_depth == 0) {
997 uint32_t base = FuncGen_stackPop(&fg);
998 FuncGen_stackPush(&fg, out, WasmValType_i32);
999 fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1000 0, base, offset);
1001 }
1002 break;
1003 }
1004 case WasmOpcode_i32_load8_u: {
1005 (void)InputStream_readLeb128_u32(&in);
1006 uint32_t offset = InputStream_readLeb128_u32(&in);
1007 if (unreachable_depth == 0) {
1008 uint32_t base = FuncGen_stackPop(&fg);
1009 FuncGen_stackPush(&fg, out, WasmValType_i32);
1010 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1011 0, base, offset);
1012 }
1013 break;
1014 }
1015 case WasmOpcode_i32_load16_s: {
1016 uint32_t align = InputStream_readLeb128_u32(&in);
1017 uint32_t offset = InputStream_readLeb128_u32(&in);
1018 if (unreachable_depth == 0) {
1019 uint32_t base = FuncGen_stackPop(&fg);
1020 FuncGen_stackPush(&fg, out, WasmValType_i32);
1021 if (align < 1 || isBigEndian) {
1022 fputs("(int16_t)(\n", out);
1023 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1024 if (byte_i > 0) fputs(" |\n", out);
1025 FuncGen_cont(&fg, out);
1026 fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1027 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1028 }
1029 fputc(')', out);
1030 } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32
1031 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1032 fputs(";\n", out);
1033 }
1034 break;
1035 }
1036 case WasmOpcode_i32_load16_u: {
1037 uint32_t align = InputStream_readLeb128_u32(&in);
1038 uint32_t offset = InputStream_readLeb128_u32(&in);
1039 if (unreachable_depth == 0) {
1040 uint32_t base = FuncGen_stackPop(&fg);
1041 FuncGen_stackPush(&fg, out, WasmValType_i32);
1042 if (align < 1 || isBigEndian) {
1043 fseek(out, -1, SEEK_CUR);
1044 fputc('\n', out);
1045 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1046 if (byte_i > 0) fputs(" |\n", out);
1047 FuncGen_cont(&fg, out);
1048 fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1049 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1050 }
1051 } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32
1052 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1053 fputs(";\n", out);
1054 }
1055 break;
1056 }
1057 case WasmOpcode_i64_load8_s: {
1058 (void)InputStream_readLeb128_u32(&in);
1059 uint32_t offset = InputStream_readLeb128_u32(&in);
1060 if (unreachable_depth == 0) {
1061 uint32_t base = FuncGen_stackPop(&fg);
1062 FuncGen_stackPush(&fg, out, WasmValType_i64);
1063 fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1064 0, base, offset);
1065 }
1066 break;
1067 }
1068 case WasmOpcode_i64_load8_u: {
1069 (void)InputStream_readLeb128_u32(&in);
1070 uint32_t offset = InputStream_readLeb128_u32(&in);
1071 if (unreachable_depth == 0) {
1072 uint32_t base = FuncGen_stackPop(&fg);
1073 FuncGen_stackPush(&fg, out, WasmValType_i64);
1074 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
1075 0, base, offset);
1076 }
1077 break;
1078 }
1079 case WasmOpcode_i64_load16_s: {
1080 uint32_t align = InputStream_readLeb128_u32(&in);
1081 uint32_t offset = InputStream_readLeb128_u32(&in);
1082 if (unreachable_depth == 0) {
1083 uint32_t base = FuncGen_stackPop(&fg);
1084 FuncGen_stackPush(&fg, out, WasmValType_i64);
1085 if (align < 1 || isBigEndian) {
1086 fputs("(int16_t)(\n", out);
1087 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1088 if (byte_i > 0) fputs(" |\n", out);
1089 FuncGen_cont(&fg, out);
1090 fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1091 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1092 }
1093 fputc(')', out);
1094 } else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32
1095 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1096 fputs(";\n", out);
1097 }
1098 break;
1099 }
1100 case WasmOpcode_i64_load16_u: {
1101 uint32_t align = InputStream_readLeb128_u32(&in);
1102 uint32_t offset = InputStream_readLeb128_u32(&in);
1103 if (unreachable_depth == 0) {
1104 uint32_t base = FuncGen_stackPop(&fg);
1105 FuncGen_stackPush(&fg, out, WasmValType_i64);
1106 if (align < 1 || isBigEndian) {
1107 fseek(out, -1, SEEK_CUR);
1108 fputc('\n', out);
1109 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1110 if (byte_i > 0) fputs(" |\n", out);
1111 FuncGen_cont(&fg, out);
1112 fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1113 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1114 }
1115 } else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32
1116 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1117 fputs(";\n", out);
1118 }
1119 break;
1120 }
1121 case WasmOpcode_i64_load32_s: {
1122 uint32_t align = InputStream_readLeb128_u32(&in);
1123 uint32_t offset = InputStream_readLeb128_u32(&in);
1124 if (unreachable_depth == 0) {
1125 uint32_t base = FuncGen_stackPop(&fg);
1126 FuncGen_stackPush(&fg, out, WasmValType_i64);
1127 if (align < 2 || isBigEndian) {
1128 fputs("(int32_t)(\n", out);
1129 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
1130 if (byte_i > 0) fputs(" |\n", out);
1131 FuncGen_cont(&fg, out);
1132 fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1133 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1134 }
1135 fputc(')', out);
1136 } else fprintf(out, "*(const int32_t *)&m%" PRIu32 "[l%" PRIu32
1137 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1138 fputs(";\n", out);
1139 }
1140 break;
1141 }
1142 case WasmOpcode_i64_load32_u: {
1143 uint32_t align = InputStream_readLeb128_u32(&in);
1144 uint32_t offset = InputStream_readLeb128_u32(&in);
1145 if (unreachable_depth == 0) {
1146 uint32_t base = FuncGen_stackPop(&fg);
1147 FuncGen_stackPush(&fg, out, WasmValType_i64);
1148 if (align < 2 || isBigEndian) {
1149 fseek(out, -1, SEEK_CUR);
1150 fputc('\n', out);
1151 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
1152 if (byte_i > 0) fputs(" |\n", out);
1153 FuncGen_cont(&fg, out);
1154 fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
1155 PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
1156 }
1157 } else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32
1158 " + UINT32_C(%" PRIu32 ")]", 0, base, offset);
1159 fputs(";\n", out);
1160 }
1161 break;
1162 }
1163
1164 case WasmOpcode_i32_store: {
1165 uint32_t align = InputStream_readLeb128_u32(&in);
1166 uint32_t offset = InputStream_readLeb128_u32(&in);
1167 if (unreachable_depth == 0) {
1168 uint32_t value = FuncGen_stackPop(&fg);
1169 uint32_t base = FuncGen_stackPop(&fg);
1170 if (align < 2 || isBigEndian) {
1171 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
1172 FuncGen_indent(&fg, out);
1173 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1174 "(uint8_t)(l%" PRIu32 " >> %2u);\n",
1175 0, base, offset + byte_i, value, byte_i << 3);
1176 }
1177 } else {
1178 FuncGen_indent(&fg, out);
1179 fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32
1180 " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
1181 0, base, offset, value);
1182 }
1183 }
1184 break;
1185 }
1186 case WasmOpcode_i64_store: {
1187 uint32_t align = InputStream_readLeb128_u32(&in);
1188 uint32_t offset = InputStream_readLeb128_u32(&in);
1189 if (unreachable_depth == 0) {
1190 uint32_t value = FuncGen_stackPop(&fg);
1191 uint32_t base = FuncGen_stackPop(&fg);
1192 if (align < 3 || isBigEndian) {
1193 for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
1194 FuncGen_indent(&fg, out);
1195 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1196 "(uint8_t)(l%" PRIu32 " >> %2u);\n",
1197 0, base, offset + byte_i, value, byte_i << 3);
1198 }
1199 } else {
1200 FuncGen_indent(&fg, out);
1201 fprintf(out, "*(uint64_t *)&m%" PRIu32 "[l%" PRIu32
1202 " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
1203 0, base, offset, value);
1204 }
1205 }
1206 break;
1207 }
1208 case WasmOpcode_f32_store: {
1209 uint32_t align = InputStream_readLeb128_u32(&in);
1210 uint32_t offset = InputStream_readLeb128_u32(&in);
1211 if (unreachable_depth == 0) {
1212 uint32_t value = FuncGen_stackPop(&fg);
1213 uint32_t base = FuncGen_stackPop(&fg);
1214 if (align < 2 || isBigEndian) {
1215 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
1216 FuncGen_indent(&fg, out);
1217 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1218 "(uint8_t)(i32_reinterpret_f32(l%" PRIu32 ") >> %2u);\n",
1219 0, base, offset + byte_i, value, byte_i << 3);
1220 }
1221 } else {
1222 FuncGen_indent(&fg, out);
1223 fprintf(out, "*(float *)&m%" PRIu32 "[l%" PRIu32
1224 " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
1225 0, base, offset, value);
1226 }
1227 }
1228 break;
1229 }
1230 case WasmOpcode_f64_store: {
1231 uint32_t align = InputStream_readLeb128_u32(&in);
1232 uint32_t offset = InputStream_readLeb128_u32(&in);
1233 if (unreachable_depth == 0) {
1234 uint32_t value = FuncGen_stackPop(&fg);
1235 uint32_t base = FuncGen_stackPop(&fg);
1236 if (align < 3 || isBigEndian) {
1237 for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
1238 FuncGen_indent(&fg, out);
1239 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1240 "(uint8_t)(i64_reinterpret_f64(l%" PRIu32 ") >> %2u);\n",
1241 0, base, offset + byte_i, value, byte_i << 3);
1242 }
1243 } else {
1244 FuncGen_indent(&fg, out);
1245 fprintf(out, "*(double *)&m%" PRIu32 "[l%" PRIu32
1246 " + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
1247 0, base, offset, value);
1248 }
1249 }
1250 break;
1251 }
1252 case WasmOpcode_i32_store8: {
1253 (void)InputStream_readLeb128_u32(&in);
1254 uint32_t offset = InputStream_readLeb128_u32(&in);
1255 if (unreachable_depth == 0) {
1256 uint32_t value = FuncGen_stackPop(&fg);
1257 uint32_t base = FuncGen_stackPop(&fg);
1258 FuncGen_indent(&fg, out);
1259 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
1260 ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
1261 }
1262 break;
1263 }
1264 case WasmOpcode_i32_store16: {
1265 uint32_t align = InputStream_readLeb128_u32(&in);
1266 uint32_t offset = InputStream_readLeb128_u32(&in);
1267 if (unreachable_depth == 0) {
1268 uint32_t value = FuncGen_stackPop(&fg);
1269 uint32_t base = FuncGen_stackPop(&fg);
1270 if (align < 1 || isBigEndian) {
1271 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1272 FuncGen_indent(&fg, out);
1273 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1274 "(uint8_t)(l%" PRIu32 " >> %2u);\n",
1275 0, base, offset + byte_i, value, byte_i << 3);
1276 }
1277 } else {
1278 FuncGen_indent(&fg, out);
1279 fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32
1280 " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n",
1281 0, base, offset, value);
1282 }
1283 }
1284 break;
1285 }
1286 case WasmOpcode_i64_store8: {
1287 (void)InputStream_readLeb128_u32(&in);
1288 uint32_t offset = InputStream_readLeb128_u32(&in);
1289 if (unreachable_depth == 0) {
1290 uint32_t value = FuncGen_stackPop(&fg);
1291 uint32_t base = FuncGen_stackPop(&fg);
1292 FuncGen_indent(&fg, out);
1293 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
1294 ")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
1295 }
1296 break;
1297 }
1298 case WasmOpcode_i64_store16: {
1299 uint32_t align = InputStream_readLeb128_u32(&in);
1300 uint32_t offset = InputStream_readLeb128_u32(&in);
1301 if (unreachable_depth == 0) {
1302 uint32_t value = FuncGen_stackPop(&fg);
1303 uint32_t base = FuncGen_stackPop(&fg);
1304 if (align < 1 || isBigEndian) {
1305 for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
1306 FuncGen_indent(&fg, out);
1307 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1308 "(uint8_t)(l%" PRIu32 " >> %2u);\n",
1309 0, base, offset + byte_i, value, byte_i << 3);
1310 }
1311 } else {
1312 FuncGen_indent(&fg, out);
1313 fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32
1314 " + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n",
1315 0, base, offset, value);
1316 }
1317 }
1318 break;
1319 }
1320 case WasmOpcode_i64_store32: {
1321 uint32_t align = InputStream_readLeb128_u32(&in);
1322 uint32_t offset = InputStream_readLeb128_u32(&in);
1323 if (unreachable_depth == 0) {
1324 uint32_t value = FuncGen_stackPop(&fg);
1325 uint32_t base = FuncGen_stackPop(&fg);
1326 if (align < 2 || isBigEndian) {
1327 for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
1328 FuncGen_indent(&fg, out);
1329 fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
1330 "(uint8_t)(l%" PRIu32 " >> %2u);\n",
1331 0, base, offset + byte_i, value, byte_i << 3);
1332 }
1333 } else {
1334 FuncGen_indent(&fg, out);
1335 fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32
1336 " + UINT32_C(%" PRIu32 ")] = (uint32_t)l%" PRIu32 ";\n",
1337 0, base, offset, value);
1338 }
1339 }
1340 break;
1341 }
1342
1343 case WasmOpcode_memory_size: {
1344 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
1345 if (unreachable_depth == 0) {
1346 FuncGen_stackPush(&fg, out, WasmValType_i32);
1347 fprintf(out, "p%" PRIu32 ";\n", mem_idx);
1348 }
1349 break;
1350 }
1351 case WasmOpcode_memory_grow: {
1352 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
1353 if (unreachable_depth == 0) {
1354 uint32_t pages = FuncGen_stackPop(&fg);
1355 FuncGen_stackPush(&fg, out, WasmValType_i32);
1356 fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", l%" PRIu32 ");\n",
1357 mem_idx, mem_idx, pages);
1358 }
1359 break;
1360 }
1361
1362 case WasmOpcode_i32_const: {
1363 uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in);
1364 if (unreachable_depth == 0) {
1365 FuncGen_stackPush(&fg, out, WasmValType_i32);
1366 fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value);
1367 }
1368 break;
1369 }
1370 case WasmOpcode_i64_const: {
1371 uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in);
1372 if (unreachable_depth == 0) {
1373 FuncGen_stackPush(&fg, out, WasmValType_i64);
1374 fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value);
1375 }
1376 break;
1377 }
1378 case WasmOpcode_f32_const: {
1379 uint32_t value = InputStream_readLittle_u32(&in);
1380 if (unreachable_depth == 0) {
1381 FuncGen_stackPush(&fg, out, WasmValType_f32);
1382 fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value);
1383 }
1384 break;
1385 }
1386 case WasmOpcode_f64_const: {
1387 uint64_t value = InputStream_readLittle_u64(&in);
1388 if (unreachable_depth == 0) {
1389 FuncGen_stackPush(&fg, out, WasmValType_f64);
1390 fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value);
1391 }
1392 break;
1393 }
1394
1395 case WasmOpcode_i32_eqz:
1396 if (unreachable_depth == 0) {
1397 uint32_t lhs = FuncGen_stackPop(&fg);
1398 FuncGen_stackPush(&fg, out, WasmValType_i32);
1399 fprintf(out, "!l%" PRIu32 ";\n", lhs);
1400 }
1401 break;
1402 case WasmOpcode_i32_eq:
1403 if (unreachable_depth == 0) {
1404 uint32_t rhs = FuncGen_stackPop(&fg);
1405 uint32_t lhs = FuncGen_stackPop(&fg);
1406 FuncGen_stackPush(&fg, out, WasmValType_i32);
1407 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1408 }
1409 break;
1410 case WasmOpcode_i32_ne:
1411 if (unreachable_depth == 0) {
1412 uint32_t rhs = FuncGen_stackPop(&fg);
1413 uint32_t lhs = FuncGen_stackPop(&fg);
1414 FuncGen_stackPush(&fg, out, WasmValType_i32);
1415 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1416 }
1417 break;
1418 case WasmOpcode_i32_lt_s:
1419 if (unreachable_depth == 0) {
1420 uint32_t rhs = FuncGen_stackPop(&fg);
1421 uint32_t lhs = FuncGen_stackPop(&fg);
1422 FuncGen_stackPush(&fg, out, WasmValType_i32);
1423 fprintf(out, "(int32_t)l%" PRIu32 " < (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1424 }
1425 break;
1426 case WasmOpcode_i32_lt_u:
1427 if (unreachable_depth == 0) {
1428 uint32_t rhs = FuncGen_stackPop(&fg);
1429 uint32_t lhs = FuncGen_stackPop(&fg);
1430 FuncGen_stackPush(&fg, out, WasmValType_i32);
1431 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1432 }
1433 break;
1434 case WasmOpcode_i32_gt_s:
1435 if (unreachable_depth == 0) {
1436 uint32_t rhs = FuncGen_stackPop(&fg);
1437 uint32_t lhs = FuncGen_stackPop(&fg);
1438 FuncGen_stackPush(&fg, out, WasmValType_i32);
1439 fprintf(out, "(int32_t)l%" PRIu32 " > (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1440 }
1441 break;
1442 case WasmOpcode_i32_gt_u:
1443 if (unreachable_depth == 0) {
1444 uint32_t rhs = FuncGen_stackPop(&fg);
1445 uint32_t lhs = FuncGen_stackPop(&fg);
1446 FuncGen_stackPush(&fg, out, WasmValType_i32);
1447 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1448 }
1449 break;
1450 case WasmOpcode_i32_le_s:
1451 if (unreachable_depth == 0) {
1452 uint32_t rhs = FuncGen_stackPop(&fg);
1453 uint32_t lhs = FuncGen_stackPop(&fg);
1454 FuncGen_stackPush(&fg, out, WasmValType_i32);
1455 fprintf(out, "(int32_t)l%" PRIu32 " <= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1456 }
1457 break;
1458 case WasmOpcode_i32_le_u:
1459 if (unreachable_depth == 0) {
1460 uint32_t rhs = FuncGen_stackPop(&fg);
1461 uint32_t lhs = FuncGen_stackPop(&fg);
1462 FuncGen_stackPush(&fg, out, WasmValType_i32);
1463 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1464 }
1465 break;
1466 case WasmOpcode_i32_ge_s:
1467 if (unreachable_depth == 0) {
1468 uint32_t rhs = FuncGen_stackPop(&fg);
1469 uint32_t lhs = FuncGen_stackPop(&fg);
1470 FuncGen_stackPush(&fg, out, WasmValType_i32);
1471 fprintf(out, "(int32_t)l%" PRIu32 " >= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1472 }
1473 break;
1474 case WasmOpcode_i32_ge_u:
1475 if (unreachable_depth == 0) {
1476 uint32_t rhs = FuncGen_stackPop(&fg);
1477 uint32_t lhs = FuncGen_stackPop(&fg);
1478 FuncGen_stackPush(&fg, out, WasmValType_i32);
1479 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1480 }
1481 break;
1482
1483 case WasmOpcode_i64_eqz:
1484 if (unreachable_depth == 0) {
1485 uint32_t lhs = FuncGen_stackPop(&fg);
1486 FuncGen_stackPush(&fg, out, WasmValType_i32);
1487 fprintf(out, "!l%" PRIu32 ";\n", lhs);
1488 }
1489 break;
1490 case WasmOpcode_i64_eq:
1491 if (unreachable_depth == 0) {
1492 uint32_t rhs = FuncGen_stackPop(&fg);
1493 uint32_t lhs = FuncGen_stackPop(&fg);
1494 FuncGen_stackPush(&fg, out, WasmValType_i32);
1495 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1496 }
1497 break;
1498 case WasmOpcode_i64_ne:
1499 if (unreachable_depth == 0) {
1500 uint32_t rhs = FuncGen_stackPop(&fg);
1501 uint32_t lhs = FuncGen_stackPop(&fg);
1502 FuncGen_stackPush(&fg, out, WasmValType_i32);
1503 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1504 }
1505 break;
1506 case WasmOpcode_i64_lt_s:
1507 if (unreachable_depth == 0) {
1508 uint32_t rhs = FuncGen_stackPop(&fg);
1509 uint32_t lhs = FuncGen_stackPop(&fg);
1510 FuncGen_stackPush(&fg, out, WasmValType_i32);
1511 fprintf(out, "(int64_t)l%" PRIu32 " < (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1512 }
1513 break;
1514 case WasmOpcode_i64_lt_u:
1515 if (unreachable_depth == 0) {
1516 uint32_t rhs = FuncGen_stackPop(&fg);
1517 uint32_t lhs = FuncGen_stackPop(&fg);
1518 FuncGen_stackPush(&fg, out, WasmValType_i32);
1519 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1520 }
1521 break;
1522 case WasmOpcode_i64_gt_s:
1523 if (unreachable_depth == 0) {
1524 uint32_t rhs = FuncGen_stackPop(&fg);
1525 uint32_t lhs = FuncGen_stackPop(&fg);
1526 FuncGen_stackPush(&fg, out, WasmValType_i32);
1527 fprintf(out, "(int64_t)l%" PRIu32 " > (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1528 }
1529 break;
1530 case WasmOpcode_i64_gt_u:
1531 if (unreachable_depth == 0) {
1532 uint32_t rhs = FuncGen_stackPop(&fg);
1533 uint32_t lhs = FuncGen_stackPop(&fg);
1534 FuncGen_stackPush(&fg, out, WasmValType_i32);
1535 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1536 }
1537 break;
1538 case WasmOpcode_i64_le_s:
1539 if (unreachable_depth == 0) {
1540 uint32_t rhs = FuncGen_stackPop(&fg);
1541 uint32_t lhs = FuncGen_stackPop(&fg);
1542 FuncGen_stackPush(&fg, out, WasmValType_i32);
1543 fprintf(out, "(int64_t)l%" PRIu32 " <= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1544 }
1545 break;
1546 case WasmOpcode_i64_le_u:
1547 if (unreachable_depth == 0) {
1548 uint32_t rhs = FuncGen_stackPop(&fg);
1549 uint32_t lhs = FuncGen_stackPop(&fg);
1550 FuncGen_stackPush(&fg, out, WasmValType_i32);
1551 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1552 }
1553 break;
1554 case WasmOpcode_i64_ge_s:
1555 if (unreachable_depth == 0) {
1556 uint32_t rhs = FuncGen_stackPop(&fg);
1557 uint32_t lhs = FuncGen_stackPop(&fg);
1558 FuncGen_stackPush(&fg, out, WasmValType_i32);
1559 fprintf(out, "(int64_t)l%" PRIu32 " >= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1560 }
1561 break;
1562 case WasmOpcode_i64_ge_u:
1563 if (unreachable_depth == 0) {
1564 uint32_t rhs = FuncGen_stackPop(&fg);
1565 uint32_t lhs = FuncGen_stackPop(&fg);
1566 FuncGen_stackPush(&fg, out, WasmValType_i32);
1567 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1568 }
1569 break;
1570
1571 case WasmOpcode_f32_eq:
1572 if (unreachable_depth == 0) {
1573 uint32_t rhs = FuncGen_stackPop(&fg);
1574 uint32_t lhs = FuncGen_stackPop(&fg);
1575 FuncGen_stackPush(&fg, out, WasmValType_i32);
1576 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1577 }
1578 break;
1579 case WasmOpcode_f32_ne:
1580 if (unreachable_depth == 0) {
1581 uint32_t rhs = FuncGen_stackPop(&fg);
1582 uint32_t lhs = FuncGen_stackPop(&fg);
1583 FuncGen_stackPush(&fg, out, WasmValType_i32);
1584 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1585 }
1586 break;
1587 case WasmOpcode_f32_lt:
1588 if (unreachable_depth == 0) {
1589 uint32_t rhs = FuncGen_stackPop(&fg);
1590 uint32_t lhs = FuncGen_stackPop(&fg);
1591 FuncGen_stackPush(&fg, out, WasmValType_i32);
1592 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1593 }
1594 break;
1595 case WasmOpcode_f32_gt:
1596 if (unreachable_depth == 0) {
1597 uint32_t rhs = FuncGen_stackPop(&fg);
1598 uint32_t lhs = FuncGen_stackPop(&fg);
1599 FuncGen_stackPush(&fg, out, WasmValType_i32);
1600 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1601 }
1602 break;
1603 case WasmOpcode_f32_le:
1604 if (unreachable_depth == 0) {
1605 uint32_t rhs = FuncGen_stackPop(&fg);
1606 uint32_t lhs = FuncGen_stackPop(&fg);
1607 FuncGen_stackPush(&fg, out, WasmValType_i32);
1608 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1609 }
1610 break;
1611 case WasmOpcode_f32_ge:
1612 if (unreachable_depth == 0) {
1613 uint32_t rhs = FuncGen_stackPop(&fg);
1614 uint32_t lhs = FuncGen_stackPop(&fg);
1615 FuncGen_stackPush(&fg, out, WasmValType_i32);
1616 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1617 }
1618 break;
1619
1620 case WasmOpcode_f64_eq:
1621 if (unreachable_depth == 0) {
1622 uint32_t rhs = FuncGen_stackPop(&fg);
1623 uint32_t lhs = FuncGen_stackPop(&fg);
1624 FuncGen_stackPush(&fg, out, WasmValType_i32);
1625 fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
1626 }
1627 break;
1628 case WasmOpcode_f64_ne:
1629 if (unreachable_depth == 0) {
1630 uint32_t rhs = FuncGen_stackPop(&fg);
1631 uint32_t lhs = FuncGen_stackPop(&fg);
1632 FuncGen_stackPush(&fg, out, WasmValType_i32);
1633 fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
1634 }
1635 break;
1636 case WasmOpcode_f64_lt:
1637 if (unreachable_depth == 0) {
1638 uint32_t rhs = FuncGen_stackPop(&fg);
1639 uint32_t lhs = FuncGen_stackPop(&fg);
1640 FuncGen_stackPush(&fg, out, WasmValType_i32);
1641 fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
1642 }
1643 break;
1644 case WasmOpcode_f64_gt:
1645 if (unreachable_depth == 0) {
1646 uint32_t rhs = FuncGen_stackPop(&fg);
1647 uint32_t lhs = FuncGen_stackPop(&fg);
1648 FuncGen_stackPush(&fg, out, WasmValType_i32);
1649 fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
1650 }
1651 break;
1652 case WasmOpcode_f64_le:
1653 if (unreachable_depth == 0) {
1654 uint32_t rhs = FuncGen_stackPop(&fg);
1655 uint32_t lhs = FuncGen_stackPop(&fg);
1656 FuncGen_stackPush(&fg, out, WasmValType_i32);
1657 fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
1658 }
1659 break;
1660 case WasmOpcode_f64_ge:
1661 if (unreachable_depth == 0) {
1662 uint32_t rhs = FuncGen_stackPop(&fg);
1663 uint32_t lhs = FuncGen_stackPop(&fg);
1664 FuncGen_stackPush(&fg, out, WasmValType_i32);
1665 fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
1666 }
1667 break;
1668
1669 case WasmOpcode_i32_clz:
1670 if (unreachable_depth == 0) {
1671 uint32_t lhs = FuncGen_stackPop(&fg);
1672 FuncGen_stackPush(&fg, out, WasmValType_i32);
1673 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clz(l%" PRIu32 ") : 32;\n",
1674 lhs, lhs);
1675 }
1676 break;
1677 case WasmOpcode_i32_ctz:
1678 if (unreachable_depth == 0) {
1679 uint32_t lhs = FuncGen_stackPop(&fg);
1680 FuncGen_stackPush(&fg, out, WasmValType_i32);
1681 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctz(l%" PRIu32 ") : 32;\n",
1682 lhs, lhs);
1683 }
1684 break;
1685 case WasmOpcode_i32_popcnt:
1686 if (unreachable_depth == 0) {
1687 uint32_t lhs = FuncGen_stackPop(&fg);
1688 FuncGen_stackPush(&fg, out, WasmValType_i32);
1689 fprintf(out, "__builtin_popcount(l%" PRIu32 ");\n", lhs);
1690 }
1691 break;
1692 case WasmOpcode_i32_add:
1693 if (unreachable_depth == 0) {
1694 uint32_t rhs = FuncGen_stackPop(&fg);
1695 uint32_t lhs = FuncGen_stackPop(&fg);
1696 FuncGen_stackPush(&fg, out, WasmValType_i32);
1697 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
1698 }
1699 break;
1700 case WasmOpcode_i32_sub:
1701 if (unreachable_depth == 0) {
1702 uint32_t rhs = FuncGen_stackPop(&fg);
1703 uint32_t lhs = FuncGen_stackPop(&fg);
1704 FuncGen_stackPush(&fg, out, WasmValType_i32);
1705 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
1706 }
1707 break;
1708 case WasmOpcode_i32_mul:
1709 if (unreachable_depth == 0) {
1710 uint32_t rhs = FuncGen_stackPop(&fg);
1711 uint32_t lhs = FuncGen_stackPop(&fg);
1712 FuncGen_stackPush(&fg, out, WasmValType_i32);
1713 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
1714 }
1715 break;
1716 case WasmOpcode_i32_div_s:
1717 if (unreachable_depth == 0) {
1718 uint32_t rhs = FuncGen_stackPop(&fg);
1719 uint32_t lhs = FuncGen_stackPop(&fg);
1720 FuncGen_stackPush(&fg, out, WasmValType_i32);
1721 fprintf(out, "(int32_t)l%" PRIu32 " / (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1722 }
1723 break;
1724 case WasmOpcode_i32_div_u:
1725 if (unreachable_depth == 0) {
1726 uint32_t rhs = FuncGen_stackPop(&fg);
1727 uint32_t lhs = FuncGen_stackPop(&fg);
1728 FuncGen_stackPush(&fg, out, WasmValType_i32);
1729 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
1730 }
1731 break;
1732 case WasmOpcode_i32_rem_s:
1733 if (unreachable_depth == 0) {
1734 uint32_t rhs = FuncGen_stackPop(&fg);
1735 uint32_t lhs = FuncGen_stackPop(&fg);
1736 FuncGen_stackPush(&fg, out, WasmValType_i32);
1737 fprintf(out, "(int32_t)l%" PRIu32 " %% (int32_t)l%" PRIu32 ";\n", lhs, rhs);
1738 }
1739 break;
1740 case WasmOpcode_i32_rem_u:
1741 if (unreachable_depth == 0) {
1742 uint32_t rhs = FuncGen_stackPop(&fg);
1743 uint32_t lhs = FuncGen_stackPop(&fg);
1744 FuncGen_stackPush(&fg, out, WasmValType_i32);
1745 fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
1746 }
1747 break;
1748 case WasmOpcode_i32_and:
1749 if (unreachable_depth == 0) {
1750 uint32_t rhs = FuncGen_stackPop(&fg);
1751 uint32_t lhs = FuncGen_stackPop(&fg);
1752 FuncGen_stackPush(&fg, out, WasmValType_i32);
1753 fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
1754 }
1755 break;
1756 case WasmOpcode_i32_or:
1757 if (unreachable_depth == 0) {
1758 uint32_t rhs = FuncGen_stackPop(&fg);
1759 uint32_t lhs = FuncGen_stackPop(&fg);
1760 FuncGen_stackPush(&fg, out, WasmValType_i32);
1761 fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
1762 }
1763 break;
1764 case WasmOpcode_i32_xor:
1765 if (unreachable_depth == 0) {
1766 uint32_t rhs = FuncGen_stackPop(&fg);
1767 uint32_t lhs = FuncGen_stackPop(&fg);
1768 FuncGen_stackPush(&fg, out, WasmValType_i32);
1769 fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
1770 }
1771 break;
1772 case WasmOpcode_i32_shl:
1773 if (unreachable_depth == 0) {
1774 uint32_t rhs = FuncGen_stackPop(&fg);
1775 uint32_t lhs = FuncGen_stackPop(&fg);
1776 FuncGen_stackPush(&fg, out, WasmValType_i32);
1777 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1778 }
1779 break;
1780 case WasmOpcode_i32_shr_s:
1781 if (unreachable_depth == 0) {
1782 uint32_t rhs = FuncGen_stackPop(&fg);
1783 uint32_t lhs = FuncGen_stackPop(&fg);
1784 FuncGen_stackPush(&fg, out, WasmValType_i32);
1785 fprintf(out, "(int32_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1786 }
1787 break;
1788 case WasmOpcode_i32_shr_u:
1789 if (unreachable_depth == 0) {
1790 uint32_t rhs = FuncGen_stackPop(&fg);
1791 uint32_t lhs = FuncGen_stackPop(&fg);
1792 FuncGen_stackPush(&fg, out, WasmValType_i32);
1793 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
1794 }
1795 break;
1796 case WasmOpcode_i32_rotl:
1797 if (unreachable_depth == 0) {
1798 uint32_t rhs = FuncGen_stackPop(&fg);
1799 uint32_t lhs = FuncGen_stackPop(&fg);
1800 FuncGen_stackPush(&fg, out, WasmValType_i32);
1801 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F) | "
1802 "l%" PRIu32 " >> (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
1803 }
1804 break;
1805 case WasmOpcode_i32_rotr:
1806 if (unreachable_depth == 0) {
1807 uint32_t rhs = FuncGen_stackPop(&fg);
1808 uint32_t lhs = FuncGen_stackPop(&fg);
1809 FuncGen_stackPush(&fg, out, WasmValType_i32);
1810 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F) | "
1811 "l%" PRIu32 " << (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
1812 }
1813 break;
1814
1815 case WasmOpcode_i64_clz:
1816 if (unreachable_depth == 0) {
1817 uint32_t lhs = FuncGen_stackPop(&fg);
1818 FuncGen_stackPush(&fg, out, WasmValType_i64);
1819 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clzll(l%" PRIu32 ") : 64;\n",
1820 lhs, lhs);
1821 }
1822 break;
1823 case WasmOpcode_i64_ctz:
1824 if (unreachable_depth == 0) {
1825 uint32_t lhs = FuncGen_stackPop(&fg);
1826 FuncGen_stackPush(&fg, out, WasmValType_i64);
1827 fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctzll(l%" PRIu32 ") : 64;\n",
1828 lhs, lhs);
1829 }
1830 break;
1831 case WasmOpcode_i64_popcnt:
1832 if (unreachable_depth == 0) {
1833 uint32_t lhs = FuncGen_stackPop(&fg);
1834 FuncGen_stackPush(&fg, out, WasmValType_i64);
1835 fprintf(out, "__builtin_popcountll(l%" PRIu32 ");\n", lhs);
1836 }
1837 break;
1838 case WasmOpcode_i64_add:
1839 if (unreachable_depth == 0) {
1840 uint32_t rhs = FuncGen_stackPop(&fg);
1841 uint32_t lhs = FuncGen_stackPop(&fg);
1842 FuncGen_stackPush(&fg, out, WasmValType_i64);
1843 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
1844 }
1845 break;
1846 case WasmOpcode_i64_sub:
1847 if (unreachable_depth == 0) {
1848 uint32_t rhs = FuncGen_stackPop(&fg);
1849 uint32_t lhs = FuncGen_stackPop(&fg);
1850 FuncGen_stackPush(&fg, out, WasmValType_i64);
1851 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
1852 }
1853 break;
1854 case WasmOpcode_i64_mul:
1855 if (unreachable_depth == 0) {
1856 uint32_t rhs = FuncGen_stackPop(&fg);
1857 uint32_t lhs = FuncGen_stackPop(&fg);
1858 FuncGen_stackPush(&fg, out, WasmValType_i64);
1859 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
1860 }
1861 break;
1862 case WasmOpcode_i64_div_s:
1863 if (unreachable_depth == 0) {
1864 uint32_t rhs = FuncGen_stackPop(&fg);
1865 uint32_t lhs = FuncGen_stackPop(&fg);
1866 FuncGen_stackPush(&fg, out, WasmValType_i64);
1867 fprintf(out, "(int64_t)l%" PRIu32 " / (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1868 }
1869 break;
1870 case WasmOpcode_i64_div_u:
1871 if (unreachable_depth == 0) {
1872 uint32_t rhs = FuncGen_stackPop(&fg);
1873 uint32_t lhs = FuncGen_stackPop(&fg);
1874 FuncGen_stackPush(&fg, out, WasmValType_i64);
1875 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
1876 }
1877 break;
1878 case WasmOpcode_i64_rem_s:
1879 if (unreachable_depth == 0) {
1880 uint32_t rhs = FuncGen_stackPop(&fg);
1881 uint32_t lhs = FuncGen_stackPop(&fg);
1882 FuncGen_stackPush(&fg, out, WasmValType_i64);
1883 fprintf(out, "(int64_t)l%" PRIu32 " %% (int64_t)l%" PRIu32 ";\n", lhs, rhs);
1884 }
1885 break;
1886 case WasmOpcode_i64_rem_u:
1887 if (unreachable_depth == 0) {
1888 uint32_t rhs = FuncGen_stackPop(&fg);
1889 uint32_t lhs = FuncGen_stackPop(&fg);
1890 FuncGen_stackPush(&fg, out, WasmValType_i64);
1891 fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
1892 }
1893 break;
1894 case WasmOpcode_i64_and:
1895 if (unreachable_depth == 0) {
1896 uint32_t rhs = FuncGen_stackPop(&fg);
1897 uint32_t lhs = FuncGen_stackPop(&fg);
1898 FuncGen_stackPush(&fg, out, WasmValType_i64);
1899 fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
1900 }
1901 break;
1902 case WasmOpcode_i64_or:
1903 if (unreachable_depth == 0) {
1904 uint32_t rhs = FuncGen_stackPop(&fg);
1905 uint32_t lhs = FuncGen_stackPop(&fg);
1906 FuncGen_stackPush(&fg, out, WasmValType_i64);
1907 fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
1908 }
1909 break;
1910 case WasmOpcode_i64_xor:
1911 if (unreachable_depth == 0) {
1912 uint32_t rhs = FuncGen_stackPop(&fg);
1913 uint32_t lhs = FuncGen_stackPop(&fg);
1914 FuncGen_stackPush(&fg, out, WasmValType_i64);
1915 fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
1916 }
1917 break;
1918 case WasmOpcode_i64_shl:
1919 if (unreachable_depth == 0) {
1920 uint32_t rhs = FuncGen_stackPop(&fg);
1921 uint32_t lhs = FuncGen_stackPop(&fg);
1922 FuncGen_stackPush(&fg, out, WasmValType_i64);
1923 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1924 }
1925 break;
1926 case WasmOpcode_i64_shr_s:
1927 if (unreachable_depth == 0) {
1928 uint32_t rhs = FuncGen_stackPop(&fg);
1929 uint32_t lhs = FuncGen_stackPop(&fg);
1930 FuncGen_stackPush(&fg, out, WasmValType_i64);
1931 fprintf(out, "(int64_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1932 }
1933 break;
1934 case WasmOpcode_i64_shr_u:
1935 if (unreachable_depth == 0) {
1936 uint32_t rhs = FuncGen_stackPop(&fg);
1937 uint32_t lhs = FuncGen_stackPop(&fg);
1938 FuncGen_stackPush(&fg, out, WasmValType_i64);
1939 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
1940 }
1941 break;
1942 case WasmOpcode_i64_rotl:
1943 if (unreachable_depth == 0) {
1944 uint32_t rhs = FuncGen_stackPop(&fg);
1945 uint32_t lhs = FuncGen_stackPop(&fg);
1946 FuncGen_stackPush(&fg, out, WasmValType_i64);
1947 fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F) | "
1948 "l%" PRIu32 " >> (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
1949 }
1950 break;
1951 case WasmOpcode_i64_rotr:
1952 if (unreachable_depth == 0) {
1953 uint32_t rhs = FuncGen_stackPop(&fg);
1954 uint32_t lhs = FuncGen_stackPop(&fg);
1955 FuncGen_stackPush(&fg, out, WasmValType_i64);
1956 fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F) | "
1957 "l%" PRIu32 " << (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
1958 }
1959 break;
1960
1961 case WasmOpcode_f32_abs:
1962 if (unreachable_depth == 0) {
1963 uint32_t lhs = FuncGen_stackPop(&fg);
1964 FuncGen_stackPush(&fg, out, WasmValType_f32);
1965 fprintf(out, "fabsf(l%" PRIu32 ");\n", lhs);
1966 }
1967 break;
1968 case WasmOpcode_f32_neg:
1969 if (unreachable_depth == 0) {
1970 uint32_t lhs = FuncGen_stackPop(&fg);
1971 FuncGen_stackPush(&fg, out, WasmValType_f32);
1972 fprintf(out, "-l%" PRIu32 ";\n", lhs);
1973 }
1974 break;
1975 case WasmOpcode_f32_ceil:
1976 if (unreachable_depth == 0) {
1977 uint32_t lhs = FuncGen_stackPop(&fg);
1978 FuncGen_stackPush(&fg, out, WasmValType_f32);
1979 fprintf(out, "ceilf(l%" PRIu32 ");\n", lhs);
1980 }
1981 break;
1982 case WasmOpcode_f32_floor:
1983 if (unreachable_depth == 0) {
1984 uint32_t lhs = FuncGen_stackPop(&fg);
1985 FuncGen_stackPush(&fg, out, WasmValType_f32);
1986 fprintf(out, "floorf(l%" PRIu32 ");\n", lhs);
1987 }
1988 break;
1989 case WasmOpcode_f32_trunc:
1990 if (unreachable_depth == 0) {
1991 uint32_t lhs = FuncGen_stackPop(&fg);
1992 FuncGen_stackPush(&fg, out, WasmValType_f32);
1993 fprintf(out, "truncf(l%" PRIu32 ");\n", lhs);
1994 }
1995 break;
1996 case WasmOpcode_f32_nearest:
1997 if (unreachable_depth == 0) {
1998 uint32_t lhs = FuncGen_stackPop(&fg);
1999 FuncGen_stackPush(&fg, out, WasmValType_f32);
2000 fprintf(out, "roundf(l%" PRIu32 ");\n", lhs);
2001 }
2002 break;
2003 case WasmOpcode_f32_sqrt:
2004 if (unreachable_depth == 0) {
2005 uint32_t lhs = FuncGen_stackPop(&fg);
2006 FuncGen_stackPush(&fg, out, WasmValType_f32);
2007 fprintf(out, "sqrtf(l%" PRIu32 ");\n", lhs);
2008 }
2009 break;
2010 case WasmOpcode_f32_add:
2011 if (unreachable_depth == 0) {
2012 uint32_t rhs = FuncGen_stackPop(&fg);
2013 uint32_t lhs = FuncGen_stackPop(&fg);
2014 FuncGen_stackPush(&fg, out, WasmValType_f32);
2015 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
2016 }
2017 break;
2018 case WasmOpcode_f32_sub:
2019 if (unreachable_depth == 0) {
2020 uint32_t rhs = FuncGen_stackPop(&fg);
2021 uint32_t lhs = FuncGen_stackPop(&fg);
2022 FuncGen_stackPush(&fg, out, WasmValType_f32);
2023 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
2024 }
2025 break;
2026 case WasmOpcode_f32_mul:
2027 if (unreachable_depth == 0) {
2028 uint32_t rhs = FuncGen_stackPop(&fg);
2029 uint32_t lhs = FuncGen_stackPop(&fg);
2030 FuncGen_stackPush(&fg, out, WasmValType_f32);
2031 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
2032 }
2033 break;
2034 case WasmOpcode_f32_div:
2035 if (unreachable_depth == 0) {
2036 uint32_t rhs = FuncGen_stackPop(&fg);
2037 uint32_t lhs = FuncGen_stackPop(&fg);
2038 FuncGen_stackPush(&fg, out, WasmValType_f32);
2039 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
2040 }
2041 break;
2042 case WasmOpcode_f32_min:
2043 if (unreachable_depth == 0) {
2044 uint32_t rhs = FuncGen_stackPop(&fg);
2045 uint32_t lhs = FuncGen_stackPop(&fg);
2046 FuncGen_stackPush(&fg, out, WasmValType_f32);
2047 fprintf(out, "fminf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2048 }
2049 break;
2050 case WasmOpcode_f32_max:
2051 if (unreachable_depth == 0) {
2052 uint32_t rhs = FuncGen_stackPop(&fg);
2053 uint32_t lhs = FuncGen_stackPop(&fg);
2054 FuncGen_stackPush(&fg, out, WasmValType_f32);
2055 fprintf(out, "fmaxf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2056 }
2057 break;
2058 case WasmOpcode_f32_copysign:
2059 if (unreachable_depth == 0) {
2060 uint32_t rhs = FuncGen_stackPop(&fg);
2061 uint32_t lhs = FuncGen_stackPop(&fg);
2062 FuncGen_stackPush(&fg, out, WasmValType_f32);
2063 fprintf(out, "copysignf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2064 }
2065 break;
2066
2067 case WasmOpcode_f64_abs:
2068 if (unreachable_depth == 0) {
2069 uint32_t lhs = FuncGen_stackPop(&fg);
2070 FuncGen_stackPush(&fg, out, WasmValType_f64);
2071 fprintf(out, "fabs(l%" PRIu32 ");\n", lhs);
2072 }
2073 break;
2074 case WasmOpcode_f64_neg:
2075 if (unreachable_depth == 0) {
2076 uint32_t lhs = FuncGen_stackPop(&fg);
2077 FuncGen_stackPush(&fg, out, WasmValType_f64);
2078 fprintf(out, "-l%" PRIu32 ";\n", lhs);
2079 }
2080 break;
2081 case WasmOpcode_f64_ceil:
2082 if (unreachable_depth == 0) {
2083 uint32_t lhs = FuncGen_stackPop(&fg);
2084 FuncGen_stackPush(&fg, out, WasmValType_f64);
2085 fprintf(out, "ceil(l%" PRIu32 ");\n", lhs);
2086 }
2087 break;
2088 case WasmOpcode_f64_floor:
2089 if (unreachable_depth == 0) {
2090 uint32_t lhs = FuncGen_stackPop(&fg);
2091 FuncGen_stackPush(&fg, out, WasmValType_f64);
2092 fprintf(out, "floor(l%" PRIu32 ");\n", lhs);
2093 }
2094 break;
2095 case WasmOpcode_f64_trunc:
2096 if (unreachable_depth == 0) {
2097 uint32_t lhs = FuncGen_stackPop(&fg);
2098 FuncGen_stackPush(&fg, out, WasmValType_f64);
2099 fprintf(out, "trunc(l%" PRIu32 ");\n", lhs);
2100 }
2101 break;
2102 case WasmOpcode_f64_nearest:
2103 if (unreachable_depth == 0) {
2104 uint32_t lhs = FuncGen_stackPop(&fg);
2105 FuncGen_stackPush(&fg, out, WasmValType_f64);
2106 fprintf(out, "round(l%" PRIu32 ");\n", lhs);
2107 }
2108 break;
2109 case WasmOpcode_f64_sqrt:
2110 if (unreachable_depth == 0) {
2111 uint32_t lhs = FuncGen_stackPop(&fg);
2112 FuncGen_stackPush(&fg, out, WasmValType_f64);
2113 fprintf(out, "sqrt(l%" PRIu32 ");\n", lhs);
2114 }
2115 break;
2116 case WasmOpcode_f64_add:
2117 if (unreachable_depth == 0) {
2118 uint32_t rhs = FuncGen_stackPop(&fg);
2119 uint32_t lhs = FuncGen_stackPop(&fg);
2120 FuncGen_stackPush(&fg, out, WasmValType_f64);
2121 fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
2122 }
2123 break;
2124 case WasmOpcode_f64_sub:
2125 if (unreachable_depth == 0) {
2126 uint32_t rhs = FuncGen_stackPop(&fg);
2127 uint32_t lhs = FuncGen_stackPop(&fg);
2128 FuncGen_stackPush(&fg, out, WasmValType_f64);
2129 fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
2130 }
2131 break;
2132 case WasmOpcode_f64_mul:
2133 if (unreachable_depth == 0) {
2134 uint32_t rhs = FuncGen_stackPop(&fg);
2135 uint32_t lhs = FuncGen_stackPop(&fg);
2136 FuncGen_stackPush(&fg, out, WasmValType_f64);
2137 fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
2138 }
2139 break;
2140 case WasmOpcode_f64_div:
2141 if (unreachable_depth == 0) {
2142 uint32_t rhs = FuncGen_stackPop(&fg);
2143 uint32_t lhs = FuncGen_stackPop(&fg);
2144 FuncGen_stackPush(&fg, out, WasmValType_f64);
2145 fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
2146 }
2147 break;
2148 case WasmOpcode_f64_min:
2149 if (unreachable_depth == 0) {
2150 uint32_t rhs = FuncGen_stackPop(&fg);
2151 uint32_t lhs = FuncGen_stackPop(&fg);
2152 FuncGen_stackPush(&fg, out, WasmValType_f64);
2153 fprintf(out, "fmin(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2154 }
2155 break;
2156 case WasmOpcode_f64_max:
2157 if (unreachable_depth == 0) {
2158 uint32_t rhs = FuncGen_stackPop(&fg);
2159 uint32_t lhs = FuncGen_stackPop(&fg);
2160 FuncGen_stackPush(&fg, out, WasmValType_f64);
2161 fprintf(out, "fmax(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2162 }
2163 break;
2164 case WasmOpcode_f64_copysign:
2165 if (unreachable_depth == 0) {
2166 uint32_t rhs = FuncGen_stackPop(&fg);
2167 uint32_t lhs = FuncGen_stackPop(&fg);
2168 FuncGen_stackPush(&fg, out, WasmValType_f64);
2169 fprintf(out, "copysign(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
2170 }
2171 break;
2172
2173 case WasmOpcode_i32_wrap_i64:
2174 if (unreachable_depth == 0) {
2175 uint32_t lhs = FuncGen_stackPop(&fg);
2176 FuncGen_stackPush(&fg, out, WasmValType_i32);
2177 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2178 }
2179 break;
2180 case WasmOpcode_i32_trunc_f32_s:
2181 if (unreachable_depth == 0) {
2182 uint32_t lhs = FuncGen_stackPop(&fg);
2183 FuncGen_stackPush(&fg, out, WasmValType_i32);
2184 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2185 }
2186 break;
2187 case WasmOpcode_i32_trunc_f32_u:
2188 if (unreachable_depth == 0) {
2189 uint32_t lhs = FuncGen_stackPop(&fg);
2190 FuncGen_stackPush(&fg, out, WasmValType_i32);
2191 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2192 }
2193 break;
2194 case WasmOpcode_i32_trunc_f64_s:
2195 if (unreachable_depth == 0) {
2196 uint32_t lhs = FuncGen_stackPop(&fg);
2197 FuncGen_stackPush(&fg, out, WasmValType_i32);
2198 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2199 }
2200 break;
2201 case WasmOpcode_i32_trunc_f64_u:
2202 if (unreachable_depth == 0) {
2203 uint32_t lhs = FuncGen_stackPop(&fg);
2204 FuncGen_stackPush(&fg, out, WasmValType_i32);
2205 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2206 }
2207 break;
2208 case WasmOpcode_i64_extend_i32_s:
2209 if (unreachable_depth == 0) {
2210 uint32_t lhs = FuncGen_stackPop(&fg);
2211 FuncGen_stackPush(&fg, out, WasmValType_i64);
2212 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2213 }
2214 break;
2215 case WasmOpcode_i64_extend_i32_u:
2216 if (unreachable_depth == 0) {
2217 uint32_t lhs = FuncGen_stackPop(&fg);
2218 FuncGen_stackPush(&fg, out, WasmValType_i64);
2219 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2220 }
2221 break;
2222 case WasmOpcode_i64_trunc_f32_s:
2223 if (unreachable_depth == 0) {
2224 uint32_t lhs = FuncGen_stackPop(&fg);
2225 FuncGen_stackPush(&fg, out, WasmValType_i64);
2226 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2227 }
2228 break;
2229 case WasmOpcode_i64_trunc_f32_u:
2230 if (unreachable_depth == 0) {
2231 uint32_t lhs = FuncGen_stackPop(&fg);
2232 FuncGen_stackPush(&fg, out, WasmValType_i64);
2233 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2234 }
2235 break;
2236 case WasmOpcode_i64_trunc_f64_s:
2237 if (unreachable_depth == 0) {
2238 uint32_t lhs = FuncGen_stackPop(&fg);
2239 FuncGen_stackPush(&fg, out, WasmValType_i64);
2240 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2241 }
2242 break;
2243 case WasmOpcode_i64_trunc_f64_u:
2244 if (unreachable_depth == 0) {
2245 uint32_t lhs = FuncGen_stackPop(&fg);
2246 FuncGen_stackPush(&fg, out, WasmValType_i64);
2247 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2248 }
2249 break;
2250 case WasmOpcode_f32_convert_i32_s:
2251 if (unreachable_depth == 0) {
2252 uint32_t lhs = FuncGen_stackPop(&fg);
2253 FuncGen_stackPush(&fg, out, WasmValType_f32);
2254 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2255 }
2256 break;
2257 case WasmOpcode_f32_convert_i32_u:
2258 if (unreachable_depth == 0) {
2259 uint32_t lhs = FuncGen_stackPop(&fg);
2260 FuncGen_stackPush(&fg, out, WasmValType_f32);
2261 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2262 }
2263 break;
2264 case WasmOpcode_f32_convert_i64_s:
2265 if (unreachable_depth == 0) {
2266 uint32_t lhs = FuncGen_stackPop(&fg);
2267 FuncGen_stackPush(&fg, out, WasmValType_f32);
2268 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2269 }
2270 break;
2271 case WasmOpcode_f32_convert_i64_u:
2272 if (unreachable_depth == 0) {
2273 uint32_t lhs = FuncGen_stackPop(&fg);
2274 FuncGen_stackPush(&fg, out, WasmValType_f32);
2275 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2276 }
2277 break;
2278 case WasmOpcode_f32_demote_f64:
2279 if (unreachable_depth == 0) {
2280 uint32_t lhs = FuncGen_stackPop(&fg);
2281 FuncGen_stackPush(&fg, out, WasmValType_f32);
2282 fprintf(out, "(float)l%" PRIu32 ";\n", lhs);
2283 }
2284 break;
2285 case WasmOpcode_f64_convert_i32_s:
2286 if (unreachable_depth == 0) {
2287 uint32_t lhs = FuncGen_stackPop(&fg);
2288 FuncGen_stackPush(&fg, out, WasmValType_f64);
2289 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2290 }
2291 break;
2292 case WasmOpcode_f64_convert_i32_u:
2293 if (unreachable_depth == 0) {
2294 uint32_t lhs = FuncGen_stackPop(&fg);
2295 FuncGen_stackPush(&fg, out, WasmValType_f64);
2296 fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
2297 }
2298 break;
2299 case WasmOpcode_f64_convert_i64_s:
2300 if (unreachable_depth == 0) {
2301 uint32_t lhs = FuncGen_stackPop(&fg);
2302 FuncGen_stackPush(&fg, out, WasmValType_f64);
2303 fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
2304 }
2305 break;
2306 case WasmOpcode_f64_convert_i64_u:
2307 if (unreachable_depth == 0) {
2308 uint32_t lhs = FuncGen_stackPop(&fg);
2309 FuncGen_stackPush(&fg, out, WasmValType_f64);
2310 fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
2311 }
2312 break;
2313 case WasmOpcode_f64_promote_f32:
2314 if (unreachable_depth == 0) {
2315 uint32_t lhs = FuncGen_stackPop(&fg);
2316 FuncGen_stackPush(&fg, out, WasmValType_f64);
2317 fprintf(out, "(double)l%" PRIu32 ";\n", lhs);
2318 }
2319 break;
2320 case WasmOpcode_i32_reinterpret_f32:
2321 if (unreachable_depth == 0) {
2322 uint32_t lhs = FuncGen_stackPop(&fg);
2323 FuncGen_stackPush(&fg, out, WasmValType_i32);
2324 fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs);
2325 }
2326 break;
2327 case WasmOpcode_i64_reinterpret_f64:
2328 if (unreachable_depth == 0) {
2329 uint32_t lhs = FuncGen_stackPop(&fg);
2330 FuncGen_stackPush(&fg, out, WasmValType_i64);
2331 fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs);
2332 }
2333 break;
2334 case WasmOpcode_f32_reinterpret_i32:
2335 if (unreachable_depth == 0) {
2336 uint32_t lhs = FuncGen_stackPop(&fg);
2337 FuncGen_stackPush(&fg, out, WasmValType_f32);
2338 fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs);
2339 }
2340 break;
2341 case WasmOpcode_f64_reinterpret_i64:
2342 if (unreachable_depth == 0) {
2343 uint32_t lhs = FuncGen_stackPop(&fg);
2344 FuncGen_stackPush(&fg, out, WasmValType_f64);
2345 fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs);
2346 }
2347 break;
2348
2349 case WasmOpcode_i32_extend8_s:
2350 if (unreachable_depth == 0) {
2351 uint32_t lhs = FuncGen_stackPop(&fg);
2352 FuncGen_stackPush(&fg, out, WasmValType_i32);
2353 fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
2354 }
2355 break;
2356 case WasmOpcode_i32_extend16_s:
2357 if (unreachable_depth == 0) {
2358 uint32_t lhs = FuncGen_stackPop(&fg);
2359 FuncGen_stackPush(&fg, out, WasmValType_i32);
2360 fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
2361 }
2362 break;
2363 case WasmOpcode_i64_extend8_s:
2364 if (unreachable_depth == 0) {
2365 uint32_t lhs = FuncGen_stackPop(&fg);
2366 FuncGen_stackPush(&fg, out, WasmValType_i64);
2367 fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
2368 }
2369 break;
2370 case WasmOpcode_i64_extend16_s:
2371 if (unreachable_depth == 0) {
2372 uint32_t lhs = FuncGen_stackPop(&fg);
2373 FuncGen_stackPush(&fg, out, WasmValType_i64);
2374 fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
2375 }
2376 break;
2377 case WasmOpcode_i64_extend32_s:
2378 if (unreachable_depth == 0) {
2379 uint32_t lhs = FuncGen_stackPop(&fg);
2380 FuncGen_stackPush(&fg, out, WasmValType_i64);
2381 fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
2382 }
2383 break;
2384
2385 case WasmOpcode_prefixed:
2386 switch (InputStream_readLeb128_u32(&in)) {
2387 case WasmPrefixedOpcode_i32_trunc_sat_f32_s:
2388 case WasmPrefixedOpcode_i32_trunc_sat_f32_u:
2389 case WasmPrefixedOpcode_i32_trunc_sat_f64_s:
2390 case WasmPrefixedOpcode_i32_trunc_sat_f64_u:
2391 case WasmPrefixedOpcode_i64_trunc_sat_f32_s:
2392 case WasmPrefixedOpcode_i64_trunc_sat_f32_u:
2393 case WasmPrefixedOpcode_i64_trunc_sat_f64_s:
2394 case WasmPrefixedOpcode_i64_trunc_sat_f64_u:
2395 if (unreachable_depth == 0) panic("unimplemented opcode");
2396
2397 case WasmPrefixedOpcode_memory_init:
2398 (void)InputStream_readLeb128_u32(&in);
2399 (void)InputStream_readByte(&in);
2400 if (unreachable_depth == 0) panic("unimplemented opcode");
2401
2402 case WasmPrefixedOpcode_data_drop:
2403 (void)InputStream_readLeb128_u32(&in);
2404 if (unreachable_depth == 0) panic("unimplemented opcode");
2405
2406 case WasmPrefixedOpcode_memory_copy: {
2407 uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in);
2408 uint32_t src_mem_idx = InputStream_readLeb128_u32(&in);
2409 if (unreachable_depth == 0) {
2410 uint32_t n = FuncGen_stackPop(&fg);
2411 uint32_t src = FuncGen_stackPop(&fg);
2412 uint32_t dst = FuncGen_stackPop(&fg);
2413 FuncGen_indent(&fg, out);
2414 fprintf(out, "memcpy(&m%" PRIu32 "[l%" PRIu32 "], "
2415 "&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n",
2416 dst_mem_idx, dst, src_mem_idx, src, n);
2417 }
2418 break;
2419 }
2420
2421 case WasmPrefixedOpcode_memory_fill: {
2422 uint32_t mem_idx = InputStream_readLeb128_u32(&in);
2423 if (unreachable_depth == 0) {
2424 uint32_t n = FuncGen_stackPop(&fg);
2425 uint32_t c = FuncGen_stackPop(&fg);
2426 uint32_t s = FuncGen_stackPop(&fg);
2427 FuncGen_indent(&fg, out);
2428 fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], "
2429 "l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n);
2430 }
2431 break;
2432 }
2433
2434 case WasmPrefixedOpcode_table_init:
2435 (void)InputStream_readLeb128_u32(&in);
2436 (void)InputStream_readLeb128_u32(&in);
2437 if (unreachable_depth == 0) panic("unimplemented opcode");
2438
2439 case WasmPrefixedOpcode_elem_drop:
2440 (void)InputStream_readLeb128_u32(&in);
2441 if (unreachable_depth == 0) panic("unimplemented opcode");
2442
2443 case WasmPrefixedOpcode_table_copy:
2444 (void)InputStream_readLeb128_u32(&in);
2445 (void)InputStream_readLeb128_u32(&in);
2446 if (unreachable_depth == 0) panic("unimplemented opcode");
2447
2448 case WasmPrefixedOpcode_table_grow:
2449 (void)InputStream_readLeb128_u32(&in);
2450 if (unreachable_depth == 0) panic("unimplemented opcode");
2451
2452 case WasmPrefixedOpcode_table_size:
2453 (void)InputStream_readLeb128_u32(&in);
2454 if (unreachable_depth == 0) panic("unimplemented opcode");
2455
2456 case WasmPrefixedOpcode_table_fill:
2457 (void)InputStream_readLeb128_u32(&in);
2458 if (unreachable_depth == 0) panic("unimplemented opcode");
2459 }
2460 break;
2461 }
2462 }
2463 for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
2464 if (param_used[param_i]) continue;
2465 FuncGen_indent(&fg, out);
2466 fprintf(out, "(void)l%" PRIu32 ";\n", param_i);
2467 }
2468 switch (func_type->result->len) {
2469 case 0: break;
2470 case 1:
2471 FuncGen_indent(&fg, out);
2472 fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
2473 break;
2474 default: panic("multiple function returns not supported");
2475 }
2476 fputs("}\n\n", out);
2477 }
2478 }
2479
2480 (void)InputStream_skipToSection(&in, WasmSectionId_data);
2481 {
2482 uint32_t len = InputStream_readLeb128_u32(&in);
2483 fputs("static void init_data(void) {\n", out);
2484 for (uint32_t i = 0; i < mems_len; i += 1)
2485 fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n"
2486 " m%" PRIu32 " = calloc(p%" PRIu32 ", UINT32_C(1) << 16);\n",
2487 i, mems[i].limits.min, i, i);
2488 for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
2489 uint32_t mem_idx;
2490 switch (InputStream_readLeb128_u32(&in)) {
2491 case 0:
2492 mem_idx = 0;
2493 break;
2494
2495 case 2:
2496 mem_idx = InputStream_readLeb128_u32(&in);
2497 break;
2498
2499 default: panic("unsupported data kind");
2500 }
2501 uint32_t offset = evalExpr(&in);
2502 uint32_t segment_len = InputStream_readLeb128_u32(&in);
2503 fputc('\n', out);
2504 fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {",
2505 segment_i, segment_len);
2506 for (uint32_t i = 0; i < segment_len; i += 1) {
2507 if (i % 32 == 0) fputs("\n ", out);
2508 fprintf(out, " 0x%02hhX,", InputStream_readByte(&in));
2509 }
2510 fprintf(out, "\n"
2511 " };\n"
2512 " memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n",
2513 mem_idx, offset, segment_i, segment_len);
2514 }
2515 fputs("}\n", out);
2516 }
2517
2518 InputStream_close(&in);
2519 fclose(out);
2520}
stage1/zig1.c deleted-4567
......@@ -1,4567 +0,0 @@
1// TODO get rid of _GNU_SOURCE
2#define _GNU_SOURCE
3#include <assert.h>
4#include <errno.h>
5#include <limits.h>
6#include <math.h>
7#include <stdbool.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <inttypes.h>
13
14#include <fcntl.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <time.h>
18#include <unistd.h>
19
20#ifdef __linux__
21#include <sys/random.h>
22#endif
23
24#include <zstd.h>
25
26#if defined(__APPLE__)
27#define ZIG_TRIPLE_OS "macos"
28#elif defined(_WIN32)
29#define ZIG_TRIPLE_OS "windows"
30#elif defined(__linux__)
31#define ZIG_TRIPLE_OS "linux"
32#elif defined(__FreeBSD__)
33#define ZIG_TRIPLE_OS "freebsd"
34#elif defined(__NetBSD__)
35#define ZIG_TRIPLE_OS "netbsd"
36#elif defined(__DragonFly__)
37#define ZIG_TRIPLE_OS "dragonfly"
38#elif defined(__OpenBSD__)
39#define ZIG_TRIPLE_OS "openbsd"
40#elif defined(__HAIKU__)
41#define ZIG_TRIPLE_OS "haiku"
42#elif defined(__sun)
43#define ZIG_TRIPLE_OS "solaris"
44#else
45#error please add more os definitions above this line
46#endif
47
48#if defined(__x86_64__)
49#define ZIG_TRIPLE_ARCH "x86_64"
50#elif defined(__aarch64__)
51#define ZIG_TRIPLE_ARCH "aarch64"
52#elif defined(__ARM_EABI__)
53#define ZIG_TRIPLE_ARCH "arm"
54#else
55#error please add more arch definitions above this line
56#endif
57
58enum wasi_errno_t {
59 WASI_ESUCCESS = 0,
60 WASI_E2BIG = 1,
61 WASI_EACCES = 2,
62 WASI_EADDRINUSE = 3,
63 WASI_EADDRNOTAVAIL = 4,
64 WASI_EAFNOSUPPORT = 5,
65 WASI_EAGAIN = 6,
66 WASI_EALREADY = 7,
67 WASI_EBADF = 8,
68 WASI_EBADMSG = 9,
69 WASI_EBUSY = 10,
70 WASI_ECANCELED = 11,
71 WASI_ECHILD = 12,
72 WASI_ECONNABORTED = 13,
73 WASI_ECONNREFUSED = 14,
74 WASI_ECONNRESET = 15,
75 WASI_EDEADLK = 16,
76 WASI_EDESTADDRREQ = 17,
77 WASI_EDOM = 18,
78 WASI_EDQUOT = 19,
79 WASI_EEXIST = 20,
80 WASI_EFAULT = 21,
81 WASI_EFBIG = 22,
82 WASI_EHOSTUNREACH = 23,
83 WASI_EIDRM = 24,
84 WASI_EILSEQ = 25,
85 WASI_EINPROGRESS = 26,
86 WASI_EINTR = 27,
87 WASI_EINVAL = 28,
88 WASI_EIO = 29,
89 WASI_EISCONN = 30,
90 WASI_EISDIR = 31,
91 WASI_ELOOP = 32,
92 WASI_EMFILE = 33,
93 WASI_EMLINK = 34,
94 WASI_EMSGSIZE = 35,
95 WASI_EMULTIHOP = 36,
96 WASI_ENAMETOOLONG = 37,
97 WASI_ENETDOWN = 38,
98 WASI_ENETRESET = 39,
99 WASI_ENETUNREACH = 40,
100 WASI_ENFILE = 41,
101 WASI_ENOBUFS = 42,
102 WASI_ENODEV = 43,
103 WASI_ENOENT = 44,
104 WASI_ENOEXEC = 45,
105 WASI_ENOLCK = 46,
106 WASI_ENOLINK = 47,
107 WASI_ENOMEM = 48,
108 WASI_ENOMSG = 49,
109 WASI_ENOPROTOOPT = 50,
110 WASI_ENOSPC = 51,
111 WASI_ENOSYS = 52,
112 WASI_ENOTCONN = 53,
113 WASI_ENOTDIR = 54,
114 WASI_ENOTEMPTY = 55,
115 WASI_ENOTRECOVERABLE = 56,
116 WASI_ENOTSOCK = 57,
117 WASI_EOPNOTSUPP = 58,
118 WASI_ENOTTY = 59,
119 WASI_ENXIO = 60,
120 WASI_EOVERFLOW = 61,
121 WASI_EOWNERDEAD = 62,
122 WASI_EPERM = 63,
123 WASI_EPIPE = 64,
124 WASI_EPROTO = 65,
125 WASI_EPROTONOSUPPORT = 66,
126 WASI_EPROTOTYPE = 67,
127 WASI_ERANGE = 68,
128 WASI_EROFS = 69,
129 WASI_ESPIPE = 70,
130 WASI_ESRCH = 71,
131 WASI_ESTALE = 72,
132 WASI_ETIMEDOUT = 73,
133 WASI_ETXTBSY = 74,
134 WASI_EXDEV = 75,
135 WASI_ENOTCAPABLE = 76,
136};
137
138static void panic(const char *msg) {
139 fprintf(stderr, "%s\n", msg);
140 abort();
141}
142
143static uint32_t min_u32(uint32_t a, uint32_t b) {
144 return (a < b) ? a : b;
145}
146
147static uint32_t rotl32(uint32_t n, unsigned c) {
148 const unsigned mask = CHAR_BIT * sizeof(n) - 1;
149 c &= mask & 31;
150 return (n << c) | (n >> ((-c) & mask));
151}
152
153static uint32_t rotr32(uint32_t n, unsigned c) {
154 const unsigned mask = CHAR_BIT * sizeof(n) - 1;
155 c &= mask & 31;
156 return (n >> c) | (n << ((-c) & mask));
157}
158
159static uint64_t rotl64(uint64_t n, unsigned c) {
160 const unsigned mask = CHAR_BIT * sizeof(n) - 1;
161 c &= mask & 63;
162 return (n << c) | (n >> ((-c) & mask));
163}
164
165static uint64_t rotr64(uint64_t n, unsigned c) {
166 const unsigned mask = CHAR_BIT * sizeof(n) - 1;
167 c &= mask & 63;
168 return (n >> c) | (n << ((-c) & mask));
169}
170
171static void *arena_alloc(size_t n) {
172 void *ptr = malloc(n);
173 if (!ptr) panic("out of memory");
174#ifndef NDEBUG
175 memset(ptr, 0xaa, n); // to match the zig version
176#endif
177 return ptr;
178}
179
180static int err_wrap(const char *prefix, int rc) {
181 if (rc == -1) {
182 perror(prefix);
183 abort();
184 }
185 return rc;
186}
187
188static bool bs_isSet(const uint32_t *bitset, uint32_t index) {
189 return (bitset[index >> 5] >> (index & 0x1f)) & 1;
190}
191static void bs_set(uint32_t *bitset, uint32_t index) {
192 bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f));
193}
194static void bs_unset(uint32_t *bitset, uint32_t index) {
195 bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f));
196}
197static void bs_setValue(uint32_t *bitset, uint32_t index, bool value) {
198 if (value) bs_set(bitset, index); else bs_unset(bitset, index);
199}
200
201struct ByteSlice {
202 char *ptr;
203 size_t len;
204};
205
206static struct ByteSlice read_file_alloc(const char *file_path) {
207 FILE *f = fopen(file_path, "rb");
208 if (!f) {
209 fprintf(stderr, "failed to read %s: ", file_path);
210 perror("");
211 abort();
212 }
213 if (fseek(f, 0L, SEEK_END) == -1) panic("failed to seek");
214 struct ByteSlice res;
215 res.len = ftell(f);
216 res.ptr = malloc(res.len);
217 rewind(f);
218 size_t amt_read = fread(res.ptr, 1, res.len, f);
219 if (amt_read != res.len) panic("short read");
220 fclose(f);
221 return res;
222}
223
224
225struct Preopen {
226 int wasi_fd;
227 int host_fd;
228 const char *name;
229 size_t name_len;
230};
231
232static struct Preopen preopens_buffer[10];
233static size_t preopens_len = 0;
234
235static void add_preopen(int wasi_fd, const char *name, int host_fd) {
236 preopens_buffer[preopens_len].wasi_fd = wasi_fd;
237 preopens_buffer[preopens_len].host_fd = host_fd;
238 preopens_buffer[preopens_len].name = name;
239 preopens_buffer[preopens_len].name_len = strlen(name);
240 preopens_len += 1;
241}
242
243static const struct Preopen *find_preopen(int32_t wasi_fd) {
244 for (size_t i = 0; i < preopens_len; i += 1) {
245 const struct Preopen *preopen = &preopens_buffer[i];
246 if (preopen->wasi_fd == wasi_fd) {
247 return preopen;
248 }
249 }
250 return NULL;
251}
252
253static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB
254
255static uint16_t read_u16_le(const char *ptr) {
256 const uint8_t *u8_ptr = (const uint8_t *)ptr;
257 return
258 (((uint64_t)u8_ptr[0]) << 0x00) |
259 (((uint64_t)u8_ptr[1]) << 0x08);
260}
261
262static uint32_t read_u32_le(const char *ptr) {
263 const uint8_t *u8_ptr = (const uint8_t *)ptr;
264 return
265 (((uint64_t)u8_ptr[0]) << 0x00) |
266 (((uint64_t)u8_ptr[1]) << 0x08) |
267 (((uint64_t)u8_ptr[2]) << 0x10) |
268 (((uint64_t)u8_ptr[3]) << 0x18);
269}
270
271static uint64_t read_u64_le(const char *ptr) {
272 const uint8_t *u8_ptr = (const uint8_t *)ptr;
273 return
274 (((uint64_t)u8_ptr[0]) << 0x00) |
275 (((uint64_t)u8_ptr[1]) << 0x08) |
276 (((uint64_t)u8_ptr[2]) << 0x10) |
277 (((uint64_t)u8_ptr[3]) << 0x18) |
278 (((uint64_t)u8_ptr[4]) << 0x20) |
279 (((uint64_t)u8_ptr[5]) << 0x28) |
280 (((uint64_t)u8_ptr[6]) << 0x30) |
281 (((uint64_t)u8_ptr[7]) << 0x38);
282}
283
284static void write_u16_le(char *ptr, uint16_t x) {
285 uint8_t *u8_ptr = (uint8_t*)ptr;
286 u8_ptr[0] = (x >> 0x00);
287 u8_ptr[1] = (x >> 0x08);
288}
289
290static void write_u32_le(char *ptr, uint32_t x) {
291 uint8_t *u8_ptr = (uint8_t*)ptr;
292 u8_ptr[0] = (x >> 0x00);
293 u8_ptr[1] = (x >> 0x08);
294 u8_ptr[2] = (x >> 0x10);
295 u8_ptr[3] = (x >> 0x18);
296}
297
298static void write_u64_le(char *ptr, uint64_t x) {
299 uint8_t *u8_ptr = (uint8_t*)ptr;
300 u8_ptr[0] = (x >> 0x00);
301 u8_ptr[1] = (x >> 0x08);
302 u8_ptr[2] = (x >> 0x10);
303 u8_ptr[3] = (x >> 0x18);
304 u8_ptr[4] = (x >> 0x20);
305 u8_ptr[5] = (x >> 0x28);
306 u8_ptr[6] = (x >> 0x30);
307 u8_ptr[7] = (x >> 0x38);
308}
309
310static uint32_t read32_uleb128(const char *ptr, uint32_t *i) {
311 uint32_t result = 0;
312 uint32_t shift = 0;
313
314 for (;;) {
315 uint32_t byte = ptr[*i];
316 *i += 1;
317 result |= ((byte & 0x7f) << shift);
318 shift += 7;
319 if ((byte & 0x80) == 0) return result;
320 if (shift >= 32) panic("read32_uleb128 failed");
321 }
322}
323
324static int64_t read64_ileb128(const char *ptr, uint32_t *i) {
325 int64_t result = 0;
326 uint32_t shift = 0;
327
328 for (;;) {
329 uint64_t byte = ptr[*i];
330 *i += 1;
331 result |= ((byte & 0x7f) << shift);
332 shift += 7;
333 if ((byte & 0x80) == 0) {
334 if ((byte & 0x40) && (shift < 64)) {
335 uint64_t extend = 0;
336 result |= (~extend << shift);
337 }
338 return result;
339 }
340 if (shift >= 64) panic("read64_ileb128 failed");
341 }
342}
343
344static int32_t read32_ileb128(const char *ptr, uint32_t *i) {
345 return read64_ileb128(ptr, i);
346}
347
348static struct ByteSlice read_name(char *ptr, uint32_t *i) {
349 uint32_t len = read32_uleb128(ptr, i);
350 struct ByteSlice res;
351 res.ptr = ptr + *i;
352 res.len = len;
353 *i += len;
354 return res;
355}
356
357enum Section {
358 Section_custom,
359 Section_type,
360 Section_import,
361 Section_function,
362 Section_table,
363 Section_memory,
364 Section_global,
365 Section_export,
366 Section_start,
367 Section_element,
368 Section_code,
369 Section_data,
370 Section_data_count,
371};
372
373enum Op {
374 Op_unreachable,
375 Op_br_void,
376 Op_br_32,
377 Op_br_64,
378 Op_br_nez_void,
379 Op_br_nez_32,
380 Op_br_nez_64,
381 Op_br_eqz_void,
382 Op_br_eqz_32,
383 Op_br_eqz_64,
384 Op_br_table_void,
385 Op_br_table_32,
386 Op_br_table_64,
387 Op_return_void,
388 Op_return_32,
389 Op_return_64,
390 Op_call_import,
391 Op_call_func,
392 Op_call_indirect,
393 Op_drop_32,
394 Op_drop_64,
395 Op_select_32,
396 Op_select_64,
397 Op_local_get_32,
398 Op_local_get_64,
399 Op_local_set_32,
400 Op_local_set_64,
401 Op_local_tee_32,
402 Op_local_tee_64,
403 Op_global_get_0_32,
404 Op_global_get_32,
405 Op_global_set_0_32,
406 Op_global_set_32,
407 Op_load_0_8,
408 Op_load_8,
409 Op_load_0_16,
410 Op_load_16,
411 Op_load_0_32,
412 Op_load_32,
413 Op_load_0_64,
414 Op_load_64,
415 Op_store_0_8,
416 Op_store_8,
417 Op_store_0_16,
418 Op_store_16,
419 Op_store_0_32,
420 Op_store_32,
421 Op_store_0_64,
422 Op_store_64,
423 Op_mem_size,
424 Op_mem_grow,
425 Op_const_0_32,
426 Op_const_0_64,
427 Op_const_1_32,
428 Op_const_1_64,
429 Op_const_32,
430 Op_const_64,
431 Op_const_umax_32,
432 Op_const_umax_64,
433 Op_eqz_32,
434 Op_eq_32,
435 Op_ne_32,
436 Op_slt_32,
437 Op_ult_32,
438 Op_sgt_32,
439 Op_ugt_32,
440 Op_sle_32,
441 Op_ule_32,
442 Op_sge_32,
443 Op_uge_32,
444 Op_eqz_64,
445 Op_eq_64,
446 Op_ne_64,
447 Op_slt_64,
448 Op_ult_64,
449 Op_sgt_64,
450 Op_ugt_64,
451 Op_sle_64,
452 Op_ule_64,
453 Op_sge_64,
454 Op_uge_64,
455 Op_feq_32,
456 Op_fne_32,
457 Op_flt_32,
458 Op_fgt_32,
459 Op_fle_32,
460 Op_fge_32,
461 Op_feq_64,
462 Op_fne_64,
463 Op_flt_64,
464 Op_fgt_64,
465 Op_fle_64,
466 Op_fge_64,
467 Op_clz_32,
468 Op_ctz_32,
469 Op_popcnt_32,
470 Op_add_32,
471 Op_sub_32,
472 Op_mul_32,
473 Op_sdiv_32,
474 Op_udiv_32,
475 Op_srem_32,
476 Op_urem_32,
477 Op_and_32,
478 Op_or_32,
479 Op_xor_32,
480 Op_shl_32,
481 Op_ashr_32,
482 Op_lshr_32,
483 Op_rol_32,
484 Op_ror_32,
485 Op_clz_64,
486 Op_ctz_64,
487 Op_popcnt_64,
488 Op_add_64,
489 Op_sub_64,
490 Op_mul_64,
491 Op_sdiv_64,
492 Op_udiv_64,
493 Op_srem_64,
494 Op_urem_64,
495 Op_and_64,
496 Op_or_64,
497 Op_xor_64,
498 Op_shl_64,
499 Op_ashr_64,
500 Op_lshr_64,
501 Op_rol_64,
502 Op_ror_64,
503 Op_fabs_32,
504 Op_fneg_32,
505 Op_ceil_32,
506 Op_floor_32,
507 Op_trunc_32,
508 Op_nearest_32,
509 Op_sqrt_32,
510 Op_fadd_32,
511 Op_fsub_32,
512 Op_fmul_32,
513 Op_fdiv_32,
514 Op_fmin_32,
515 Op_fmax_32,
516 Op_copysign_32,
517 Op_fabs_64,
518 Op_fneg_64,
519 Op_ceil_64,
520 Op_floor_64,
521 Op_trunc_64,
522 Op_nearest_64,
523 Op_sqrt_64,
524 Op_fadd_64,
525 Op_fsub_64,
526 Op_fmul_64,
527 Op_fdiv_64,
528 Op_fmin_64,
529 Op_fmax_64,
530 Op_copysign_64,
531 Op_ftos_32_32,
532 Op_ftou_32_32,
533 Op_ftos_32_64,
534 Op_ftou_32_64,
535 Op_sext_64_32,
536 Op_ftos_64_32,
537 Op_ftou_64_32,
538 Op_ftos_64_64,
539 Op_ftou_64_64,
540 Op_stof_32_32,
541 Op_utof_32_32,
542 Op_stof_32_64,
543 Op_utof_32_64,
544 Op_ftof_32_64,
545 Op_stof_64_32,
546 Op_utof_64_32,
547 Op_stof_64_64,
548 Op_utof_64_64,
549 Op_ftof_64_32,
550 Op_sext8_32,
551 Op_sext16_32,
552 Op_sext8_64,
553 Op_sext16_64,
554 Op_sext32_64,
555 Op_memcpy,
556 Op_memset,
557
558 Op_wrap_32_64 = Op_drop_32,
559 Op_zext_64_32 = Op_const_0_32,
560 Op_last = Op_memset,
561};
562
563enum WasmOp {
564 WasmOp_unreachable = 0x00,
565 WasmOp_nop = 0x01,
566 WasmOp_block = 0x02,
567 WasmOp_loop = 0x03,
568 WasmOp_if = 0x04,
569 WasmOp_else = 0x05,
570 WasmOp_end = 0x0B,
571 WasmOp_br = 0x0C,
572 WasmOp_br_if = 0x0D,
573 WasmOp_br_table = 0x0E,
574 WasmOp_return = 0x0F,
575 WasmOp_call = 0x10,
576 WasmOp_call_indirect = 0x11,
577 WasmOp_drop = 0x1A,
578 WasmOp_select = 0x1B,
579 WasmOp_local_get = 0x20,
580 WasmOp_local_set = 0x21,
581 WasmOp_local_tee = 0x22,
582 WasmOp_global_get = 0x23,
583 WasmOp_global_set = 0x24,
584 WasmOp_i32_load = 0x28,
585 WasmOp_i64_load = 0x29,
586 WasmOp_f32_load = 0x2A,
587 WasmOp_f64_load = 0x2B,
588 WasmOp_i32_load8_s = 0x2C,
589 WasmOp_i32_load8_u = 0x2D,
590 WasmOp_i32_load16_s = 0x2E,
591 WasmOp_i32_load16_u = 0x2F,
592 WasmOp_i64_load8_s = 0x30,
593 WasmOp_i64_load8_u = 0x31,
594 WasmOp_i64_load16_s = 0x32,
595 WasmOp_i64_load16_u = 0x33,
596 WasmOp_i64_load32_s = 0x34,
597 WasmOp_i64_load32_u = 0x35,
598 WasmOp_i32_store = 0x36,
599 WasmOp_i64_store = 0x37,
600 WasmOp_f32_store = 0x38,
601 WasmOp_f64_store = 0x39,
602 WasmOp_i32_store8 = 0x3A,
603 WasmOp_i32_store16 = 0x3B,
604 WasmOp_i64_store8 = 0x3C,
605 WasmOp_i64_store16 = 0x3D,
606 WasmOp_i64_store32 = 0x3E,
607 WasmOp_memory_size = 0x3F,
608 WasmOp_memory_grow = 0x40,
609 WasmOp_i32_const = 0x41,
610 WasmOp_i64_const = 0x42,
611 WasmOp_f32_const = 0x43,
612 WasmOp_f64_const = 0x44,
613 WasmOp_i32_eqz = 0x45,
614 WasmOp_i32_eq = 0x46,
615 WasmOp_i32_ne = 0x47,
616 WasmOp_i32_lt_s = 0x48,
617 WasmOp_i32_lt_u = 0x49,
618 WasmOp_i32_gt_s = 0x4A,
619 WasmOp_i32_gt_u = 0x4B,
620 WasmOp_i32_le_s = 0x4C,
621 WasmOp_i32_le_u = 0x4D,
622 WasmOp_i32_ge_s = 0x4E,
623 WasmOp_i32_ge_u = 0x4F,
624 WasmOp_i64_eqz = 0x50,
625 WasmOp_i64_eq = 0x51,
626 WasmOp_i64_ne = 0x52,
627 WasmOp_i64_lt_s = 0x53,
628 WasmOp_i64_lt_u = 0x54,
629 WasmOp_i64_gt_s = 0x55,
630 WasmOp_i64_gt_u = 0x56,
631 WasmOp_i64_le_s = 0x57,
632 WasmOp_i64_le_u = 0x58,
633 WasmOp_i64_ge_s = 0x59,
634 WasmOp_i64_ge_u = 0x5A,
635 WasmOp_f32_eq = 0x5B,
636 WasmOp_f32_ne = 0x5C,
637 WasmOp_f32_lt = 0x5D,
638 WasmOp_f32_gt = 0x5E,
639 WasmOp_f32_le = 0x5F,
640 WasmOp_f32_ge = 0x60,
641 WasmOp_f64_eq = 0x61,
642 WasmOp_f64_ne = 0x62,
643 WasmOp_f64_lt = 0x63,
644 WasmOp_f64_gt = 0x64,
645 WasmOp_f64_le = 0x65,
646 WasmOp_f64_ge = 0x66,
647 WasmOp_i32_clz = 0x67,
648 WasmOp_i32_ctz = 0x68,
649 WasmOp_i32_popcnt = 0x69,
650 WasmOp_i32_add = 0x6A,
651 WasmOp_i32_sub = 0x6B,
652 WasmOp_i32_mul = 0x6C,
653 WasmOp_i32_div_s = 0x6D,
654 WasmOp_i32_div_u = 0x6E,
655 WasmOp_i32_rem_s = 0x6F,
656 WasmOp_i32_rem_u = 0x70,
657 WasmOp_i32_and = 0x71,
658 WasmOp_i32_or = 0x72,
659 WasmOp_i32_xor = 0x73,
660 WasmOp_i32_shl = 0x74,
661 WasmOp_i32_shr_s = 0x75,
662 WasmOp_i32_shr_u = 0x76,
663 WasmOp_i32_rotl = 0x77,
664 WasmOp_i32_rotr = 0x78,
665 WasmOp_i64_clz = 0x79,
666 WasmOp_i64_ctz = 0x7A,
667 WasmOp_i64_popcnt = 0x7B,
668 WasmOp_i64_add = 0x7C,
669 WasmOp_i64_sub = 0x7D,
670 WasmOp_i64_mul = 0x7E,
671 WasmOp_i64_div_s = 0x7F,
672 WasmOp_i64_div_u = 0x80,
673 WasmOp_i64_rem_s = 0x81,
674 WasmOp_i64_rem_u = 0x82,
675 WasmOp_i64_and = 0x83,
676 WasmOp_i64_or = 0x84,
677 WasmOp_i64_xor = 0x85,
678 WasmOp_i64_shl = 0x86,
679 WasmOp_i64_shr_s = 0x87,
680 WasmOp_i64_shr_u = 0x88,
681 WasmOp_i64_rotl = 0x89,
682 WasmOp_i64_rotr = 0x8A,
683 WasmOp_f32_abs = 0x8B,
684 WasmOp_f32_neg = 0x8C,
685 WasmOp_f32_ceil = 0x8D,
686 WasmOp_f32_floor = 0x8E,
687 WasmOp_f32_trunc = 0x8F,
688 WasmOp_f32_nearest = 0x90,
689 WasmOp_f32_sqrt = 0x91,
690 WasmOp_f32_add = 0x92,
691 WasmOp_f32_sub = 0x93,
692 WasmOp_f32_mul = 0x94,
693 WasmOp_f32_div = 0x95,
694 WasmOp_f32_min = 0x96,
695 WasmOp_f32_max = 0x97,
696 WasmOp_f32_copysign = 0x98,
697 WasmOp_f64_abs = 0x99,
698 WasmOp_f64_neg = 0x9A,
699 WasmOp_f64_ceil = 0x9B,
700 WasmOp_f64_floor = 0x9C,
701 WasmOp_f64_trunc = 0x9D,
702 WasmOp_f64_nearest = 0x9E,
703 WasmOp_f64_sqrt = 0x9F,
704 WasmOp_f64_add = 0xA0,
705 WasmOp_f64_sub = 0xA1,
706 WasmOp_f64_mul = 0xA2,
707 WasmOp_f64_div = 0xA3,
708 WasmOp_f64_min = 0xA4,
709 WasmOp_f64_max = 0xA5,
710 WasmOp_f64_copysign = 0xA6,
711 WasmOp_i32_wrap_i64 = 0xA7,
712 WasmOp_i32_trunc_f32_s = 0xA8,
713 WasmOp_i32_trunc_f32_u = 0xA9,
714 WasmOp_i32_trunc_f64_s = 0xAA,
715 WasmOp_i32_trunc_f64_u = 0xAB,
716 WasmOp_i64_extend_i32_s = 0xAC,
717 WasmOp_i64_extend_i32_u = 0xAD,
718 WasmOp_i64_trunc_f32_s = 0xAE,
719 WasmOp_i64_trunc_f32_u = 0xAF,
720 WasmOp_i64_trunc_f64_s = 0xB0,
721 WasmOp_i64_trunc_f64_u = 0xB1,
722 WasmOp_f32_convert_i32_s = 0xB2,
723 WasmOp_f32_convert_i32_u = 0xB3,
724 WasmOp_f32_convert_i64_s = 0xB4,
725 WasmOp_f32_convert_i64_u = 0xB5,
726 WasmOp_f32_demote_f64 = 0xB6,
727 WasmOp_f64_convert_i32_s = 0xB7,
728 WasmOp_f64_convert_i32_u = 0xB8,
729 WasmOp_f64_convert_i64_s = 0xB9,
730 WasmOp_f64_convert_i64_u = 0xBA,
731 WasmOp_f64_promote_f32 = 0xBB,
732 WasmOp_i32_reinterpret_f32 = 0xBC,
733 WasmOp_i64_reinterpret_f64 = 0xBD,
734 WasmOp_f32_reinterpret_i32 = 0xBE,
735 WasmOp_f64_reinterpret_i64 = 0xBF,
736 WasmOp_i32_extend8_s = 0xC0,
737 WasmOp_i32_extend16_s = 0xC1,
738 WasmOp_i64_extend8_s = 0xC2,
739 WasmOp_i64_extend16_s = 0xC3,
740 WasmOp_i64_extend32_s = 0xC4,
741
742 WasmOp_prefixed = 0xFC,
743};
744
745enum WasmPrefixedOp {
746 WasmPrefixedOp_i32_trunc_sat_f32_s = 0x00,
747 WasmPrefixedOp_i32_trunc_sat_f32_u = 0x01,
748 WasmPrefixedOp_i32_trunc_sat_f64_s = 0x02,
749 WasmPrefixedOp_i32_trunc_sat_f64_u = 0x03,
750 WasmPrefixedOp_i64_trunc_sat_f32_s = 0x04,
751 WasmPrefixedOp_i64_trunc_sat_f32_u = 0x05,
752 WasmPrefixedOp_i64_trunc_sat_f64_s = 0x06,
753 WasmPrefixedOp_i64_trunc_sat_f64_u = 0x07,
754 WasmPrefixedOp_memory_init = 0x08,
755 WasmPrefixedOp_data_drop = 0x09,
756 WasmPrefixedOp_memory_copy = 0x0A,
757 WasmPrefixedOp_memory_fill = 0x0B,
758 WasmPrefixedOp_table_init = 0x0C,
759 WasmPrefixedOp_elem_drop = 0x0D,
760 WasmPrefixedOp_table_copy = 0x0E,
761 WasmPrefixedOp_table_grow = 0x0F,
762 WasmPrefixedOp_table_size = 0x10,
763 WasmPrefixedOp_table_fill = 0x11,
764};
765
766static const uint32_t wasm_page_size = 64 * 1024;
767
768struct ProgramCounter {
769 uint32_t opcode;
770 uint32_t operand;
771};
772
773struct TypeInfo {
774 uint32_t param_count;
775 // bitset with param_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit
776 uint32_t param_types;
777 uint32_t result_count;
778 // bitset with result_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit
779 uint32_t result_types;
780};
781
782struct Function {
783 uint32_t id;
784 // Index to start of code in opcodes/operands.
785 struct ProgramCounter entry_pc;
786 uint32_t type_idx;
787 uint32_t locals_size;
788};
789
790enum ImpMod {
791 ImpMod_wasi_snapshot_preview1,
792};
793
794enum ImpName {
795 ImpName_args_get,
796 ImpName_args_sizes_get,
797 ImpName_clock_time_get,
798 ImpName_debug,
799 ImpName_debug_slice,
800 ImpName_environ_get,
801 ImpName_environ_sizes_get,
802 ImpName_fd_close,
803 ImpName_fd_fdstat_get,
804 ImpName_fd_filestat_get,
805 ImpName_fd_filestat_set_size,
806 ImpName_fd_filestat_set_times,
807 ImpName_fd_pread,
808 ImpName_fd_prestat_dir_name,
809 ImpName_fd_prestat_get,
810 ImpName_fd_pwrite,
811 ImpName_fd_read,
812 ImpName_fd_readdir,
813 ImpName_fd_write,
814 ImpName_path_create_directory,
815 ImpName_path_filestat_get,
816 ImpName_path_open,
817 ImpName_path_remove_directory,
818 ImpName_path_rename,
819 ImpName_path_unlink_file,
820 ImpName_proc_exit,
821 ImpName_random_get,
822};
823
824struct Import {
825 enum ImpMod mod;
826 enum ImpName name;
827 uint32_t type_idx;
828};
829
830struct VirtualMachine {
831 uint32_t *stack;
832 /// Points to one after the last stack item.
833 uint32_t stack_top;
834 struct ProgramCounter pc;
835 /// Actual memory usage of the WASI code. The capacity is max_memory.
836 uint32_t memory_len;
837 const char *mod_ptr;
838 uint8_t *opcodes;
839 uint32_t *operands;
840 struct Function *functions;
841 /// Type index to start of type in module_bytes.
842 struct TypeInfo *types;
843 uint64_t *globals;
844 char *memory;
845 struct Import *imports;
846 uint32_t imports_len;
847 const char **args;
848 uint32_t *table;
849};
850
851static int to_host_fd(int32_t wasi_fd) {
852 const struct Preopen *preopen = find_preopen(wasi_fd);
853 if (!preopen) return wasi_fd;
854 return preopen->host_fd;
855}
856
857static enum wasi_errno_t to_wasi_err(int err) {
858 switch (err) {
859 case E2BIG: return WASI_E2BIG;
860 case EACCES: return WASI_EACCES;
861 case EADDRINUSE: return WASI_EADDRINUSE;
862 case EADDRNOTAVAIL: return WASI_EADDRNOTAVAIL;
863 case EAFNOSUPPORT: return WASI_EAFNOSUPPORT;
864 case EAGAIN: return WASI_EAGAIN;
865 case EALREADY: return WASI_EALREADY;
866 case EBADF: return WASI_EBADF;
867 case EBADMSG: return WASI_EBADMSG;
868 case EBUSY: return WASI_EBUSY;
869 case ECANCELED: return WASI_ECANCELED;
870 case ECHILD: return WASI_ECHILD;
871 case ECONNABORTED: return WASI_ECONNABORTED;
872 case ECONNREFUSED: return WASI_ECONNREFUSED;
873 case ECONNRESET: return WASI_ECONNRESET;
874 case EDEADLK: return WASI_EDEADLK;
875 case EDESTADDRREQ: return WASI_EDESTADDRREQ;
876 case EDOM: return WASI_EDOM;
877 case EDQUOT: return WASI_EDQUOT;
878 case EEXIST: return WASI_EEXIST;
879 case EFAULT: return WASI_EFAULT;
880 case EFBIG: return WASI_EFBIG;
881 case EHOSTUNREACH: return WASI_EHOSTUNREACH;
882 case EIDRM: return WASI_EIDRM;
883 case EILSEQ: return WASI_EILSEQ;
884 case EINPROGRESS: return WASI_EINPROGRESS;
885 case EINTR: return WASI_EINTR;
886 case EINVAL: return WASI_EINVAL;
887 case EIO: return WASI_EIO;
888 case EISCONN: return WASI_EISCONN;
889 case EISDIR: return WASI_EISDIR;
890 case ELOOP: return WASI_ELOOP;
891 case EMFILE: return WASI_EMFILE;
892 case EMLINK: return WASI_EMLINK;
893 case EMSGSIZE: return WASI_EMSGSIZE;
894 case EMULTIHOP: return WASI_EMULTIHOP;
895 case ENAMETOOLONG: return WASI_ENAMETOOLONG;
896 case ENETDOWN: return WASI_ENETDOWN;
897 case ENETRESET: return WASI_ENETRESET;
898 case ENETUNREACH: return WASI_ENETUNREACH;
899 case ENFILE: return WASI_ENFILE;
900 case ENOBUFS: return WASI_ENOBUFS;
901 case ENODEV: return WASI_ENODEV;
902 case ENOENT: return WASI_ENOENT;
903 case ENOEXEC: return WASI_ENOEXEC;
904 case ENOLCK: return WASI_ENOLCK;
905 case ENOLINK: return WASI_ENOLINK;
906 case ENOMEM: return WASI_ENOMEM;
907 case ENOMSG: return WASI_ENOMSG;
908 case ENOPROTOOPT: return WASI_ENOPROTOOPT;
909 case ENOSPC: return WASI_ENOSPC;
910 case ENOSYS: return WASI_ENOSYS;
911 case ENOTCONN: return WASI_ENOTCONN;
912 case ENOTDIR: return WASI_ENOTDIR;
913 case ENOTEMPTY: return WASI_ENOTEMPTY;
914 case ENOTRECOVERABLE: return WASI_ENOTRECOVERABLE;
915 case ENOTSOCK: return WASI_ENOTSOCK;
916 case EOPNOTSUPP: return WASI_EOPNOTSUPP;
917 case ENOTTY: return WASI_ENOTTY;
918 case ENXIO: return WASI_ENXIO;
919 case EOVERFLOW: return WASI_EOVERFLOW;
920 case EOWNERDEAD: return WASI_EOWNERDEAD;
921 case EPERM: return WASI_EPERM;
922 case EPIPE: return WASI_EPIPE;
923 case EPROTO: return WASI_EPROTO;
924 case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT;
925 case EPROTOTYPE: return WASI_EPROTOTYPE;
926 case ERANGE: return WASI_ERANGE;
927 case EROFS: return WASI_EROFS;
928 case ESPIPE: return WASI_ESPIPE;
929 case ESRCH: return WASI_ESRCH;
930 case ESTALE: return WASI_ESTALE;
931 case ETIMEDOUT: return WASI_ETIMEDOUT;
932 case ETXTBSY: return WASI_ETXTBSY;
933 case EXDEV: return WASI_EXDEV;
934 default:
935 fprintf(stderr, "unexpected errno: %s\n", strerror(err));
936 abort();
937 };
938}
939
940enum wasi_filetype_t {
941 wasi_filetype_t_UNKNOWN,
942 wasi_filetype_t_BLOCK_DEVICE,
943 wasi_filetype_t_CHARACTER_DEVICE,
944 wasi_filetype_t_DIRECTORY,
945 wasi_filetype_t_REGULAR_FILE,
946 wasi_filetype_t_SOCKET_DGRAM,
947 wasi_filetype_t_SOCKET_STREAM,
948 wasi_filetype_t_SYMBOLIC_LINK,
949};
950
951static const uint16_t WASI_O_CREAT = 0x0001;
952static const uint16_t WASI_O_DIRECTORY = 0x0002;
953static const uint16_t WASI_O_EXCL = 0x0004;
954static const uint16_t WASI_O_TRUNC = 0x0008;
955
956static const uint16_t WASI_FDFLAG_APPEND = 0x0001;
957static const uint16_t WASI_FDFLAG_DSYNC = 0x0002;
958static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004;
959static const uint16_t WASI_FDFLAG_SYNC = 0x0010;
960
961static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull;
962static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull;
963
964static enum wasi_filetype_t to_wasi_filetype(mode_t st_mode) {
965 switch (st_mode & S_IFMT) {
966 case S_IFBLK:
967 return wasi_filetype_t_BLOCK_DEVICE;
968 case S_IFCHR:
969 return wasi_filetype_t_CHARACTER_DEVICE;
970 case S_IFDIR:
971 return wasi_filetype_t_DIRECTORY;
972 case S_IFLNK:
973 return wasi_filetype_t_SYMBOLIC_LINK;
974 case S_IFREG:
975 return wasi_filetype_t_REGULAR_FILE;
976 default:
977 return wasi_filetype_t_UNKNOWN;
978 }
979}
980
981static uint64_t to_wasi_timestamp(struct timespec ts) {
982 return ts.tv_sec * 1000000000ull + ts.tv_nsec;
983}
984
985/// const filestat_t = extern struct {
986/// dev: device_t, u64
987/// ino: inode_t, u64
988/// filetype: filetype_t, u8
989/// nlink: linkcount_t, u64
990/// size: filesize_t, u64
991/// atim: timestamp_t, u64
992/// mtim: timestamp_t, u64
993/// ctim: timestamp_t, u64
994/// };
995static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm,
996 uint32_t buf, struct stat st)
997{
998 write_u64_le(vm->memory + buf + 0x00, 0); // device
999 write_u64_le(vm->memory + buf + 0x08, st.st_ino);
1000 write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode));
1001 write_u64_le(vm->memory + buf + 0x18, 1); // nlink
1002 write_u64_le(vm->memory + buf + 0x20, st.st_size);
1003#if defined(__APPLE__)
1004 write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atimespec));
1005 write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtimespec));
1006 write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctimespec));
1007#else
1008 write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim));
1009 write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim));
1010 write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim));
1011#endif
1012 return WASI_ESUCCESS;
1013}
1014
1015/// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
1016static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm,
1017 uint32_t argc, uint32_t argv_buf_size)
1018{
1019 uint32_t args_len = 0;
1020 size_t buf_size = 0;
1021 while (vm->args[args_len]) {
1022 buf_size += strlen(vm->args[args_len]) + 1;
1023 args_len += 1;
1024 }
1025 write_u32_le(vm->memory + argc, args_len);
1026 write_u32_le(vm->memory + argv_buf_size, buf_size);
1027 return WASI_ESUCCESS;
1028}
1029
1030/// extern fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t;
1031static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm,
1032 uint32_t argv, uint32_t argv_buf)
1033{
1034 uint32_t argv_buf_i = 0;
1035 uint32_t arg_i = 0;
1036 for (;; arg_i += 1) {
1037 const char *arg = vm->args[arg_i];
1038 if (!arg) break;
1039 // Write the arg to the buffer.
1040 uint32_t argv_ptr = argv_buf + argv_buf_i;
1041 uint32_t arg_len = strlen(arg) + 1;
1042 memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len);
1043 argv_buf_i += arg_len;
1044
1045 write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr);
1046 }
1047 return WASI_ESUCCESS;
1048}
1049
1050/// extern fn random_get(buf: [*]u8, buf_len: usize) errno_t;
1051static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm,
1052 uint32_t buf, uint32_t buf_len)
1053{
1054#ifdef __linux__
1055 if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) {
1056 panic("getrandom failed");
1057 }
1058#else
1059 for (uint32_t i = 0; i < buf_len; i += 1) {
1060 vm->memory[buf + i] = rand();
1061 }
1062#endif
1063 return WASI_ESUCCESS;
1064}
1065
1066/// fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
1067/// const prestat_t = extern struct {
1068/// pr_type: u8,
1069/// u: usize,
1070/// };
1071static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm,
1072 int32_t fd, uint32_t buf)
1073{
1074 const struct Preopen *preopen = find_preopen(fd);
1075 if (!preopen) return WASI_EBADF;
1076 write_u32_le(vm->memory + buf + 0, 0);
1077 write_u32_le(vm->memory + buf + 4, preopen->name_len);
1078 return WASI_ESUCCESS;
1079}
1080
1081/// fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
1082static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm,
1083 int32_t fd, uint32_t path, uint32_t path_len)
1084{
1085 const struct Preopen *preopen = find_preopen(fd);
1086 if (!preopen) return WASI_EBADF;
1087 if (path_len != preopen->name_len)
1088 panic("wasi_fd_prestat_dir_name expects correct name_len");
1089 memcpy(vm->memory + path, preopen->name, path_len);
1090 return WASI_ESUCCESS;
1091}
1092
1093/// extern fn fd_close(fd: fd_t) errno_t;
1094static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) {
1095 int host_fd = to_host_fd(fd);
1096 close(host_fd);
1097 return WASI_ESUCCESS;
1098}
1099
1100static enum wasi_errno_t wasi_fd_read(
1101 struct VirtualMachine *vm,
1102 int32_t fd,
1103 uint32_t iovs, // [*]const iovec_t
1104 uint32_t iovs_len, // usize
1105 uint32_t nread // *usize
1106) {
1107 int host_fd = to_host_fd(fd);
1108 uint32_t i = 0;
1109 size_t total_read = 0;
1110 for (; i < iovs_len; i += 1) {
1111 uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
1112 uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
1113 ssize_t amt_read = read(host_fd, vm->memory + ptr, len);
1114 if (amt_read < 0) return to_wasi_err(errno);
1115 total_read += amt_read;
1116 if (amt_read != len) break;
1117 }
1118 write_u32_le(vm->memory + nread, total_read);
1119 return WASI_ESUCCESS;
1120}
1121
1122/// extern fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
1123/// const ciovec_t = extern struct {
1124/// base: [*]const u8,
1125/// len: usize,
1126/// };
1127static enum wasi_errno_t wasi_fd_write(struct VirtualMachine *vm,
1128 int32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t nwritten)
1129{
1130 int host_fd = to_host_fd(fd);
1131 size_t total_written = 0;
1132 for (uint32_t i = 0; i < iovs_len; i += 1) {
1133 uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
1134 uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
1135 ssize_t written = write(host_fd, vm->memory + ptr, len);
1136 if (written < 0) return to_wasi_err(errno);
1137 total_written += written;
1138 if (written != len) break;
1139 }
1140 write_u32_le(vm->memory + nwritten, total_written);
1141 return WASI_ESUCCESS;
1142}
1143
1144static enum wasi_errno_t wasi_fd_pwrite(
1145 struct VirtualMachine *vm,
1146 int32_t fd,
1147 uint32_t iovs, // [*]const ciovec_t
1148 uint32_t iovs_len, // usize
1149 uint64_t offset, // wasi.filesize_t,
1150 uint32_t written_ptr // *usize
1151) {
1152 int host_fd = to_host_fd(fd);
1153 uint32_t i = 0;
1154 size_t written = 0;
1155 for (; i < iovs_len; i += 1) {
1156 uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
1157 uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
1158 ssize_t w = pwrite(host_fd, vm->memory + ptr, len, offset + written);
1159 if (w < 0) return to_wasi_err(errno);
1160 written += w;
1161 if (w != len) break;
1162 }
1163 write_u32_le(vm->memory + written_ptr, written);
1164 return WASI_ESUCCESS;
1165}
1166
1167///extern fn path_open(
1168/// dirfd: fd_t,
1169/// dirflags: lookupflags_t,
1170/// path: [*]const u8,
1171/// path_len: usize,
1172/// oflags: oflags_t,
1173/// fs_rights_base: rights_t,
1174/// fs_rights_inheriting: rights_t,
1175/// fs_flags: fdflags_t,
1176/// fd: *fd_t,
1177///) errno_t;
1178static enum wasi_errno_t wasi_path_open(
1179 struct VirtualMachine *vm,
1180 int32_t dirfd,
1181 uint32_t dirflags, // wasi.lookupflags_t,
1182 uint32_t path,
1183 uint32_t path_len,
1184 uint16_t oflags, // wasi.oflags_t,
1185 uint64_t fs_rights_base, // wasi.rights_t,
1186 uint64_t fs_rights_inheriting, // wasi.rights_t,
1187 uint16_t fs_flags, // wasi.fdflags_t,
1188 uint32_t fd
1189) {
1190 char sub_path[PATH_MAX];
1191 memcpy(sub_path, vm->memory + path, path_len);
1192 sub_path[path_len] = 0;
1193
1194 int host_fd = to_host_fd(dirfd);
1195 uint32_t flags =
1196 (((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) |
1197 (((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) |
1198 (((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) |
1199 (((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) |
1200 (((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) |
1201 (((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) |
1202 (((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) |
1203 (((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0);
1204
1205 if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) &&
1206 ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0))
1207 {
1208 flags |= O_RDWR;
1209 } else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) {
1210 flags |= O_WRONLY;
1211 } else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) {
1212 flags |= O_RDONLY; // no-op because O_RDONLY is 0
1213 }
1214 mode_t mode = 0644;
1215 int res_fd = openat(host_fd, sub_path, flags, mode);
1216 if (res_fd == -1) return to_wasi_err(errno);
1217 write_u32_le(vm->memory + fd, res_fd);
1218 return WASI_ESUCCESS;
1219}
1220
1221static enum wasi_errno_t wasi_path_filestat_get(
1222 struct VirtualMachine *vm,
1223 int32_t fd,
1224 uint32_t flags, // wasi.lookupflags_t,
1225 uint32_t path, // [*]const u8
1226 uint32_t path_len, // usize
1227 uint32_t buf // *filestat_t
1228) {
1229 char sub_path[PATH_MAX];
1230 memcpy(sub_path, vm->memory + path, path_len);
1231 sub_path[path_len] = 0;
1232
1233 int host_fd = to_host_fd(fd);
1234 struct stat st;
1235 if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno);
1236 return finish_wasi_stat(vm, buf, st);
1237}
1238
1239/// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
1240static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm,
1241 int32_t wasi_fd, uint32_t path, uint32_t path_len)
1242{
1243 char sub_path[PATH_MAX];
1244 memcpy(sub_path, vm->memory + path, path_len);
1245 sub_path[path_len] = 0;
1246
1247 int host_fd = to_host_fd(wasi_fd);
1248 if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno);
1249 return WASI_ESUCCESS;
1250}
1251
1252static enum wasi_errno_t wasi_path_rename(
1253 struct VirtualMachine *vm,
1254 int32_t old_fd,
1255 uint32_t old_path_ptr, // [*]const u8
1256 uint32_t old_path_len, // usize
1257 int32_t new_fd,
1258 uint32_t new_path_ptr, // [*]const u8
1259 uint32_t new_path_len // usize
1260) {
1261 char old_path[PATH_MAX];
1262 memcpy(old_path, vm->memory + old_path_ptr, old_path_len);
1263 old_path[old_path_len] = 0;
1264
1265 char new_path[PATH_MAX];
1266 memcpy(new_path, vm->memory + new_path_ptr, new_path_len);
1267 new_path[new_path_len] = 0;
1268
1269 int old_host_fd = to_host_fd(old_fd);
1270 int new_host_fd = to_host_fd(new_fd);
1271 if (renameat(old_host_fd, old_path, new_host_fd, new_path) == -1) return to_wasi_err(errno);
1272 return WASI_ESUCCESS;
1273}
1274
1275/// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
1276static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
1277 int host_fd = to_host_fd(fd);
1278 struct stat st;
1279 if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
1280 return finish_wasi_stat(vm, buf, st);
1281}
1282
1283static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm,
1284 int32_t fd, uint64_t size)
1285{
1286 int host_fd = to_host_fd(fd);
1287 if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno);
1288 return WASI_ESUCCESS;
1289}
1290
1291/// pub extern "wasi_snapshot_preview1" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
1292/// pub const fdstat_t = extern struct {
1293/// fs_filetype: filetype_t, u8
1294/// fs_flags: fdflags_t, u16
1295/// fs_rights_base: rights_t, u64
1296/// fs_rights_inheriting: rights_t, u64
1297/// };
1298static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
1299 int host_fd = to_host_fd(fd);
1300 struct stat st;
1301 if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
1302 write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode));
1303 write_u16_le(vm->memory + buf + 0x02, 0); // flags
1304 write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base
1305 write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting
1306 return WASI_ESUCCESS;
1307}
1308
1309/// extern fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
1310static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm,
1311 uint32_t clock_id, uint64_t precision, uint32_t timestamp)
1312{
1313 if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC");
1314 struct timespec ts;
1315 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno);
1316 uint64_t wasi_ts = to_wasi_timestamp(ts);
1317 write_u64_le(vm->memory + timestamp, wasi_ts);
1318 return WASI_ESUCCESS;
1319}
1320
1321///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void;
1322void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) {
1323 fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64 " %" PRIx64 "\n", vm->memory + text, n, n);
1324}
1325
1326/// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void;
1327void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) {
1328 fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr);
1329}
1330
1331enum StackType {
1332 ST_32,
1333 ST_64,
1334};
1335
1336struct Label {
1337 enum WasmOp opcode;
1338 uint32_t stack_index;
1339 uint32_t stack_offset;
1340 struct TypeInfo type_info;
1341 // this is a UINT32_MAX terminated linked list that is stored in the operands array
1342 uint32_t ref_list;
1343 union {
1344 struct ProgramCounter loop_pc;
1345 uint32_t else_ref;
1346 } extra;
1347};
1348
1349static uint32_t Label_operandCount(const struct Label *label) {
1350 if (label->opcode == WasmOp_loop) {
1351 return label->type_info.param_count;
1352 } else {
1353 return label->type_info.result_count;
1354 }
1355}
1356
1357static enum StackType Label_operandType(const struct Label *label, uint32_t index) {
1358 if (label->opcode == WasmOp_loop) {
1359 return bs_isSet(&label->type_info.param_types, index);
1360 } else {
1361 return bs_isSet(&label->type_info.result_types, index);
1362 }
1363}
1364
1365#define max_stack_depth (1 << 12)
1366
1367struct StackInfo {
1368 uint32_t top_index;
1369 uint32_t top_offset;
1370 uint32_t types[max_stack_depth >> 5];
1371 uint32_t offsets[max_stack_depth];
1372};
1373
1374static enum StackType si_top(const struct StackInfo *si) {
1375 return bs_isSet(si->types, si->top_index - 1);
1376}
1377
1378static enum StackType si_local(const struct StackInfo *si, uint32_t local_idx) {
1379 return bs_isSet(si->types, local_idx);
1380}
1381
1382static void si_push(struct StackInfo *si, enum StackType entry_type) {
1383 bs_setValue(si->types, si->top_index, entry_type);
1384 si->offsets[si->top_index] = si->top_offset;
1385 si->top_index += 1;
1386 si->top_offset += 1 + entry_type;
1387}
1388
1389static void si_pop(struct StackInfo *si, enum StackType entry_type) {
1390 assert(si_top(si) == entry_type);
1391 si->top_index -= 1;
1392 si->top_offset -= 1 + entry_type;
1393 assert(si->top_offset == si->offsets[si->top_index]);
1394}
1395
1396static void vm_decodeCode(struct VirtualMachine *vm, struct TypeInfo *func_type_info,
1397 uint32_t *code_i, struct ProgramCounter *pc, struct StackInfo *stack)
1398{
1399 const char *mod_ptr = vm->mod_ptr;
1400 uint8_t *opcodes = vm->opcodes;
1401 uint32_t *operands = vm->operands;
1402
1403 // push return address
1404 uint32_t frame_size = stack->top_offset;
1405 si_push(stack, ST_32);
1406 si_push(stack, ST_32);
1407
1408 uint32_t unreachable_depth = 0;
1409 uint32_t label_i = 0;
1410 static struct Label labels[1 << 9];
1411#ifndef NDEBUG
1412 memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version
1413#endif
1414 labels[label_i].opcode = WasmOp_block;
1415 labels[label_i].stack_index = stack->top_index;
1416 labels[label_i].stack_offset = stack->top_offset;
1417 labels[label_i].type_info = *func_type_info;
1418 labels[label_i].ref_list = UINT32_MAX;
1419
1420 enum {
1421 State_default,
1422 State_bool_not,
1423 } state = State_default;
1424
1425 for (;;) {
1426 assert(stack->top_index >= labels[0].stack_index);
1427 assert(stack->top_offset >= labels[0].stack_offset);
1428 enum WasmOp opcode = (uint8_t)mod_ptr[*code_i];
1429 *code_i += 1;
1430 enum WasmPrefixedOp prefixed_opcode;
1431 if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i);
1432
1433 //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand);
1434 //struct ProgramCounter old_pc = *pc;
1435
1436 if (unreachable_depth == 0)
1437 switch (opcode) {
1438 case WasmOp_unreachable:
1439 case WasmOp_nop:
1440 case WasmOp_block:
1441 case WasmOp_loop:
1442 case WasmOp_else:
1443 case WasmOp_end:
1444 case WasmOp_br:
1445 case WasmOp_return:
1446 case WasmOp_call:
1447 case WasmOp_local_get:
1448 case WasmOp_local_set:
1449 case WasmOp_local_tee:
1450 case WasmOp_global_get:
1451 case WasmOp_global_set:
1452 case WasmOp_drop:
1453 case WasmOp_select:
1454 break; // handled manually below
1455
1456 case WasmOp_if:
1457 case WasmOp_br_if:
1458 case WasmOp_br_table:
1459 case WasmOp_call_indirect:
1460 si_pop(stack, ST_32);
1461 break;
1462
1463 case WasmOp_memory_size:
1464 case WasmOp_i32_const:
1465 case WasmOp_f32_const:
1466 si_push(stack, ST_32);
1467 break;
1468
1469 case WasmOp_i64_const:
1470 case WasmOp_f64_const:
1471 si_push(stack, ST_64);
1472 break;
1473
1474 case WasmOp_i32_load:
1475 case WasmOp_f32_load:
1476 case WasmOp_i32_load8_s:
1477 case WasmOp_i32_load8_u:
1478 case WasmOp_i32_load16_s:
1479 case WasmOp_i32_load16_u:
1480 si_pop(stack, ST_32);
1481 si_push(stack, ST_32);
1482 break;
1483
1484 case WasmOp_i64_load:
1485 case WasmOp_f64_load:
1486 case WasmOp_i64_load8_s:
1487 case WasmOp_i64_load8_u:
1488 case WasmOp_i64_load16_s:
1489 case WasmOp_i64_load16_u:
1490 case WasmOp_i64_load32_s:
1491 case WasmOp_i64_load32_u:
1492 si_pop(stack, ST_32);
1493 si_push(stack, ST_64);
1494 break;
1495
1496 case WasmOp_memory_grow:
1497 case WasmOp_i32_eqz:
1498 case WasmOp_i32_clz:
1499 case WasmOp_i32_ctz:
1500 case WasmOp_i32_popcnt:
1501 case WasmOp_f32_abs:
1502 case WasmOp_f32_neg:
1503 case WasmOp_f32_ceil:
1504 case WasmOp_f32_floor:
1505 case WasmOp_f32_trunc:
1506 case WasmOp_f32_nearest:
1507 case WasmOp_f32_sqrt:
1508 case WasmOp_i32_trunc_f32_s:
1509 case WasmOp_i32_trunc_f32_u:
1510 case WasmOp_f32_convert_i32_s:
1511 case WasmOp_f32_convert_i32_u:
1512 case WasmOp_i32_reinterpret_f32:
1513 case WasmOp_f32_reinterpret_i32:
1514 case WasmOp_i32_extend8_s:
1515 case WasmOp_i32_extend16_s:
1516 si_pop(stack, ST_32);
1517 si_push(stack, ST_32);
1518 break;
1519
1520 case WasmOp_i64_eqz:
1521 case WasmOp_i32_wrap_i64:
1522 case WasmOp_i32_trunc_f64_s:
1523 case WasmOp_i32_trunc_f64_u:
1524 case WasmOp_f32_convert_i64_s:
1525 case WasmOp_f32_convert_i64_u:
1526 case WasmOp_f32_demote_f64:
1527 si_pop(stack, ST_64);
1528 si_push(stack, ST_32);
1529 break;
1530
1531 case WasmOp_i64_clz:
1532 case WasmOp_i64_ctz:
1533 case WasmOp_i64_popcnt:
1534 case WasmOp_f64_abs:
1535 case WasmOp_f64_neg:
1536 case WasmOp_f64_ceil:
1537 case WasmOp_f64_floor:
1538 case WasmOp_f64_trunc:
1539 case WasmOp_f64_nearest:
1540 case WasmOp_f64_sqrt:
1541 case WasmOp_i64_trunc_f64_s:
1542 case WasmOp_i64_trunc_f64_u:
1543 case WasmOp_f64_convert_i64_s:
1544 case WasmOp_f64_convert_i64_u:
1545 case WasmOp_i64_reinterpret_f64:
1546 case WasmOp_f64_reinterpret_i64:
1547 case WasmOp_i64_extend8_s:
1548 case WasmOp_i64_extend16_s:
1549 case WasmOp_i64_extend32_s:
1550 si_pop(stack, ST_64);
1551 si_push(stack, ST_64);
1552 break;
1553
1554 case WasmOp_i64_extend_i32_s:
1555 case WasmOp_i64_extend_i32_u:
1556 case WasmOp_i64_trunc_f32_s:
1557 case WasmOp_i64_trunc_f32_u:
1558 case WasmOp_f64_convert_i32_s:
1559 case WasmOp_f64_convert_i32_u:
1560 case WasmOp_f64_promote_f32:
1561 si_pop(stack, ST_32);
1562 si_push(stack, ST_64);
1563 break;
1564
1565 case WasmOp_i32_store:
1566 case WasmOp_f32_store:
1567 case WasmOp_i32_store8:
1568 case WasmOp_i32_store16:
1569 si_pop(stack, ST_32);
1570 si_pop(stack, ST_32);
1571 break;
1572
1573 case WasmOp_i64_store:
1574 case WasmOp_f64_store:
1575 case WasmOp_i64_store8:
1576 case WasmOp_i64_store16:
1577 case WasmOp_i64_store32:
1578 si_pop(stack, ST_64);
1579 si_pop(stack, ST_32);
1580 break;
1581
1582 case WasmOp_i32_eq:
1583 case WasmOp_i32_ne:
1584 case WasmOp_i32_lt_s:
1585 case WasmOp_i32_lt_u:
1586 case WasmOp_i32_gt_s:
1587 case WasmOp_i32_gt_u:
1588 case WasmOp_i32_le_s:
1589 case WasmOp_i32_le_u:
1590 case WasmOp_i32_ge_s:
1591 case WasmOp_i32_ge_u:
1592 case WasmOp_f32_eq:
1593 case WasmOp_f32_ne:
1594 case WasmOp_f32_lt:
1595 case WasmOp_f32_gt:
1596 case WasmOp_f32_le:
1597 case WasmOp_f32_ge:
1598 si_pop(stack, ST_32);
1599 si_pop(stack, ST_32);
1600 si_push(stack, ST_32);
1601 break;
1602
1603 case WasmOp_i64_eq:
1604 case WasmOp_i64_ne:
1605 case WasmOp_i64_lt_s:
1606 case WasmOp_i64_lt_u:
1607 case WasmOp_i64_gt_s:
1608 case WasmOp_i64_gt_u:
1609 case WasmOp_i64_le_s:
1610 case WasmOp_i64_le_u:
1611 case WasmOp_i64_ge_s:
1612 case WasmOp_i64_ge_u:
1613 case WasmOp_f64_eq:
1614 case WasmOp_f64_ne:
1615 case WasmOp_f64_lt:
1616 case WasmOp_f64_gt:
1617 case WasmOp_f64_le:
1618 case WasmOp_f64_ge:
1619 si_pop(stack, ST_64);
1620 si_pop(stack, ST_64);
1621 si_push(stack, ST_32);
1622 break;
1623
1624 case WasmOp_i32_add:
1625 case WasmOp_i32_sub:
1626 case WasmOp_i32_mul:
1627 case WasmOp_i32_div_s:
1628 case WasmOp_i32_div_u:
1629 case WasmOp_i32_rem_s:
1630 case WasmOp_i32_rem_u:
1631 case WasmOp_i32_and:
1632 case WasmOp_i32_or:
1633 case WasmOp_i32_xor:
1634 case WasmOp_i32_shl:
1635 case WasmOp_i32_shr_s:
1636 case WasmOp_i32_shr_u:
1637 case WasmOp_i32_rotl:
1638 case WasmOp_i32_rotr:
1639 case WasmOp_f32_add:
1640 case WasmOp_f32_sub:
1641 case WasmOp_f32_mul:
1642 case WasmOp_f32_div:
1643 case WasmOp_f32_min:
1644 case WasmOp_f32_max:
1645 case WasmOp_f32_copysign:
1646 si_pop(stack, ST_32);
1647 si_pop(stack, ST_32);
1648 si_push(stack, ST_32);
1649 break;
1650
1651 case WasmOp_i64_add:
1652 case WasmOp_i64_sub:
1653 case WasmOp_i64_mul:
1654 case WasmOp_i64_div_s:
1655 case WasmOp_i64_div_u:
1656 case WasmOp_i64_rem_s:
1657 case WasmOp_i64_rem_u:
1658 case WasmOp_i64_and:
1659 case WasmOp_i64_or:
1660 case WasmOp_i64_xor:
1661 case WasmOp_i64_shl:
1662 case WasmOp_i64_shr_s:
1663 case WasmOp_i64_shr_u:
1664 case WasmOp_i64_rotl:
1665 case WasmOp_i64_rotr:
1666 case WasmOp_f64_add:
1667 case WasmOp_f64_sub:
1668 case WasmOp_f64_mul:
1669 case WasmOp_f64_div:
1670 case WasmOp_f64_min:
1671 case WasmOp_f64_max:
1672 case WasmOp_f64_copysign:
1673 si_pop(stack, ST_64);
1674 si_pop(stack, ST_64);
1675 si_push(stack, ST_64);
1676 break;
1677
1678 case WasmOp_prefixed:
1679 switch (prefixed_opcode) {
1680 case WasmPrefixedOp_i32_trunc_sat_f32_s:
1681 case WasmPrefixedOp_i32_trunc_sat_f32_u:
1682 si_pop(stack, ST_32);
1683 si_push(stack, ST_32);
1684 break;
1685
1686 case WasmPrefixedOp_i32_trunc_sat_f64_s:
1687 case WasmPrefixedOp_i32_trunc_sat_f64_u:
1688 si_pop(stack, ST_64);
1689 si_push(stack, ST_32);
1690 break;
1691
1692 case WasmPrefixedOp_i64_trunc_sat_f32_s:
1693 case WasmPrefixedOp_i64_trunc_sat_f32_u:
1694 si_pop(stack, ST_32);
1695 si_push(stack, ST_64);
1696 break;
1697
1698 case WasmPrefixedOp_i64_trunc_sat_f64_s:
1699 case WasmPrefixedOp_i64_trunc_sat_f64_u:
1700 si_pop(stack, ST_64);
1701 si_push(stack, ST_64);
1702 break;
1703
1704 case WasmPrefixedOp_memory_init:
1705 case WasmPrefixedOp_memory_copy:
1706 case WasmPrefixedOp_memory_fill:
1707 case WasmPrefixedOp_table_init:
1708 case WasmPrefixedOp_table_copy:
1709 si_pop(stack, ST_32);
1710 si_pop(stack, ST_32);
1711 si_pop(stack, ST_32);
1712 break;
1713
1714 case WasmPrefixedOp_table_fill:
1715 si_pop(stack, ST_32);
1716 panic("si_pop(stack, unreachable);");
1717 si_pop(stack, ST_32);
1718 break;
1719
1720 case WasmPrefixedOp_data_drop:
1721 case WasmPrefixedOp_elem_drop:
1722 break;
1723
1724 case WasmPrefixedOp_table_grow:
1725 si_pop(stack, ST_32);
1726 panic("si_pop(stack, unreachable);");
1727 si_push(stack, ST_32);
1728 break;
1729
1730 case WasmPrefixedOp_table_size:
1731 si_push(stack, ST_32);
1732 break;
1733
1734 default: panic("unexpected prefixed opcode");
1735 }
1736 break;
1737
1738 default: panic("unexpected opcode");
1739 }
1740 switch (opcode) {
1741 case WasmOp_unreachable:
1742 if (unreachable_depth == 0) {
1743 opcodes[pc->opcode] = Op_unreachable;
1744 pc->opcode += 1;
1745 unreachable_depth += 1;
1746 }
1747 break;
1748
1749 case WasmOp_nop:
1750 case WasmOp_i32_reinterpret_f32:
1751 case WasmOp_i64_reinterpret_f64:
1752 case WasmOp_f32_reinterpret_i32:
1753 case WasmOp_f64_reinterpret_i64:
1754 break;
1755
1756 case WasmOp_block:
1757 case WasmOp_loop:
1758 case WasmOp_if:
1759 {
1760 int64_t block_type = read64_ileb128(mod_ptr, code_i);
1761 if (unreachable_depth == 0) {
1762 label_i += 1;
1763 struct Label *label = &labels[label_i];
1764 label->opcode = opcode;
1765 if (block_type < 0) {
1766 label->type_info.param_count = 0;
1767 label->type_info.param_types = 0;
1768 label->type_info.result_count = block_type != -0x40;
1769 switch (block_type) {
1770 case -0x40:
1771 case -1:
1772 case -3:
1773 label->type_info.result_types = 0;
1774 break;
1775 case -2:
1776 case -4:
1777 label->type_info.result_types = UINT32_MAX;
1778 break;
1779 default: panic("unexpected param type");
1780 }
1781 } else label->type_info = vm->types[block_type];
1782
1783 uint32_t param_i = label->type_info.param_count;
1784 while (param_i > 0) {
1785 param_i -= 1;
1786 si_pop(stack, bs_isSet(&label->type_info.param_types, param_i));
1787 }
1788 label->stack_index = stack->top_index;
1789 label->stack_offset = stack->top_offset;
1790 label->ref_list = UINT32_MAX;
1791 for (; param_i < label->type_info.param_count; param_i += 1)
1792 si_push(stack, bs_isSet(&label->type_info.param_types, param_i));
1793
1794 switch (opcode) {
1795 case WasmOp_block:
1796 break;
1797
1798 case WasmOp_loop:
1799 label->extra.loop_pc = *pc;
1800 break;
1801
1802 case WasmOp_if:
1803 if (state == State_bool_not) {
1804 pc->opcode -= 1;
1805 opcodes[pc->opcode] = Op_br_nez_void;
1806 } else opcodes[pc->opcode] = Op_br_eqz_void;
1807 pc->opcode += 1;
1808 operands[pc->operand] = 0;
1809 label->extra.else_ref = pc->operand + 1;
1810 pc->operand += 3;
1811 break;
1812
1813 default: panic("unexpected label opcode");
1814 }
1815 } else unreachable_depth += 1;
1816 }
1817 break;
1818
1819 case WasmOp_else:
1820 if (unreachable_depth <= 1) {
1821 struct Label *label = &labels[label_i];
1822 assert(label->opcode == WasmOp_if);
1823 label->opcode = WasmOp_else;
1824
1825 if (unreachable_depth == 0) {
1826 uint32_t operand_count = Label_operandCount(label);
1827 for (uint32_t operand_i = operand_count; operand_i > 0; ) {
1828 operand_i -= 1;
1829 si_pop(stack, Label_operandType(label, operand_i));
1830 }
1831 assert(stack->top_index == label->stack_index);
1832 assert(stack->top_offset == label->stack_offset);
1833
1834 switch (operand_count) {
1835 case 0:
1836 opcodes[pc->opcode] = Op_br_void;
1837 break;
1838
1839 case 1:
1840 //fprintf(stderr, "label_i=%u operand_type=%d\n",
1841 // label_i, Label_operandType(label, 0));
1842 switch (Label_operandType(label, 0)) {
1843 case ST_32: opcodes[pc->opcode] = Op_br_32; break;
1844 case ST_64: opcodes[pc->opcode] = Op_br_64; break;
1845 }
1846 break;
1847
1848 default: panic("unexpected operand count");
1849 }
1850 pc->opcode += 1;
1851 operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
1852 operands[pc->operand + 1] = label->ref_list;
1853 label->ref_list = pc->operand + 1;
1854 pc->operand += 3;
1855 } else unreachable_depth = 0;
1856
1857 operands[label->extra.else_ref + 0] = pc->opcode;
1858 operands[label->extra.else_ref + 1] = pc->operand;
1859 for (uint32_t param_i = 0; param_i < label->type_info.param_count; param_i += 1)
1860 si_push(stack, bs_isSet(&label->type_info.param_types, param_i));
1861 }
1862 break;
1863
1864 case WasmOp_end:
1865 if (unreachable_depth <= 1) {
1866 struct Label *label = &labels[label_i];
1867 struct ProgramCounter *target_pc = (label->opcode == WasmOp_loop) ? &label->extra.loop_pc : pc;
1868 if (label->opcode == WasmOp_if) {
1869 operands[label->extra.else_ref + 0] = target_pc->opcode;
1870 operands[label->extra.else_ref + 1] = target_pc->operand;
1871 }
1872 uint32_t ref = label->ref_list;
1873 while (ref != UINT32_MAX) {
1874 uint32_t next_ref = operands[ref];
1875 operands[ref + 0] = target_pc->opcode;
1876 operands[ref + 1] = target_pc->operand;
1877 ref = next_ref;
1878 }
1879
1880 if (unreachable_depth == 0) {
1881 for (uint32_t result_i = label->type_info.result_count; result_i > 0; ) {
1882 result_i -= 1;
1883 si_pop(stack, bs_isSet(&label->type_info.result_types, result_i));
1884 }
1885 } else unreachable_depth = 0;
1886
1887 if (label_i == 0) {
1888 assert(stack->top_index == label->stack_index);
1889 assert(stack->top_offset == label->stack_offset);
1890
1891 switch (labels[0].type_info.result_count) {
1892 case 0:
1893 opcodes[pc->opcode] = Op_return_void;
1894 break;
1895
1896 case 1:
1897 switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) {
1898 case ST_32: opcodes[pc->opcode] = Op_return_32; break;
1899 case ST_64: opcodes[pc->opcode] = Op_return_64; break;
1900 }
1901 break;
1902
1903 default: panic("unexpected operand count");
1904 }
1905 pc->opcode += 1;
1906 operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset;
1907 operands[pc->operand + 1] = frame_size;
1908 pc->operand += 2;
1909 return;
1910 }
1911 label_i -= 1;
1912
1913 stack->top_index = label->stack_index;
1914 stack->top_offset = label->stack_offset;
1915 for (uint32_t result_i = 0; result_i < label->type_info.result_count; result_i += 1)
1916 si_push(stack, bs_isSet(&label->type_info.result_types, result_i));
1917 } else unreachable_depth -= 1;
1918 break;
1919
1920 case WasmOp_br:
1921 case WasmOp_br_if:
1922 {
1923 uint32_t label_idx = read32_uleb128(mod_ptr, code_i);
1924 if (unreachable_depth == 0) {
1925 struct Label *label = &labels[label_i - label_idx];
1926 uint32_t operand_count = Label_operandCount(label);
1927 uint32_t operand_i = operand_count;
1928 while (operand_i > 0) {
1929 operand_i -= 1;
1930 si_pop(stack, Label_operandType(label, operand_i));
1931 }
1932
1933 switch (opcode) {
1934 case WasmOp_br:
1935 switch (operand_count) {
1936 case 0:
1937 opcodes[pc->opcode] = Op_br_void;
1938 break;
1939
1940 case 1:
1941 switch (Label_operandType(label, 0)) {
1942 case ST_32: opcodes[pc->opcode] = Op_br_32; break;
1943 case ST_64: opcodes[pc->opcode] = Op_br_64; break;
1944 }
1945 break;
1946
1947 default: panic("unexpected operand count");
1948 }
1949 break;
1950
1951 case WasmOp_br_if:
1952 switch (operand_count) {
1953 case 0:
1954 if (state == State_bool_not) {
1955 pc->opcode -= 1;
1956 opcodes[pc->opcode] = Op_br_eqz_void;
1957 } else opcodes[pc->opcode] = Op_br_nez_void;
1958 break;
1959
1960 case 1:
1961 switch (Label_operandType(label, 0)) {
1962 case ST_32:
1963 if (state == State_bool_not) {
1964 pc->opcode -= 1;
1965 opcodes[pc->opcode] = Op_br_eqz_32;
1966 } else opcodes[pc->opcode] = Op_br_nez_32;
1967 break;
1968
1969 case ST_64:
1970 if (state == State_bool_not) {
1971 pc->opcode -= 1;
1972 opcodes[pc->opcode] = Op_br_eqz_64;
1973 } else opcodes[pc->opcode] = Op_br_nez_64;
1974 break;
1975 }
1976 break;
1977
1978 default: panic("unexpected operand count");
1979 }
1980 break;
1981
1982 default: panic("unexpected opcode");
1983 }
1984 pc->opcode += 1;
1985 operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
1986 operands[pc->operand + 1] = label->ref_list;
1987 label->ref_list = pc->operand + 1;
1988 pc->operand += 3;
1989
1990 switch (opcode) {
1991 case WasmOp_br:
1992 unreachable_depth += 1;
1993 break;
1994
1995 case WasmOp_br_if:
1996 for (; operand_i < operand_count; operand_i += 1)
1997 si_push(stack, Label_operandType(label, operand_i));
1998 break;
1999
2000 default: panic("unexpected opcode");
2001 }
2002 }
2003 }
2004 break;
2005
2006 case WasmOp_br_table:
2007 {
2008 uint32_t labels_len = read32_uleb128(mod_ptr, code_i);
2009 for (uint32_t i = 0; i <= labels_len; i += 1) {
2010 uint32_t label_idx = read32_uleb128(mod_ptr, code_i);
2011 if (unreachable_depth != 0) continue;
2012 struct Label *label = &labels[label_i - label_idx];
2013 if (i == 0) {
2014 uint32_t operand_count = Label_operandCount(label);
2015 for (uint32_t operand_i = operand_count; operand_i > 0; ) {
2016 operand_i -= 1;
2017 si_pop(stack, Label_operandType(label, operand_i));
2018 }
2019
2020 switch (operand_count) {
2021 case 0:
2022 opcodes[pc->opcode] = Op_br_table_void;
2023 break;
2024
2025 case 1:
2026 switch (Label_operandType(label, 0)) {
2027 case ST_32: opcodes[pc->opcode] = Op_br_table_32; break;
2028 case ST_64: opcodes[pc->opcode] = Op_br_table_64; break;
2029 }
2030 break;
2031
2032 default: panic("unexpected operand count");
2033 }
2034 pc->opcode += 1;
2035 operands[pc->operand] = labels_len;
2036 pc->operand += 1;
2037 }
2038 operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
2039 operands[pc->operand + 1] = label->ref_list;
2040 label->ref_list = pc->operand + 1;
2041 pc->operand += 3;
2042 }
2043 if (unreachable_depth == 0) unreachable_depth += 1;
2044 }
2045 break;
2046
2047 case WasmOp_return:
2048 if (unreachable_depth == 0) {
2049 for (uint32_t result_i = labels[0].type_info.result_count; result_i > 0; ) {
2050 result_i -= 1;
2051 si_pop(stack, bs_isSet(&labels[0].type_info.result_types, result_i));
2052 }
2053
2054 switch (labels[0].type_info.result_count) {
2055 case 0:
2056 opcodes[pc->opcode] = Op_return_void;
2057 break;
2058
2059 case 1:
2060 switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) {
2061 case ST_32: opcodes[pc->opcode] = Op_return_32; break;
2062 case ST_64: opcodes[pc->opcode] = Op_return_64; break;
2063 }
2064 break;
2065
2066 default: panic("unexpected operand count");
2067 }
2068 pc->opcode += 1;
2069 operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset;
2070 operands[pc->operand + 1] = frame_size;
2071 pc->operand += 2;
2072 unreachable_depth += 1;
2073 }
2074 break;
2075
2076 case WasmOp_call:
2077 {
2078 uint32_t fn_id = read32_uleb128(mod_ptr, code_i);
2079 if (unreachable_depth == 0) {
2080 uint32_t type_idx;
2081 if (fn_id < vm->imports_len) {
2082 opcodes[pc->opcode + 0] = Op_call_import;
2083 opcodes[pc->opcode + 1] = fn_id;
2084 pc->opcode += 2;
2085 type_idx = vm->imports[fn_id].type_idx;
2086 } else {
2087 uint32_t fn_idx = fn_id - vm->imports_len;
2088 opcodes[pc->opcode] = Op_call_func;
2089 pc->opcode += 1;
2090 operands[pc->operand] = fn_idx;
2091 pc->operand += 1;
2092 type_idx = vm->functions[fn_idx].type_idx;
2093 }
2094 struct TypeInfo *type_info = &vm->types[type_idx];
2095
2096 for (uint32_t param_i = type_info->param_count; param_i > 0; ) {
2097 param_i -= 1;
2098 si_pop(stack, bs_isSet(&type_info->param_types, param_i));
2099 }
2100 for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1)
2101 si_push(stack, bs_isSet(&type_info->result_types, result_i));
2102 }
2103 }
2104 break;
2105
2106 case WasmOp_call_indirect:
2107 {
2108 uint32_t type_idx = read32_uleb128(mod_ptr, code_i);
2109 if (read32_uleb128(mod_ptr, code_i) != 0) panic("unexpected table index");
2110 if (unreachable_depth == 0) {
2111 opcodes[pc->opcode] = Op_call_indirect;
2112 pc->opcode += 1;
2113
2114 struct TypeInfo *type_info = &vm->types[type_idx];
2115 for (uint32_t param_i = type_info->param_count; param_i > 0; ) {
2116 param_i -= 1;
2117 si_pop(stack, bs_isSet(&type_info->param_types, param_i));
2118 }
2119 for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1)
2120 si_push(stack, bs_isSet(&type_info->result_types, result_i));
2121 }
2122 }
2123 break;
2124
2125 case WasmOp_select:
2126 case WasmOp_drop:
2127 if (unreachable_depth == 0) {
2128 if (opcode == WasmOp_select) si_pop(stack, ST_32);
2129 enum StackType operand_type = si_top(stack);
2130 si_pop(stack, operand_type);
2131 if (opcode == WasmOp_select) {
2132 si_pop(stack, operand_type);
2133 si_push(stack, operand_type);
2134 }
2135 switch (opcode) {
2136 case WasmOp_select:
2137 switch (operand_type) {
2138 case ST_32: opcodes[pc->opcode] = Op_select_32; break;
2139 case ST_64: opcodes[pc->opcode] = Op_select_64; break;
2140 }
2141 break;
2142
2143 case WasmOp_drop:
2144 switch (operand_type) {
2145 case ST_32: opcodes[pc->opcode] = Op_drop_32; break;
2146 case ST_64: opcodes[pc->opcode] = Op_drop_64; break;
2147 }
2148 break;
2149
2150 default: panic("unexpected opcode");
2151 }
2152 pc->opcode += 1;
2153 }
2154 break;
2155
2156 case WasmOp_local_get:
2157 case WasmOp_local_set:
2158 case WasmOp_local_tee:
2159 {
2160 uint32_t local_idx = read32_uleb128(mod_ptr, code_i);
2161 if (unreachable_depth == 0) {
2162 enum StackType local_type = si_local(stack, local_idx);
2163 switch (opcode) {
2164 case WasmOp_local_get:
2165 switch (local_type) {
2166 case ST_32: opcodes[pc->opcode] = Op_local_get_32; break;
2167 case ST_64: opcodes[pc->opcode] = Op_local_get_64; break;
2168 }
2169 break;
2170
2171 case WasmOp_local_set:
2172 switch (local_type) {
2173 case ST_32: opcodes[pc->opcode] = Op_local_set_32; break;
2174 case ST_64: opcodes[pc->opcode] = Op_local_set_64; break;
2175 }
2176 break;
2177
2178 case WasmOp_local_tee:
2179 switch (local_type) {
2180 case ST_32: opcodes[pc->opcode] = Op_local_tee_32; break;
2181 case ST_64: opcodes[pc->opcode] = Op_local_tee_64; break;
2182 }
2183 break;
2184
2185 default: panic("unexpected opcode");
2186 }
2187 pc->opcode += 1;
2188 operands[pc->operand] = stack->top_offset - stack->offsets[local_idx];
2189 pc->operand += 1;
2190 switch (opcode) {
2191 case WasmOp_local_get:
2192 si_push(stack, local_type);
2193 break;
2194
2195 case WasmOp_local_set:
2196 si_pop(stack, local_type);
2197 break;
2198
2199 case WasmOp_local_tee:
2200 si_pop(stack, local_type);
2201 si_push(stack, local_type);
2202 break;
2203
2204 default: panic("unexpected opcode");
2205 }
2206 }
2207 }
2208 break;
2209
2210 case WasmOp_global_get:
2211 case WasmOp_global_set:
2212 {
2213 uint32_t global_idx = read32_uleb128(mod_ptr, code_i);
2214 if (unreachable_depth == 0) {
2215 enum StackType global_type = ST_32; // all globals assumed to be 32-bit
2216 switch (opcode) {
2217 case WasmOp_global_get:
2218 switch (global_idx) {
2219 case 0: opcodes[pc->opcode] = Op_global_get_0_32; break;
2220 default: opcodes[pc->opcode] = Op_global_get_32; break;
2221 }
2222 break;
2223
2224 case WasmOp_global_set:
2225 switch (global_idx) {
2226 case 0: opcodes[pc->opcode] = Op_global_set_0_32; break;
2227 default: opcodes[pc->opcode] = Op_global_set_32; break;
2228 }
2229 break;
2230
2231 default: panic("unexpected opcode");
2232 }
2233 pc->opcode += 1;
2234 if (global_idx != 0) {
2235 operands[pc->operand] = global_idx;
2236 pc->operand += 1;
2237 }
2238 switch (opcode) {
2239 case WasmOp_global_get:
2240 si_push(stack, global_type);
2241 break;
2242
2243 case WasmOp_global_set:
2244 si_pop(stack, global_type);
2245 break;
2246
2247 default: panic("unexpected opcode");
2248 }
2249 }
2250 }
2251 break;
2252
2253 case WasmOp_i32_load:
2254 case WasmOp_i64_load:
2255 case WasmOp_f32_load:
2256 case WasmOp_f64_load:
2257 case WasmOp_i32_load8_s:
2258 case WasmOp_i32_load8_u:
2259 case WasmOp_i32_load16_s:
2260 case WasmOp_i32_load16_u:
2261 case WasmOp_i64_load8_s:
2262 case WasmOp_i64_load8_u:
2263 case WasmOp_i64_load16_s:
2264 case WasmOp_i64_load16_u:
2265 case WasmOp_i64_load32_s:
2266 case WasmOp_i64_load32_u:
2267 case WasmOp_i32_store:
2268 case WasmOp_i64_store:
2269 case WasmOp_f32_store:
2270 case WasmOp_f64_store:
2271 case WasmOp_i32_store8:
2272 case WasmOp_i32_store16:
2273 case WasmOp_i64_store8:
2274 case WasmOp_i64_store16:
2275 case WasmOp_i64_store32:
2276 {
2277 uint32_t alignment = read32_uleb128(mod_ptr, code_i);
2278 uint32_t offset = read32_uleb128(mod_ptr, code_i);
2279 (void)alignment;
2280 if (unreachable_depth == 0) {
2281 switch (opcode) {
2282 default: break;
2283
2284 case WasmOp_i64_store8: case WasmOp_i64_store16: case WasmOp_i64_store32:
2285 opcodes[pc->opcode] = Op_drop_32;
2286 pc->opcode += 1;
2287 break;
2288 }
2289 switch (opcode) {
2290 case WasmOp_i32_load8_s: case WasmOp_i32_load8_u:
2291 case WasmOp_i64_load8_s: case WasmOp_i64_load8_u:
2292 switch (offset) {
2293 case 0: opcodes[pc->opcode] = Op_load_0_8; break;
2294 default: opcodes[pc->opcode] = Op_load_8; break;
2295 }
2296 break;
2297
2298 case WasmOp_i32_load16_s: case WasmOp_i32_load16_u:
2299 case WasmOp_i64_load16_s: case WasmOp_i64_load16_u:
2300 switch (offset) {
2301 case 0: opcodes[pc->opcode] = Op_load_0_16; break;
2302 default: opcodes[pc->opcode] = Op_load_16; break;
2303 }
2304 break;
2305
2306 case WasmOp_i32_load: case WasmOp_f32_load:
2307 case WasmOp_i64_load32_s: case WasmOp_i64_load32_u:
2308 switch (offset) {
2309 case 0: opcodes[pc->opcode] = Op_load_0_32; break;
2310 default: opcodes[pc->opcode] = Op_load_32; break;
2311 }
2312 break;
2313
2314 case WasmOp_i64_load: case WasmOp_f64_load:
2315 switch (offset) {
2316 case 0: opcodes[pc->opcode] = Op_load_0_64; break;
2317 default: opcodes[pc->opcode] = Op_load_64; break;
2318 }
2319 break;
2320
2321 case WasmOp_i32_store8: case WasmOp_i64_store8:
2322 switch (offset) {
2323 case 0: opcodes[pc->opcode] = Op_store_0_8; break;
2324 default: opcodes[pc->opcode] = Op_store_8; break;
2325 }
2326 break;
2327
2328 case WasmOp_i32_store16: case WasmOp_i64_store16:
2329 switch (offset) {
2330 case 0: opcodes[pc->opcode] = Op_store_0_16; break;
2331 default: opcodes[pc->opcode] = Op_store_16; break;
2332 }
2333 break;
2334
2335 case WasmOp_i32_store: case WasmOp_f32_store: case WasmOp_i64_store32:
2336 switch (offset) {
2337 case 0: opcodes[pc->opcode] = Op_store_0_32; break;
2338 default: opcodes[pc->opcode] = Op_store_32; break;
2339 }
2340 break;
2341
2342 case WasmOp_i64_store: case WasmOp_f64_store:
2343 switch (offset) {
2344 case 0: opcodes[pc->opcode] = Op_store_0_64; break;
2345 default: opcodes[pc->opcode] = Op_store_64; break;
2346 }
2347 break;
2348
2349 default: panic("unexpected opcode");
2350 }
2351 pc->opcode += 1;
2352 switch (offset) {
2353 case 0: break;
2354
2355 default:
2356 operands[pc->operand] = offset;
2357 pc->operand += 1;
2358 break;
2359 }
2360 switch (opcode) {
2361 default: break;
2362
2363 case WasmOp_i32_load8_s: case WasmOp_i64_load8_s:
2364 opcodes[pc->opcode] = Op_sext8_32;
2365 pc->opcode += 1;
2366 break;
2367
2368 case WasmOp_i32_load16_s: case WasmOp_i64_load16_s:
2369 opcodes[pc->opcode] = Op_sext16_32;
2370 pc->opcode += 1;
2371 break;
2372 }
2373 switch (opcode) {
2374 default: break;
2375
2376 case WasmOp_i64_load8_s: case WasmOp_i64_load16_s: case WasmOp_i64_load32_s:
2377 opcodes[pc->opcode] = Op_sext_64_32;
2378 pc->opcode += 1;
2379 break;
2380
2381 case WasmOp_i64_load8_u: case WasmOp_i64_load16_u: case WasmOp_i64_load32_u:
2382 opcodes[pc->opcode] = Op_zext_64_32;
2383 pc->opcode += 1;
2384 break;
2385 }
2386 }
2387 }
2388 break;
2389
2390 case WasmOp_memory_size:
2391 case WasmOp_memory_grow:
2392 {
2393 if (mod_ptr[*code_i] != 0) panic("unexpected memory index");
2394 *code_i += 1;
2395 if (unreachable_depth == 0) {
2396 switch (opcode) {
2397 case WasmOp_memory_size: opcodes[pc->opcode] = Op_mem_size; break;
2398 case WasmOp_memory_grow: opcodes[pc->opcode] = Op_mem_grow; break;
2399 default: panic("unexpected opcode");
2400 }
2401 pc->opcode += 1;
2402 }
2403 }
2404 break;
2405
2406 case WasmOp_i32_const:
2407 case WasmOp_f32_const:
2408 {
2409 uint32_t value;
2410 switch (opcode) {
2411 case WasmOp_i32_const: value = read32_ileb128(mod_ptr, code_i); break;
2412
2413 case WasmOp_f32_const:
2414 value = read_u32_le(&mod_ptr[*code_i]);
2415 *code_i += sizeof(value);
2416 break;
2417
2418 default: panic("unexpected opcode");
2419 }
2420 if (unreachable_depth == 0) {
2421 switch (value) {
2422 case 0: opcodes[pc->opcode] = Op_const_0_32; break;
2423 case 1: opcodes[pc->opcode] = Op_const_1_32; break;
2424
2425 default:
2426 opcodes[pc->opcode] = Op_const_32;
2427 operands[pc->operand] = value;
2428 pc->operand += 1;
2429 break;
2430
2431 case UINT32_MAX: opcodes[pc->opcode] = Op_const_umax_32; break;
2432 }
2433 pc->opcode += 1;
2434 }
2435 }
2436 break;
2437
2438 case WasmOp_i64_const:
2439 case WasmOp_f64_const:
2440 {
2441 uint64_t value;
2442 switch (opcode) {
2443 case WasmOp_i64_const: value = read64_ileb128(mod_ptr, code_i); break;
2444
2445 case WasmOp_f64_const:
2446 value = read_u64_le(&mod_ptr[*code_i]);
2447 *code_i += sizeof(value);
2448 break;
2449
2450 default: panic("unexpected opcode");
2451 }
2452
2453 if (unreachable_depth == 0) {
2454 switch (value) {
2455 case 0: opcodes[pc->opcode] = Op_const_0_64; break;
2456 case 1: opcodes[pc->opcode] = Op_const_1_64; break;
2457
2458 default:
2459 opcodes[pc->opcode] = Op_const_64;
2460 operands[pc->operand + 0] = (uint32_t)(value >> 0);
2461 operands[pc->operand + 1] = (uint32_t)(value >> 32);
2462 pc->operand += 2;
2463 break;
2464
2465 case UINT64_MAX: opcodes[pc->opcode] = Op_const_umax_64; break;
2466 }
2467 pc->opcode += 1;
2468 }
2469 }
2470 break;
2471
2472 default:
2473 if (unreachable_depth == 0) {
2474 switch (opcode) {
2475 case WasmOp_i32_eqz: opcodes[pc->opcode] = Op_eqz_32; break;
2476 case WasmOp_i32_eq: opcodes[pc->opcode] = Op_eq_32; break;
2477 case WasmOp_i32_ne: opcodes[pc->opcode] = Op_ne_32; break;
2478 case WasmOp_i32_lt_s: opcodes[pc->opcode] = Op_slt_32; break;
2479 case WasmOp_i32_lt_u: opcodes[pc->opcode] = Op_ult_32; break;
2480 case WasmOp_i32_gt_s: opcodes[pc->opcode] = Op_sgt_32; break;
2481 case WasmOp_i32_gt_u: opcodes[pc->opcode] = Op_ugt_32; break;
2482 case WasmOp_i32_le_s: opcodes[pc->opcode] = Op_sle_32; break;
2483 case WasmOp_i32_le_u: opcodes[pc->opcode] = Op_ule_32; break;
2484 case WasmOp_i32_ge_s: opcodes[pc->opcode] = Op_sge_32; break;
2485 case WasmOp_i32_ge_u: opcodes[pc->opcode] = Op_uge_32; break;
2486 case WasmOp_i64_eqz: opcodes[pc->opcode] = Op_eqz_64; break;
2487 case WasmOp_i64_eq: opcodes[pc->opcode] = Op_eq_64; break;
2488 case WasmOp_i64_ne: opcodes[pc->opcode] = Op_ne_64; break;
2489 case WasmOp_i64_lt_s: opcodes[pc->opcode] = Op_slt_64; break;
2490 case WasmOp_i64_lt_u: opcodes[pc->opcode] = Op_ult_64; break;
2491 case WasmOp_i64_gt_s: opcodes[pc->opcode] = Op_sgt_64; break;
2492 case WasmOp_i64_gt_u: opcodes[pc->opcode] = Op_ugt_64; break;
2493 case WasmOp_i64_le_s: opcodes[pc->opcode] = Op_sle_64; break;
2494 case WasmOp_i64_le_u: opcodes[pc->opcode] = Op_ule_64; break;
2495 case WasmOp_i64_ge_s: opcodes[pc->opcode] = Op_sge_64; break;
2496 case WasmOp_i64_ge_u: opcodes[pc->opcode] = Op_uge_64; break;
2497 case WasmOp_f32_eq: opcodes[pc->opcode] = Op_feq_32; break;
2498 case WasmOp_f32_ne: opcodes[pc->opcode] = Op_fne_32; break;
2499 case WasmOp_f32_lt: opcodes[pc->opcode] = Op_flt_32; break;
2500 case WasmOp_f32_gt: opcodes[pc->opcode] = Op_fgt_32; break;
2501 case WasmOp_f32_le: opcodes[pc->opcode] = Op_fle_32; break;
2502 case WasmOp_f32_ge: opcodes[pc->opcode] = Op_fge_32; break;
2503 case WasmOp_f64_eq: opcodes[pc->opcode] = Op_feq_64; break;
2504 case WasmOp_f64_ne: opcodes[pc->opcode] = Op_fne_64; break;
2505 case WasmOp_f64_lt: opcodes[pc->opcode] = Op_flt_64; break;
2506 case WasmOp_f64_gt: opcodes[pc->opcode] = Op_fgt_64; break;
2507 case WasmOp_f64_le: opcodes[pc->opcode] = Op_fle_64; break;
2508 case WasmOp_f64_ge: opcodes[pc->opcode] = Op_fge_64; break;
2509 case WasmOp_i32_clz: opcodes[pc->opcode] = Op_clz_32; break;
2510 case WasmOp_i32_ctz: opcodes[pc->opcode] = Op_ctz_32; break;
2511 case WasmOp_i32_popcnt: opcodes[pc->opcode] = Op_popcnt_32; break;
2512 case WasmOp_i32_add: opcodes[pc->opcode] = Op_add_32; break;
2513 case WasmOp_i32_sub: opcodes[pc->opcode] = Op_sub_32; break;
2514 case WasmOp_i32_mul: opcodes[pc->opcode] = Op_mul_32; break;
2515 case WasmOp_i32_div_s: opcodes[pc->opcode] = Op_sdiv_32; break;
2516 case WasmOp_i32_div_u: opcodes[pc->opcode] = Op_udiv_32; break;
2517 case WasmOp_i32_rem_s: opcodes[pc->opcode] = Op_srem_32; break;
2518 case WasmOp_i32_rem_u: opcodes[pc->opcode] = Op_urem_32; break;
2519 case WasmOp_i32_and: opcodes[pc->opcode] = Op_and_32; break;
2520 case WasmOp_i32_or: opcodes[pc->opcode] = Op_or_32; break;
2521 case WasmOp_i32_xor: opcodes[pc->opcode] = Op_xor_32; break;
2522 case WasmOp_i32_shl: opcodes[pc->opcode] = Op_shl_32; break;
2523 case WasmOp_i32_shr_s: opcodes[pc->opcode] = Op_ashr_32; break;
2524 case WasmOp_i32_shr_u: opcodes[pc->opcode] = Op_lshr_32; break;
2525 case WasmOp_i32_rotl: opcodes[pc->opcode] = Op_rol_32; break;
2526 case WasmOp_i32_rotr: opcodes[pc->opcode] = Op_ror_32; break;
2527 case WasmOp_i64_clz: opcodes[pc->opcode] = Op_clz_64; break;
2528 case WasmOp_i64_ctz: opcodes[pc->opcode] = Op_ctz_64; break;
2529 case WasmOp_i64_popcnt: opcodes[pc->opcode] = Op_popcnt_64; break;
2530 case WasmOp_i64_add: opcodes[pc->opcode] = Op_add_64; break;
2531 case WasmOp_i64_sub: opcodes[pc->opcode] = Op_sub_64; break;
2532 case WasmOp_i64_mul: opcodes[pc->opcode] = Op_mul_64; break;
2533 case WasmOp_i64_div_s: opcodes[pc->opcode] = Op_sdiv_64; break;
2534 case WasmOp_i64_div_u: opcodes[pc->opcode] = Op_udiv_64; break;
2535 case WasmOp_i64_rem_s: opcodes[pc->opcode] = Op_srem_64; break;
2536 case WasmOp_i64_rem_u: opcodes[pc->opcode] = Op_urem_64; break;
2537 case WasmOp_i64_and: opcodes[pc->opcode] = Op_and_64; break;
2538 case WasmOp_i64_or: opcodes[pc->opcode] = Op_or_64; break;
2539 case WasmOp_i64_xor: opcodes[pc->opcode] = Op_xor_64; break;
2540 case WasmOp_i64_shl: opcodes[pc->opcode] = Op_shl_64; break;
2541 case WasmOp_i64_shr_s: opcodes[pc->opcode] = Op_ashr_64; break;
2542 case WasmOp_i64_shr_u: opcodes[pc->opcode] = Op_lshr_64; break;
2543 case WasmOp_i64_rotl: opcodes[pc->opcode] = Op_rol_64; break;
2544 case WasmOp_i64_rotr: opcodes[pc->opcode] = Op_ror_64; break;
2545 case WasmOp_f32_abs: opcodes[pc->opcode] = Op_fabs_32; break;
2546 case WasmOp_f32_neg: opcodes[pc->opcode] = Op_fneg_32; break;
2547 case WasmOp_f32_ceil: opcodes[pc->opcode] = Op_ceil_32; break;
2548 case WasmOp_f32_floor: opcodes[pc->opcode] = Op_floor_32; break;
2549 case WasmOp_f32_trunc: opcodes[pc->opcode] = Op_trunc_32; break;
2550 case WasmOp_f32_nearest: opcodes[pc->opcode] = Op_nearest_32; break;
2551 case WasmOp_f32_sqrt: opcodes[pc->opcode] = Op_sqrt_32; break;
2552 case WasmOp_f32_add: opcodes[pc->opcode] = Op_fadd_32; break;
2553 case WasmOp_f32_sub: opcodes[pc->opcode] = Op_fsub_32; break;
2554 case WasmOp_f32_mul: opcodes[pc->opcode] = Op_fmul_32; break;
2555 case WasmOp_f32_div: opcodes[pc->opcode] = Op_fdiv_32; break;
2556 case WasmOp_f32_min: opcodes[pc->opcode] = Op_fmin_32; break;
2557 case WasmOp_f32_max: opcodes[pc->opcode] = Op_fmax_32; break;
2558 case WasmOp_f32_copysign: opcodes[pc->opcode] = Op_copysign_32; break;
2559 case WasmOp_f64_abs: opcodes[pc->opcode] = Op_fabs_64; break;
2560 case WasmOp_f64_neg: opcodes[pc->opcode] = Op_fneg_64; break;
2561 case WasmOp_f64_ceil: opcodes[pc->opcode] = Op_ceil_64; break;
2562 case WasmOp_f64_floor: opcodes[pc->opcode] = Op_floor_64; break;
2563 case WasmOp_f64_trunc: opcodes[pc->opcode] = Op_trunc_64; break;
2564 case WasmOp_f64_nearest: opcodes[pc->opcode] = Op_nearest_64; break;
2565 case WasmOp_f64_sqrt: opcodes[pc->opcode] = Op_sqrt_64; break;
2566 case WasmOp_f64_add: opcodes[pc->opcode] = Op_fadd_64; break;
2567 case WasmOp_f64_sub: opcodes[pc->opcode] = Op_fsub_64; break;
2568 case WasmOp_f64_mul: opcodes[pc->opcode] = Op_fmul_64; break;
2569 case WasmOp_f64_div: opcodes[pc->opcode] = Op_fdiv_64; break;
2570 case WasmOp_f64_min: opcodes[pc->opcode] = Op_fmin_64; break;
2571 case WasmOp_f64_max: opcodes[pc->opcode] = Op_fmax_64; break;
2572 case WasmOp_f64_copysign: opcodes[pc->opcode] = Op_copysign_64; break;
2573 case WasmOp_i32_wrap_i64: opcodes[pc->opcode] = Op_wrap_32_64; break;
2574 case WasmOp_i32_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_32_32; break;
2575 case WasmOp_i32_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_32_32; break;
2576 case WasmOp_i32_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_32_64; break;
2577 case WasmOp_i32_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_32_64; break;
2578 case WasmOp_i64_extend_i32_s: opcodes[pc->opcode] = Op_sext_64_32; break;
2579 case WasmOp_i64_extend_i32_u: opcodes[pc->opcode] = Op_zext_64_32; break;
2580 case WasmOp_i64_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_64_32; break;
2581 case WasmOp_i64_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_64_32; break;
2582 case WasmOp_i64_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_64_64; break;
2583 case WasmOp_i64_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_64_64; break;
2584 case WasmOp_f32_convert_i32_s: opcodes[pc->opcode] = Op_stof_32_32; break;
2585 case WasmOp_f32_convert_i32_u: opcodes[pc->opcode] = Op_utof_32_32; break;
2586 case WasmOp_f32_convert_i64_s: opcodes[pc->opcode] = Op_stof_32_64; break;
2587 case WasmOp_f32_convert_i64_u: opcodes[pc->opcode] = Op_utof_32_64; break;
2588 case WasmOp_f32_demote_f64: opcodes[pc->opcode] = Op_ftof_32_64; break;
2589 case WasmOp_f64_convert_i32_s: opcodes[pc->opcode] = Op_stof_64_32; break;
2590 case WasmOp_f64_convert_i32_u: opcodes[pc->opcode] = Op_utof_64_32; break;
2591 case WasmOp_f64_convert_i64_s: opcodes[pc->opcode] = Op_stof_64_64; break;
2592 case WasmOp_f64_convert_i64_u: opcodes[pc->opcode] = Op_utof_64_64; break;
2593 case WasmOp_f64_promote_f32: opcodes[pc->opcode] = Op_ftof_64_32; break;
2594 case WasmOp_i32_extend8_s: opcodes[pc->opcode] = Op_sext8_32; break;
2595 case WasmOp_i32_extend16_s: opcodes[pc->opcode] = Op_sext16_32; break;
2596 case WasmOp_i64_extend8_s: opcodes[pc->opcode] = Op_sext8_64; break;
2597 case WasmOp_i64_extend16_s: opcodes[pc->opcode] = Op_sext16_64; break;
2598 case WasmOp_i64_extend32_s: opcodes[pc->opcode] = Op_sext32_64; break;
2599 default: panic("unexpected opcode");
2600 }
2601 pc->opcode += 1;
2602 }
2603 break;
2604
2605 case WasmOp_prefixed:
2606 switch (prefixed_opcode) {
2607 case WasmPrefixedOp_memory_copy:
2608 if (mod_ptr[*code_i + 0] != 0 || mod_ptr[*code_i + 1] != 0)
2609 panic("unexpected memory index");
2610 *code_i += 2;
2611 if (unreachable_depth == 0) {
2612 opcodes[pc->opcode] = Op_memcpy;
2613 pc->opcode += 1;
2614 }
2615 break;
2616
2617 case WasmPrefixedOp_memory_fill:
2618 if (mod_ptr[*code_i] != 0) panic("unexpected memory index");
2619 *code_i += 1;
2620 if (unreachable_depth == 0) {
2621 opcodes[pc->opcode] = Op_memset;
2622 pc->opcode += 1;
2623 }
2624 break;
2625
2626 default: panic("unexpected opcode");
2627 }
2628 break;
2629 }
2630 switch (opcode) {
2631 default: state = State_default; break;
2632 case WasmOp_i32_eqz: state = State_bool_not; break;
2633 }
2634
2635 //for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) {
2636 // fprintf(stderr, "decoded opcode[%u] = %u\n", i, opcodes[i]);
2637 //}
2638 //for (uint32_t i = old_pc.operand; i < pc->operand; i += 1) {
2639 // fprintf(stderr, "decoded operand[%u] = %u\n", i, operands[i]);
2640 //}
2641 }
2642}
2643
2644static void vm_push_u32(struct VirtualMachine *vm, uint32_t value) {
2645 vm->stack[vm->stack_top + 0] = value;
2646 vm->stack_top += 1;
2647}
2648
2649static void vm_push_i32(struct VirtualMachine *vm, int32_t value) {
2650 vm_push_u32(vm, (uint32_t)value);
2651}
2652
2653static void vm_push_u64(struct VirtualMachine *vm, uint64_t value) {
2654 vm->stack[vm->stack_top + 0] = (uint32_t)(value >> 0);
2655 vm->stack[vm->stack_top + 1] = (uint32_t)(value >> 32);
2656 vm->stack_top += 2;
2657}
2658
2659static void vm_push_i64(struct VirtualMachine *vm, int64_t value) {
2660 vm_push_u64(vm, (uint64_t)value);
2661}
2662
2663static void vm_push_f32(struct VirtualMachine *vm, float value) {
2664 uint32_t integer;
2665 memcpy(&integer, &value, sizeof(integer));
2666 vm_push_u32(vm, integer);
2667}
2668
2669static void vm_push_f64(struct VirtualMachine *vm, double value) {
2670 uint64_t integer;
2671 memcpy(&integer, &value, sizeof(integer));
2672 vm_push_u64(vm, integer);
2673}
2674
2675static uint32_t vm_pop_u32(struct VirtualMachine *vm) {
2676 vm->stack_top -= 1;
2677 return vm->stack[vm->stack_top + 0];
2678}
2679
2680static int32_t vm_pop_i32(struct VirtualMachine *vm) {
2681 return (int32_t)vm_pop_u32(vm);
2682}
2683
2684static uint64_t vm_pop_u64(struct VirtualMachine *vm) {
2685 vm->stack_top -= 2;
2686 return vm->stack[vm->stack_top + 0] | (uint64_t)vm->stack[vm->stack_top + 1] << 32;
2687}
2688
2689static int64_t vm_pop_i64(struct VirtualMachine *vm) {
2690 return (int64_t)vm_pop_u64(vm);
2691}
2692
2693static float vm_pop_f32(struct VirtualMachine *vm) {
2694 uint32_t integer = vm_pop_u32(vm);
2695 float result;
2696 memcpy(&result, &integer, sizeof(result));
2697 return result;
2698}
2699
2700static double vm_pop_f64(struct VirtualMachine *vm) {
2701 uint64_t integer = vm_pop_u64(vm);
2702 double result;
2703 memcpy(&result, &integer, sizeof(result));
2704 return result;
2705}
2706
2707static void vm_callImport(struct VirtualMachine *vm, const struct Import *import) {
2708 switch (import->mod) {
2709 case ImpMod_wasi_snapshot_preview1: switch (import->name) {
2710 case ImpName_fd_prestat_get:
2711 {
2712 uint32_t buf = vm_pop_u32(vm);
2713 int32_t fd = vm_pop_i32(vm);
2714 vm_push_u32(vm, wasi_fd_prestat_get(vm, fd, buf));
2715 }
2716 break;
2717 case ImpName_fd_prestat_dir_name:
2718 {
2719 uint32_t path_len = vm_pop_u32(vm);
2720 uint32_t path = vm_pop_u32(vm);
2721 int32_t fd = vm_pop_i32(vm);
2722 vm_push_u32(vm, wasi_fd_prestat_dir_name(vm, fd, path, path_len));
2723 }
2724 break;
2725 case ImpName_fd_close:
2726 {
2727 int32_t fd = vm_pop_i32(vm);
2728 vm_push_u32(vm, wasi_fd_close(vm, fd));
2729 }
2730 break;
2731 case ImpName_fd_read:
2732 {
2733 uint32_t nread = vm_pop_u32(vm);
2734 uint32_t iovs_len = vm_pop_u32(vm);
2735 uint32_t iovs = vm_pop_u32(vm);
2736 int32_t fd = vm_pop_i32(vm);
2737 vm_push_u32(vm, wasi_fd_read(vm, fd, iovs, iovs_len, nread));
2738 }
2739 break;
2740 case ImpName_fd_filestat_get:
2741 {
2742 uint32_t buf = vm_pop_u32(vm);
2743 int32_t fd = vm_pop_i32(vm);
2744 vm_push_u32(vm, wasi_fd_filestat_get(vm, fd, buf));
2745 }
2746 break;
2747 case ImpName_fd_filestat_set_size:
2748 {
2749 uint64_t size = vm_pop_u64(vm);
2750 int32_t fd = vm_pop_i32(vm);
2751 vm_push_u32(vm, wasi_fd_filestat_set_size(vm, fd, size));
2752 }
2753 break;
2754 case ImpName_fd_filestat_set_times:
2755 {
2756 panic("unexpected call to fd_filestat_set_times");
2757 }
2758 break;
2759 case ImpName_fd_fdstat_get:
2760 {
2761 uint32_t buf = vm_pop_u32(vm);
2762 int32_t fd = vm_pop_i32(vm);
2763 vm_push_u32(vm, wasi_fd_fdstat_get(vm, fd, buf));
2764 }
2765 break;
2766 case ImpName_fd_readdir:
2767 {
2768 panic("unexpected call to fd_readdir");
2769 }
2770 break;
2771 case ImpName_fd_write:
2772 {
2773 uint32_t nwritten = vm_pop_u32(vm);
2774 uint32_t iovs_len = vm_pop_u32(vm);
2775 uint32_t iovs = vm_pop_u32(vm);
2776 int32_t fd = vm_pop_i32(vm);
2777 vm_push_u32(vm, wasi_fd_write(vm, fd, iovs, iovs_len, nwritten));
2778 }
2779 break;
2780 case ImpName_fd_pwrite:
2781 {
2782 uint32_t nwritten = vm_pop_u32(vm);
2783 uint64_t offset = vm_pop_u64(vm);
2784 uint32_t iovs_len = vm_pop_u32(vm);
2785 uint32_t iovs = vm_pop_u32(vm);
2786 int32_t fd = vm_pop_i32(vm);
2787 vm_push_u32(vm, wasi_fd_pwrite(vm, fd, iovs, iovs_len, offset, nwritten));
2788 }
2789 break;
2790 case ImpName_proc_exit:
2791 {
2792 uint32_t code = vm_pop_u32(vm);
2793 exit(code);
2794 }
2795 break;
2796 case ImpName_args_sizes_get:
2797 {
2798 uint32_t argv_buf_size = vm_pop_u32(vm);
2799 uint32_t argc = vm_pop_u32(vm);
2800 vm_push_u32(vm, wasi_args_sizes_get(vm, argc, argv_buf_size));
2801 }
2802 break;
2803 case ImpName_args_get:
2804 {
2805 uint32_t argv_buf = vm_pop_u32(vm);
2806 uint32_t argv = vm_pop_u32(vm);
2807 vm_push_u32(vm, wasi_args_get(vm, argv, argv_buf));
2808 }
2809 break;
2810 case ImpName_random_get:
2811 {
2812 uint32_t buf_len = vm_pop_u32(vm);
2813 uint32_t buf = vm_pop_u32(vm);
2814 vm_push_u32(vm, wasi_random_get(vm, buf, buf_len));
2815 }
2816 break;
2817 case ImpName_environ_sizes_get:
2818 {
2819 panic("unexpected call to environ_sizes_get");
2820 }
2821 break;
2822 case ImpName_environ_get:
2823 {
2824 panic("unexpected call to environ_get");
2825 }
2826 break;
2827 case ImpName_path_filestat_get:
2828 {
2829 uint32_t buf = vm_pop_u32(vm);
2830 uint32_t path_len = vm_pop_u32(vm);
2831 uint32_t path = vm_pop_u32(vm);
2832 uint32_t flags = vm_pop_u32(vm);
2833 int32_t fd = vm_pop_i32(vm);
2834 vm_push_u32(vm, wasi_path_filestat_get(vm, fd, flags, path, path_len, buf));
2835 }
2836 break;
2837 case ImpName_path_create_directory:
2838 {
2839 uint32_t path_len = vm_pop_u32(vm);
2840 uint32_t path = vm_pop_u32(vm);
2841 int32_t fd = vm_pop_i32(vm);
2842 vm_push_u32(vm, wasi_path_create_directory(vm, fd, path, path_len));
2843 }
2844 break;
2845 case ImpName_path_rename:
2846 {
2847 uint32_t new_path_len = vm_pop_u32(vm);
2848 uint32_t new_path = vm_pop_u32(vm);
2849 int32_t new_fd = vm_pop_i32(vm);
2850 uint32_t old_path_len = vm_pop_u32(vm);
2851 uint32_t old_path = vm_pop_u32(vm);
2852 int32_t old_fd = vm_pop_i32(vm);
2853 vm_push_u32(vm, wasi_path_rename(
2854 vm,
2855 old_fd,
2856 old_path,
2857 old_path_len,
2858 new_fd,
2859 new_path,
2860 new_path_len
2861 ));
2862 }
2863 break;
2864 case ImpName_path_open:
2865 {
2866 uint32_t fd = vm_pop_u32(vm);
2867 uint32_t fs_flags = vm_pop_u32(vm);
2868 uint64_t fs_rights_inheriting = vm_pop_u64(vm);
2869 uint64_t fs_rights_base = vm_pop_u64(vm);
2870 uint32_t oflags = vm_pop_u32(vm);
2871 uint32_t path_len = vm_pop_u32(vm);
2872 uint32_t path = vm_pop_u32(vm);
2873 uint32_t dirflags = vm_pop_u32(vm);
2874 int32_t dirfd = vm_pop_i32(vm);
2875 vm_push_u32(vm, wasi_path_open(
2876 vm,
2877 dirfd,
2878 dirflags,
2879 path,
2880 path_len,
2881 oflags,
2882 fs_rights_base,
2883 fs_rights_inheriting,
2884 fs_flags,
2885 fd
2886 ));
2887 }
2888 break;
2889 case ImpName_path_remove_directory:
2890 {
2891 panic("unexpected call to path_remove_directory");
2892 }
2893 break;
2894 case ImpName_path_unlink_file:
2895 {
2896 panic("unexpected call to path_unlink_file");
2897 }
2898 break;
2899 case ImpName_clock_time_get:
2900 {
2901 uint32_t timestamp = vm_pop_u32(vm);
2902 uint64_t precision = vm_pop_u64(vm);
2903 uint32_t clock_id = vm_pop_u32(vm);
2904 vm_push_u32(vm, wasi_clock_time_get(vm, clock_id, precision, timestamp));
2905 }
2906 break;
2907 case ImpName_fd_pread:
2908 {
2909 panic("unexpected call to fd_pread");
2910 }
2911 break;
2912 case ImpName_debug:
2913 {
2914 uint64_t number = vm_pop_u64(vm);
2915 uint32_t text = vm_pop_u32(vm);
2916 wasi_debug(vm, text, number);
2917 }
2918 break;
2919 case ImpName_debug_slice:
2920 {
2921 uint32_t len = vm_pop_u32(vm);
2922 uint32_t ptr = vm_pop_u32(vm);
2923 wasi_debug_slice(vm, ptr, len);
2924 }
2925 break;
2926 }
2927 break;
2928 }
2929}
2930
2931static void vm_call(struct VirtualMachine *vm, const struct Function *func) {
2932 //struct TypeInfo *type_info = &vm->types[func->type_idx];
2933 //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_size: %u\n",
2934 // func->id, type_info->param_count, type_info->result_count, func->locals_size);
2935
2936 // Push zeroed locals to stack
2937 memset(&vm->stack[vm->stack_top], 0, func->locals_size * sizeof(uint32_t));
2938 vm->stack_top += func->locals_size;
2939
2940 vm_push_u32(vm, vm->pc.opcode);
2941 vm_push_u32(vm, vm->pc.operand);
2942
2943 vm->pc = func->entry_pc;
2944}
2945
2946static void vm_br_void(struct VirtualMachine *vm) {
2947 uint32_t stack_adjust = vm->operands[vm->pc.operand];
2948
2949 vm->stack_top -= stack_adjust;
2950
2951 vm->pc.opcode = vm->operands[vm->pc.operand + 1];
2952 vm->pc.operand = vm->operands[vm->pc.operand + 2];
2953}
2954
2955static void vm_br_u32(struct VirtualMachine *vm) {
2956 uint32_t stack_adjust = vm->operands[vm->pc.operand];
2957
2958 uint32_t result = vm_pop_u32(vm);
2959 vm->stack_top -= stack_adjust;
2960 vm_push_u32(vm, result);
2961
2962 vm->pc.opcode = vm->operands[vm->pc.operand + 1];
2963 vm->pc.operand = vm->operands[vm->pc.operand + 2];
2964}
2965
2966static void vm_br_u64(struct VirtualMachine *vm) {
2967 uint32_t stack_adjust = vm->operands[vm->pc.operand];
2968
2969 uint64_t result = vm_pop_u64(vm);
2970 vm->stack_top -= stack_adjust;
2971 vm_push_u64(vm, result);
2972
2973 vm->pc.opcode = vm->operands[vm->pc.operand + 1];
2974 vm->pc.operand = vm->operands[vm->pc.operand + 2];
2975}
2976
2977static void vm_return_void(struct VirtualMachine *vm) {
2978 uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
2979 uint32_t frame_size = vm->operands[vm->pc.operand + 1];
2980
2981 vm->stack_top -= stack_adjust;
2982 vm->pc.operand = vm_pop_u32(vm);
2983 vm->pc.opcode = vm_pop_u32(vm);
2984
2985 vm->stack_top -= frame_size;
2986}
2987
2988static void vm_return_u32(struct VirtualMachine *vm) {
2989 uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
2990 uint32_t frame_size = vm->operands[vm->pc.operand + 1];
2991
2992 uint32_t result = vm_pop_u32(vm);
2993
2994 vm->stack_top -= stack_adjust;
2995 vm->pc.operand = vm_pop_u32(vm);
2996 vm->pc.opcode = vm_pop_u32(vm);
2997
2998 vm->stack_top -= frame_size;
2999 vm_push_u32(vm, result);
3000}
3001
3002static void vm_return_u64(struct VirtualMachine *vm) {
3003 uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
3004 uint32_t frame_size = vm->operands[vm->pc.operand + 1];
3005
3006 uint64_t result = vm_pop_u64(vm);
3007
3008 vm->stack_top -= stack_adjust;
3009 vm->pc.operand = vm_pop_u32(vm);
3010 vm->pc.opcode = vm_pop_u32(vm);
3011
3012 vm->stack_top -= frame_size;
3013 vm_push_u64(vm, result);
3014}
3015
3016static void vm_run(struct VirtualMachine *vm) {
3017 uint8_t *opcodes = vm->opcodes;
3018 uint32_t *operands = vm->operands;
3019 struct ProgramCounter *pc = &vm->pc;
3020 uint32_t global_0 = vm->globals[0];
3021 for (;;) {
3022 enum Op op = opcodes[pc->opcode];
3023 //fprintf(stderr, "stack[%u:%u]=%x:%x pc=%x:%x op=%u\n",
3024 // vm->stack_top - 2, vm->stack_top - 1,
3025 // vm->stack[vm->stack_top - 2], vm->stack[vm->stack_top - 1],
3026 // pc->opcode, pc->operand, op);
3027 pc->opcode += 1;
3028 switch (op) {
3029 case Op_unreachable:
3030 panic("unreachable reached");
3031 case Op_br_void:
3032 vm_br_void(vm);
3033 break;
3034 case Op_br_32:
3035 vm_br_u32(vm);
3036 break;
3037 case Op_br_64:
3038 vm_br_u64(vm);
3039 break;
3040 case Op_br_nez_void:
3041 if (vm_pop_u32(vm) != 0) {
3042 vm_br_void(vm);
3043 } else {
3044 pc->operand += 3;
3045 }
3046 break;
3047 case Op_br_nez_32:
3048 if (vm_pop_u32(vm) != 0) {
3049 vm_br_u32(vm);
3050 } else {
3051 pc->operand += 3;
3052 }
3053 break;
3054 case Op_br_nez_64:
3055 if (vm_pop_u32(vm) != 0) {
3056 vm_br_u64(vm);
3057 } else {
3058 pc->operand += 3;
3059 }
3060 break;
3061 case Op_br_eqz_void:
3062 if (vm_pop_u32(vm) == 0) {
3063 vm_br_void(vm);
3064 } else {
3065 pc->operand += 3;
3066 }
3067 break;
3068 case Op_br_eqz_32:
3069 if (vm_pop_u32(vm) == 0) {
3070 vm_br_u32(vm);
3071 } else {
3072 pc->operand += 3;
3073 }
3074 break;
3075 case Op_br_eqz_64:
3076 if (vm_pop_u32(vm) == 0) {
3077 vm_br_u64(vm);
3078 } else {
3079 pc->operand += 3;
3080 }
3081 break;
3082 case Op_br_table_void:
3083 {
3084 uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
3085 pc->operand += 1 + index * 3;
3086 vm_br_void(vm);
3087 }
3088 break;
3089 case Op_br_table_32:
3090 {
3091 uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
3092 pc->operand += 1 + index * 3;
3093 vm_br_u32(vm);
3094 }
3095 break;
3096 case Op_br_table_64:
3097 {
3098 uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
3099 pc->operand += 1 + index * 3;
3100 vm_br_u64(vm);
3101 }
3102 break;
3103 case Op_return_void:
3104 vm_return_void(vm);
3105 break;
3106 case Op_return_32:
3107 vm_return_u32(vm);
3108 break;
3109 case Op_return_64:
3110 vm_return_u64(vm);
3111 break;
3112 case Op_call_import:
3113 {
3114 uint8_t import_idx = opcodes[pc->opcode];
3115 pc->opcode += 1;
3116 vm_callImport(vm, &vm->imports[import_idx]);
3117 }
3118 break;
3119 case Op_call_func:
3120 {
3121 uint32_t func_idx = operands[pc->operand];
3122 pc->operand += 1;
3123 vm_call(vm, &vm->functions[func_idx]);
3124 }
3125 break;
3126 case Op_call_indirect:
3127 {
3128 uint32_t fn_id = vm->table[vm_pop_u32(vm)];
3129 if (fn_id < vm->imports_len)
3130 vm_callImport(vm, &vm->imports[fn_id]);
3131 else
3132 vm_call(vm, &vm->functions[fn_id - vm->imports_len]);
3133 }
3134 break;
3135
3136 case Op_drop_32:
3137 vm->stack_top -= 1;
3138 break;
3139 case Op_drop_64:
3140 vm->stack_top -= 2;
3141 break;
3142 case Op_select_32:
3143 {
3144 uint32_t c = vm_pop_u32(vm);
3145 uint32_t b = vm_pop_u32(vm);
3146 uint32_t a = vm_pop_u32(vm);
3147 uint32_t result = (c != 0) ? a : b;
3148 vm_push_u32(vm, result);
3149 }
3150 break;
3151 case Op_select_64:
3152 {
3153 uint32_t c = vm_pop_u32(vm);
3154 uint64_t b = vm_pop_u64(vm);
3155 uint64_t a = vm_pop_u64(vm);
3156 uint64_t result = (c != 0) ? a : b;
3157 vm_push_u64(vm, result);
3158 }
3159 break;
3160
3161 case Op_local_get_32:
3162 {
3163 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3164 pc->operand += 1;
3165 vm_push_u32(vm, *local);
3166 }
3167 break;
3168 case Op_local_get_64:
3169 {
3170 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3171 pc->operand += 1;
3172 vm_push_u64(vm, local[0] | (uint64_t)local[1] << 32);
3173 }
3174 break;
3175 case Op_local_set_32:
3176 {
3177 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3178 pc->operand += 1;
3179 *local = vm_pop_u32(vm);
3180 }
3181 break;
3182 case Op_local_set_64:
3183 {
3184 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3185 pc->operand += 1;
3186 uint64_t value = vm_pop_u64(vm);
3187 local[0] = (uint32_t)(value >> 0);
3188 local[1] = (uint32_t)(value >> 32);
3189 }
3190 break;
3191 case Op_local_tee_32:
3192 {
3193 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3194 pc->operand += 1;
3195 *local = vm->stack[vm->stack_top - 1];
3196 }
3197 break;
3198 case Op_local_tee_64:
3199 {
3200 uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
3201 pc->operand += 1;
3202 local[0] = vm->stack[vm->stack_top - 2];
3203 local[1] = vm->stack[vm->stack_top - 1];
3204 }
3205 break;
3206
3207 case Op_global_get_0_32:
3208 vm_push_u32(vm, global_0);
3209 break;
3210 case Op_global_get_32:
3211 {
3212 uint32_t idx = operands[pc->operand];
3213 pc->operand += 1;
3214 vm_push_u32(vm, vm->globals[idx]);
3215 }
3216 break;
3217 case Op_global_set_0_32:
3218 global_0 = vm_pop_u32(vm);
3219 break;
3220 case Op_global_set_32:
3221 {
3222 uint32_t idx = operands[pc->operand];
3223 pc->operand += 1;
3224 vm->globals[idx] = vm_pop_u32(vm);
3225 }
3226 break;
3227
3228 case Op_load_0_8:
3229 {
3230 uint32_t address = vm_pop_u32(vm);
3231 vm_push_u32(vm, (uint8_t)vm->memory[address]);
3232 }
3233 break;
3234 case Op_load_8:
3235 {
3236 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3237 pc->operand += 1;
3238 vm_push_u32(vm, (uint8_t)vm->memory[address]);
3239 }
3240 break;
3241 case Op_load_0_16:
3242 {
3243 uint32_t address = vm_pop_u32(vm);
3244 vm_push_u32(vm, read_u16_le(&vm->memory[address]));
3245 }
3246 break;
3247 case Op_load_16:
3248 {
3249 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3250 pc->operand += 1;
3251 vm_push_u32(vm, read_u16_le(&vm->memory[address]));
3252 }
3253 break;
3254 case Op_load_0_32:
3255 {
3256 uint32_t address = vm_pop_u32(vm);
3257 vm_push_u32(vm, read_u32_le(&vm->memory[address]));
3258 }
3259 break;
3260 case Op_load_32:
3261 {
3262 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3263 pc->operand += 1;
3264 vm_push_u32(vm, read_u32_le(&vm->memory[address]));
3265 }
3266 break;
3267 case Op_load_0_64:
3268 {
3269 uint32_t address = vm_pop_u32(vm);
3270 vm_push_u64(vm, read_u64_le(&vm->memory[address]));
3271 }
3272 break;
3273 case Op_load_64:
3274 {
3275 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3276 pc->operand += 1;
3277 vm_push_u64(vm, read_u64_le(&vm->memory[address]));
3278 }
3279 break;
3280 case Op_store_0_8:
3281 {
3282 uint8_t value = (uint8_t)vm_pop_u32(vm);
3283 uint32_t address = vm_pop_u32(vm);
3284 vm->memory[address] = value;
3285 }
3286 break;
3287 case Op_store_8:
3288 {
3289 uint8_t value = (uint8_t)vm_pop_u32(vm);
3290 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3291 pc->operand += 1;
3292 vm->memory[address] = value;
3293 }
3294 break;
3295 case Op_store_0_16:
3296 {
3297 uint16_t value = (uint16_t)vm_pop_u32(vm);
3298 uint32_t address = vm_pop_u32(vm);
3299 write_u16_le(&vm->memory[address], value);
3300 }
3301 break;
3302 case Op_store_16:
3303 {
3304 uint16_t value = (uint16_t)vm_pop_u32(vm);
3305 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3306 pc->operand += 1;
3307 write_u16_le(&vm->memory[address], value);
3308 }
3309 break;
3310 case Op_store_0_32:
3311 {
3312 uint32_t value = vm_pop_u32(vm);
3313 uint32_t address = vm_pop_u32(vm);
3314 write_u32_le(&vm->memory[address], value);
3315 }
3316 break;
3317 case Op_store_32:
3318 {
3319 uint32_t value = vm_pop_u32(vm);
3320 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3321 pc->operand += 1;
3322 write_u32_le(&vm->memory[address], value);
3323 }
3324 break;
3325 case Op_store_0_64:
3326 {
3327 uint64_t value = vm_pop_u64(vm);
3328 uint32_t address = vm_pop_u32(vm);
3329 write_u64_le(&vm->memory[address], value);
3330 }
3331 break;
3332 case Op_store_64:
3333 {
3334 uint64_t value = vm_pop_u64(vm);
3335 uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
3336 pc->operand += 1;
3337 write_u64_le(&vm->memory[address], value);
3338 }
3339 break;
3340 case Op_mem_size:
3341 vm_push_u32(vm, vm->memory_len / wasm_page_size);
3342 break;
3343 case Op_mem_grow:
3344 {
3345 uint32_t page_count = vm_pop_u32(vm);
3346 uint32_t old_page_count = vm->memory_len / wasm_page_size;
3347 uint32_t new_len = vm->memory_len + page_count * wasm_page_size;
3348 if (new_len > max_memory) {
3349 vm_push_i32(vm, -1);
3350 } else {
3351 vm->memory_len = new_len;
3352 vm_push_u32(vm, old_page_count);
3353 }
3354 }
3355 break;
3356
3357 case Op_const_0_32:
3358 vm_push_i32(vm, 0);
3359 break;
3360 case Op_const_0_64:
3361 vm_push_i64(vm, 0);
3362 break;
3363 case Op_const_1_32:
3364 vm_push_i32(vm, 1);
3365 break;
3366 case Op_const_1_64:
3367 vm_push_i64(vm, 1);
3368 break;
3369 case Op_const_32:
3370 {
3371 uint32_t value = operands[pc->operand];
3372 pc->operand += 1;
3373 vm_push_i32(vm, value);
3374 }
3375 break;
3376 case Op_const_64:
3377 {
3378 uint64_t value = ((uint64_t)operands[pc->operand]) |
3379 (((uint64_t)operands[pc->operand + 1]) << 32);
3380 pc->operand += 2;
3381 vm_push_i64(vm, value);
3382 }
3383 break;
3384 case Op_const_umax_32:
3385 vm_push_i32(vm, -1);
3386 break;
3387 case Op_const_umax_64:
3388 vm_push_i64(vm, -1);
3389 break;
3390
3391 case Op_eqz_32:
3392 {
3393 uint32_t lhs = vm_pop_u32(vm);
3394 vm_push_u32(vm, lhs == 0);
3395 }
3396 break;
3397 case Op_eq_32:
3398 {
3399 uint32_t rhs = vm_pop_u32(vm);
3400 uint32_t lhs = vm_pop_u32(vm);
3401 vm_push_u32(vm, lhs == rhs);
3402 }
3403 break;
3404 case Op_ne_32:
3405 {
3406 uint32_t rhs = vm_pop_u32(vm);
3407 uint32_t lhs = vm_pop_u32(vm);
3408 vm_push_u32(vm, lhs != rhs);
3409 }
3410 break;
3411 case Op_slt_32:
3412 {
3413 int32_t rhs = vm_pop_i32(vm);
3414 int32_t lhs = vm_pop_i32(vm);
3415 vm_push_u32(vm, lhs < rhs);
3416 }
3417 break;
3418 case Op_ult_32:
3419 {
3420 uint32_t rhs = vm_pop_u32(vm);
3421 uint32_t lhs = vm_pop_u32(vm);
3422 vm_push_u32(vm, lhs < rhs);
3423 }
3424 break;
3425 case Op_sgt_32:
3426 {
3427 int32_t rhs = vm_pop_i32(vm);
3428 int32_t lhs = vm_pop_i32(vm);
3429 vm_push_u32(vm, lhs > rhs);
3430 }
3431 break;
3432 case Op_ugt_32:
3433 {
3434 uint32_t rhs = vm_pop_u32(vm);
3435 uint32_t lhs = vm_pop_u32(vm);
3436 vm_push_u32(vm, lhs > rhs);
3437 }
3438 break;
3439 case Op_sle_32:
3440 {
3441 int32_t rhs = vm_pop_i32(vm);
3442 int32_t lhs = vm_pop_i32(vm);
3443 vm_push_u32(vm, lhs <= rhs);
3444 }
3445 break;
3446 case Op_ule_32:
3447 {
3448 uint32_t rhs = vm_pop_u32(vm);
3449 uint32_t lhs = vm_pop_u32(vm);
3450 vm_push_u32(vm, lhs <= rhs);
3451 }
3452 break;
3453 case Op_sge_32:
3454 {
3455 int32_t rhs = vm_pop_i32(vm);
3456 int32_t lhs = vm_pop_i32(vm);
3457 vm_push_u32(vm, lhs >= rhs);
3458 }
3459 break;
3460 case Op_uge_32:
3461 {
3462 uint32_t rhs = vm_pop_u32(vm);
3463 uint32_t lhs = vm_pop_u32(vm);
3464 vm_push_u32(vm, lhs >= rhs);
3465 }
3466 break;
3467
3468 case Op_eqz_64:
3469 {
3470 uint64_t lhs = vm_pop_u64(vm);
3471 vm_push_u32(vm, lhs == 0);
3472 }
3473 break;
3474 case Op_eq_64:
3475 {
3476 uint64_t rhs = vm_pop_u64(vm);
3477 uint64_t lhs = vm_pop_u64(vm);
3478 vm_push_u32(vm, lhs == rhs);
3479 }
3480 break;
3481 case Op_ne_64:
3482 {
3483 uint64_t rhs = vm_pop_u64(vm);
3484 uint64_t lhs = vm_pop_u64(vm);
3485 vm_push_u32(vm, lhs != rhs);
3486 }
3487 break;
3488 case Op_slt_64:
3489 {
3490 int64_t rhs = vm_pop_i64(vm);
3491 int64_t lhs = vm_pop_i64(vm);
3492 vm_push_u32(vm, lhs < rhs);
3493 }
3494 break;
3495 case Op_ult_64:
3496 {
3497 uint64_t rhs = vm_pop_u64(vm);
3498 uint64_t lhs = vm_pop_u64(vm);
3499 vm_push_u32(vm, lhs < rhs);
3500 }
3501 break;
3502 case Op_sgt_64:
3503 {
3504 int64_t rhs = vm_pop_i64(vm);
3505 int64_t lhs = vm_pop_i64(vm);
3506 vm_push_u32(vm, lhs > rhs);
3507 }
3508 break;
3509 case Op_ugt_64:
3510 {
3511 uint64_t rhs = vm_pop_u64(vm);
3512 uint64_t lhs = vm_pop_u64(vm);
3513 vm_push_u32(vm, lhs > rhs);
3514 }
3515 break;
3516 case Op_sle_64:
3517 {
3518 int64_t rhs = vm_pop_i64(vm);
3519 int64_t lhs = vm_pop_i64(vm);
3520 vm_push_u32(vm, lhs <= rhs);
3521 }
3522 break;
3523 case Op_ule_64:
3524 {
3525 uint64_t rhs = vm_pop_u64(vm);
3526 uint64_t lhs = vm_pop_u64(vm);
3527 vm_push_u32(vm, lhs <= rhs);
3528 }
3529 break;
3530 case Op_sge_64:
3531 {
3532 int64_t rhs = vm_pop_i64(vm);
3533 int64_t lhs = vm_pop_i64(vm);
3534 vm_push_u32(vm, lhs >= rhs);
3535 }
3536 break;
3537 case Op_uge_64:
3538 {
3539 uint64_t rhs = vm_pop_u64(vm);
3540 uint64_t lhs = vm_pop_u64(vm);
3541 vm_push_u32(vm, lhs >= rhs);
3542 }
3543 break;
3544
3545 case Op_feq_32:
3546 {
3547 float rhs = vm_pop_f32(vm);
3548 float lhs = vm_pop_f32(vm);
3549 vm_push_u32(vm, lhs == rhs);
3550 }
3551 break;
3552 case Op_fne_32:
3553 {
3554 float rhs = vm_pop_f32(vm);
3555 float lhs = vm_pop_f32(vm);
3556 vm_push_u32(vm, lhs != rhs);
3557 }
3558 break;
3559 case Op_flt_32:
3560 {
3561 float rhs = vm_pop_f32(vm);
3562 float lhs = vm_pop_f32(vm);
3563 vm_push_u32(vm, lhs < rhs);
3564 }
3565 break;
3566 case Op_fgt_32:
3567 {
3568 float rhs = vm_pop_f32(vm);
3569 float lhs = vm_pop_f32(vm);
3570 vm_push_u32(vm, lhs > rhs);
3571 }
3572 break;
3573 case Op_fle_32:
3574 {
3575 float rhs = vm_pop_f32(vm);
3576 float lhs = vm_pop_f32(vm);
3577 vm_push_u32(vm, lhs <= rhs);
3578 }
3579 break;
3580 case Op_fge_32:
3581 {
3582 float rhs = vm_pop_f32(vm);
3583 float lhs = vm_pop_f32(vm);
3584 vm_push_u32(vm, lhs >= rhs);
3585 }
3586 break;
3587
3588 case Op_feq_64:
3589 {
3590 double rhs = vm_pop_f64(vm);
3591 double lhs = vm_pop_f64(vm);
3592 vm_push_u32(vm, lhs == rhs);
3593 }
3594 break;
3595 case Op_fne_64:
3596 {
3597 double rhs = vm_pop_f64(vm);
3598 double lhs = vm_pop_f64(vm);
3599 vm_push_u32(vm, lhs != rhs);
3600 }
3601 break;
3602 case Op_flt_64:
3603 {
3604 double rhs = vm_pop_f64(vm);
3605 double lhs = vm_pop_f64(vm);
3606 vm_push_u32(vm, lhs <= rhs);
3607 }
3608 break;
3609 case Op_fgt_64:
3610 {
3611 double rhs = vm_pop_f64(vm);
3612 double lhs = vm_pop_f64(vm);
3613 vm_push_u32(vm, lhs > rhs);
3614 }
3615 break;
3616 case Op_fle_64:
3617 {
3618 double rhs = vm_pop_f64(vm);
3619 double lhs = vm_pop_f64(vm);
3620 vm_push_u32(vm, lhs <= rhs);
3621 }
3622 break;
3623 case Op_fge_64:
3624 {
3625 double rhs = vm_pop_f64(vm);
3626 double lhs = vm_pop_f64(vm);
3627 vm_push_u32(vm, lhs >= rhs);
3628 }
3629 break;
3630
3631 case Op_clz_32:
3632 {
3633 uint32_t operand = vm_pop_u32(vm);
3634 uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand);
3635 vm_push_u32(vm, result);
3636 }
3637 break;
3638 case Op_ctz_32:
3639 {
3640 uint32_t operand = vm_pop_u32(vm);
3641 uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand);
3642 vm_push_u32(vm, result);
3643 }
3644 break;
3645 case Op_popcnt_32:
3646 {
3647 uint32_t operand = vm_pop_u32(vm);
3648 uint32_t result = __builtin_popcount(operand);
3649 vm_push_u32(vm, result);
3650 }
3651 break;
3652 case Op_add_32:
3653 {
3654 uint32_t rhs = vm_pop_u32(vm);
3655 uint32_t lhs = vm_pop_u32(vm);
3656 vm_push_u32(vm, lhs + rhs);
3657 }
3658 break;
3659 case Op_sub_32:
3660 {
3661 uint32_t rhs = vm_pop_u32(vm);
3662 uint32_t lhs = vm_pop_u32(vm);
3663 vm_push_u32(vm, lhs - rhs);
3664 }
3665 break;
3666 case Op_mul_32:
3667 {
3668 uint32_t rhs = vm_pop_u32(vm);
3669 uint32_t lhs = vm_pop_u32(vm);
3670 vm_push_u32(vm, lhs * rhs);
3671 }
3672 break;
3673 case Op_sdiv_32:
3674 {
3675 int32_t rhs = vm_pop_i32(vm);
3676 int32_t lhs = vm_pop_i32(vm);
3677 vm_push_i32(vm, lhs / rhs);
3678 }
3679 break;
3680 case Op_udiv_32:
3681 {
3682 uint32_t rhs = vm_pop_u32(vm);
3683 uint32_t lhs = vm_pop_u32(vm);
3684 vm_push_u32(vm, lhs / rhs);
3685 }
3686 break;
3687 case Op_srem_32:
3688 {
3689 int32_t rhs = vm_pop_i32(vm);
3690 int32_t lhs = vm_pop_i32(vm);
3691 vm_push_i32(vm, lhs % rhs);
3692 }
3693 break;
3694 case Op_urem_32:
3695 {
3696 uint32_t rhs = vm_pop_u32(vm);
3697 uint32_t lhs = vm_pop_u32(vm);
3698 vm_push_u32(vm, lhs % rhs);
3699 }
3700 break;
3701 case Op_and_32:
3702 {
3703 uint32_t rhs = vm_pop_u32(vm);
3704 uint32_t lhs = vm_pop_u32(vm);
3705 vm_push_u32(vm, lhs & rhs);
3706 }
3707 break;
3708 case Op_or_32:
3709 {
3710 uint32_t rhs = vm_pop_u32(vm);
3711 uint32_t lhs = vm_pop_u32(vm);
3712 vm_push_u32(vm, lhs | rhs);
3713 }
3714 break;
3715 case Op_xor_32:
3716 {
3717 uint32_t rhs = vm_pop_u32(vm);
3718 uint32_t lhs = vm_pop_u32(vm);
3719 vm_push_u32(vm, lhs ^ rhs);
3720 }
3721 break;
3722 case Op_shl_32:
3723 {
3724 uint32_t rhs = vm_pop_u32(vm);
3725 uint32_t lhs = vm_pop_u32(vm);
3726 vm_push_u32(vm, lhs << (rhs & 0x1f));
3727 }
3728 break;
3729 case Op_ashr_32:
3730 {
3731 uint32_t rhs = vm_pop_u32(vm);
3732 int32_t lhs = vm_pop_i32(vm);
3733 vm_push_i32(vm, lhs >> (rhs & 0x1f));
3734 }
3735 break;
3736 case Op_lshr_32:
3737 {
3738 uint32_t rhs = vm_pop_u32(vm);
3739 uint32_t lhs = vm_pop_u32(vm);
3740 vm_push_u32(vm, lhs >> (rhs & 0x1f));
3741 }
3742 break;
3743 case Op_rol_32:
3744 {
3745 uint32_t rhs = vm_pop_u32(vm);
3746 uint32_t lhs = vm_pop_u32(vm);
3747 vm_push_u32(vm, rotl32(lhs, rhs));
3748 }
3749 break;
3750 case Op_ror_32:
3751 {
3752 uint32_t rhs = vm_pop_u32(vm);
3753 uint32_t lhs = vm_pop_u32(vm);
3754 vm_push_u32(vm, rotr32(lhs, rhs));
3755 }
3756 break;
3757
3758 case Op_clz_64:
3759 {
3760 uint64_t operand = vm_pop_u64(vm);
3761 uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand);
3762 vm_push_u64(vm, result);
3763 }
3764 break;
3765 case Op_ctz_64:
3766 {
3767 uint64_t operand = vm_pop_u64(vm);
3768 uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand);
3769 vm_push_u64(vm, result);
3770 }
3771 break;
3772 case Op_popcnt_64:
3773 {
3774 uint64_t operand = vm_pop_u64(vm);
3775 uint64_t result = __builtin_popcountll(operand);
3776 vm_push_u64(vm, result);
3777 }
3778 break;
3779 case Op_add_64:
3780 {
3781 uint64_t rhs = vm_pop_u64(vm);
3782 uint64_t lhs = vm_pop_u64(vm);
3783 vm_push_u64(vm, lhs + rhs);
3784 }
3785 break;
3786 case Op_sub_64:
3787 {
3788 uint64_t rhs = vm_pop_u64(vm);
3789 uint64_t lhs = vm_pop_u64(vm);
3790 vm_push_u64(vm, lhs - rhs);
3791 }
3792 break;
3793 case Op_mul_64:
3794 {
3795 uint64_t rhs = vm_pop_u64(vm);
3796 uint64_t lhs = vm_pop_u64(vm);
3797 vm_push_u64(vm, lhs * rhs);
3798 }
3799 break;
3800 case Op_sdiv_64:
3801 {
3802 int64_t rhs = vm_pop_i64(vm);
3803 int64_t lhs = vm_pop_i64(vm);
3804 vm_push_i64(vm, lhs / rhs);
3805 }
3806 break;
3807 case Op_udiv_64:
3808 {
3809 uint64_t rhs = vm_pop_u64(vm);
3810 uint64_t lhs = vm_pop_u64(vm);
3811 vm_push_u64(vm, lhs / rhs);
3812 }
3813 break;
3814 case Op_srem_64:
3815 {
3816 int64_t rhs = vm_pop_i64(vm);
3817 int64_t lhs = vm_pop_i64(vm);
3818 vm_push_i64(vm, lhs % rhs);
3819 }
3820 break;
3821 case Op_urem_64:
3822 {
3823 uint64_t rhs = vm_pop_u64(vm);
3824 uint64_t lhs = vm_pop_u64(vm);
3825 vm_push_u64(vm, lhs % rhs);
3826 }
3827 break;
3828 case Op_and_64:
3829 {
3830 uint64_t rhs = vm_pop_u64(vm);
3831 uint64_t lhs = vm_pop_u64(vm);
3832 vm_push_u64(vm, lhs & rhs);
3833 }
3834 break;
3835 case Op_or_64:
3836 {
3837 uint64_t rhs = vm_pop_u64(vm);
3838 uint64_t lhs = vm_pop_u64(vm);
3839 vm_push_u64(vm, lhs | rhs);
3840 }
3841 break;
3842 case Op_xor_64:
3843 {
3844 uint64_t rhs = vm_pop_u64(vm);
3845 uint64_t lhs = vm_pop_u64(vm);
3846 vm_push_u64(vm, lhs ^ rhs);
3847 }
3848 break;
3849 case Op_shl_64:
3850 {
3851 uint64_t rhs = vm_pop_u64(vm);
3852 uint64_t lhs = vm_pop_u64(vm);
3853 vm_push_u64(vm, lhs << (rhs & 0x3f));
3854 }
3855 break;
3856 case Op_ashr_64:
3857 {
3858 uint64_t rhs = vm_pop_u64(vm);
3859 int64_t lhs = vm_pop_i64(vm);
3860 vm_push_i64(vm, lhs >> (rhs & 0x3f));
3861 }
3862 break;
3863 case Op_lshr_64:
3864 {
3865 uint64_t rhs = vm_pop_u64(vm);
3866 uint64_t lhs = vm_pop_u64(vm);
3867 vm_push_u64(vm, lhs >> (rhs & 0x3f));
3868 }
3869 break;
3870 case Op_rol_64:
3871 {
3872 uint64_t rhs = vm_pop_u64(vm);
3873 uint64_t lhs = vm_pop_u64(vm);
3874 vm_push_u64(vm, rotl64(lhs, rhs));
3875 }
3876 break;
3877 case Op_ror_64:
3878 {
3879 uint64_t rhs = vm_pop_u64(vm);
3880 uint64_t lhs = vm_pop_u64(vm);
3881 vm_push_u64(vm, rotr64(lhs, rhs));
3882 }
3883 break;
3884
3885 case Op_fabs_32:
3886 vm_push_f32(vm, fabsf(vm_pop_f32(vm)));
3887 break;
3888 case Op_fneg_32:
3889 vm_push_f32(vm, -vm_pop_f32(vm));
3890 break;
3891 case Op_ceil_32:
3892 vm_push_f32(vm, ceilf(vm_pop_f32(vm)));
3893 break;
3894 case Op_floor_32:
3895 vm_push_f32(vm, floorf(vm_pop_f32(vm)));
3896 break;
3897 case Op_trunc_32:
3898 vm_push_f32(vm, truncf(vm_pop_f32(vm)));
3899 break;
3900 case Op_nearest_32:
3901 vm_push_f32(vm, roundf(vm_pop_f32(vm)));
3902 break;
3903 case Op_sqrt_32:
3904 vm_push_f32(vm, sqrtf(vm_pop_f32(vm)));
3905 break;
3906 case Op_fadd_32:
3907 {
3908 float rhs = vm_pop_f32(vm);
3909 float lhs = vm_pop_f32(vm);
3910 vm_push_f32(vm, lhs + rhs);
3911 }
3912 break;
3913 case Op_fsub_32:
3914 {
3915 float rhs = vm_pop_f32(vm);
3916 float lhs = vm_pop_f32(vm);
3917 vm_push_f32(vm, lhs - rhs);
3918 }
3919 break;
3920 case Op_fmul_32:
3921 {
3922 float rhs = vm_pop_f32(vm);
3923 float lhs = vm_pop_f32(vm);
3924 vm_push_f32(vm, lhs * rhs);
3925 }
3926 break;
3927 case Op_fdiv_32:
3928 {
3929 float rhs = vm_pop_f32(vm);
3930 float lhs = vm_pop_f32(vm);
3931 vm_push_f32(vm, lhs / rhs);
3932 }
3933 break;
3934 case Op_fmin_32:
3935 {
3936 float rhs = vm_pop_f32(vm);
3937 float lhs = vm_pop_f32(vm);
3938 vm_push_f32(vm, fminf(lhs, rhs));
3939 }
3940 break;
3941 case Op_fmax_32:
3942 {
3943 float rhs = vm_pop_f32(vm);
3944 float lhs = vm_pop_f32(vm);
3945 vm_push_f32(vm, fmaxf(lhs, rhs));
3946 }
3947 break;
3948 case Op_copysign_32:
3949 {
3950 float rhs = vm_pop_f32(vm);
3951 float lhs = vm_pop_f32(vm);
3952 vm_push_f32(vm, copysignf(lhs, rhs));
3953 }
3954 break;
3955
3956 case Op_fabs_64:
3957 vm_push_f64(vm, fabs(vm_pop_f64(vm)));
3958 break;
3959 case Op_fneg_64:
3960 vm_push_f64(vm, -vm_pop_f64(vm));
3961 break;
3962 case Op_ceil_64:
3963 vm_push_f64(vm, ceil(vm_pop_f64(vm)));
3964 break;
3965 case Op_floor_64:
3966 vm_push_f64(vm, floor(vm_pop_f64(vm)));
3967 break;
3968 case Op_trunc_64:
3969 vm_push_f64(vm, trunc(vm_pop_f64(vm)));
3970 break;
3971 case Op_nearest_64:
3972 vm_push_f64(vm, round(vm_pop_f64(vm)));
3973 break;
3974 case Op_sqrt_64:
3975 vm_push_f64(vm, sqrt(vm_pop_f64(vm)));
3976 break;
3977 case Op_fadd_64:
3978 {
3979 double rhs = vm_pop_f64(vm);
3980 double lhs = vm_pop_f64(vm);
3981 vm_push_f64(vm, lhs + rhs);
3982 }
3983 break;
3984 case Op_fsub_64:
3985 {
3986 double rhs = vm_pop_f64(vm);
3987 double lhs = vm_pop_f64(vm);
3988 vm_push_f64(vm, lhs - rhs);
3989 }
3990 break;
3991 case Op_fmul_64:
3992 {
3993 double rhs = vm_pop_f64(vm);
3994 double lhs = vm_pop_f64(vm);
3995 vm_push_f64(vm, lhs * rhs);
3996 }
3997 break;
3998 case Op_fdiv_64:
3999 {
4000 double rhs = vm_pop_f64(vm);
4001 double lhs = vm_pop_f64(vm);
4002 vm_push_f64(vm, lhs / rhs);
4003 }
4004 break;
4005 case Op_fmin_64:
4006 {
4007 double rhs = vm_pop_f64(vm);
4008 double lhs = vm_pop_f64(vm);
4009 vm_push_f64(vm, fmin(lhs, rhs));
4010 }
4011 break;
4012 case Op_fmax_64:
4013 {
4014 double rhs = vm_pop_f64(vm);
4015 double lhs = vm_pop_f64(vm);
4016 vm_push_f64(vm, fmax(lhs, rhs));
4017 }
4018 break;
4019 case Op_copysign_64:
4020 {
4021 double rhs = vm_pop_f64(vm);
4022 double lhs = vm_pop_f64(vm);
4023 vm_push_f64(vm, copysign(lhs, rhs));
4024 }
4025 break;
4026
4027 case Op_ftos_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break;
4028 case Op_ftou_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break;
4029 case Op_ftos_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break;
4030 case Op_ftou_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break;
4031 case Op_sext_64_32: vm_push_i64(vm, vm_pop_i32(vm)); break;
4032 case Op_ftos_64_32: vm_push_i64(vm, (int64_t)vm_pop_f32(vm)); break;
4033 case Op_ftou_64_32: vm_push_u64(vm, (uint64_t)vm_pop_f32(vm)); break;
4034 case Op_ftos_64_64: vm_push_i64(vm, (int64_t)vm_pop_f64(vm)); break;
4035 case Op_ftou_64_64: vm_push_u64(vm, (uint64_t)vm_pop_f64(vm)); break;
4036 case Op_stof_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break;
4037 case Op_utof_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break;
4038 case Op_stof_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break;
4039 case Op_utof_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break;
4040 case Op_ftof_32_64: vm_push_f32(vm, (float)vm_pop_f64(vm)); break;
4041 case Op_stof_64_32: vm_push_f64(vm, (double)vm_pop_i32(vm)); break;
4042 case Op_utof_64_32: vm_push_f64(vm, (double)vm_pop_u32(vm)); break;
4043 case Op_stof_64_64: vm_push_f64(vm, (double)vm_pop_i64(vm)); break;
4044 case Op_utof_64_64: vm_push_f64(vm, (double)vm_pop_u64(vm)); break;
4045 case Op_ftof_64_32: vm_push_f64(vm, (double)vm_pop_f32(vm)); break;
4046 case Op_sext8_32: vm_push_i32(vm, (int8_t)vm_pop_i32(vm)); break;
4047 case Op_sext16_32: vm_push_i32(vm, (int16_t)vm_pop_i32(vm)); break;
4048 case Op_sext8_64: vm_push_i64(vm, (int8_t)vm_pop_i64(vm)); break;
4049 case Op_sext16_64: vm_push_i64(vm, (int16_t)vm_pop_i64(vm)); break;
4050 case Op_sext32_64: vm_push_i64(vm, (int32_t)vm_pop_i64(vm)); break;
4051
4052 case Op_memcpy:
4053 {
4054 uint32_t n = vm_pop_u32(vm);
4055 uint32_t src = vm_pop_u32(vm);
4056 uint32_t dest = vm_pop_u32(vm);
4057 assert(dest + n <= vm->memory_len);
4058 assert(src + n <= vm->memory_len);
4059 assert(src + n <= dest || dest + n <= src); // overlapping
4060 memcpy(vm->memory + dest, vm->memory + src, n);
4061 }
4062 break;
4063 case Op_memset:
4064 {
4065 uint32_t n = vm_pop_u32(vm);
4066 uint8_t value = (uint8_t)vm_pop_u32(vm);
4067 uint32_t dest = vm_pop_u32(vm);
4068 assert(dest + n <= vm->memory_len);
4069 memset(vm->memory + dest, value, n);
4070 }
4071 break;
4072 }
4073 }
4074}
4075
4076static size_t common_prefix(const char *a, const char *b) {
4077 size_t i = 0;
4078 for (; a[i] == b[i]; i += 1) {}
4079 return i;
4080}
4081
4082int main(int argc, char **argv) {
4083 char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
4084
4085 const char *zig_lib_dir_path = argv[1];
4086 const char *cmake_binary_dir_path = argv[2];
4087 const char *root_name = argv[3];
4088 size_t argv_i = 4;
4089 const char *wasm_file = argv[argv_i];
4090
4091 size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path);
4092 const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len;
4093
4094 size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path);
4095
4096 const char *new_argv[30];
4097 char new_argv_buf[PATH_MAX + 1024];
4098 uint32_t new_argv_i = 0;
4099 uint32_t new_argv_buf_i = 0;
4100
4101 int cache_dir = -1;
4102 {
4103 char cache_dir_buf[PATH_MAX * 2];
4104 size_t i = 0;
4105 size_t cmake_binary_dir_path_len = strlen(cmake_binary_dir_path);
4106
4107 memcpy(cache_dir_buf + i, cmake_binary_dir_path, cmake_binary_dir_path_len);
4108 i += cmake_binary_dir_path_len;
4109
4110 cache_dir_buf[i] = '/';
4111 i += 1;
4112
4113 memcpy(cache_dir_buf + i, "zig1-cache", strlen("zig1-cache"));
4114 i += strlen("zig1-cache");
4115
4116 cache_dir_buf[i] = 0;
4117
4118 mkdir(cache_dir_buf, 0777);
4119 cache_dir = err_wrap("opening cache dir",
4120 open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC));
4121 }
4122
4123 // Construct a new argv for the WASI code which has absolute paths
4124 // converted to relative paths, and has the target and terminal status
4125 // autodetected.
4126
4127 // wasm file path
4128 new_argv[new_argv_i] = argv[argv_i];
4129 new_argv_i += 1;
4130 argv_i += 1;
4131
4132 for (; argv[argv_i]; argv_i += 1) {
4133 new_argv[new_argv_i] = argv[argv_i];
4134 new_argv_i += 1;
4135 }
4136
4137 {
4138 new_argv[new_argv_i] = "--name";
4139 new_argv_i += 1;
4140
4141 new_argv[new_argv_i] = root_name;
4142 new_argv_i += 1;
4143
4144 char *emit_bin_arg = new_argv_buf + new_argv_buf_i;
4145 memcpy(new_argv_buf + new_argv_buf_i, "-femit-bin=", strlen("-femit-bin="));
4146 new_argv_buf_i += strlen("-femit-bin=");
4147 memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
4148 new_argv_buf_i += rel_cmake_bin_path_len;
4149 new_argv_buf[new_argv_buf_i] = '/';
4150 new_argv_buf_i += 1;
4151 memcpy(new_argv_buf + new_argv_buf_i, root_name, strlen(root_name));
4152 new_argv_buf_i += strlen(root_name);
4153 memcpy(new_argv_buf + new_argv_buf_i, ".c", 3);
4154 new_argv_buf_i += 3;
4155
4156 new_argv[new_argv_i] = emit_bin_arg;
4157 new_argv_i += 1;
4158 }
4159
4160 {
4161 new_argv[new_argv_i] = "--pkg-begin";
4162 new_argv_i += 1;
4163
4164 new_argv[new_argv_i] = "build_options";
4165 new_argv_i += 1;
4166
4167 char *build_options_path = new_argv_buf + new_argv_buf_i;
4168 memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
4169 new_argv_buf_i += rel_cmake_bin_path_len;
4170 new_argv_buf[new_argv_buf_i] = '/';
4171 new_argv_buf_i += 1;
4172 memcpy(new_argv_buf + new_argv_buf_i, "config.zig", strlen("config.zig"));
4173 new_argv_buf_i += strlen("config.zig");
4174 new_argv_buf[new_argv_buf_i] = 0;
4175 new_argv_buf_i += 1;
4176
4177 new_argv[new_argv_i] = build_options_path;
4178 new_argv_i += 1;
4179
4180 new_argv[new_argv_i] = "--pkg-end";
4181 new_argv_i += 1;
4182 }
4183
4184 {
4185 new_argv[new_argv_i] = "-target";
4186 new_argv_i += 1;
4187
4188 new_argv[new_argv_i] = ZIG_TRIPLE_ARCH "-" ZIG_TRIPLE_OS;
4189 new_argv_i += 1;
4190 }
4191
4192 if (isatty(STDERR_FILENO) != 0) {
4193 new_argv[new_argv_i] = "--color";
4194 new_argv_i += 1;
4195
4196 new_argv[new_argv_i] = "on";
4197 new_argv_i += 1;
4198 }
4199
4200 new_argv[new_argv_i] = NULL;
4201
4202 const struct ByteSlice compressed_bytes = read_file_alloc(wasm_file);
4203
4204 const size_t max_uncompressed_size = 2500000;
4205 char *mod_ptr = arena_alloc(max_uncompressed_size);
4206 size_t mod_len = ZSTD_decompress(mod_ptr, max_uncompressed_size,
4207 compressed_bytes.ptr, compressed_bytes.len);
4208
4209 int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC));
4210 int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC));
4211
4212 add_preopen(0, "stdin", STDIN_FILENO);
4213 add_preopen(1, "stdout", STDOUT_FILENO);
4214 add_preopen(2, "stderr", STDERR_FILENO);
4215 add_preopen(3, ".", cwd);
4216 add_preopen(4, "/cache", cache_dir);
4217 add_preopen(5, "/lib", zig_lib_dir);
4218
4219 uint32_t i = 0;
4220
4221 if (mod_ptr[0] != 0 || mod_ptr[1] != 'a' || mod_ptr[2] != 's' || mod_ptr[3] != 'm') {
4222 panic("bad magic");
4223 }
4224 i += 4;
4225
4226 uint32_t version = read_u32_le(mod_ptr + i);
4227 i += 4;
4228 if (version != 1) panic("bad wasm version");
4229
4230 uint32_t section_starts[13];
4231 memset(&section_starts, 0, sizeof(uint32_t) * 13);
4232
4233 while (i < mod_len) {
4234 uint8_t section_id = mod_ptr[i];
4235 i += 1;
4236 uint32_t section_len = read32_uleb128(mod_ptr, &i);
4237 section_starts[section_id] = i;
4238 i += section_len;
4239 }
4240
4241 // Map type indexes to offsets into the module.
4242 struct TypeInfo *types;
4243 {
4244 i = section_starts[Section_type];
4245 uint32_t types_len = read32_uleb128(mod_ptr, &i);
4246 types = arena_alloc(sizeof(struct TypeInfo) * types_len);
4247 for (size_t type_i = 0; type_i < types_len; type_i += 1) {
4248 struct TypeInfo *info = &types[type_i];
4249 if (mod_ptr[i] != 0x60) panic("bad type byte");
4250 i += 1;
4251
4252 info->param_count = read32_uleb128(mod_ptr, &i);
4253 if (info->param_count > 32) panic("found a type with over 32 parameters");
4254 info->param_types = 0;
4255 for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) {
4256 int64_t param_type = read64_ileb128(mod_ptr, &i);
4257 switch (param_type) {
4258 case -1: case -3: bs_unset(&info->param_types, param_i); break;
4259 case -2: case -4: bs_set(&info->param_types, param_i); break;
4260 default: panic("unexpected param type");
4261 }
4262 }
4263
4264 info->result_count = read32_uleb128(mod_ptr, &i);
4265 info->result_types = 0;
4266 for (uint32_t result_i = 0; result_i < info->result_count; result_i += 1) {
4267 int64_t result_type = read64_ileb128(mod_ptr, &i);
4268 switch (result_type) {
4269 case -1: case -3: bs_unset(&info->result_types, result_i); break;
4270 case -2: case -4: bs_set(&info->result_types, result_i); break;
4271 default: panic("unexpected result type");
4272 }
4273 }
4274 }
4275 }
4276
4277 // Count the imported functions so we can correct function references.
4278 struct Import *imports;
4279 uint32_t imports_len;
4280 {
4281 i = section_starts[Section_import];
4282 imports_len = read32_uleb128(mod_ptr, &i);
4283 imports = arena_alloc(sizeof(struct Import) * imports_len);
4284 for (size_t imp_i = 0; imp_i < imports_len; imp_i += 1) {
4285 struct Import *imp = &imports[imp_i];
4286
4287 struct ByteSlice mod_name = read_name(mod_ptr, &i);
4288 if (mod_name.len == strlen("wasi_snapshot_preview1") &&
4289 memcmp(mod_name.ptr, "wasi_snapshot_preview1", mod_name.len) == 0) {
4290 imp->mod = ImpMod_wasi_snapshot_preview1;
4291 } else panic("unknown import module");
4292
4293 struct ByteSlice sym_name = read_name(mod_ptr, &i);
4294 if (sym_name.len == strlen("args_get") &&
4295 memcmp(sym_name.ptr, "args_get", sym_name.len) == 0) {
4296 imp->name = ImpName_args_get;
4297 } else if (sym_name.len == strlen("args_sizes_get") &&
4298 memcmp(sym_name.ptr, "args_sizes_get", sym_name.len) == 0) {
4299 imp->name = ImpName_args_sizes_get;
4300 } else if (sym_name.len == strlen("clock_time_get") &&
4301 memcmp(sym_name.ptr, "clock_time_get", sym_name.len) == 0) {
4302 imp->name = ImpName_clock_time_get;
4303 } else if (sym_name.len == strlen("debug") &&
4304 memcmp(sym_name.ptr, "debug", sym_name.len) == 0) {
4305 imp->name = ImpName_debug;
4306 } else if (sym_name.len == strlen("debug_slice") &&
4307 memcmp(sym_name.ptr, "debug_slice", sym_name.len) == 0) {
4308 imp->name = ImpName_debug_slice;
4309 } else if (sym_name.len == strlen("environ_get") &&
4310 memcmp(sym_name.ptr, "environ_get", sym_name.len) == 0) {
4311 imp->name = ImpName_environ_get;
4312 } else if (sym_name.len == strlen("environ_sizes_get") &&
4313 memcmp(sym_name.ptr, "environ_sizes_get", sym_name.len) == 0) {
4314 imp->name = ImpName_environ_sizes_get;
4315 } else if (sym_name.len == strlen("fd_close") &&
4316 memcmp(sym_name.ptr, "fd_close", sym_name.len) == 0) {
4317 imp->name = ImpName_fd_close;
4318 } else if (sym_name.len == strlen("fd_fdstat_get") &&
4319 memcmp(sym_name.ptr, "fd_fdstat_get", sym_name.len) == 0) {
4320 imp->name = ImpName_fd_fdstat_get;
4321 } else if (sym_name.len == strlen("fd_filestat_get") &&
4322 memcmp(sym_name.ptr, "fd_filestat_get", sym_name.len) == 0) {
4323 imp->name = ImpName_fd_filestat_get;
4324 } else if (sym_name.len == strlen("fd_filestat_set_size") &&
4325 memcmp(sym_name.ptr, "fd_filestat_set_size", sym_name.len) == 0) {
4326 imp->name = ImpName_fd_filestat_set_size;
4327 } else if (sym_name.len == strlen("fd_filestat_set_times") &&
4328 memcmp(sym_name.ptr, "fd_filestat_set_times", sym_name.len) == 0) {
4329 imp->name = ImpName_fd_filestat_set_times;
4330 } else if (sym_name.len == strlen("fd_pread") &&
4331 memcmp(sym_name.ptr, "fd_pread", sym_name.len) == 0) {
4332 imp->name = ImpName_fd_pread;
4333 } else if (sym_name.len == strlen("fd_prestat_dir_name") &&
4334 memcmp(sym_name.ptr, "fd_prestat_dir_name", sym_name.len) == 0) {
4335 imp->name = ImpName_fd_prestat_dir_name;
4336 } else if (sym_name.len == strlen("fd_prestat_get") &&
4337 memcmp(sym_name.ptr, "fd_prestat_get", sym_name.len) == 0) {
4338 imp->name = ImpName_fd_prestat_get;
4339 } else if (sym_name.len == strlen("fd_pwrite") &&
4340 memcmp(sym_name.ptr, "fd_pwrite", sym_name.len) == 0) {
4341 imp->name = ImpName_fd_pwrite;
4342 } else if (sym_name.len == strlen("fd_read") &&
4343 memcmp(sym_name.ptr, "fd_read", sym_name.len) == 0) {
4344 imp->name = ImpName_fd_read;
4345 } else if (sym_name.len == strlen("fd_readdir") &&
4346 memcmp(sym_name.ptr, "fd_readdir", sym_name.len) == 0) {
4347 imp->name = ImpName_fd_readdir;
4348 } else if (sym_name.len == strlen("fd_write") &&
4349 memcmp(sym_name.ptr, "fd_write", sym_name.len) == 0) {
4350 imp->name = ImpName_fd_write;
4351 } else if (sym_name.len == strlen("path_create_directory") &&
4352 memcmp(sym_name.ptr, "path_create_directory", sym_name.len) == 0) {
4353 imp->name = ImpName_path_create_directory;
4354 } else if (sym_name.len == strlen("path_filestat_get") &&
4355 memcmp(sym_name.ptr, "path_filestat_get", sym_name.len) == 0) {
4356 imp->name = ImpName_path_filestat_get;
4357 } else if (sym_name.len == strlen("path_open") &&
4358 memcmp(sym_name.ptr, "path_open", sym_name.len) == 0) {
4359 imp->name = ImpName_path_open;
4360 } else if (sym_name.len == strlen("path_remove_directory") &&
4361 memcmp(sym_name.ptr, "path_remove_directory", sym_name.len) == 0) {
4362 imp->name = ImpName_path_remove_directory;
4363 } else if (sym_name.len == strlen("path_rename") &&
4364 memcmp(sym_name.ptr, "path_rename", sym_name.len) == 0) {
4365 imp->name = ImpName_path_rename;
4366 } else if (sym_name.len == strlen("path_unlink_file") &&
4367 memcmp(sym_name.ptr, "path_unlink_file", sym_name.len) == 0) {
4368 imp->name = ImpName_path_unlink_file;
4369 } else if (sym_name.len == strlen("proc_exit") &&
4370 memcmp(sym_name.ptr, "proc_exit", sym_name.len) == 0) {
4371 imp->name = ImpName_proc_exit;
4372 } else if (sym_name.len == strlen("random_get") &&
4373 memcmp(sym_name.ptr, "random_get", sym_name.len) == 0) {
4374 imp->name = ImpName_random_get;
4375 } else panic("unknown import name");
4376
4377 uint32_t desc = read32_uleb128(mod_ptr, &i);
4378 if (desc != 0) panic("external kind not function");
4379 imp->type_idx = read32_uleb128(mod_ptr, &i);
4380 }
4381 }
4382
4383 // Find _start in the exports
4384 uint32_t start_fn_idx;
4385 {
4386 i = section_starts[Section_export];
4387 uint32_t count = read32_uleb128(mod_ptr, &i);
4388 for (; count > 0; count -= 1) {
4389 struct ByteSlice name = read_name(mod_ptr, &i);
4390 uint32_t desc = read32_uleb128(mod_ptr, &i);
4391 start_fn_idx = read32_uleb128(mod_ptr, &i);
4392 if (desc == 0 && name.len == strlen("_start") &&
4393 memcmp(name.ptr, "_start", name.len) == 0)
4394 {
4395 break;
4396 }
4397 }
4398 if (count == 0) panic("_start symbol not found");
4399 }
4400
4401 // Map function indexes to offsets into the module and type index.
4402 struct Function *functions;
4403 uint32_t functions_len;
4404 {
4405 i = section_starts[Section_function];
4406 functions_len = read32_uleb128(mod_ptr, &i);
4407 functions = arena_alloc(sizeof(struct Function) * functions_len);
4408 for (size_t func_i = 0; func_i < functions_len; func_i += 1) {
4409 struct Function *func = &functions[func_i];
4410 func->id = imports_len + func_i;
4411 func->type_idx = read32_uleb128(mod_ptr, &i);
4412 }
4413 }
4414
4415 // Allocate and initialize globals.
4416 uint64_t *globals;
4417 {
4418 i = section_starts[Section_global];
4419 uint32_t globals_len = read32_uleb128(mod_ptr, &i);
4420 globals = arena_alloc(sizeof(uint64_t) * globals_len);
4421 for (size_t glob_i = 0; glob_i < globals_len; glob_i += 1) {
4422 uint64_t *global = &globals[glob_i];
4423 uint32_t content_type = read32_uleb128(mod_ptr, &i);
4424 uint32_t mutability = read32_uleb128(mod_ptr, &i);
4425 if (mutability != 1) panic("expected mutable global");
4426 if (content_type != 0x7f) panic("unexpected content type");
4427 uint8_t opcode = mod_ptr[i];
4428 i += 1;
4429 if (opcode != WasmOp_i32_const) panic("expected i32_const op");
4430 uint32_t init = read32_ileb128(mod_ptr, &i);
4431 *global = (uint32_t)init;
4432 }
4433 }
4434
4435 // Allocate and initialize memory.
4436 uint32_t memory_len;
4437 {
4438 i = section_starts[Section_memory];
4439 uint32_t memories_len = read32_uleb128(mod_ptr, &i);
4440 if (memories_len != 1) panic("unexpected memory count");
4441 uint32_t flags = read32_uleb128(mod_ptr, &i);
4442 (void)flags;
4443 memory_len = read32_uleb128(mod_ptr, &i) * wasm_page_size;
4444
4445 i = section_starts[Section_data];
4446 uint32_t datas_count = read32_uleb128(mod_ptr, &i);
4447 for (; datas_count > 0; datas_count -= 1) {
4448 uint32_t mode = read32_uleb128(mod_ptr, &i);
4449 if (mode != 0) panic("expected mode 0");
4450 enum WasmOp opcode = mod_ptr[i];
4451 i += 1;
4452 if (opcode != WasmOp_i32_const) panic("expected opcode i32_const");
4453 uint32_t offset = read32_uleb128(mod_ptr, &i);
4454 enum WasmOp end = mod_ptr[i];
4455 if (end != WasmOp_end) panic("expected end opcode");
4456 i += 1;
4457 uint32_t bytes_len = read32_uleb128(mod_ptr, &i);
4458 memcpy(memory + offset, mod_ptr + i, bytes_len);
4459 i += bytes_len;
4460 }
4461 }
4462
4463 uint32_t *table = NULL;
4464 {
4465 i = section_starts[Section_table];
4466 uint32_t table_count = read32_uleb128(mod_ptr, &i);
4467 if (table_count > 1) {
4468 panic("expected only one table section");
4469 } else if (table_count == 1) {
4470 uint32_t element_type = read32_uleb128(mod_ptr, &i);
4471 (void)element_type;
4472 uint32_t has_max = read32_uleb128(mod_ptr, &i);
4473 if (has_max != 1) panic("expected has_max==1");
4474 uint32_t initial = read32_uleb128(mod_ptr, &i);
4475 (void)initial;
4476 uint32_t maximum = read32_uleb128(mod_ptr, &i);
4477
4478 i = section_starts[Section_element];
4479 uint32_t element_section_count = read32_uleb128(mod_ptr, &i);
4480 if (element_section_count != 1) panic("expected one element section");
4481 uint32_t flags = read32_uleb128(mod_ptr, &i);
4482 (void)flags;
4483 enum WasmOp opcode = mod_ptr[i];
4484 i += 1;
4485 if (opcode != WasmOp_i32_const) panic("expected op i32_const");
4486 uint32_t offset = read32_uleb128(mod_ptr, &i);
4487 enum WasmOp end = mod_ptr[i];
4488 if (end != WasmOp_end) panic("expected op end");
4489 i += 1;
4490 uint32_t elem_count = read32_uleb128(mod_ptr, &i);
4491
4492 table = arena_alloc(sizeof(uint32_t) * maximum);
4493 memset(table, 0, sizeof(uint32_t) * maximum);
4494
4495 for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) {
4496 table[elem_i + offset] = read32_uleb128(mod_ptr, &i);
4497 }
4498 }
4499 }
4500
4501 struct VirtualMachine vm;
4502#ifndef NDEBUG
4503 memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version
4504#endif
4505 vm.stack = arena_alloc(sizeof(uint32_t) * 10000000),
4506 vm.mod_ptr = mod_ptr;
4507 vm.opcodes = arena_alloc(2000000);
4508 vm.operands = arena_alloc(sizeof(uint32_t) * 2000000);
4509 vm.stack_top = 0;
4510 vm.functions = functions;
4511 vm.types = types;
4512 vm.globals = globals;
4513 vm.memory = memory;
4514 vm.memory_len = memory_len;
4515 vm.imports = imports;
4516 vm.imports_len = imports_len;
4517 vm.args = new_argv;
4518 vm.table = table;
4519
4520 {
4521 uint32_t code_i = section_starts[Section_code];
4522 uint32_t codes_len = read32_uleb128(mod_ptr, &code_i);
4523 if (codes_len != functions_len) panic("code/function length mismatch");
4524 struct ProgramCounter pc;
4525 pc.opcode = 0;
4526 pc.operand = 0;
4527 struct StackInfo stack;
4528 for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) {
4529 struct Function *func = &functions[func_i];
4530 uint32_t size = read32_uleb128(mod_ptr, &code_i);
4531 uint32_t code_begin = code_i;
4532
4533 stack.top_index = 0;
4534 stack.top_offset = 0;
4535 struct TypeInfo *type_info = &vm.types[func->type_idx];
4536 for (uint32_t param_i = 0; param_i < type_info->param_count; param_i += 1)
4537 si_push(&stack, bs_isSet(&type_info->param_types, param_i));
4538 uint32_t params_size = stack.top_offset;
4539
4540 for (uint32_t local_sets_count = read32_uleb128(mod_ptr, &code_i);
4541 local_sets_count > 0; local_sets_count -= 1)
4542 {
4543 uint32_t local_set_count = read32_uleb128(mod_ptr, &code_i);
4544 enum StackType local_type;
4545 switch (read64_ileb128(mod_ptr, &code_i)) {
4546 case -1: case -3: local_type = ST_32; break;
4547 case -2: case -4: local_type = ST_64; break;
4548 default: panic("unexpected local type");
4549 }
4550 for (; local_set_count > 0; local_set_count -= 1)
4551 si_push(&stack, local_type);
4552 }
4553 func->locals_size = stack.top_offset - params_size;
4554
4555 func->entry_pc = pc;
4556 //fprintf(stderr, "decoding func id %u with pc %u:%u\n", func->id, pc.opcode, pc.operand);
4557 vm_decodeCode(&vm, type_info, &code_i, &pc, &stack);
4558 if (code_i != code_begin + size) panic("bad code size");
4559 }
4560 //fprintf(stderr, "%u opcodes\n%u operands\n", pc.opcode, pc.operand);
4561 }
4562
4563 vm_call(&vm, &vm.functions[start_fn_idx - imports_len]);
4564 vm_run(&vm);
4565
4566 return 0;
4567}