mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-26 13:01:34 +03:00
use zig-wasm2c for bootstrapping
This commit is contained in:
committed by
Andrew Kelley
parent
a63305bc50
commit
1263346774
+37
-14
@@ -179,8 +179,8 @@ set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std")
|
||||
set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
|
||||
set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
|
||||
|
||||
set(STAGE1_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/stage1/zig1.c"
|
||||
set(ZIG_WASM2C_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/stage1/wasm2c.c"
|
||||
"${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/huf_decompress.c"
|
||||
"${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_ddict.c"
|
||||
"${CMAKE_SOURCE_DIR}/stage1/zstd/lib/decompress/zstd_decompress.c"
|
||||
@@ -709,30 +709,53 @@ target_link_libraries(zigcpp LINK_PUBLIC
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(ZIG1_COMPILE_FLAGS "/std:c99")
|
||||
set(ZIG2_COMPILE_FLAGS "/std:c99")
|
||||
set(ZIG_WASM2C_COMPILE_FLAGS "/std:c99 /O2")
|
||||
set(ZIG1_COMPILE_FLAGS "/std:c99 /Os")
|
||||
set(ZIG2_COMPILE_FLAGS "/std:c99 /O0")
|
||||
set(ZIG2_LINK_FLAGS "/STACK:16777216")
|
||||
else()
|
||||
set(ZIG_WASM2C_COMPILE_FLAGS "-std=c99 -O2")
|
||||
set(ZIG1_COMPILE_FLAGS "-std=c99")
|
||||
set(ZIG2_COMPILE_FLAGS "-std=c99")
|
||||
set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000")
|
||||
endif()
|
||||
|
||||
add_executable(zig1 ${STAGE1_SOURCES})
|
||||
set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS})
|
||||
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}-${CMAKE_HOST_SYSTEM_NAME}" HOST_TARGET_TRIPLE)
|
||||
set(ZIG1_WASM_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst")
|
||||
set(ZIG1_C_SOURCE "${CMAKE_BINARY_DIR}/zig1.c")
|
||||
set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c")
|
||||
set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c")
|
||||
|
||||
add_executable(zig-wasm2c ${ZIG_WASM2C_SOURCES})
|
||||
set_target_properties(zig-wasm2c PROPERTIES COMPILE_FLAGS ${ZIG_WASM2C_COMPILE_FLAGS})
|
||||
target_include_directories(zig-wasm2c PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib")
|
||||
target_compile_definitions(zig-wasm2c PRIVATE ZSTD_DISABLE_ASM)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${ZIG1_C_SOURCE}"
|
||||
COMMAND zig-wasm2c "${ZIG1_WASM_SOURCE}" "${ZIG1_C_SOURCE}"
|
||||
DEPENDS zig-wasm2c "${ZIG1_WASM_SOURCE}"
|
||||
COMMENT STATUS "Converting ${ZIG1_WASM_SOURCE} to ${ZIG1_C_SOURCE}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
add_executable(zig1 ${ZIG1_C_SOURCE} "${CMAKE_SOURCE_DIR}/stage1/wasi.c")
|
||||
set_target_properties(zig1 PROPERTIES
|
||||
COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS}
|
||||
LINK_FLAGS ${ZIG2_LINK_FLAGS})
|
||||
target_link_libraries(zig1 LINK_PUBLIC m)
|
||||
target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/stage1/zstd/lib")
|
||||
target_compile_definitions(zig1 PRIVATE ZSTD_DISABLE_ASM)
|
||||
|
||||
set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c")
|
||||
set(ZIG1_WASM_ZST_SOURCE "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst")
|
||||
set(BUILD_ZIG2_ARGS
|
||||
"${CMAKE_SOURCE_DIR}/lib"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
zig2
|
||||
"${ZIG1_WASM_ZST_SOURCE}"
|
||||
build-exe src/main.zig -ofmt=c -lc
|
||||
-OReleaseSmall
|
||||
--name zig2 -femit-bin="${ZIG2_C_SOURCE}"
|
||||
--pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end
|
||||
-target "${HOST_TARGET_TRIPLE}"
|
||||
--color on
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
@@ -743,14 +766,14 @@ add_custom_command(
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c")
|
||||
set(BUILD_COMPILER_RT_ARGS
|
||||
"${CMAKE_SOURCE_DIR}/lib"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
compiler_rt
|
||||
"${CMAKE_SOURCE_DIR}/stage1/zig1.wasm.zst"
|
||||
build-obj lib/compiler_rt.zig -ofmt=c
|
||||
-OReleaseSmall
|
||||
--name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}"
|
||||
--pkg-begin build_options "${CMAKE_BINARY_DIR}/config.zig" --pkg-end
|
||||
-target "${HOST_TARGET_TRIPLE}"
|
||||
--color on
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#ifndef FUNC_GEN_H
|
||||
#define FUNC_GEN_H
|
||||
|
||||
#include "panic.h"
|
||||
#include "wasm.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Block {
|
||||
uint32_t type;
|
||||
uint32_t label;
|
||||
uint32_t stack_i;
|
||||
};
|
||||
|
||||
struct FuncGen {
|
||||
int8_t *type;
|
||||
uint32_t *stack;
|
||||
struct Block *block;
|
||||
uint32_t type_i;
|
||||
uint32_t stack_i;
|
||||
uint32_t block_i;
|
||||
uint32_t type_len;
|
||||
uint32_t stack_len;
|
||||
uint32_t block_len;
|
||||
};
|
||||
|
||||
static void FuncGen_init(struct FuncGen *self) {
|
||||
memset(self, 0, sizeof(struct FuncGen));
|
||||
}
|
||||
|
||||
static void FuncGen_reset(struct FuncGen *self) {
|
||||
self->type_i = 0;
|
||||
self->stack_i = 0;
|
||||
self->block_i = 0;
|
||||
}
|
||||
|
||||
static void FuncGen_free(struct FuncGen *self) {
|
||||
free(self->block);
|
||||
free(self->stack);
|
||||
free(self->type);
|
||||
}
|
||||
|
||||
static void FuncGen_outdent(struct FuncGen *self, FILE *out) {
|
||||
for (uint32_t i = 0; i < self->block_i; i += 1) fputs(" ", out);
|
||||
}
|
||||
|
||||
static void FuncGen_indent(struct FuncGen *self, FILE *out) {
|
||||
FuncGen_outdent(self, out);
|
||||
fputs(" ", out);
|
||||
}
|
||||
|
||||
static void FuncGen_cont(struct FuncGen *self, FILE *out) {
|
||||
FuncGen_indent(self, out);
|
||||
fputs(" ", out);
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_localAlloc(struct FuncGen *self, int8_t type) {
|
||||
if (self->type_i == self->type_len) {
|
||||
self->type_len += 10;
|
||||
self->type_len *= 2;
|
||||
self->type = realloc(self->type, sizeof(int8_t) * self->type_len);
|
||||
if (self->type == NULL) panic("out of memory");
|
||||
}
|
||||
uint32_t local_i = self->type_i;
|
||||
self->type[local_i] = type;
|
||||
self->type_i += 1;
|
||||
return local_i;
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_localDeclare(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
uint32_t local_i = FuncGen_localAlloc(self, (int8_t)val_type);
|
||||
fprintf(out, "%s l%" PRIu32, WasmValType_toC(val_type), local_i);
|
||||
return local_i;
|
||||
}
|
||||
|
||||
static enum WasmValType FuncGen_localType(const struct FuncGen *self, uint32_t local_idx) {
|
||||
return self->type[local_idx];
|
||||
}
|
||||
|
||||
static void FuncGen_stackPush(struct FuncGen *self, FILE *out, enum WasmValType val_type) {
|
||||
if (self->stack_i == self->stack_len) {
|
||||
self->stack_len += 10;
|
||||
self->stack_len *= 2;
|
||||
self->stack = realloc(self->stack, sizeof(uint32_t) * self->stack_len);
|
||||
if (self->stack == NULL) panic("out of memory");
|
||||
}
|
||||
FuncGen_indent(self, out);
|
||||
fputs("const ", out);
|
||||
self->stack[self->stack_i] = FuncGen_localDeclare(self, out, val_type);
|
||||
self->stack_i += 1;
|
||||
fputs(" = ", out);
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_stackAt(const struct FuncGen *self, uint32_t stack_idx) {
|
||||
return self->stack[self->stack_i - 1 - stack_idx];
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_stackPop(struct FuncGen *self) {
|
||||
self->stack_i -= 1;
|
||||
return self->stack[self->stack_i];
|
||||
}
|
||||
|
||||
static void FuncGen_label(struct FuncGen *self, FILE *out, uint32_t label) {
|
||||
FuncGen_indent(self, out);
|
||||
fprintf(out, "goto l%" PRIu32 ";\n", label);
|
||||
FuncGen_outdent(self, out);
|
||||
fprintf(out, "l%" PRIu32 ":;\n", label);
|
||||
}
|
||||
|
||||
static void FuncGen_blockBegin(struct FuncGen *self, FILE *out, enum WasmOpcode kind, int64_t type) {
|
||||
if (self->block_i == self->block_len) {
|
||||
self->block_len += 10;
|
||||
self->block_len *= 2;
|
||||
self->block = realloc(self->block, sizeof(struct Block) * self->block_len);
|
||||
if (self->block == NULL) panic("out of memory");
|
||||
}
|
||||
uint32_t label = FuncGen_localAlloc(self, type < 0 ? ~(int8_t)kind : (int8_t)kind);
|
||||
FuncGen_indent(self, out);
|
||||
if (kind == WasmOpcode_if) fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(self));
|
||||
fputs("{\n", out);
|
||||
self->block[self->block_i].type = type < 0 ? ~type : type;
|
||||
self->block[self->block_i].label = label;
|
||||
self->block[self->block_i].stack_i = self->stack_i;
|
||||
self->block_i += 1;
|
||||
if (kind == WasmOpcode_loop) FuncGen_label(self, out, label);
|
||||
}
|
||||
|
||||
static enum WasmOpcode FuncGen_blockKind(const struct FuncGen *self, uint32_t label_idx) {
|
||||
int8_t kind = self->type[self->block[self->block_i - 1 - label_idx].label];
|
||||
return (enum WasmOpcode)(kind < 0 ? ~kind : kind);
|
||||
}
|
||||
|
||||
static int64_t FuncGen_blockType(const struct FuncGen *self, uint32_t label_idx) {
|
||||
struct Block *block = &self->block[self->block_i - 1 - label_idx];
|
||||
return self->type[block->label] < 0 ? ~(int64_t)block->type : (int64_t)block->type;
|
||||
}
|
||||
|
||||
static uint32_t FuncGen_blockLabel(const struct FuncGen *self, uint32_t label_idx) {
|
||||
return self->block[self->block_i - 1 - label_idx].label;
|
||||
}
|
||||
|
||||
static void FuncGen_blockEnd(struct FuncGen *self, FILE *out) {
|
||||
enum WasmOpcode kind = FuncGen_blockKind(self, 0);
|
||||
uint32_t label = FuncGen_blockLabel(self, 0);
|
||||
if (kind != WasmOpcode_loop) FuncGen_label(self, out, label);
|
||||
self->block_i -= 1;
|
||||
FuncGen_indent(self, out);
|
||||
fputs("}\n", out);
|
||||
if (self->stack_i != self->block[self->block_i].stack_i) {
|
||||
FuncGen_indent(self, out);
|
||||
fprintf(out, "// stack mismatch %u != %u\n", self->stack_i, self->block[self->block_i].stack_i);
|
||||
}
|
||||
self->stack_i = self->block[self->block_i].stack_i;
|
||||
}
|
||||
|
||||
static bool FuncGen_done(const struct FuncGen *self) {
|
||||
return self->block_i == 0;
|
||||
}
|
||||
|
||||
#endif /* FUNC_GEN_H */
|
||||
@@ -0,0 +1,241 @@
|
||||
#ifndef INPUT_STREAM_H
|
||||
#define INPUT_STREAM_H
|
||||
|
||||
#include "panic.h"
|
||||
#include "wasm.h"
|
||||
|
||||
#include <zstd.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct InputStream {
|
||||
FILE *stream;
|
||||
ZSTD_DStream *ds;
|
||||
ZSTD_outBuffer out;
|
||||
ZSTD_inBuffer in;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
static void InputStream_open(struct InputStream *self, const char *path) {
|
||||
self->stream = fopen(path, "rb");
|
||||
if (self->stream == NULL) panic("unable to open input file");
|
||||
self->ds = ZSTD_createDStream();
|
||||
if (self->ds == NULL) panic("unable to create zstd context");
|
||||
size_t in_size = ZSTD_initDStream(self->ds);
|
||||
if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size));
|
||||
self->out.size = ZSTD_DStreamOutSize();
|
||||
self->out.dst = malloc(self->out.size + ZSTD_DStreamInSize());
|
||||
if (self->out.dst == NULL) panic("unable to allocate input buffers");
|
||||
self->out.pos = 0;
|
||||
self->in.src = (const char *)self->out.dst + self->out.size;
|
||||
self->in.size = fread((void *)self->in.src, 1, in_size, self->stream);
|
||||
self->in.pos = 0;
|
||||
self->pos = 0;
|
||||
}
|
||||
|
||||
static void InputStream_close(struct InputStream *self) {
|
||||
free(self->out.dst);
|
||||
ZSTD_freeDStream(self->ds);
|
||||
fclose(self->stream);
|
||||
}
|
||||
|
||||
static bool InputStream_atEnd(struct InputStream *self) {
|
||||
while (self->pos >= self->out.pos) {
|
||||
self->out.pos = 0;
|
||||
self->pos = 0;
|
||||
size_t in_size = ZSTD_decompressStream(self->ds, &self->out, &self->in);
|
||||
if (ZSTD_isError(in_size)) panic(ZSTD_getErrorName(in_size));
|
||||
if (self->in.pos >= self->in.size) {
|
||||
size_t max_in_size = ZSTD_DStreamInSize();
|
||||
if (in_size > max_in_size) in_size = max_in_size;
|
||||
self->in.size = fread((void *)self->in.src, 1, in_size, self->stream);
|
||||
self->in.pos = 0;
|
||||
if (self->in.pos >= self->in.size) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint8_t InputStream_readByte(struct InputStream *self) {
|
||||
if (InputStream_atEnd(self)) panic("unexpected end of input stream");
|
||||
uint8_t value = ((uint8_t *)self->out.dst)[self->pos];
|
||||
self->pos += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint32_t InputStream_readLittle_u32(struct InputStream *self) {
|
||||
uint32_t value = 0;
|
||||
value |= (uint32_t)InputStream_readByte(self) << 0;
|
||||
value |= (uint32_t)InputStream_readByte(self) << 8;
|
||||
value |= (uint32_t)InputStream_readByte(self) << 16;
|
||||
value |= (uint32_t)InputStream_readByte(self) << 24;
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint64_t InputStream_readLittle_u64(struct InputStream *self) {
|
||||
uint64_t value = 0;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 0;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 8;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 16;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 24;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 32;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 40;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 48;
|
||||
value |= (uint64_t)InputStream_readByte(self) << 56;
|
||||
return value;
|
||||
}
|
||||
|
||||
static float InputStream_readLittle_f32(struct InputStream *self) {
|
||||
uint32_t value = InputStream_readLittle_u32(self);
|
||||
float result;
|
||||
memcpy(&result, &value, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static double InputStream_readLittle_f64(struct InputStream *self) {
|
||||
uint64_t value = InputStream_readLittle_u64(self);
|
||||
double result;
|
||||
memcpy(&result, &value, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t InputStream_readLeb128_u32(struct InputStream *self) {
|
||||
uint32_t value = 0;
|
||||
uint8_t shift = 0;
|
||||
uint8_t byte;
|
||||
do {
|
||||
byte = InputStream_readByte(self);
|
||||
assert(shift < 32);
|
||||
value |= (uint32_t)(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
return value;
|
||||
}
|
||||
|
||||
static int32_t InputStream_readLeb128_i32(struct InputStream *self) {
|
||||
uint32_t value = 0;
|
||||
uint8_t shift = 0;
|
||||
uint8_t byte;
|
||||
do {
|
||||
byte = InputStream_readByte(self);
|
||||
assert(shift < 64);
|
||||
value |= (uint32_t)(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
if (shift < 32) {
|
||||
uint32_t mask = -((uint32_t)1 << shift);
|
||||
if (byte & 0x40) value |= mask; else value &= ~mask;
|
||||
}
|
||||
return (int32_t)value;
|
||||
}
|
||||
|
||||
static int64_t InputStream_readLeb128_u64(struct InputStream *self) {
|
||||
uint64_t value = 0;
|
||||
uint8_t shift = 0;
|
||||
uint8_t byte;
|
||||
do {
|
||||
byte = InputStream_readByte(self);
|
||||
assert(shift < 64);
|
||||
value |= (uint64_t)(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
return value;
|
||||
}
|
||||
|
||||
static int64_t InputStream_readLeb128_i64(struct InputStream *self) {
|
||||
uint64_t value = 0;
|
||||
uint8_t shift = 0;
|
||||
uint8_t byte;
|
||||
do {
|
||||
byte = InputStream_readByte(self);
|
||||
assert(shift < 64);
|
||||
value |= (uint64_t)(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
if (shift < 64) {
|
||||
uint64_t mask = -((uint64_t)1 << shift);
|
||||
if (byte & 0x40) value |= mask; else value &= ~mask;
|
||||
}
|
||||
return (int64_t)value;
|
||||
}
|
||||
|
||||
static char *InputStream_readName(struct InputStream *self) {
|
||||
uint32_t len = InputStream_readLeb128_u32(self);
|
||||
char *name = malloc(len + 1);
|
||||
if (name == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < len; ) {
|
||||
if (InputStream_atEnd(self)) panic("unexpected end of input stream");
|
||||
size_t remaining = self->out.pos - self->pos;
|
||||
if (remaining > len - i) remaining = len - i;
|
||||
memcpy(&name[i], &((char *)self->out.dst)[self->pos], remaining);
|
||||
i += remaining;
|
||||
self->pos += remaining;
|
||||
}
|
||||
name[len] = '\0';
|
||||
return name;
|
||||
}
|
||||
|
||||
static void InputStream_skipBytes(struct InputStream *self, size_t len) {
|
||||
for (size_t i = 0; i < len; ) {
|
||||
if (InputStream_atEnd(self)) panic("unexpected end of input stream");
|
||||
size_t remaining = self->out.pos - self->pos;
|
||||
if (remaining > len - i) remaining = len - i;
|
||||
i += remaining;
|
||||
self->pos += remaining;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t InputStream_skipToSection(struct InputStream *self, uint8_t expected_id) {
|
||||
while (true) {
|
||||
uint8_t id = InputStream_readByte(self);
|
||||
uint32_t size = InputStream_readLeb128_u32(self);
|
||||
if (id == expected_id) return size;
|
||||
InputStream_skipBytes(self, size);
|
||||
}
|
||||
}
|
||||
|
||||
struct ResultType {
|
||||
uint32_t len;
|
||||
int8_t types[1];
|
||||
};
|
||||
static struct ResultType *InputStream_readResultType(struct InputStream *self) {
|
||||
uint32_t len = InputStream_readLeb128_u32(self);
|
||||
struct ResultType *result_type = malloc(offsetof(struct ResultType, types) + sizeof(int8_t) * len);
|
||||
if (result_type == NULL) panic("out of memory");
|
||||
result_type->len = len;
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
int64_t val_type = InputStream_readLeb128_i64(self);
|
||||
switch (val_type) {
|
||||
case WasmValType_i32: case WasmValType_i64:
|
||||
case WasmValType_f32: case WasmValType_f64:
|
||||
break;
|
||||
|
||||
default: panic("unsupported valtype");
|
||||
}
|
||||
result_type->types[i] = val_type;
|
||||
}
|
||||
return result_type;
|
||||
}
|
||||
|
||||
struct Limits {
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
};
|
||||
static struct Limits InputStream_readLimits(struct InputStream *self) {
|
||||
struct Limits limits;
|
||||
uint8_t kind = InputStream_readByte(self);
|
||||
limits.min = InputStream_readLeb128_u32(self);
|
||||
switch (kind) {
|
||||
case 0x00: limits.max = UINT32_MAX; break;
|
||||
case 0x01: limits.max = InputStream_readLeb128_u32(self); break;
|
||||
default: panic("unsupported limit kind");
|
||||
}
|
||||
return limits;
|
||||
}
|
||||
|
||||
#endif /* INPUT_STREAM_H */
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef PANIC_H
|
||||
#define PANIC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void panic(const char *reason) {
|
||||
fprintf(stderr, "%s\n", reason);
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif /* PANIC_H */
|
||||
+948
@@ -0,0 +1,948 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
||||
#define LOG_TRACE 0
|
||||
|
||||
enum wasi_errno {
|
||||
wasi_errno_success = 0,
|
||||
wasi_errno_2big = 1,
|
||||
wasi_errno_acces = 2,
|
||||
wasi_errno_addrinuse = 3,
|
||||
wasi_errno_addrnotavail = 4,
|
||||
wasi_errno_afnosupport = 5,
|
||||
wasi_errno_again = 6,
|
||||
wasi_errno_already = 7,
|
||||
wasi_errno_badf = 8,
|
||||
wasi_errno_badmsg = 9,
|
||||
wasi_errno_busy = 10,
|
||||
wasi_errno_canceled = 11,
|
||||
wasi_errno_child = 12,
|
||||
wasi_errno_connaborted = 13,
|
||||
wasi_errno_connrefused = 14,
|
||||
wasi_errno_connreset = 15,
|
||||
wasi_errno_deadlk = 16,
|
||||
wasi_errno_destaddrreq = 17,
|
||||
wasi_errno_dom = 18,
|
||||
wasi_errno_dquot = 19,
|
||||
wasi_errno_exist = 20,
|
||||
wasi_errno_fault = 21,
|
||||
wasi_errno_fbig = 22,
|
||||
wasi_errno_hostunreach = 23,
|
||||
wasi_errno_idrm = 24,
|
||||
wasi_errno_ilseq = 25,
|
||||
wasi_errno_inprogress = 26,
|
||||
wasi_errno_intr = 27,
|
||||
wasi_errno_inval = 28,
|
||||
wasi_errno_io = 29,
|
||||
wasi_errno_isconn = 30,
|
||||
wasi_errno_isdir = 31,
|
||||
wasi_errno_loop = 32,
|
||||
wasi_errno_mfile = 33,
|
||||
wasi_errno_mlink = 34,
|
||||
wasi_errno_msgsize = 35,
|
||||
wasi_errno_multihop = 36,
|
||||
wasi_errno_nametoolong = 37,
|
||||
wasi_errno_netdown = 38,
|
||||
wasi_errno_netreset = 39,
|
||||
wasi_errno_netunreach = 40,
|
||||
wasi_errno_nfile = 41,
|
||||
wasi_errno_nobufs = 42,
|
||||
wasi_errno_nodev = 43,
|
||||
wasi_errno_noent = 44,
|
||||
wasi_errno_noexec = 45,
|
||||
wasi_errno_nolck = 46,
|
||||
wasi_errno_nolink = 47,
|
||||
wasi_errno_nomem = 48,
|
||||
wasi_errno_nomsg = 49,
|
||||
wasi_errno_noprotoopt = 50,
|
||||
wasi_errno_nospc = 51,
|
||||
wasi_errno_nosys = 52,
|
||||
wasi_errno_notconn = 53,
|
||||
wasi_errno_notdir = 54,
|
||||
wasi_errno_notempty = 55,
|
||||
wasi_errno_notrecoverable = 56,
|
||||
wasi_errno_notsock = 57,
|
||||
wasi_errno_opnotsupp = 58,
|
||||
wasi_errno_notty = 59,
|
||||
wasi_errno_nxio = 60,
|
||||
wasi_errno_overflow = 61,
|
||||
wasi_errno_ownerdead = 62,
|
||||
wasi_errno_perm = 63,
|
||||
wasi_errno_pipe = 64,
|
||||
wasi_errno_proto = 65,
|
||||
wasi_errno_protonosupport = 66,
|
||||
wasi_errno_prototype = 67,
|
||||
wasi_errno_range = 68,
|
||||
wasi_errno_rofs = 69,
|
||||
wasi_errno_spipe = 70,
|
||||
wasi_errno_srch = 71,
|
||||
wasi_errno_stale = 72,
|
||||
wasi_errno_timedout = 73,
|
||||
wasi_errno_txtbsy = 74,
|
||||
wasi_errno_xdev = 75,
|
||||
wasi_errno_notcapable = 76,
|
||||
};
|
||||
|
||||
enum wasi_oflags {
|
||||
wasi_oflags_creat = 1 << 0,
|
||||
wasi_oflags_directory = 1 << 1,
|
||||
wasi_oflags_excl = 1 << 2,
|
||||
wasi_oflags_trunc = 1 << 3,
|
||||
};
|
||||
|
||||
enum wasi_rights {
|
||||
wasi_rights_fd_datasync = 1ull << 0,
|
||||
wasi_rights_fd_read = 1ull << 1,
|
||||
wasi_rights_fd_seek = 1ull << 2,
|
||||
wasi_rights_fd_fdstat_set_flags = 1ull << 3,
|
||||
wasi_rights_fd_sync = 1ull << 4,
|
||||
wasi_rights_fd_tell = 1ull << 5,
|
||||
wasi_rights_fd_write = 1ull << 6,
|
||||
wasi_rights_fd_advise = 1ull << 7,
|
||||
wasi_rights_fd_allocate = 1ull << 8,
|
||||
wasi_rights_path_create_directory = 1ull << 9,
|
||||
wasi_rights_path_create_file = 1ull << 10,
|
||||
wasi_rights_path_link_source = 1ull << 11,
|
||||
wasi_rights_path_link_target = 1ull << 12,
|
||||
wasi_rights_path_open = 1ull << 13,
|
||||
wasi_rights_fd_readdir = 1ull << 14,
|
||||
wasi_rights_path_readlink = 1ull << 15,
|
||||
wasi_rights_path_rename_source = 1ull << 16,
|
||||
wasi_rights_path_rename_target = 1ull << 17,
|
||||
wasi_rights_path_filestat_get = 1ull << 18,
|
||||
wasi_rights_path_filestat_set_size = 1ull << 19,
|
||||
wasi_rights_path_filestat_set_times = 1ull << 20,
|
||||
wasi_rights_fd_filestat_get = 1ull << 21,
|
||||
wasi_rights_fd_filestat_set_size = 1ull << 22,
|
||||
wasi_rights_fd_filestat_set_times = 1ull << 23,
|
||||
wasi_rights_path_symlink = 1ull << 24,
|
||||
wasi_rights_path_remove_directory = 1ull << 25,
|
||||
wasi_rights_path_unlink_file = 1ull << 26,
|
||||
wasi_rights_poll_fd_readwrite = 1ull << 27,
|
||||
wasi_rights_sock_shutdown = 1ull << 28,
|
||||
wasi_rights_sock_accept = 1ull << 29,
|
||||
};
|
||||
|
||||
enum wasi_clockid {
|
||||
wasi_clockid_realtime = 0,
|
||||
wasi_clockid_monotonic = 1,
|
||||
wasi_clockid_process_cputime_id = 2,
|
||||
wasi_clockid_thread_cputime_id = 3,
|
||||
};
|
||||
|
||||
enum wasi_filetype {
|
||||
wasi_filetype_unknown = 0,
|
||||
wasi_filetype_block_device = 1,
|
||||
wasi_filetype_character_device = 2,
|
||||
wasi_filetype_directory = 3,
|
||||
wasi_filetype_regular_file = 4,
|
||||
wasi_filetype_socket_dgram = 5,
|
||||
wasi_filetype_socket_stream = 6,
|
||||
wasi_filetype_symbolic_link = 7,
|
||||
};
|
||||
|
||||
enum wasi_fdflags {
|
||||
wasi_fdflags_append = 1 << 0,
|
||||
wasi_fdflags_dsync = 1 << 1,
|
||||
wasi_fdflags_nonblock = 1 << 2,
|
||||
wasi_fdflags_rsync = 1 << 3,
|
||||
wasi_fdflags_sync = 1 << 4,
|
||||
};
|
||||
|
||||
struct wasi_filestat {
|
||||
uint64_t dev;
|
||||
uint64_t ino;
|
||||
uint64_t filetype;
|
||||
uint64_t nlink;
|
||||
uint64_t size;
|
||||
uint64_t atim;
|
||||
uint64_t mtim;
|
||||
uint64_t ctim;
|
||||
};
|
||||
|
||||
struct wasi_fdstat {
|
||||
uint16_t fs_filetype;
|
||||
uint16_t fs_flags;
|
||||
uint32_t padding;
|
||||
uint64_t fs_rights_inheriting;
|
||||
};
|
||||
|
||||
struct wasi_ciovec {
|
||||
uint32_t ptr;
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
extern uint8_t **const wasm_memory;
|
||||
extern void wasm__start(void);
|
||||
|
||||
static int global_argc;
|
||||
static char **global_argv;
|
||||
|
||||
static uint32_t de_len;
|
||||
struct DirEntry {
|
||||
enum wasi_filetype filetype;
|
||||
time_t atim;
|
||||
time_t mtim;
|
||||
time_t ctim;
|
||||
char *guest_path;
|
||||
char *host_path;
|
||||
} *des;
|
||||
|
||||
static uint32_t fd_len;
|
||||
static struct FileDescriptor {
|
||||
uint32_t de;
|
||||
FILE *stream;
|
||||
} *fds;
|
||||
|
||||
static void *dupe(const void *data, size_t len) {
|
||||
void *copy = malloc(len);
|
||||
if (copy == NULL) panic("out of memory");
|
||||
memcpy(copy, data, len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "usage: %s <zig-lib-path> <args...>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
global_argc = argc;
|
||||
global_argv = argv;
|
||||
|
||||
time_t now = time(NULL);
|
||||
srand((unsigned)now);
|
||||
|
||||
de_len = 4;
|
||||
des = calloc(de_len, sizeof(struct DirEntry));
|
||||
if (des == NULL) panic("out of memory");
|
||||
|
||||
des[0].filetype = wasi_filetype_character_device;
|
||||
|
||||
des[1].filetype = wasi_filetype_directory;
|
||||
des[1].guest_path = dupe(".", sizeof("."));
|
||||
des[1].host_path = dupe(".", sizeof("."));
|
||||
|
||||
des[2].filetype = wasi_filetype_directory;
|
||||
des[2].guest_path = dupe("/cache", sizeof("/cache"));
|
||||
des[2].atim = now;
|
||||
des[2].mtim = now;
|
||||
des[2].ctim = now;
|
||||
|
||||
des[3].filetype = wasi_filetype_directory;
|
||||
des[3].guest_path = dupe("/lib", sizeof("/lib"));
|
||||
des[3].host_path = dupe(argv[1], strlen(argv[1]));
|
||||
|
||||
fd_len = 6;
|
||||
fds = calloc(sizeof(struct FileDescriptor), fd_len);
|
||||
if (fds == NULL) panic("out of memory");
|
||||
fds[0].stream = stdin;
|
||||
fds[1].stream = stdout;
|
||||
fds[2].stream = stderr;
|
||||
fds[3].de = 1;
|
||||
fds[4].de = 2;
|
||||
fds[5].de = 3;
|
||||
|
||||
wasm__start();
|
||||
}
|
||||
|
||||
static 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) {
|
||||
if (path[0] != '/') {
|
||||
if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
|
||||
if (des[fds[dir_fd].de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
||||
}
|
||||
|
||||
struct DirEntry *new_des = realloc(des, (de_len + 1) * sizeof(struct DirEntry));
|
||||
if (new_des == NULL) return wasi_errno_nomem;
|
||||
des = new_des;
|
||||
|
||||
struct DirEntry *de = &des[de_len];
|
||||
de->filetype = filetype;
|
||||
de->atim = tim;
|
||||
de->mtim = tim;
|
||||
de->ctim = tim;
|
||||
if (path[0] == '/') {
|
||||
de->guest_path = malloc(path_len + 1);
|
||||
if (de->guest_path == NULL) return wasi_errno_nomem;
|
||||
memcpy(&de->guest_path[0], path, path_len);
|
||||
de->guest_path[path_len] = '\0';
|
||||
|
||||
de->host_path = malloc(path_len + 1);
|
||||
if (de->host_path == NULL) return wasi_errno_nomem;
|
||||
memcpy(&de->host_path[0], path, path_len);
|
||||
de->host_path[path_len] = '\0';
|
||||
} else {
|
||||
const struct DirEntry *dir_de = &des[fds[dir_fd].de];
|
||||
if (dir_de->guest_path != NULL) {
|
||||
size_t dir_guest_path_len = strlen(dir_de->guest_path);
|
||||
de->guest_path = malloc(dir_guest_path_len + 1 + path_len + 1);
|
||||
if (de->guest_path == NULL) return wasi_errno_nomem;
|
||||
memcpy(&de->guest_path[0], dir_de->guest_path, dir_guest_path_len);
|
||||
de->guest_path[dir_guest_path_len] = '/';
|
||||
memcpy(&de->guest_path[dir_guest_path_len + 1], path, path_len);
|
||||
de->guest_path[dir_guest_path_len + 1 + path_len] = '\0';
|
||||
} else de->guest_path = NULL;
|
||||
|
||||
if (dir_de->host_path != NULL) {
|
||||
size_t dir_host_path_len = strlen(dir_de->host_path);
|
||||
de->host_path = malloc(dir_host_path_len + 1 + path_len + 1);
|
||||
if (de->host_path == NULL) { free(de->guest_path); return wasi_errno_nomem; }
|
||||
memcpy(&de->host_path[0], dir_de->host_path, dir_host_path_len);
|
||||
de->host_path[dir_host_path_len] = '/';
|
||||
memcpy(&de->host_path[dir_host_path_len + 1], path, path_len);
|
||||
de->host_path[dir_host_path_len + 1 + path_len] = '\0';
|
||||
} else de->host_path = NULL;
|
||||
}
|
||||
|
||||
if (res_de != NULL) *res_de = de_len;
|
||||
de_len += 1;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
static enum wasi_errno DirEntry_lookup(uint32_t dir_fd, uint32_t flags, const char *path, uint32_t path_len, uint32_t *res_de) {
|
||||
(void)flags;
|
||||
if (path[0] == '/') {
|
||||
for (uint32_t de = 0; de < de_len; de += 1) {
|
||||
if (des[de].guest_path == NULL) continue;
|
||||
if (memcmp(&des[de].guest_path[0], path, path_len) != 0) continue;
|
||||
if (des[de].guest_path[path_len] != '\0') continue;
|
||||
if (res_de != NULL) *res_de = de;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
} else {
|
||||
if (dir_fd >= fd_len || fds[dir_fd].de >= de_len) return wasi_errno_badf;
|
||||
const struct DirEntry *dir_de = &des[fds[dir_fd].de];
|
||||
if (dir_de->filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
||||
|
||||
size_t dir_guest_path_len = strlen(dir_de->guest_path);
|
||||
for (uint32_t de = 0; de < de_len; de += 1) {
|
||||
if (des[de].guest_path == NULL) continue;
|
||||
if (memcmp(&des[de].guest_path[0], dir_de->guest_path, dir_guest_path_len) != 0) continue;
|
||||
if (des[de].guest_path[dir_guest_path_len] != '/') continue;
|
||||
if (memcmp(&des[de].guest_path[dir_guest_path_len + 1], path, path_len) != 0) continue;
|
||||
if (des[de].guest_path[dir_guest_path_len + 1 + path_len] != '\0') continue;
|
||||
if (res_de != NULL) *res_de = de;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
}
|
||||
return wasi_errno_noent;
|
||||
}
|
||||
|
||||
static void DirEntry_filestat(uint32_t de, struct wasi_filestat *res_filestat) {
|
||||
res_filestat->dev = 0;
|
||||
res_filestat->ino = de;
|
||||
res_filestat->filetype = des[de].filetype;
|
||||
res_filestat->nlink = 1;
|
||||
res_filestat->size = 0;
|
||||
res_filestat->atim = des[de].atim * UINT64_C(1000000000);
|
||||
res_filestat->mtim = des[de].mtim * UINT64_C(1000000000);
|
||||
res_filestat->ctim = des[de].ctim * UINT64_C(1000000000);
|
||||
}
|
||||
|
||||
static void DirEntry_unlink(uint32_t de) {
|
||||
free(des[de].guest_path);
|
||||
des[de].guest_path = NULL;
|
||||
free(des[de].host_path);
|
||||
des[de].host_path = NULL;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_args_sizes_get(uint32_t argv_size, uint32_t argv_buf_size) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
uint32_t *argv_size_ptr = (uint32_t *)&m[argv_size];
|
||||
uint32_t *argv_buf_size_ptr = (uint32_t *)&m[argv_buf_size];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_args_sizes_get()\n");
|
||||
#endif
|
||||
|
||||
int c_argc = global_argc;
|
||||
char **c_argv = global_argv;
|
||||
uint32_t size = 0;
|
||||
for (int i = 0; i < c_argc; i += 1) {
|
||||
if (i == 1) continue;
|
||||
size += strlen(c_argv[i]) + 1;
|
||||
}
|
||||
*argv_size_ptr = c_argc - 1;
|
||||
*argv_buf_size_ptr = size;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_args_get(uint32_t argv, uint32_t argv_buf) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
uint32_t *argv_ptr = (uint32_t *)&m[argv];
|
||||
char *argv_buf_ptr = (char *)&m[argv_buf];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_args_get()\n");
|
||||
#endif
|
||||
|
||||
int c_argc = global_argc;
|
||||
char **c_argv = global_argv;
|
||||
uint32_t dst_i = 0;
|
||||
uint32_t argv_buf_i = 0;
|
||||
for (int src_i = 0; src_i < c_argc; src_i += 1) {
|
||||
if (src_i == 1) continue;
|
||||
argv_ptr[dst_i] = argv_buf + argv_buf_i;
|
||||
dst_i += 1;
|
||||
strcpy(&argv_buf_ptr[argv_buf_i], c_argv[src_i]);
|
||||
argv_buf_i += strlen(c_argv[src_i]) + 1;
|
||||
}
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_prestat_get(uint32_t fd, uint32_t res_prestat) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
uint32_t *res_prestat_ptr = (uint32_t *)&m[res_prestat];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_get(%u)\n", fd);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
|
||||
res_prestat_ptr[0] = 0;
|
||||
res_prestat_ptr[1] = strlen(des[fds[fd].de].guest_path);
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_prestat_dir_name(uint32_t fd, uint32_t path, uint32_t path_len) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
char *path_ptr = (char *)&m[path];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_prestat_dir_name(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
strncpy(path_ptr, des[fds[fd].de].guest_path, path_len);
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
void wasi_snapshot_preview1_proc_exit(uint32_t rval) {
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_proc_exit(%u)\n", rval);
|
||||
#endif
|
||||
|
||||
exit(rval);
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_close(uint32_t fd) {
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_close(%u)\n", fd);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
if (fds[fd].stream != NULL) fclose(fds[fd].stream);
|
||||
|
||||
fds[fd].de = ~0;
|
||||
fds[fd].stream = NULL;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_path_create_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *path_ptr = (const char *)&m[path];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_path_create_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
||||
#endif
|
||||
|
||||
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, NULL);
|
||||
switch (lookup_errno) {
|
||||
case wasi_errno_success: return wasi_errno_exist;
|
||||
case wasi_errno_noent: break;
|
||||
default: return lookup_errno;
|
||||
}
|
||||
return DirEntry_create(fd, path_ptr, path_len, wasi_filetype_directory, time(NULL), NULL);
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_read(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
||||
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_read(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
switch (des[fds[fd].de].filetype) {
|
||||
case wasi_filetype_character_device: break;
|
||||
case wasi_filetype_regular_file: break;
|
||||
case wasi_filetype_directory: return wasi_errno_inval;
|
||||
default: panic("unimplemented");
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
||||
size_t read_size = 0;
|
||||
if (fds[fd].stream != NULL)
|
||||
read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
||||
else
|
||||
panic("unimplemented");
|
||||
size += read_size;
|
||||
if (read_size < iovs_ptr[i].len) break;
|
||||
}
|
||||
|
||||
if (size > 0) des[fds[fd].de].atim = time(NULL);
|
||||
*res_size_ptr = size;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_filestat_get(uint32_t fd, uint32_t res_filestat) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_get(%u)\n", fd);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
DirEntry_filestat(fds[fd].de, res_filestat_ptr);
|
||||
if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_success;
|
||||
if (fds[fd].stream == NULL) return wasi_errno_success;
|
||||
fpos_t pos;
|
||||
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
|
||||
long size = ftell(fds[fd].stream);
|
||||
if (size < 0) return wasi_errno_io;
|
||||
res_filestat_ptr->size = size;
|
||||
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_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) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *old_path_ptr = (const char *)&m[old_path];
|
||||
const char *new_path_ptr = (const char *)&m[new_path];
|
||||
#if LOG_TRACE
|
||||
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);
|
||||
#endif
|
||||
|
||||
uint32_t old_de;
|
||||
enum wasi_errno old_lookup_errno = DirEntry_lookup(fd, 0, old_path_ptr, old_path_len, &old_de);
|
||||
if (old_lookup_errno != wasi_errno_success) return old_lookup_errno;
|
||||
DirEntry_unlink(old_de);
|
||||
|
||||
uint32_t de;
|
||||
enum wasi_errno new_lookup_errno = DirEntry_lookup(new_fd, 0, new_path_ptr, new_path_len, &de);
|
||||
switch (new_lookup_errno) {
|
||||
case wasi_errno_success: DirEntry_unlink(de); break;
|
||||
case wasi_errno_noent: break;
|
||||
default: return new_lookup_errno;
|
||||
}
|
||||
|
||||
uint32_t new_de;
|
||||
enum wasi_errno create_errno =
|
||||
DirEntry_create(new_fd, new_path_ptr, new_path_len, des[old_de].filetype, 0, &new_de);
|
||||
if (create_errno != wasi_errno_success) return create_errno;
|
||||
des[new_de].atim = des[old_de].atim;
|
||||
des[new_de].mtim = des[old_de].mtim;
|
||||
des[new_de].ctim = time(NULL);
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_filestat_set_size(uint32_t fd, uint64_t size) {
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_filestat_set_size(%u, %llu)\n", fd, (unsigned long long)size);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
if (des[fds[fd].de].filetype != wasi_filetype_regular_file) return wasi_errno_inval;
|
||||
|
||||
if (fds[fd].stream == NULL) return wasi_errno_success;
|
||||
fpos_t pos;
|
||||
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
if (fseek(fds[fd].stream, 0, SEEK_END) < 0) return wasi_errno_io;
|
||||
long old_size = ftell(fds[fd].stream);
|
||||
if (old_size < 0) return wasi_errno_io;
|
||||
if (size > (unsigned long)old_size) {
|
||||
if (fseek(fds[fd].stream, size - 1, SEEK_SET) < 0) return wasi_errno_io;
|
||||
fputc(0, fds[fd].stream);
|
||||
} else if (size < (unsigned long)old_size) panic("unimplemented");
|
||||
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_pwrite(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
||||
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_pwrite(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
switch (des[fds[fd].de].filetype) {
|
||||
case wasi_filetype_character_device: break;
|
||||
case wasi_filetype_regular_file: break;
|
||||
case wasi_filetype_directory: return wasi_errno_inval;
|
||||
default: panic("unimplemented");
|
||||
}
|
||||
|
||||
fpos_t pos;
|
||||
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
|
||||
|
||||
size_t size = 0;
|
||||
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
||||
size_t written_size = 0;
|
||||
if (fds[fd].stream != NULL)
|
||||
written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
||||
else
|
||||
written_size = iovs_ptr[i].len;
|
||||
size += written_size;
|
||||
if (written_size < iovs_ptr[i].len) break;
|
||||
}
|
||||
|
||||
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
|
||||
if (size > 0) {
|
||||
time_t now = time(NULL);
|
||||
des[fds[fd].de].atim = now;
|
||||
des[fds[fd].de].mtim = now;
|
||||
}
|
||||
*res_size_ptr = size;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_random_get(uint32_t buf, uint32_t buf_len) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
uint8_t *buf_ptr = (uint8_t *)&m[buf];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_random_get(%u)\n", buf_len);
|
||||
#endif
|
||||
|
||||
for (uint32_t i = 0; i < buf_len; i += 1) buf_ptr[i] = (uint8_t)rand();
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_filestat_set_times(uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) {
|
||||
(void)fd;
|
||||
(void)atim;
|
||||
(void)mtim;
|
||||
(void)fst_flags;
|
||||
#if LOG_TRACE
|
||||
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);
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_environ_sizes_get(uint32_t environ_size, uint32_t environ_buf_size) {
|
||||
(void)environ_size;
|
||||
(void)environ_buf_size;
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_environ_sizes_get()\n");
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_environ_get(uint32_t environ, uint32_t environ_buf) {
|
||||
(void)environ;
|
||||
(void)environ_buf;
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_environ_get()\n");
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_path_filestat_get(uint32_t fd, uint32_t flags, uint32_t path, uint32_t path_len, uint32_t res_filestat) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *path_ptr = (const char *)&m[path];
|
||||
struct wasi_filestat *res_filestat_ptr = (struct wasi_filestat *)&m[res_filestat];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_path_filestat_get(%u, 0x%X, \"%.*s\")\n", fd, flags, (int)path_len, path_ptr);
|
||||
#endif
|
||||
|
||||
uint32_t de;
|
||||
enum wasi_errno lookup_errno = DirEntry_lookup(fd, flags, path_ptr, path_len, &de);
|
||||
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
||||
DirEntry_filestat(de, res_filestat_ptr);
|
||||
if (des[de].filetype == wasi_filetype_regular_file && des[de].host_path != NULL) {
|
||||
FILE *stream = fopen(des[de].host_path, "rb");
|
||||
if (stream != NULL) {
|
||||
if (fseek(stream, 0, SEEK_END) >= 0) {
|
||||
long size = ftell(stream);
|
||||
if (size >= 0) res_filestat_ptr->size = size;
|
||||
}
|
||||
fclose(stream);
|
||||
}
|
||||
}
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_fdstat_get(uint32_t fd, uint32_t res_fdstat) {
|
||||
(void)fd;
|
||||
(void)res_fdstat;
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_fdstat_get(%u)\n", fd);
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_readdir(uint32_t fd, uint32_t buf, uint32_t buf_len, uint64_t cookie, uint32_t res_size) {
|
||||
(void)fd;
|
||||
(void)buf;
|
||||
(void)buf_len;
|
||||
(void)cookie;
|
||||
(void)res_size;
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_readdir(%u, 0x%X, %u, %llu)\n", fd, buf, buf_len, (unsigned long long)cookie);
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_write(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t res_size) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
||||
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_write(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
switch (des[fds[fd].de].filetype) {
|
||||
case wasi_filetype_character_device: break;
|
||||
case wasi_filetype_regular_file: break;
|
||||
case wasi_filetype_directory: return wasi_errno_inval;
|
||||
default: panic("unimplemented");
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
||||
size_t written_size = 0;
|
||||
if (fds[fd].stream != NULL)
|
||||
written_size = fwrite(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
||||
else
|
||||
written_size = iovs_ptr[i].len;
|
||||
size += written_size;
|
||||
if (written_size < iovs_ptr[i].len) break;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
time_t now = time(NULL);
|
||||
des[fds[fd].de].atim = now;
|
||||
des[fds[fd].de].mtim = now;
|
||||
}
|
||||
*res_size_ptr = size;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_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) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *path_ptr = (const char *)&m[path];
|
||||
(void)fs_rights_inheriting;
|
||||
uint32_t *res_fd_ptr = (uint32_t *)&m[res_fd];
|
||||
#if LOG_TRACE
|
||||
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);
|
||||
#endif
|
||||
|
||||
bool creat = (oflags & wasi_oflags_creat) != 0;
|
||||
bool directory = (oflags & wasi_oflags_directory) != 0;
|
||||
bool excl = (oflags & wasi_oflags_excl) != 0;
|
||||
bool trunc = (oflags & wasi_oflags_trunc) != 0;
|
||||
bool append = (fdflags & wasi_fdflags_append) != 0;
|
||||
|
||||
uint32_t de;
|
||||
enum wasi_errno lookup_errno = DirEntry_lookup(fd, dirflags, path_ptr, path_len, &de);
|
||||
if (lookup_errno == wasi_errno_success) {
|
||||
if (directory && des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
||||
|
||||
struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
|
||||
if (new_fds == NULL) return wasi_errno_nomem;
|
||||
fds = new_fds;
|
||||
|
||||
fds[fd_len].de = de;
|
||||
switch (des[de].filetype) {
|
||||
case wasi_filetype_directory: fds[fd_len].stream = NULL; break;
|
||||
default: panic("unimplemented");
|
||||
}
|
||||
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "fd = %u\n", fd_len);
|
||||
#endif
|
||||
*res_fd_ptr = fd_len;
|
||||
fd_len += 1;
|
||||
}
|
||||
if (lookup_errno != wasi_errno_noent) return lookup_errno;
|
||||
|
||||
struct FileDescriptor *new_fds = realloc(fds, (fd_len + 1) * sizeof(struct FileDescriptor));
|
||||
if (new_fds == NULL) return wasi_errno_nomem;
|
||||
fds = new_fds;
|
||||
|
||||
enum wasi_filetype filetype = directory ? wasi_filetype_directory : wasi_filetype_regular_file;
|
||||
enum wasi_errno create_errno = DirEntry_create(fd, path_ptr, path_len, filetype, 0, &de);
|
||||
if (create_errno != wasi_errno_success) return create_errno;
|
||||
FILE *stream;
|
||||
if (!directory) {
|
||||
if (des[de].host_path == NULL) {
|
||||
if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
|
||||
time_t now = time(NULL);
|
||||
des[de].atim = now;
|
||||
des[de].mtim = now;
|
||||
des[de].ctim = now;
|
||||
stream = NULL;
|
||||
} else {
|
||||
if (oflags != (append ? wasi_oflags_creat : wasi_oflags_creat | wasi_oflags_trunc)) {
|
||||
char mode[] = "rb+";
|
||||
if ((fs_rights_base & wasi_rights_fd_write) == 0) mode[2] = '\0';
|
||||
stream = fopen(des[de].host_path, mode);
|
||||
if (stream != NULL) {
|
||||
if (append || excl || trunc) fclose(stream);
|
||||
if (excl) {
|
||||
DirEntry_unlink(de);
|
||||
de_len -= 1;
|
||||
return wasi_errno_exist;
|
||||
}
|
||||
} else if (!creat) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_noent; }
|
||||
}
|
||||
if (append || trunc || stream == NULL) {
|
||||
char mode[] = "wb+";
|
||||
if ((fs_rights_base & wasi_rights_fd_read) == 0) mode[2] = '\0';
|
||||
if (trunc || !append) {
|
||||
stream = fopen(des[de].host_path, mode);
|
||||
if (append && stream != NULL) fclose(stream);
|
||||
}
|
||||
if (append) {
|
||||
mode[0] = 'a';
|
||||
stream = fopen(des[de].host_path, mode);
|
||||
}
|
||||
}
|
||||
if (stream == NULL) { DirEntry_unlink(de); de_len -= 1; return wasi_errno_isdir; }
|
||||
}
|
||||
} else stream = NULL;
|
||||
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "fd = %u\n", fd_len);
|
||||
#endif
|
||||
fds[fd_len].de = de;
|
||||
fds[fd_len].stream = stream;
|
||||
*res_fd_ptr = fd_len;
|
||||
fd_len += 1;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_clock_time_get(uint32_t id, uint64_t precision, uint32_t res_timestamp) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
(void)precision;
|
||||
uint64_t *res_timestamp_ptr = (uint64_t *)&m[res_timestamp];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_clock_time_get(%u, %llu)\n", id, (unsigned long long)precision);
|
||||
#endif
|
||||
|
||||
switch (id) {
|
||||
case wasi_clockid_realtime:
|
||||
*res_timestamp_ptr = time(NULL) * UINT64_C(1000000000);
|
||||
break;
|
||||
case wasi_clockid_monotonic:
|
||||
case wasi_clockid_process_cputime_id:
|
||||
case wasi_clockid_thread_cputime_id:
|
||||
*res_timestamp_ptr = clock() * (UINT64_C(1000000000) / CLOCKS_PER_SEC);
|
||||
break;
|
||||
default: return wasi_errno_inval;
|
||||
}
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_path_remove_directory(uint32_t fd, uint32_t path, uint32_t path_len) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *path_ptr = (const char *)&m[path];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_path_remove_directory(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
||||
#endif
|
||||
|
||||
uint32_t de;
|
||||
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
|
||||
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
||||
if (des[de].filetype != wasi_filetype_directory) return wasi_errno_notdir;
|
||||
DirEntry_unlink(de);
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_path_unlink_file(uint32_t fd, uint32_t path, uint32_t path_len) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *path_ptr = (const char *)&m[path];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_path_unlink_file(%u, \"%.*s\")\n", fd, (int)path_len, path_ptr);
|
||||
#endif
|
||||
|
||||
uint32_t de;
|
||||
enum wasi_errno lookup_errno = DirEntry_lookup(fd, 0, path_ptr, path_len, &de);
|
||||
if (lookup_errno != wasi_errno_success) return lookup_errno;
|
||||
if (des[de].filetype == wasi_filetype_directory) return wasi_errno_isdir;
|
||||
if (des[de].filetype != wasi_filetype_regular_file) panic("unimplemented");
|
||||
DirEntry_unlink(de);
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_fd_pread(uint32_t fd, uint32_t iovs, uint32_t iovs_len, uint64_t offset, uint32_t res_size) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
struct wasi_ciovec *iovs_ptr = (struct wasi_ciovec *)&m[iovs];
|
||||
uint32_t *res_size_ptr = (uint32_t *)&m[res_size];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_fd_pread(%u, 0x%X, %u)\n", fd, iovs, iovs_len);
|
||||
#endif
|
||||
|
||||
if (fd >= fd_len || fds[fd].de >= de_len) return wasi_errno_badf;
|
||||
switch (des[fds[fd].de].filetype) {
|
||||
case wasi_filetype_character_device: break;
|
||||
case wasi_filetype_regular_file: break;
|
||||
case wasi_filetype_directory: return wasi_errno_inval;
|
||||
default: panic("unimplemented");
|
||||
}
|
||||
|
||||
fpos_t pos;
|
||||
if (fgetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
if (fseek(fds[fd].stream, offset, SEEK_SET) < 0) return wasi_errno_io;
|
||||
|
||||
size_t size = 0;
|
||||
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
||||
size_t read_size = 0;
|
||||
if (fds[fd].stream != NULL)
|
||||
read_size = fread(&m[iovs_ptr[i].ptr], 1, iovs_ptr[i].len, fds[fd].stream);
|
||||
else
|
||||
panic("unimplemented");
|
||||
size += read_size;
|
||||
if (read_size < iovs_ptr[i].len) break;
|
||||
}
|
||||
|
||||
if (fsetpos(fds[fd].stream, &pos) < 0) return wasi_errno_io;
|
||||
|
||||
if (size > 0) des[fds[fd].de].atim = time(NULL);
|
||||
*res_size_ptr = size;
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
uint32_t wasi_snapshot_preview1_poll_oneoff(uint32_t in, uint32_t out, uint32_t nsubscriptions, uint32_t res_nevents) {
|
||||
(void)in;
|
||||
(void)out;
|
||||
(void)nsubscriptions;
|
||||
(void)res_nevents;
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_poll_oneoff(%u)\n", nsubscriptions);
|
||||
#endif
|
||||
|
||||
panic("unimplemented");
|
||||
return wasi_errno_success;
|
||||
}
|
||||
|
||||
|
||||
void wasi_snapshot_preview1_debug(uint32_t string, uint64_t x) {
|
||||
uint8_t *const m = *wasm_memory;
|
||||
const char *string_ptr = (const char *)&m[string];
|
||||
#if LOG_TRACE
|
||||
fprintf(stderr, "wasi_snapshot_preview1_debug(\"%s\", %llu, 0x%llX)\n", string_ptr, (unsigned long long)x, (unsigned long long)x);
|
||||
#endif
|
||||
|
||||
(void)string_ptr;
|
||||
(void)x;
|
||||
}
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
#ifndef WASM_H
|
||||
#define WASM_H
|
||||
|
||||
#include "panic.h"
|
||||
|
||||
enum WasmSectionId {
|
||||
WasmSectionId_type = 1,
|
||||
WasmSectionId_import = 2,
|
||||
WasmSectionId_func = 3,
|
||||
WasmSectionId_table = 4,
|
||||
WasmSectionId_mem = 5,
|
||||
WasmSectionId_global = 6,
|
||||
WasmSectionId_export = 7,
|
||||
WasmSectionId_start = 8,
|
||||
WasmSectionId_elem = 9,
|
||||
WasmSectionId_code = 10,
|
||||
WasmSectionId_data = 11,
|
||||
WasmSectionId_datacount = 12,
|
||||
};
|
||||
|
||||
enum WasmValType {
|
||||
WasmValType_i32 = -0x01,
|
||||
WasmValType_i64 = -0x02,
|
||||
WasmValType_f32 = -0x03,
|
||||
WasmValType_f64 = -0x04,
|
||||
WasmValType_v128 = -0x05,
|
||||
WasmValType_funcref = -0x10,
|
||||
WasmValType_externref = -0x11,
|
||||
WasmValType_empty = -0x40,
|
||||
};
|
||||
static const char *WasmValType_toC(enum WasmValType val_type) {
|
||||
switch (val_type) {
|
||||
case WasmValType_i32: return "uint32_t";
|
||||
case WasmValType_i64: return "uint64_t";
|
||||
case WasmValType_f32: return "float";
|
||||
case WasmValType_f64: return "double";
|
||||
case WasmValType_v128: panic("vector types are unsupported");
|
||||
case WasmValType_funcref: return "void (*)(void)";
|
||||
case WasmValType_externref: return "void *";
|
||||
default: panic("unsupported value type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum WasmMut {
|
||||
WasmMut_const = 0x00,
|
||||
WasmMut_var = 0x01,
|
||||
};
|
||||
static const char *WasmMut_toC(enum WasmMut val_type) {
|
||||
switch (val_type) {
|
||||
case WasmMut_const: return "const ";
|
||||
case WasmMut_var: return "";
|
||||
default: panic("unsupported mut");
|
||||
}
|
||||
}
|
||||
|
||||
enum WasmOpcode {
|
||||
WasmOpcode_unreachable = 0x00,
|
||||
WasmOpcode_nop = 0x01,
|
||||
WasmOpcode_block = 0x02,
|
||||
WasmOpcode_loop = 0x03,
|
||||
WasmOpcode_if = 0x04,
|
||||
WasmOpcode_else = 0x05,
|
||||
WasmOpcode_end = 0x0B,
|
||||
WasmOpcode_br = 0x0C,
|
||||
WasmOpcode_br_if = 0x0D,
|
||||
WasmOpcode_br_table = 0x0E,
|
||||
WasmOpcode_return = 0x0F,
|
||||
WasmOpcode_call = 0x10,
|
||||
WasmOpcode_call_indirect = 0x11,
|
||||
|
||||
WasmOpcode_drop = 0x1A,
|
||||
WasmOpcode_select = 0x1B,
|
||||
WasmOpcode_select_t = 0x1C,
|
||||
|
||||
WasmOpcode_local_get = 0x20,
|
||||
WasmOpcode_local_set = 0x21,
|
||||
WasmOpcode_local_tee = 0x22,
|
||||
WasmOpcode_global_get = 0x23,
|
||||
WasmOpcode_global_set = 0x24,
|
||||
|
||||
WasmOpcode_table_get = 0x25,
|
||||
WasmOpcode_table_set = 0x26,
|
||||
|
||||
WasmOpcode_i32_load = 0x28,
|
||||
WasmOpcode_i64_load = 0x29,
|
||||
WasmOpcode_f32_load = 0x2A,
|
||||
WasmOpcode_f64_load = 0x2B,
|
||||
WasmOpcode_i32_load8_s = 0x2C,
|
||||
WasmOpcode_i32_load8_u = 0x2D,
|
||||
WasmOpcode_i32_load16_s = 0x2E,
|
||||
WasmOpcode_i32_load16_u = 0x2F,
|
||||
WasmOpcode_i64_load8_s = 0x30,
|
||||
WasmOpcode_i64_load8_u = 0x31,
|
||||
WasmOpcode_i64_load16_s = 0x32,
|
||||
WasmOpcode_i64_load16_u = 0x33,
|
||||
WasmOpcode_i64_load32_s = 0x34,
|
||||
WasmOpcode_i64_load32_u = 0x35,
|
||||
WasmOpcode_i32_store = 0x36,
|
||||
WasmOpcode_i64_store = 0x37,
|
||||
WasmOpcode_f32_store = 0x38,
|
||||
WasmOpcode_f64_store = 0x39,
|
||||
WasmOpcode_i32_store8 = 0x3A,
|
||||
WasmOpcode_i32_store16 = 0x3B,
|
||||
WasmOpcode_i64_store8 = 0x3C,
|
||||
WasmOpcode_i64_store16 = 0x3D,
|
||||
WasmOpcode_i64_store32 = 0x3E,
|
||||
WasmOpcode_memory_size = 0x3F,
|
||||
WasmOpcode_memory_grow = 0x40,
|
||||
|
||||
WasmOpcode_i32_const = 0x41,
|
||||
WasmOpcode_i64_const = 0x42,
|
||||
WasmOpcode_f32_const = 0x43,
|
||||
WasmOpcode_f64_const = 0x44,
|
||||
|
||||
WasmOpcode_i32_eqz = 0x45,
|
||||
WasmOpcode_i32_eq = 0x46,
|
||||
WasmOpcode_i32_ne = 0x47,
|
||||
WasmOpcode_i32_lt_s = 0x48,
|
||||
WasmOpcode_i32_lt_u = 0x49,
|
||||
WasmOpcode_i32_gt_s = 0x4A,
|
||||
WasmOpcode_i32_gt_u = 0x4B,
|
||||
WasmOpcode_i32_le_s = 0x4C,
|
||||
WasmOpcode_i32_le_u = 0x4D,
|
||||
WasmOpcode_i32_ge_s = 0x4E,
|
||||
WasmOpcode_i32_ge_u = 0x4F,
|
||||
|
||||
WasmOpcode_i64_eqz = 0x50,
|
||||
WasmOpcode_i64_eq = 0x51,
|
||||
WasmOpcode_i64_ne = 0x52,
|
||||
WasmOpcode_i64_lt_s = 0x53,
|
||||
WasmOpcode_i64_lt_u = 0x54,
|
||||
WasmOpcode_i64_gt_s = 0x55,
|
||||
WasmOpcode_i64_gt_u = 0x56,
|
||||
WasmOpcode_i64_le_s = 0x57,
|
||||
WasmOpcode_i64_le_u = 0x58,
|
||||
WasmOpcode_i64_ge_s = 0x59,
|
||||
WasmOpcode_i64_ge_u = 0x5A,
|
||||
|
||||
WasmOpcode_f32_eq = 0x5B,
|
||||
WasmOpcode_f32_ne = 0x5C,
|
||||
WasmOpcode_f32_lt = 0x5D,
|
||||
WasmOpcode_f32_gt = 0x5E,
|
||||
WasmOpcode_f32_le = 0x5F,
|
||||
WasmOpcode_f32_ge = 0x60,
|
||||
|
||||
WasmOpcode_f64_eq = 0x61,
|
||||
WasmOpcode_f64_ne = 0x62,
|
||||
WasmOpcode_f64_lt = 0x63,
|
||||
WasmOpcode_f64_gt = 0x64,
|
||||
WasmOpcode_f64_le = 0x65,
|
||||
WasmOpcode_f64_ge = 0x66,
|
||||
|
||||
WasmOpcode_i32_clz = 0x67,
|
||||
WasmOpcode_i32_ctz = 0x68,
|
||||
WasmOpcode_i32_popcnt = 0x69,
|
||||
WasmOpcode_i32_add = 0x6A,
|
||||
WasmOpcode_i32_sub = 0x6B,
|
||||
WasmOpcode_i32_mul = 0x6C,
|
||||
WasmOpcode_i32_div_s = 0x6D,
|
||||
WasmOpcode_i32_div_u = 0x6E,
|
||||
WasmOpcode_i32_rem_s = 0x6F,
|
||||
WasmOpcode_i32_rem_u = 0x70,
|
||||
WasmOpcode_i32_and = 0x71,
|
||||
WasmOpcode_i32_or = 0x72,
|
||||
WasmOpcode_i32_xor = 0x73,
|
||||
WasmOpcode_i32_shl = 0x74,
|
||||
WasmOpcode_i32_shr_s = 0x75,
|
||||
WasmOpcode_i32_shr_u = 0x76,
|
||||
WasmOpcode_i32_rotl = 0x77,
|
||||
WasmOpcode_i32_rotr = 0x78,
|
||||
|
||||
WasmOpcode_i64_clz = 0x79,
|
||||
WasmOpcode_i64_ctz = 0x7A,
|
||||
WasmOpcode_i64_popcnt = 0x7B,
|
||||
WasmOpcode_i64_add = 0x7C,
|
||||
WasmOpcode_i64_sub = 0x7D,
|
||||
WasmOpcode_i64_mul = 0x7E,
|
||||
WasmOpcode_i64_div_s = 0x7F,
|
||||
WasmOpcode_i64_div_u = 0x80,
|
||||
WasmOpcode_i64_rem_s = 0x81,
|
||||
WasmOpcode_i64_rem_u = 0x82,
|
||||
WasmOpcode_i64_and = 0x83,
|
||||
WasmOpcode_i64_or = 0x84,
|
||||
WasmOpcode_i64_xor = 0x85,
|
||||
WasmOpcode_i64_shl = 0x86,
|
||||
WasmOpcode_i64_shr_s = 0x87,
|
||||
WasmOpcode_i64_shr_u = 0x88,
|
||||
WasmOpcode_i64_rotl = 0x89,
|
||||
WasmOpcode_i64_rotr = 0x8A,
|
||||
|
||||
WasmOpcode_f32_abs = 0x8B,
|
||||
WasmOpcode_f32_neg = 0x8C,
|
||||
WasmOpcode_f32_ceil = 0x8D,
|
||||
WasmOpcode_f32_floor = 0x8E,
|
||||
WasmOpcode_f32_trunc = 0x8F,
|
||||
WasmOpcode_f32_nearest = 0x90,
|
||||
WasmOpcode_f32_sqrt = 0x91,
|
||||
WasmOpcode_f32_add = 0x92,
|
||||
WasmOpcode_f32_sub = 0x93,
|
||||
WasmOpcode_f32_mul = 0x94,
|
||||
WasmOpcode_f32_div = 0x95,
|
||||
WasmOpcode_f32_min = 0x96,
|
||||
WasmOpcode_f32_max = 0x97,
|
||||
WasmOpcode_f32_copysign = 0x98,
|
||||
|
||||
WasmOpcode_f64_abs = 0x99,
|
||||
WasmOpcode_f64_neg = 0x9A,
|
||||
WasmOpcode_f64_ceil = 0x9B,
|
||||
WasmOpcode_f64_floor = 0x9C,
|
||||
WasmOpcode_f64_trunc = 0x9D,
|
||||
WasmOpcode_f64_nearest = 0x9E,
|
||||
WasmOpcode_f64_sqrt = 0x9F,
|
||||
WasmOpcode_f64_add = 0xA0,
|
||||
WasmOpcode_f64_sub = 0xA1,
|
||||
WasmOpcode_f64_mul = 0xA2,
|
||||
WasmOpcode_f64_div = 0xA3,
|
||||
WasmOpcode_f64_min = 0xA4,
|
||||
WasmOpcode_f64_max = 0xA5,
|
||||
WasmOpcode_f64_copysign = 0xA6,
|
||||
|
||||
WasmOpcode_i32_wrap_i64 = 0xA7,
|
||||
WasmOpcode_i32_trunc_f32_s = 0xA8,
|
||||
WasmOpcode_i32_trunc_f32_u = 0xA9,
|
||||
WasmOpcode_i32_trunc_f64_s = 0xAA,
|
||||
WasmOpcode_i32_trunc_f64_u = 0xAB,
|
||||
WasmOpcode_i64_extend_i32_s = 0xAC,
|
||||
WasmOpcode_i64_extend_i32_u = 0xAD,
|
||||
WasmOpcode_i64_trunc_f32_s = 0xAE,
|
||||
WasmOpcode_i64_trunc_f32_u = 0xAF,
|
||||
WasmOpcode_i64_trunc_f64_s = 0xB0,
|
||||
WasmOpcode_i64_trunc_f64_u = 0xB1,
|
||||
WasmOpcode_f32_convert_i32_s = 0xB2,
|
||||
WasmOpcode_f32_convert_i32_u = 0xB3,
|
||||
WasmOpcode_f32_convert_i64_s = 0xB4,
|
||||
WasmOpcode_f32_convert_i64_u = 0xB5,
|
||||
WasmOpcode_f32_demote_f64 = 0xB6,
|
||||
WasmOpcode_f64_convert_i32_s = 0xB7,
|
||||
WasmOpcode_f64_convert_i32_u = 0xB8,
|
||||
WasmOpcode_f64_convert_i64_s = 0xB9,
|
||||
WasmOpcode_f64_convert_i64_u = 0xBA,
|
||||
WasmOpcode_f64_promote_f32 = 0xBB,
|
||||
WasmOpcode_i32_reinterpret_f32 = 0xBC,
|
||||
WasmOpcode_i64_reinterpret_f64 = 0xBD,
|
||||
WasmOpcode_f32_reinterpret_i32 = 0xBE,
|
||||
WasmOpcode_f64_reinterpret_i64 = 0xBF,
|
||||
|
||||
WasmOpcode_i32_extend8_s = 0xC0,
|
||||
WasmOpcode_i32_extend16_s = 0xC1,
|
||||
WasmOpcode_i64_extend8_s = 0xC2,
|
||||
WasmOpcode_i64_extend16_s = 0xC3,
|
||||
WasmOpcode_i64_extend32_s = 0xC4,
|
||||
|
||||
WasmOpcode_prefixed = 0xFC,
|
||||
};
|
||||
|
||||
enum WasmPrefixedOpcode {
|
||||
WasmPrefixedOpcode_i32_trunc_sat_f32_s = 0,
|
||||
WasmPrefixedOpcode_i32_trunc_sat_f32_u = 1,
|
||||
WasmPrefixedOpcode_i32_trunc_sat_f64_s = 2,
|
||||
WasmPrefixedOpcode_i32_trunc_sat_f64_u = 3,
|
||||
WasmPrefixedOpcode_i64_trunc_sat_f32_s = 4,
|
||||
WasmPrefixedOpcode_i64_trunc_sat_f32_u = 5,
|
||||
WasmPrefixedOpcode_i64_trunc_sat_f64_s = 6,
|
||||
WasmPrefixedOpcode_i64_trunc_sat_f64_u = 7,
|
||||
|
||||
WasmPrefixedOpcode_memory_init = 8,
|
||||
WasmPrefixedOpcode_data_drop = 9,
|
||||
WasmPrefixedOpcode_memory_copy = 10,
|
||||
WasmPrefixedOpcode_memory_fill = 11,
|
||||
|
||||
WasmPrefixedOpcode_table_init = 12,
|
||||
WasmPrefixedOpcode_elem_drop = 13,
|
||||
WasmPrefixedOpcode_table_copy = 14,
|
||||
WasmPrefixedOpcode_table_grow = 15,
|
||||
WasmPrefixedOpcode_table_size = 16,
|
||||
WasmPrefixedOpcode_table_fill = 17,
|
||||
};
|
||||
|
||||
#endif /* WASM_H */
|
||||
+2520
@@ -0,0 +1,2520 @@
|
||||
#include "FuncGen.h"
|
||||
#include "InputStream.h"
|
||||
#include "panic.h"
|
||||
#include "wasm.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct FuncType {
|
||||
const struct ResultType *param;
|
||||
const struct ResultType *result;
|
||||
};
|
||||
static const struct FuncType *FuncType_blockType(const struct FuncType *types, int64_t block_type) {
|
||||
if (block_type >= 0) return &types[block_type];
|
||||
|
||||
static const struct ResultType none = { 0, { 0 }};
|
||||
static const struct ResultType i32 = { 1, { WasmValType_i32 } };
|
||||
static const struct ResultType i64 = { 1, { WasmValType_i64 } };
|
||||
static const struct ResultType f32 = { 1, { WasmValType_f32 } };
|
||||
static const struct ResultType f64 = { 1, { WasmValType_f64 } };
|
||||
|
||||
static const struct FuncType none_i32 = { &none, &i32 };
|
||||
static const struct FuncType none_i64 = { &none, &i64 };
|
||||
static const struct FuncType none_f32 = { &none, &f32 };
|
||||
static const struct FuncType none_f64 = { &none, &f64 };
|
||||
static const struct FuncType none_none = { &none, &none };
|
||||
|
||||
switch (block_type) {
|
||||
case WasmValType_i32: return &none_i32;
|
||||
case WasmValType_i64: return &none_i64;
|
||||
case WasmValType_f32: return &none_f32;
|
||||
case WasmValType_f64: return &none_f64;
|
||||
case WasmValType_empty: return &none_none;
|
||||
default: panic("unsupported block type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uint32_t evalExpr(struct InputStream *in) {
|
||||
uint32_t value;
|
||||
while (true) {
|
||||
switch (InputStream_readByte(in)) {
|
||||
case WasmOpcode_end: return value;
|
||||
|
||||
case WasmOpcode_i32_const:
|
||||
value = (uint32_t)InputStream_readLeb128_i32(in);
|
||||
break;
|
||||
|
||||
default: panic("unsupported expr opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void renderExpr(FILE *out, struct InputStream *in) {
|
||||
while (true) {
|
||||
switch (InputStream_readByte(in)) {
|
||||
case WasmOpcode_end: return;
|
||||
|
||||
case WasmOpcode_i32_const: {
|
||||
uint32_t value = (uint32_t)InputStream_readLeb128_i32(in);
|
||||
fprintf(out, "UINT32_C(0x%" PRIX32 ")", value);
|
||||
break;
|
||||
}
|
||||
|
||||
default: panic("unsupported expr opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "usage: %s in.wasm.zst out.c\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *mod = "wasm";
|
||||
bool isBigEndian = false; // TODO
|
||||
|
||||
struct InputStream in;
|
||||
InputStream_open(&in, argv[1]);
|
||||
|
||||
if (InputStream_readByte(&in) != '\0' ||
|
||||
InputStream_readByte(&in) != 'a' ||
|
||||
InputStream_readByte(&in) != 's' ||
|
||||
InputStream_readByte(&in) != 'm') panic("input is not a zstd-compressed wasm file");
|
||||
if (InputStream_readLittle_u32(&in) != 1) panic("unsupported wasm version");
|
||||
|
||||
FILE *out = fopen(argv[2], "w");
|
||||
if (out == NULL) panic("unable to open output file");
|
||||
fputs("#include <math.h>\n"
|
||||
"#include <stdint.h>\n"
|
||||
"#include <stdlib.h>\n"
|
||||
"#include <string.h>\n"
|
||||
"\n"
|
||||
"static uint32_t i32_reinterpret_f32(const float src) {\n"
|
||||
" uint32_t dst;\n"
|
||||
" memcpy(&dst, &src, sizeof(dst));\n"
|
||||
" return dst;\n"
|
||||
"}\n"
|
||||
"static uint64_t i64_reinterpret_f64(const double src) {\n"
|
||||
" uint64_t dst;\n"
|
||||
" memcpy(&dst, &src, sizeof(dst));\n"
|
||||
" return dst;\n"
|
||||
"}\n"
|
||||
"static float f32_reinterpret_i32(const uint32_t src) {\n"
|
||||
" float dst;\n"
|
||||
" memcpy(&dst, &src, sizeof(dst));\n"
|
||||
" return dst;\n"
|
||||
"}\n"
|
||||
"static double f64_reinterpret_i64(const uint64_t src) {\n"
|
||||
" double dst;\n"
|
||||
" memcpy(&dst, &src, sizeof(dst));\n"
|
||||
" return dst;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t n) {\n"
|
||||
" uint32_t r = *p;\n"
|
||||
" uint32_t new_p = r + n;\n"
|
||||
" uint8_t *new_m = realloc(*m, new_p << 16);\n"
|
||||
" if (new_m == NULL) return UINT32_C(0xFFFFFFF);\n"
|
||||
" memset(&new_m[r << 16], 0, n << 16);\n"
|
||||
" *m = new_m;\n"
|
||||
" *p = new_p;\n"
|
||||
" return r;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"static int inited;\n"
|
||||
"static void init_elem(void);\n"
|
||||
"static void init_data(void);\n"
|
||||
"static void init(void) {\n"
|
||||
" if (inited != 0) return;\n"
|
||||
" init_elem();\n"
|
||||
" init_data();\n"
|
||||
" inited = 1;\n"
|
||||
"}\n"
|
||||
"\n", out);
|
||||
|
||||
struct FuncType *types;
|
||||
uint32_t max_param_len = 0;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_type);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
types = malloc(sizeof(struct FuncType) * len);
|
||||
if (types == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
if (InputStream_readByte(&in) != 0x60) panic("expected functype");
|
||||
types[i].param = InputStream_readResultType(&in);
|
||||
if (types[i].param->len > max_param_len) max_param_len = types[i].param->len;
|
||||
types[i].result = InputStream_readResultType(&in);
|
||||
}
|
||||
}
|
||||
|
||||
struct Import {
|
||||
const char *mod;
|
||||
const char *name;
|
||||
uint32_t type_idx;
|
||||
} *imports;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_import);
|
||||
uint32_t imports_len = InputStream_readLeb128_u32(&in);
|
||||
{
|
||||
imports = malloc(sizeof(struct Import) * imports_len);
|
||||
if (imports == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < imports_len; i += 1) {
|
||||
imports[i].mod = InputStream_readName(&in);
|
||||
imports[i].name = InputStream_readName(&in);
|
||||
switch (InputStream_readByte(&in)) {
|
||||
case 0x00: { // func
|
||||
imports[i].type_idx = InputStream_readLeb128_u32(&in);
|
||||
const struct FuncType *func_type = &types[imports[i].type_idx];
|
||||
switch (func_type->result->len) {
|
||||
case 0: fputs("void", out); break;
|
||||
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fprintf(out, " %s_%s(", imports[i].mod, imports[i].name);
|
||||
if (func_type->param->len == 0) fputs("void", out);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fputs(WasmValType_toC(func_type->param->types[param_i]), out);
|
||||
}
|
||||
fputs(");\n", out);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: // table
|
||||
case 0x02: // mem
|
||||
case 0x03: // global
|
||||
default:
|
||||
panic("unsupported import type");
|
||||
}
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
struct Func {
|
||||
uint32_t type_idx;
|
||||
} *funcs;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_func);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
funcs = malloc(sizeof(struct Func) * len);
|
||||
if (funcs == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
funcs[i].type_idx = InputStream_readLeb128_u32(&in);
|
||||
const struct FuncType *func_type = &types[funcs[i].type_idx];
|
||||
fputs("static ", out);
|
||||
switch (func_type->result->len) {
|
||||
case 0: fputs("void", out); break;
|
||||
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fprintf(out, " f%" PRIu32 "(", i);
|
||||
if (func_type->param->len == 0) fputs("void", out);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fprintf(out, "%s", WasmValType_toC(func_type->param->types[param_i]));
|
||||
}
|
||||
fputs(");\n", out);
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
struct Table {
|
||||
int8_t type;
|
||||
struct Limits limits;
|
||||
} *tables;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_table);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
tables = malloc(sizeof(struct Table) * len);
|
||||
if (tables == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
int64_t ref_type = InputStream_readLeb128_i64(&in);
|
||||
switch (ref_type) {
|
||||
case WasmValType_funcref:
|
||||
break;
|
||||
|
||||
default: panic("unsupported reftype");
|
||||
}
|
||||
tables[i].type = ref_type;
|
||||
tables[i].limits = InputStream_readLimits(&in);
|
||||
if (tables[i].limits.min != tables[i].limits.max) panic("growable table not supported");
|
||||
fprintf(out, "static void (*t%" PRIu32 "[UINT32_C(%" PRIu32 ")])(void);\n",
|
||||
i, tables[i].limits.min);
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
struct Mem {
|
||||
struct Limits limits;
|
||||
} *mems;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_mem);
|
||||
uint32_t mems_len = InputStream_readLeb128_u32(&in);
|
||||
{
|
||||
mems = malloc(sizeof(struct Mem) * mems_len);
|
||||
if (mems == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < mems_len; i += 1) {
|
||||
mems[i].limits = InputStream_readLimits(&in);
|
||||
fprintf(out, "static uint8_t *m%" PRIu32 ";\n"
|
||||
"static uint32_t p%" PRIu32 ";\n", i, i);
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
struct Global {
|
||||
bool mut;
|
||||
int8_t val_type;
|
||||
} *globals;
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_global);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
globals = malloc(sizeof(struct Global) * len);
|
||||
if (globals == NULL) panic("out of memory");
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
int64_t val_type = InputStream_readLeb128_i64(&in);
|
||||
enum WasmMut mut = InputStream_readByte(&in);
|
||||
fprintf(out, "%s%s g%" PRIu32 " = ", WasmMut_toC(mut), WasmValType_toC(val_type), i);
|
||||
renderExpr(out, &in);
|
||||
fputs(";\n", out);
|
||||
globals[i].mut = mut;
|
||||
globals[i].val_type = val_type;
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_export);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
for (uint32_t i = 0; i < len; i += 1) {
|
||||
char *name = InputStream_readName(&in);
|
||||
uint8_t kind = InputStream_readByte(&in);
|
||||
uint32_t idx = InputStream_readLeb128_u32(&in);
|
||||
switch (kind) {
|
||||
case 0x00: {
|
||||
if (idx < imports_len) panic("can't export an import");
|
||||
const struct FuncType *func_type = &types[funcs[idx - imports_len].type_idx];
|
||||
switch (func_type->result->len) {
|
||||
case 0: fputs("void", out); break;
|
||||
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fprintf(out, " %s_%s(", mod, name);
|
||||
if (func_type->param->len == 0) fputs("void", out);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fprintf(out, "%s l%" PRIu32, WasmValType_toC(func_type->param->types[param_i]), param_i);
|
||||
}
|
||||
fprintf(out,
|
||||
") {\n"
|
||||
" init();\n"
|
||||
" %sf%" PRIu32 "(",
|
||||
func_type->result->len > 0 ? "return " : "", idx - imports_len);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fprintf(out, "l%" PRIu32, param_i);
|
||||
}
|
||||
fputs(");\n}\n", out);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x02:
|
||||
fprintf(out, "uint8_t **const %s_%s = &m%" PRIu32 ";\n", mod, name, idx);
|
||||
break;
|
||||
|
||||
default: panic("unsupported export kind");
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
fputc('\n', out);
|
||||
}
|
||||
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_elem);
|
||||
{
|
||||
uint32_t table_i = 0;
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
fputs("static void init_elem(void) {\n", out);
|
||||
for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
|
||||
uint32_t table_idx = 0;
|
||||
uint32_t elem_type = InputStream_readLeb128_u32(&in);
|
||||
if (elem_type != 0x00) panic("unsupported elem type");
|
||||
uint32_t offset = evalExpr(&in);
|
||||
uint32_t segment_len = InputStream_readLeb128_u32(&in);
|
||||
for (uint32_t i = 0; i < segment_len; i += 1) {
|
||||
uint32_t func_id = InputStream_readLeb128_u32(&in);
|
||||
fprintf(out, " t%" PRIu32 "[UINT32_C(%" PRIu32 ")] = (void (*)(void))&",
|
||||
table_idx, offset + i);
|
||||
if (func_id < imports_len)
|
||||
fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
|
||||
else
|
||||
fprintf(out, "f%" PRIu32, func_id - imports_len);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
}
|
||||
fputs("}\n\n", out);
|
||||
}
|
||||
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_code);
|
||||
{
|
||||
struct FuncGen fg;
|
||||
FuncGen_init(&fg);
|
||||
bool *param_used = malloc(sizeof(bool) * max_param_len);
|
||||
uint32_t *param_stash = malloc(sizeof(uint32_t) * max_param_len);
|
||||
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
for (uint32_t func_i = 0; func_i < len; func_i += 1) {
|
||||
FuncGen_reset(&fg);
|
||||
|
||||
uint32_t code_len = InputStream_readLeb128_u32(&in);
|
||||
const struct FuncType *func_type = &types[funcs[func_i].type_idx];
|
||||
fputs("static ", out);
|
||||
switch (func_type->result->len) {
|
||||
case 0: fputs("void", out); break;
|
||||
case 1: fputs(WasmValType_toC(func_type->result->types[0]), out); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fprintf(out, " f%" PRIu32 "(", func_i);
|
||||
if (func_type->param->len == 0) fputs("void", out);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
param_used[param_i] = false;
|
||||
int8_t param_type = func_type->param->types[param_i];
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
FuncGen_localDeclare(&fg, out, param_type);
|
||||
}
|
||||
fputs(") {\n", out);
|
||||
|
||||
for (uint32_t local_sets_remaining = InputStream_readLeb128_u32(&in);
|
||||
local_sets_remaining > 0; local_sets_remaining -= 1) {
|
||||
uint32_t local_set_len = InputStream_readLeb128_u32(&in);
|
||||
int64_t val_type = InputStream_readLeb128_i64(&in);
|
||||
for (; local_set_len > 0; local_set_len -= 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
FuncGen_localDeclare(&fg, out, val_type);
|
||||
fputs(" = 0;\n", out);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t unreachable_depth = 0;
|
||||
for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
|
||||
result_i -= 1;
|
||||
FuncGen_indent(&fg, out);
|
||||
(void)FuncGen_localDeclare(&fg, out,
|
||||
func_type->result->types[result_i]);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
FuncGen_blockBegin(&fg, out, WasmOpcode_block, funcs[func_i].type_idx);
|
||||
while (!FuncGen_done(&fg)) {
|
||||
//static const char *mnemonics[] = {
|
||||
// [WasmOpcode_unreachable] = "unreachable",
|
||||
// [WasmOpcode_nop] = "nop",
|
||||
// [WasmOpcode_block] = "block",
|
||||
// [WasmOpcode_loop] = "loop",
|
||||
// [WasmOpcode_if] = "if",
|
||||
// [WasmOpcode_else] = "else",
|
||||
// [WasmOpcode_end] = "end",
|
||||
// [WasmOpcode_br] = "br",
|
||||
// [WasmOpcode_br_if] = "br_if",
|
||||
// [WasmOpcode_br_table] = "br_table",
|
||||
// [WasmOpcode_return] = "return",
|
||||
// [WasmOpcode_call] = "call",
|
||||
// [WasmOpcode_call_indirect] = "call_indirect",
|
||||
//
|
||||
// [WasmOpcode_drop] = "drop",
|
||||
// [WasmOpcode_select] = "select",
|
||||
// [WasmOpcode_select_t] = "select t",
|
||||
//
|
||||
// [WasmOpcode_local_get] = "local.get",
|
||||
// [WasmOpcode_local_set] = "local.set",
|
||||
// [WasmOpcode_local_tee] = "local.tee",
|
||||
// [WasmOpcode_global_get] = "global.get",
|
||||
// [WasmOpcode_global_set] = "global.set",
|
||||
// [WasmOpcode_table_get] = "table.get",
|
||||
// [WasmOpcode_table_set] = "table.set",
|
||||
//
|
||||
// [WasmOpcode_i32_load] = "i32.load",
|
||||
// [WasmOpcode_i64_load] = "i64.load",
|
||||
// [WasmOpcode_f32_load] = "f32.load",
|
||||
// [WasmOpcode_f64_load] = "f64.load",
|
||||
// [WasmOpcode_i32_load8_s] = "i32.load8_s",
|
||||
// [WasmOpcode_i32_load8_u] = "i32.load8_u",
|
||||
// [WasmOpcode_i32_load16_s] = "i32.load16_s",
|
||||
// [WasmOpcode_i32_load16_u] = "i32.load16_u",
|
||||
// [WasmOpcode_i64_load8_s] = "i64.load8_s",
|
||||
// [WasmOpcode_i64_load8_u] = "i64.load8_u",
|
||||
// [WasmOpcode_i64_load16_s] = "i64.load16_s",
|
||||
// [WasmOpcode_i64_load16_u] = "i64.load16_u",
|
||||
// [WasmOpcode_i64_load32_s] = "i64.load32_s",
|
||||
// [WasmOpcode_i64_load32_u] = "i64.load32_u",
|
||||
// [WasmOpcode_i32_store] = "i32.store",
|
||||
// [WasmOpcode_i64_store] = "i64.store",
|
||||
// [WasmOpcode_f32_store] = "f32.store",
|
||||
// [WasmOpcode_f64_store] = "f64.store",
|
||||
// [WasmOpcode_i32_store8] = "i32.store8",
|
||||
// [WasmOpcode_i32_store16] = "i32.store16",
|
||||
// [WasmOpcode_i64_store8] = "i64.store8",
|
||||
// [WasmOpcode_i64_store16] = "i64.store16",
|
||||
// [WasmOpcode_i64_store32] = "i64.store32",
|
||||
// [WasmOpcode_memory_size] = "memory.size",
|
||||
// [WasmOpcode_memory_grow] = "memory.grow",
|
||||
//
|
||||
// [WasmOpcode_i32_const] = "i32.const",
|
||||
// [WasmOpcode_i64_const] = "i64.const",
|
||||
// [WasmOpcode_f32_const] = "f32.const",
|
||||
// [WasmOpcode_f64_const] = "f64.const",
|
||||
//
|
||||
// [WasmOpcode_i32_eqz] = "i32.eqz",
|
||||
// [WasmOpcode_i32_eq] = "i32.eq",
|
||||
// [WasmOpcode_i32_ne] = "i32.ne",
|
||||
// [WasmOpcode_i32_lt_s] = "i32.lt_s",
|
||||
// [WasmOpcode_i32_lt_u] = "i32.lt_u",
|
||||
// [WasmOpcode_i32_gt_s] = "i32.gt_s",
|
||||
// [WasmOpcode_i32_gt_u] = "i32.gt_u",
|
||||
// [WasmOpcode_i32_le_s] = "i32.le_s",
|
||||
// [WasmOpcode_i32_le_u] = "i32.le_u",
|
||||
// [WasmOpcode_i32_ge_s] = "i32.ge_s",
|
||||
// [WasmOpcode_i32_ge_u] = "i32.ge_u",
|
||||
//
|
||||
// [WasmOpcode_i64_eqz] = "i64.eqz",
|
||||
// [WasmOpcode_i64_eq] = "i64.eq",
|
||||
// [WasmOpcode_i64_ne] = "i64.ne",
|
||||
// [WasmOpcode_i64_lt_s] = "i64.lt_s",
|
||||
// [WasmOpcode_i64_lt_u] = "i64.lt_u",
|
||||
// [WasmOpcode_i64_gt_s] = "i64.gt_s",
|
||||
// [WasmOpcode_i64_gt_u] = "i64.gt_u",
|
||||
// [WasmOpcode_i64_le_s] = "i64.le_s",
|
||||
// [WasmOpcode_i64_le_u] = "i64.le_u",
|
||||
// [WasmOpcode_i64_ge_s] = "i64.ge_s",
|
||||
// [WasmOpcode_i64_ge_u] = "i64.ge_u",
|
||||
//
|
||||
// [WasmOpcode_f32_eq] = "f32.eq",
|
||||
// [WasmOpcode_f32_ne] = "f32.ne",
|
||||
// [WasmOpcode_f32_lt] = "f32.lt",
|
||||
// [WasmOpcode_f32_gt] = "f32.gt",
|
||||
// [WasmOpcode_f32_le] = "f32.le",
|
||||
// [WasmOpcode_f32_ge] = "f32.ge",
|
||||
//
|
||||
// [WasmOpcode_f64_eq] = "f64.eq",
|
||||
// [WasmOpcode_f64_ne] = "f64.ne",
|
||||
// [WasmOpcode_f64_lt] = "f64.lt",
|
||||
// [WasmOpcode_f64_gt] = "f64.gt",
|
||||
// [WasmOpcode_f64_le] = "f64.le",
|
||||
// [WasmOpcode_f64_ge] = "f64.ge",
|
||||
//
|
||||
// [WasmOpcode_i32_clz] = "i32.clz",
|
||||
// [WasmOpcode_i32_ctz] = "i32.ctz",
|
||||
// [WasmOpcode_i32_popcnt] = "i32.popcnt",
|
||||
// [WasmOpcode_i32_add] = "i32.add",
|
||||
// [WasmOpcode_i32_sub] = "i32.sub",
|
||||
// [WasmOpcode_i32_mul] = "i32.mul",
|
||||
// [WasmOpcode_i32_div_s] = "i32.div_s",
|
||||
// [WasmOpcode_i32_div_u] = "i32.div_u",
|
||||
// [WasmOpcode_i32_rem_s] = "i32.rem_s",
|
||||
// [WasmOpcode_i32_rem_u] = "i32.rem_u",
|
||||
// [WasmOpcode_i32_and] = "i32.and",
|
||||
// [WasmOpcode_i32_or] = "i32.or",
|
||||
// [WasmOpcode_i32_xor] = "i32.xor",
|
||||
// [WasmOpcode_i32_shl] = "i32.shl",
|
||||
// [WasmOpcode_i32_shr_s] = "i32.shr_s",
|
||||
// [WasmOpcode_i32_shr_u] = "i32.shr_u",
|
||||
// [WasmOpcode_i32_rotl] = "i32.rotl",
|
||||
// [WasmOpcode_i32_rotr] = "i32.rotr",
|
||||
//
|
||||
// [WasmOpcode_i64_clz] = "i64.clz",
|
||||
// [WasmOpcode_i64_ctz] = "i64.ctz",
|
||||
// [WasmOpcode_i64_popcnt] = "i64.popcnt",
|
||||
// [WasmOpcode_i64_add] = "i64.add",
|
||||
// [WasmOpcode_i64_sub] = "i64.sub",
|
||||
// [WasmOpcode_i64_mul] = "i64.mul",
|
||||
// [WasmOpcode_i64_div_s] = "i64.div_s",
|
||||
// [WasmOpcode_i64_div_u] = "i64.div_u",
|
||||
// [WasmOpcode_i64_rem_s] = "i64.rem_s",
|
||||
// [WasmOpcode_i64_rem_u] = "i64.rem_u",
|
||||
// [WasmOpcode_i64_and] = "i64.and",
|
||||
// [WasmOpcode_i64_or] = "i64.or",
|
||||
// [WasmOpcode_i64_xor] = "i64.xor",
|
||||
// [WasmOpcode_i64_shl] = "i64.shl",
|
||||
// [WasmOpcode_i64_shr_s] = "i64.shr_s",
|
||||
// [WasmOpcode_i64_shr_u] = "i64.shr_u",
|
||||
// [WasmOpcode_i64_rotl] = "i64.rotl",
|
||||
// [WasmOpcode_i64_rotr] = "i64.rotr",
|
||||
//
|
||||
// [WasmOpcode_f32_abs] = "f32.abs",
|
||||
// [WasmOpcode_f32_neg] = "f32.neg",
|
||||
// [WasmOpcode_f32_ceil] = "f32.ceil",
|
||||
// [WasmOpcode_f32_floor] = "f32.floor",
|
||||
// [WasmOpcode_f32_trunc] = "f32.trunc",
|
||||
// [WasmOpcode_f32_nearest] = "f32.nearest",
|
||||
// [WasmOpcode_f32_sqrt] = "f32.sqrt",
|
||||
// [WasmOpcode_f32_add] = "f32.add",
|
||||
// [WasmOpcode_f32_sub] = "f32.sub",
|
||||
// [WasmOpcode_f32_mul] = "f32.mul",
|
||||
// [WasmOpcode_f32_div] = "f32.div",
|
||||
// [WasmOpcode_f32_min] = "f32.min",
|
||||
// [WasmOpcode_f32_max] = "f32.max",
|
||||
// [WasmOpcode_f32_copysign] = "f32.copysign",
|
||||
//
|
||||
// [WasmOpcode_f64_abs] = "f64.abs",
|
||||
// [WasmOpcode_f64_neg] = "f64.neg",
|
||||
// [WasmOpcode_f64_ceil] = "f64.ceil",
|
||||
// [WasmOpcode_f64_floor] = "f64.floor",
|
||||
// [WasmOpcode_f64_trunc] = "f64.trunc",
|
||||
// [WasmOpcode_f64_nearest] = "f64.nearest",
|
||||
// [WasmOpcode_f64_sqrt] = "f64.sqrt",
|
||||
// [WasmOpcode_f64_add] = "f64.add",
|
||||
// [WasmOpcode_f64_sub] = "f64.sub",
|
||||
// [WasmOpcode_f64_mul] = "f64.mul",
|
||||
// [WasmOpcode_f64_div] = "f64.div",
|
||||
// [WasmOpcode_f64_min] = "f64.min",
|
||||
// [WasmOpcode_f64_max] = "f64.max",
|
||||
// [WasmOpcode_f64_copysign] = "f64.copysign",
|
||||
//
|
||||
// [WasmOpcode_i32_wrap_i64] = "i32.wrap_i64",
|
||||
// [WasmOpcode_i32_trunc_f32_s] = "i32.trunc_f32_s",
|
||||
// [WasmOpcode_i32_trunc_f32_u] = "i32.trunc_f32_u",
|
||||
// [WasmOpcode_i32_trunc_f64_s] = "i32.trunc_f64_s",
|
||||
// [WasmOpcode_i32_trunc_f64_u] = "i32.trunc_f64_u",
|
||||
// [WasmOpcode_i64_extend_i32_s] = "i64.extend_i32_s",
|
||||
// [WasmOpcode_i64_extend_i32_u] = "i64.extend_i32_u",
|
||||
// [WasmOpcode_i64_trunc_f32_s] = "i64.trunc_f32_s",
|
||||
// [WasmOpcode_i64_trunc_f32_u] = "i64.trunc_f32_u",
|
||||
// [WasmOpcode_i64_trunc_f64_s] = "i64.trunc_f64_s",
|
||||
// [WasmOpcode_i64_trunc_f64_u] = "i64.trunc_f64_u",
|
||||
// [WasmOpcode_f32_convert_i32_s] = "f32.convert_i32_s",
|
||||
// [WasmOpcode_f32_convert_i32_u] = "f32.convert_i32_u",
|
||||
// [WasmOpcode_f32_convert_i64_s] = "f32.convert_i64_s",
|
||||
// [WasmOpcode_f32_convert_i64_u] = "f32.convert_i64_u",
|
||||
// [WasmOpcode_f32_demote_f64] = "f32.demote_f64",
|
||||
// [WasmOpcode_f64_convert_i32_s] = "f64.convert_i32_s",
|
||||
// [WasmOpcode_f64_convert_i32_u] = "f64.convert_i32_u",
|
||||
// [WasmOpcode_f64_convert_i64_s] = "f64.convert_i64_s",
|
||||
// [WasmOpcode_f64_convert_i64_u] = "f64.convert_i64_u",
|
||||
// [WasmOpcode_f64_promote_f32] = "f64.promote_f32",
|
||||
// [WasmOpcode_i32_reinterpret_f32] = "i32.reinterpret_f32",
|
||||
// [WasmOpcode_i64_reinterpret_f64] = "i64.reinterpret_f64",
|
||||
// [WasmOpcode_f32_reinterpret_i32] = "f32.reinterpret_i32",
|
||||
// [WasmOpcode_f64_reinterpret_i64] = "f64.reinterpret_i64",
|
||||
//
|
||||
// [WasmOpcode_i32_extend8_s] = "i32.extend8_s",
|
||||
// [WasmOpcode_i32_extend16_s] = "i32.extend16_s",
|
||||
// [WasmOpcode_i64_extend8_s] = "i64.extend8_s",
|
||||
// [WasmOpcode_i64_extend16_s] = "i64.extend16_s",
|
||||
// [WasmOpcode_i64_extend32_s] = "i64.extend32_s",
|
||||
//
|
||||
// [WasmOpcode_prefixed] = "prefixed",
|
||||
//};
|
||||
uint8_t opcode = InputStream_readByte(&in);
|
||||
//FuncGen_indent(&fg, out);
|
||||
//fprintf(out, "// %2u: ", fg.stack_i);
|
||||
//if (mnemonics[opcode])
|
||||
// fprintf(out, "%s\n", mnemonics[opcode]);
|
||||
//else
|
||||
// fprintf(out, "%02hhX\n", opcode);
|
||||
//fflush(out); // DEBUG
|
||||
switch (opcode) {
|
||||
case WasmOpcode_unreachable:
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "abort();\n");
|
||||
unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_nop:
|
||||
break;
|
||||
case WasmOpcode_block:
|
||||
case WasmOpcode_loop:
|
||||
case WasmOpcode_if: {
|
||||
int64_t block_type = InputStream_readLeb128_i64(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
const struct FuncType *func_type = FuncType_blockType(types, block_type);
|
||||
for (uint32_t param_i = func_type->param->len; param_i > 0; ) {
|
||||
param_i -= 1;
|
||||
FuncGen_indent(&fg, out);
|
||||
param_stash[param_i] =
|
||||
FuncGen_localDeclare(&fg, out, func_type->param->types[param_i]);
|
||||
fprintf(out, " = l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
||||
}
|
||||
for (uint32_t result_i = func_type->result->len; result_i > 0; ) {
|
||||
result_i -= 1;
|
||||
FuncGen_indent(&fg, out);
|
||||
(void)FuncGen_localDeclare(&fg, out,
|
||||
func_type->result->types[result_i]);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
FuncGen_blockBegin(&fg, out, opcode, block_type);
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
FuncGen_stackPush(&fg, out, func_type->param->types[param_i]);
|
||||
fprintf(out, " = l%" PRIu32 ";\n", param_stash[param_i]);
|
||||
}
|
||||
} else unreachable_depth += 1;
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_else:
|
||||
case WasmOpcode_end:
|
||||
if (unreachable_depth <= 1) {
|
||||
const struct ResultType *result_type =
|
||||
FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
|
||||
uint32_t label = FuncGen_blockLabel(&fg, 0);
|
||||
if (unreachable_depth == 0) {
|
||||
const struct ResultType *result_type =
|
||||
FuncType_blockType(types, FuncGen_blockType(&fg, 0))->result;
|
||||
for (uint32_t result_i = result_type->len; result_i > 0; ) {
|
||||
result_i -= 1;
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
||||
label - result_type->len + result_i, FuncGen_stackPop(&fg));
|
||||
}
|
||||
} else unreachable_depth -= 1;
|
||||
switch (opcode) {
|
||||
case WasmOpcode_else:
|
||||
FuncGen_outdent(&fg, out);
|
||||
fputs("} else {\n", out);
|
||||
break;
|
||||
case WasmOpcode_end:
|
||||
FuncGen_blockEnd(&fg, out);
|
||||
for (uint32_t result_i = 0; result_i < result_type->len;
|
||||
result_i += 1) {
|
||||
FuncGen_stackPush(&fg, out, result_type->types[result_i]);
|
||||
fprintf(out, "l%" PRIu32 ";\n",
|
||||
label - result_type->len + result_i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (opcode == WasmOpcode_end) unreachable_depth -= 1;
|
||||
break;
|
||||
case WasmOpcode_br:
|
||||
case WasmOpcode_br_if: {
|
||||
uint32_t label_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
enum WasmOpcode kind = FuncGen_blockKind(&fg, label_idx);
|
||||
const struct FuncType *func_type =
|
||||
FuncType_blockType(types, FuncGen_blockType(&fg, label_idx));
|
||||
uint32_t label = FuncGen_blockLabel(&fg, label_idx);
|
||||
|
||||
FuncGen_indent(&fg, out);
|
||||
if (opcode == WasmOpcode_br_if)
|
||||
fprintf(out, "if (l%" PRIu32 ") ", FuncGen_stackPop(&fg));
|
||||
fputs("{\n", out);
|
||||
const struct ResultType *label_type;
|
||||
uint32_t lhs;
|
||||
switch (kind) {
|
||||
case WasmOpcode_loop:
|
||||
label_type = func_type->param;
|
||||
lhs = label - func_type->result->len - func_type->param->len;
|
||||
break;
|
||||
default:
|
||||
label_type = func_type->result;
|
||||
lhs = label - func_type->result->len;
|
||||
break;
|
||||
}
|
||||
for (uint32_t stack_i = 0; stack_i < label_type->len; stack_i += 1) {
|
||||
uint32_t rhs;
|
||||
switch (opcode) {
|
||||
case WasmOpcode_br:
|
||||
rhs = FuncGen_stackPop(&fg);
|
||||
break;
|
||||
case WasmOpcode_br_if:
|
||||
rhs = FuncGen_stackAt(&fg, stack_i);
|
||||
break;
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n", lhs, rhs);
|
||||
lhs += 1;
|
||||
}
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "goto l%" PRIu32 ";\n", label);
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "}\n");
|
||||
if (opcode == WasmOpcode_br) unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_br_table: {
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "switch (l%" PRIu32 ") {\n", FuncGen_stackPop(&fg));
|
||||
}
|
||||
uint32_t label_len = InputStream_readLeb128_u32(&in);
|
||||
for (uint32_t i = 0; i < label_len; i += 1) {
|
||||
uint32_t label = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "case %u: goto l%" PRIu32 ";\n",
|
||||
i, FuncGen_blockLabel(&fg, label));
|
||||
}
|
||||
}
|
||||
uint32_t label = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "default: goto l%" PRIu32 ";\n",
|
||||
FuncGen_blockLabel(&fg, label));
|
||||
FuncGen_indent(&fg, out);
|
||||
fputs("}\n", out);
|
||||
unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_return:
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fputs("return", out);
|
||||
switch (func_type->result->len) {
|
||||
case 0: break;
|
||||
case 1: fprintf(out, " l%" PRIu32, FuncGen_stackPop(&fg)); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fputs(";\n", out);
|
||||
unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_call:
|
||||
case WasmOpcode_call_indirect: {
|
||||
uint32_t func_id;
|
||||
uint32_t type_idx;
|
||||
uint32_t table_idx;
|
||||
switch (opcode) {
|
||||
case WasmOpcode_call:
|
||||
func_id = InputStream_readLeb128_u32(&in);
|
||||
if (func_id < imports_len)
|
||||
type_idx = imports[func_id].type_idx;
|
||||
else
|
||||
type_idx = funcs[func_id - imports_len].type_idx;
|
||||
break;
|
||||
case WasmOpcode_call_indirect:
|
||||
type_idx = InputStream_readLeb128_u32(&in);
|
||||
table_idx = InputStream_readLeb128_u32(&in);
|
||||
func_id = FuncGen_stackPop(&fg);
|
||||
break;
|
||||
}
|
||||
if (unreachable_depth == 0) {
|
||||
const struct FuncType *callee_func_type = &types[type_idx];
|
||||
for (uint32_t param_i = callee_func_type->param->len; param_i > 0; ) {
|
||||
param_i -= 1;
|
||||
param_stash[param_i] = FuncGen_stackPop(&fg);
|
||||
}
|
||||
switch (callee_func_type->result->len) {
|
||||
case 0: FuncGen_indent(&fg, out); break;
|
||||
case 1: FuncGen_stackPush(&fg, out, callee_func_type->result->types[0]); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
switch (opcode) {
|
||||
case WasmOpcode_call:
|
||||
if (func_id < imports_len)
|
||||
fprintf(out, "%s_%s", imports[func_id].mod, imports[func_id].name);
|
||||
else
|
||||
fprintf(out, "f%" PRIu32, func_id - imports_len);
|
||||
break;
|
||||
case WasmOpcode_call_indirect:
|
||||
fputs("(*(", out);
|
||||
switch (callee_func_type->result->len) {
|
||||
case 0: fputs("void", out); break;
|
||||
case 1: fputs(WasmValType_toC(callee_func_type->result->types[0]), out); break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fputs(" (*)(", out);
|
||||
if (callee_func_type->param->len == 0) fputs("void", out);
|
||||
for (uint32_t param_i = 0; param_i < callee_func_type->param->len; param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fputs(WasmValType_toC(callee_func_type->param->types[param_i]), out);
|
||||
}
|
||||
fprintf(out, "))t%" PRIu32 "[l%" PRIu32 "])", table_idx, func_id);
|
||||
break;
|
||||
}
|
||||
fputc('(', out);
|
||||
for (uint32_t param_i = 0; param_i < callee_func_type->param->len;
|
||||
param_i += 1) {
|
||||
if (param_i > 0) fputs(", ", out);
|
||||
fprintf(out, "l%" PRIu32, param_stash[param_i]);
|
||||
}
|
||||
fputs(");\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_drop:
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "(void)l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_select:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t cond = FuncGen_stackPop(&fg);
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, lhs));
|
||||
fprintf(out, "l%" PRIu32 " ? l%" PRIu32 " : l%" PRIu32 ";\n",
|
||||
cond, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_local_get: {
|
||||
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
||||
FuncGen_stackPush(&fg, out, FuncGen_localType(&fg, local_idx));
|
||||
fprintf(out, "l%" PRIu32 ";\n", local_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_local_set: {
|
||||
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
||||
local_idx, FuncGen_stackPop(&fg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_local_tee: {
|
||||
uint32_t local_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
if (local_idx < func_type->param->len) param_used[local_idx] = true;
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "l%" PRIu32 " = l%" PRIu32 ";\n",
|
||||
local_idx, FuncGen_stackAt(&fg, 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_global_get: {
|
||||
uint32_t global_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, globals[global_idx].val_type);
|
||||
fprintf(out, "g%" PRIu32 ";\n", global_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_global_set: {
|
||||
uint32_t global_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "g%" PRIu32 " = l%" PRIu32 ";\n",
|
||||
global_idx, FuncGen_stackPop(&fg));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_table_get:
|
||||
case WasmOpcode_table_set:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
break;
|
||||
|
||||
case WasmOpcode_i32_load: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
if (align < 2 || isBigEndian) {
|
||||
fseek(out, -1, SEEK_CUR);
|
||||
fputc('\n', out);
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
} else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
if (align < 3 || isBigEndian) {
|
||||
fseek(out, -1, SEEK_CUR);
|
||||
fputc('\n', out);
|
||||
for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
} else fprintf(out, "*(const uint64_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f32_load: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
if (align < 2 || isBigEndian) {
|
||||
fputs("f32_reinterpret_i32(\n", out);
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
fputc(')', out);
|
||||
} else fprintf(out, "*(const float *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f64_load: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
if (align < 3 || isBigEndian) {
|
||||
fputs("f64_reinterpret_i64(\n", out);
|
||||
for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint64_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
fputc(')', out);
|
||||
} else fprintf(out, "*(const double *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_load8_s: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
||||
0, base, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_load8_u: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
||||
0, base, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_load16_s: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
if (align < 1 || isBigEndian) {
|
||||
fputs("(int16_t)(\n", out);
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
fputc(')', out);
|
||||
} else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_load16_u: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
if (align < 1 || isBigEndian) {
|
||||
fseek(out, -1, SEEK_CUR);
|
||||
fputc('\n', out);
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
} else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load8_s: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int8_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
||||
0, base, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load8_u: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")];\n",
|
||||
0, base, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load16_s: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
if (align < 1 || isBigEndian) {
|
||||
fputs("(int16_t)(\n", out);
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
fputc(')', out);
|
||||
} else fprintf(out, "*(const int16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load16_u: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
if (align < 1 || isBigEndian) {
|
||||
fseek(out, -1, SEEK_CUR);
|
||||
fputc('\n', out);
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint16_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
} else fprintf(out, "*(const uint16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load32_s: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
if (align < 2 || isBigEndian) {
|
||||
fputs("(int32_t)(\n", out);
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
fputc(')', out);
|
||||
} else fprintf(out, "*(const int32_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_load32_u: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
if (align < 2 || isBigEndian) {
|
||||
fseek(out, -1, SEEK_CUR);
|
||||
fputc('\n', out);
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
if (byte_i > 0) fputs(" |\n", out);
|
||||
FuncGen_cont(&fg, out);
|
||||
fprintf(out, "(uint32_t)m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%"
|
||||
PRIu32 ")] << %2u", 0, base, offset + byte_i, byte_i << 3);
|
||||
}
|
||||
} else fprintf(out, "*(const uint32_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")]", 0, base, offset);
|
||||
fputs(";\n", out);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_i32_store: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 2 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(l%" PRIu32 " >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_store: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 3 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(l%" PRIu32 " >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(uint64_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f32_store: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 2 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(i32_reinterpret_f32(l%" PRIu32 ") >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(float *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f64_store: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 3 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 8; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(i64_reinterpret_f64(l%" PRIu32 ") >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(double *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_store8: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
|
||||
")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i32_store16: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 1 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(l%" PRIu32 " >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_store8: {
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32
|
||||
")] = (uint8_t)l%" PRIu32 ";\n", 0, base, offset, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_store16: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 1 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 2; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(l%" PRIu32 " >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(uint16_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = (uint16_t)l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_store32: {
|
||||
uint32_t align = InputStream_readLeb128_u32(&in);
|
||||
uint32_t offset = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t value = FuncGen_stackPop(&fg);
|
||||
uint32_t base = FuncGen_stackPop(&fg);
|
||||
if (align < 2 || isBigEndian) {
|
||||
for (uint8_t byte_i = 0; byte_i < 4; byte_i += 1) {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "m%" PRIu32 "[l%" PRIu32 " + UINT32_C(%" PRIu32 ")] = "
|
||||
"(uint8_t)(l%" PRIu32 " >> %2u);\n",
|
||||
0, base, offset + byte_i, value, byte_i << 3);
|
||||
}
|
||||
} else {
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "*(uint32_t *)&m%" PRIu32 "[l%" PRIu32
|
||||
" + UINT32_C(%" PRIu32 ")] = (uint32_t)l%" PRIu32 ";\n",
|
||||
0, base, offset, value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_memory_size: {
|
||||
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "p%" PRIu32 ";\n", mem_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_memory_grow: {
|
||||
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t pages = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "memory_grow(&m%" PRIu32 ", &p%" PRIu32 ", l%" PRIu32 ");\n",
|
||||
mem_idx, mem_idx, pages);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_i32_const: {
|
||||
uint32_t value = (uint32_t)InputStream_readLeb128_i32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "UINT32_C(0x%" PRIX32 ");\n", value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_i64_const: {
|
||||
uint64_t value = (uint64_t)InputStream_readLeb128_i64(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "UINT64_C(0x%" PRIX64 ");\n", value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f32_const: {
|
||||
uint32_t value = InputStream_readLittle_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "f32_reinterpret_i32(UINT32_C(0x%" PRIX32 "));\n", value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WasmOpcode_f64_const: {
|
||||
uint64_t value = InputStream_readLittle_u64(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "f64_reinterpret_i64(UINT64_C(0x%" PRIX64 "));\n", value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmOpcode_i32_eqz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "!l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_eq:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_ne:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_lt_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " < (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_lt_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_gt_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " > (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_gt_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_le_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " <= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_le_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_ge_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " >= (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_ge_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_i64_eqz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "!l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_eq:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_ne:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_lt_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " < (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_lt_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_gt_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " > (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_gt_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_le_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " <= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_le_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_ge_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " >= (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_ge_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_f32_eq:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_ne:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_lt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_gt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_le:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_ge:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_f64_eq:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " == l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_ne:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_lt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " < l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_gt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " > l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_le:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " <= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_ge:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >= l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_i32_clz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clz(l%" PRIu32 ") : 32;\n",
|
||||
lhs, lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_ctz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctz(l%" PRIu32 ") : 32;\n",
|
||||
lhs, lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_popcnt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "__builtin_popcount(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_add:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_sub:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_mul:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_div_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " / (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_div_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_rem_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " %% (int32_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_rem_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_and:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_or:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_xor:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_shl:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_shr_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_shr_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_rotl:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x1F) | "
|
||||
"l%" PRIu32 " >> (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_rotr:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x1F) | "
|
||||
"l%" PRIu32 " << (-l%" PRIu32" & 0x1F);\n", lhs, rhs, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_i64_clz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " != 0 ? __builtin_clzll(l%" PRIu32 ") : 64;\n",
|
||||
lhs, lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_ctz:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " != 0 ? __builtin_ctzll(l%" PRIu32 ") : 64;\n",
|
||||
lhs, lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_popcnt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "__builtin_popcountll(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_add:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_sub:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_mul:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_div_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " / (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_div_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_rem_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " %% (int64_t)l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_rem_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " %% l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_and:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " & l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_or:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " | l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_xor:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " ^ l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_shl:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_shr_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_shr_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F);\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_rotl:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " << (l%" PRIu32 " & 0x3F) | "
|
||||
"l%" PRIu32 " >> (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_rotr:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "l%" PRIu32 " >> (l%" PRIu32 " & 0x3F) | "
|
||||
"l%" PRIu32 " << (-l%" PRIu32" & 0x3F);\n", lhs, rhs, lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_f32_abs:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "fabsf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_neg:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "-l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_ceil:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "ceilf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_floor:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "floorf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_trunc:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "truncf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_nearest:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "roundf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_sqrt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "sqrtf(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_add:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_sub:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_mul:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_div:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_min:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "fminf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_max:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "fmaxf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_copysign:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "copysignf(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_f64_abs:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "fabs(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_neg:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "-l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_ceil:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "ceil(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_floor:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "floor(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_trunc:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "trunc(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_nearest:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "round(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_sqrt:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "sqrt(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_add:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "l%" PRIu32 " + l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_sub:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "l%" PRIu32 " - l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_mul:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "l%" PRIu32 " * l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_div:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "l%" PRIu32 " / l%" PRIu32 ";\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_min:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "fmin(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_max:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "fmax(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_copysign:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t rhs = FuncGen_stackPop(&fg);
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "copysign(l%" PRIu32 ", l%" PRIu32 ");\n", lhs, rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_i32_wrap_i64:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_trunc_f32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_trunc_f32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_trunc_f64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_trunc_f64_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_extend_i32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_extend_i32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_trunc_f32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_trunc_f32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_trunc_f64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_trunc_f64_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_convert_i32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_convert_i32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_convert_i64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_convert_i64_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_demote_f64:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "(float)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_convert_i32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_convert_i32_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "(uint32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_convert_i64_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "(int64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_convert_i64_u:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "(uint64_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_promote_f32:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "(double)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_reinterpret_f32:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "i32_reinterpret_f32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_reinterpret_f64:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "i64_reinterpret_f64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f32_reinterpret_i32:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f32);
|
||||
fprintf(out, "f32_reinterpret_i32(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_f64_reinterpret_i64:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_f64);
|
||||
fprintf(out, "f64_reinterpret_i64(l%" PRIu32 ");\n", lhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_i32_extend8_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i32_extend16_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i32);
|
||||
fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_extend8_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int8_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_extend16_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int16_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
case WasmOpcode_i64_extend32_s:
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t lhs = FuncGen_stackPop(&fg);
|
||||
FuncGen_stackPush(&fg, out, WasmValType_i64);
|
||||
fprintf(out, "(int32_t)l%" PRIu32 ";\n", lhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOpcode_prefixed:
|
||||
switch (InputStream_readLeb128_u32(&in)) {
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f32_s:
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f32_u:
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f64_s:
|
||||
case WasmPrefixedOpcode_i32_trunc_sat_f64_u:
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f32_s:
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f32_u:
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f64_s:
|
||||
case WasmPrefixedOpcode_i64_trunc_sat_f64_u:
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_memory_init:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
(void)InputStream_readByte(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_data_drop:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_memory_copy: {
|
||||
uint32_t dst_mem_idx = InputStream_readLeb128_u32(&in);
|
||||
uint32_t src_mem_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t n = FuncGen_stackPop(&fg);
|
||||
uint32_t src = FuncGen_stackPop(&fg);
|
||||
uint32_t dst = FuncGen_stackPop(&fg);
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "memcpy(&m%" PRIu32 "[l%" PRIu32 "], "
|
||||
"&m%" PRIu32 "[l%" PRIu32 "], l%" PRIu32 ");\n",
|
||||
dst_mem_idx, dst, src_mem_idx, src, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmPrefixedOpcode_memory_fill: {
|
||||
uint32_t mem_idx = InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t n = FuncGen_stackPop(&fg);
|
||||
uint32_t c = FuncGen_stackPop(&fg);
|
||||
uint32_t s = FuncGen_stackPop(&fg);
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "memset(&m%" PRIu32 "[l%" PRIu32 "], "
|
||||
"l%" PRIu32 ", l%" PRIu32 ");\n", mem_idx, s, c, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WasmPrefixedOpcode_table_init:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_elem_drop:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_table_copy:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_table_grow:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_table_size:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
|
||||
case WasmPrefixedOpcode_table_fill:
|
||||
(void)InputStream_readLeb128_u32(&in);
|
||||
if (unreachable_depth == 0) panic("unimplemented opcode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (uint32_t param_i = 0; param_i < func_type->param->len; param_i += 1) {
|
||||
if (param_used[param_i]) continue;
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "(void)l%" PRIu32 ";\n", param_i);
|
||||
}
|
||||
switch (func_type->result->len) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
FuncGen_indent(&fg, out);
|
||||
fprintf(out, "return l%" PRIu32 ";\n", FuncGen_stackPop(&fg));
|
||||
break;
|
||||
default: panic("multiple function returns not supported");
|
||||
}
|
||||
fputs("}\n\n", out);
|
||||
}
|
||||
}
|
||||
|
||||
(void)InputStream_skipToSection(&in, WasmSectionId_data);
|
||||
{
|
||||
uint32_t len = InputStream_readLeb128_u32(&in);
|
||||
fputs("static void init_data(void) {\n", out);
|
||||
for (uint32_t i = 0; i < mems_len; i += 1)
|
||||
fprintf(out, " p%" PRIu32 " = UINT32_C(%" PRIu32 ");\n"
|
||||
" m%" PRIu32 " = calloc(p%" PRIu32 ", UINT32_C(1) << 16);\n",
|
||||
i, mems[i].limits.min, i, i);
|
||||
for (uint32_t segment_i = 0; segment_i < len; segment_i += 1) {
|
||||
uint32_t mem_idx;
|
||||
switch (InputStream_readLeb128_u32(&in)) {
|
||||
case 0:
|
||||
mem_idx = 0;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
mem_idx = InputStream_readLeb128_u32(&in);
|
||||
break;
|
||||
|
||||
default: panic("unsupported data kind");
|
||||
}
|
||||
uint32_t offset = evalExpr(&in);
|
||||
uint32_t segment_len = InputStream_readLeb128_u32(&in);
|
||||
fputc('\n', out);
|
||||
fprintf(out, " static const uint8_t s%" PRIu32 "[UINT32_C(%" PRIu32 ")] = {",
|
||||
segment_i, segment_len);
|
||||
for (uint32_t i = 0; i < segment_len; i += 1) {
|
||||
if (i % 32 == 0) fputs("\n ", out);
|
||||
fprintf(out, " 0x%02hhX,", InputStream_readByte(&in));
|
||||
}
|
||||
fprintf(out, "\n"
|
||||
" };\n"
|
||||
" memcpy(&m%" PRIu32 "[UINT32_C(0x%" PRIX32 ")], s%" PRIu32 ", UINT32_C(%" PRIu32 "));\n",
|
||||
mem_idx, offset, segment_i, segment_len);
|
||||
}
|
||||
fputs("}\n", out);
|
||||
}
|
||||
|
||||
InputStream_close(&in);
|
||||
fclose(out);
|
||||
}
|
||||
-4567
@@ -1,4567 +0,0 @@
|
||||
// TODO get rid of _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
#include <zstd.h>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define ZIG_TRIPLE_OS "macos"
|
||||
#elif defined(_WIN32)
|
||||
#define ZIG_TRIPLE_OS "windows"
|
||||
#elif defined(__linux__)
|
||||
#define ZIG_TRIPLE_OS "linux"
|
||||
#elif defined(__FreeBSD__)
|
||||
#define ZIG_TRIPLE_OS "freebsd"
|
||||
#elif defined(__NetBSD__)
|
||||
#define ZIG_TRIPLE_OS "netbsd"
|
||||
#elif defined(__DragonFly__)
|
||||
#define ZIG_TRIPLE_OS "dragonfly"
|
||||
#elif defined(__OpenBSD__)
|
||||
#define ZIG_TRIPLE_OS "openbsd"
|
||||
#elif defined(__HAIKU__)
|
||||
#define ZIG_TRIPLE_OS "haiku"
|
||||
#elif defined(__sun)
|
||||
#define ZIG_TRIPLE_OS "solaris"
|
||||
#else
|
||||
#error please add more os definitions above this line
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define ZIG_TRIPLE_ARCH "x86_64"
|
||||
#elif defined(__aarch64__)
|
||||
#define ZIG_TRIPLE_ARCH "aarch64"
|
||||
#elif defined(__ARM_EABI__)
|
||||
#define ZIG_TRIPLE_ARCH "arm"
|
||||
#else
|
||||
#error please add more arch definitions above this line
|
||||
#endif
|
||||
|
||||
enum wasi_errno_t {
|
||||
WASI_ESUCCESS = 0,
|
||||
WASI_E2BIG = 1,
|
||||
WASI_EACCES = 2,
|
||||
WASI_EADDRINUSE = 3,
|
||||
WASI_EADDRNOTAVAIL = 4,
|
||||
WASI_EAFNOSUPPORT = 5,
|
||||
WASI_EAGAIN = 6,
|
||||
WASI_EALREADY = 7,
|
||||
WASI_EBADF = 8,
|
||||
WASI_EBADMSG = 9,
|
||||
WASI_EBUSY = 10,
|
||||
WASI_ECANCELED = 11,
|
||||
WASI_ECHILD = 12,
|
||||
WASI_ECONNABORTED = 13,
|
||||
WASI_ECONNREFUSED = 14,
|
||||
WASI_ECONNRESET = 15,
|
||||
WASI_EDEADLK = 16,
|
||||
WASI_EDESTADDRREQ = 17,
|
||||
WASI_EDOM = 18,
|
||||
WASI_EDQUOT = 19,
|
||||
WASI_EEXIST = 20,
|
||||
WASI_EFAULT = 21,
|
||||
WASI_EFBIG = 22,
|
||||
WASI_EHOSTUNREACH = 23,
|
||||
WASI_EIDRM = 24,
|
||||
WASI_EILSEQ = 25,
|
||||
WASI_EINPROGRESS = 26,
|
||||
WASI_EINTR = 27,
|
||||
WASI_EINVAL = 28,
|
||||
WASI_EIO = 29,
|
||||
WASI_EISCONN = 30,
|
||||
WASI_EISDIR = 31,
|
||||
WASI_ELOOP = 32,
|
||||
WASI_EMFILE = 33,
|
||||
WASI_EMLINK = 34,
|
||||
WASI_EMSGSIZE = 35,
|
||||
WASI_EMULTIHOP = 36,
|
||||
WASI_ENAMETOOLONG = 37,
|
||||
WASI_ENETDOWN = 38,
|
||||
WASI_ENETRESET = 39,
|
||||
WASI_ENETUNREACH = 40,
|
||||
WASI_ENFILE = 41,
|
||||
WASI_ENOBUFS = 42,
|
||||
WASI_ENODEV = 43,
|
||||
WASI_ENOENT = 44,
|
||||
WASI_ENOEXEC = 45,
|
||||
WASI_ENOLCK = 46,
|
||||
WASI_ENOLINK = 47,
|
||||
WASI_ENOMEM = 48,
|
||||
WASI_ENOMSG = 49,
|
||||
WASI_ENOPROTOOPT = 50,
|
||||
WASI_ENOSPC = 51,
|
||||
WASI_ENOSYS = 52,
|
||||
WASI_ENOTCONN = 53,
|
||||
WASI_ENOTDIR = 54,
|
||||
WASI_ENOTEMPTY = 55,
|
||||
WASI_ENOTRECOVERABLE = 56,
|
||||
WASI_ENOTSOCK = 57,
|
||||
WASI_EOPNOTSUPP = 58,
|
||||
WASI_ENOTTY = 59,
|
||||
WASI_ENXIO = 60,
|
||||
WASI_EOVERFLOW = 61,
|
||||
WASI_EOWNERDEAD = 62,
|
||||
WASI_EPERM = 63,
|
||||
WASI_EPIPE = 64,
|
||||
WASI_EPROTO = 65,
|
||||
WASI_EPROTONOSUPPORT = 66,
|
||||
WASI_EPROTOTYPE = 67,
|
||||
WASI_ERANGE = 68,
|
||||
WASI_EROFS = 69,
|
||||
WASI_ESPIPE = 70,
|
||||
WASI_ESRCH = 71,
|
||||
WASI_ESTALE = 72,
|
||||
WASI_ETIMEDOUT = 73,
|
||||
WASI_ETXTBSY = 74,
|
||||
WASI_EXDEV = 75,
|
||||
WASI_ENOTCAPABLE = 76,
|
||||
};
|
||||
|
||||
static void panic(const char *msg) {
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
abort();
|
||||
}
|
||||
|
||||
static uint32_t min_u32(uint32_t a, uint32_t b) {
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
static uint32_t rotl32(uint32_t n, unsigned c) {
|
||||
const unsigned mask = CHAR_BIT * sizeof(n) - 1;
|
||||
c &= mask & 31;
|
||||
return (n << c) | (n >> ((-c) & mask));
|
||||
}
|
||||
|
||||
static uint32_t rotr32(uint32_t n, unsigned c) {
|
||||
const unsigned mask = CHAR_BIT * sizeof(n) - 1;
|
||||
c &= mask & 31;
|
||||
return (n >> c) | (n << ((-c) & mask));
|
||||
}
|
||||
|
||||
static uint64_t rotl64(uint64_t n, unsigned c) {
|
||||
const unsigned mask = CHAR_BIT * sizeof(n) - 1;
|
||||
c &= mask & 63;
|
||||
return (n << c) | (n >> ((-c) & mask));
|
||||
}
|
||||
|
||||
static uint64_t rotr64(uint64_t n, unsigned c) {
|
||||
const unsigned mask = CHAR_BIT * sizeof(n) - 1;
|
||||
c &= mask & 63;
|
||||
return (n >> c) | (n << ((-c) & mask));
|
||||
}
|
||||
|
||||
static void *arena_alloc(size_t n) {
|
||||
void *ptr = malloc(n);
|
||||
if (!ptr) panic("out of memory");
|
||||
#ifndef NDEBUG
|
||||
memset(ptr, 0xaa, n); // to match the zig version
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int err_wrap(const char *prefix, int rc) {
|
||||
if (rc == -1) {
|
||||
perror(prefix);
|
||||
abort();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool bs_isSet(const uint32_t *bitset, uint32_t index) {
|
||||
return (bitset[index >> 5] >> (index & 0x1f)) & 1;
|
||||
}
|
||||
static void bs_set(uint32_t *bitset, uint32_t index) {
|
||||
bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f));
|
||||
}
|
||||
static void bs_unset(uint32_t *bitset, uint32_t index) {
|
||||
bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f));
|
||||
}
|
||||
static void bs_setValue(uint32_t *bitset, uint32_t index, bool value) {
|
||||
if (value) bs_set(bitset, index); else bs_unset(bitset, index);
|
||||
}
|
||||
|
||||
struct ByteSlice {
|
||||
char *ptr;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static struct ByteSlice read_file_alloc(const char *file_path) {
|
||||
FILE *f = fopen(file_path, "rb");
|
||||
if (!f) {
|
||||
fprintf(stderr, "failed to read %s: ", file_path);
|
||||
perror("");
|
||||
abort();
|
||||
}
|
||||
if (fseek(f, 0L, SEEK_END) == -1) panic("failed to seek");
|
||||
struct ByteSlice res;
|
||||
res.len = ftell(f);
|
||||
res.ptr = malloc(res.len);
|
||||
rewind(f);
|
||||
size_t amt_read = fread(res.ptr, 1, res.len, f);
|
||||
if (amt_read != res.len) panic("short read");
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
struct Preopen {
|
||||
int wasi_fd;
|
||||
int host_fd;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
};
|
||||
|
||||
static struct Preopen preopens_buffer[10];
|
||||
static size_t preopens_len = 0;
|
||||
|
||||
static void add_preopen(int wasi_fd, const char *name, int host_fd) {
|
||||
preopens_buffer[preopens_len].wasi_fd = wasi_fd;
|
||||
preopens_buffer[preopens_len].host_fd = host_fd;
|
||||
preopens_buffer[preopens_len].name = name;
|
||||
preopens_buffer[preopens_len].name_len = strlen(name);
|
||||
preopens_len += 1;
|
||||
}
|
||||
|
||||
static const struct Preopen *find_preopen(int32_t wasi_fd) {
|
||||
for (size_t i = 0; i < preopens_len; i += 1) {
|
||||
const struct Preopen *preopen = &preopens_buffer[i];
|
||||
if (preopen->wasi_fd == wasi_fd) {
|
||||
return preopen;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB
|
||||
|
||||
static uint16_t read_u16_le(const char *ptr) {
|
||||
const uint8_t *u8_ptr = (const uint8_t *)ptr;
|
||||
return
|
||||
(((uint64_t)u8_ptr[0]) << 0x00) |
|
||||
(((uint64_t)u8_ptr[1]) << 0x08);
|
||||
}
|
||||
|
||||
static uint32_t read_u32_le(const char *ptr) {
|
||||
const uint8_t *u8_ptr = (const uint8_t *)ptr;
|
||||
return
|
||||
(((uint64_t)u8_ptr[0]) << 0x00) |
|
||||
(((uint64_t)u8_ptr[1]) << 0x08) |
|
||||
(((uint64_t)u8_ptr[2]) << 0x10) |
|
||||
(((uint64_t)u8_ptr[3]) << 0x18);
|
||||
}
|
||||
|
||||
static uint64_t read_u64_le(const char *ptr) {
|
||||
const uint8_t *u8_ptr = (const uint8_t *)ptr;
|
||||
return
|
||||
(((uint64_t)u8_ptr[0]) << 0x00) |
|
||||
(((uint64_t)u8_ptr[1]) << 0x08) |
|
||||
(((uint64_t)u8_ptr[2]) << 0x10) |
|
||||
(((uint64_t)u8_ptr[3]) << 0x18) |
|
||||
(((uint64_t)u8_ptr[4]) << 0x20) |
|
||||
(((uint64_t)u8_ptr[5]) << 0x28) |
|
||||
(((uint64_t)u8_ptr[6]) << 0x30) |
|
||||
(((uint64_t)u8_ptr[7]) << 0x38);
|
||||
}
|
||||
|
||||
static void write_u16_le(char *ptr, uint16_t x) {
|
||||
uint8_t *u8_ptr = (uint8_t*)ptr;
|
||||
u8_ptr[0] = (x >> 0x00);
|
||||
u8_ptr[1] = (x >> 0x08);
|
||||
}
|
||||
|
||||
static void write_u32_le(char *ptr, uint32_t x) {
|
||||
uint8_t *u8_ptr = (uint8_t*)ptr;
|
||||
u8_ptr[0] = (x >> 0x00);
|
||||
u8_ptr[1] = (x >> 0x08);
|
||||
u8_ptr[2] = (x >> 0x10);
|
||||
u8_ptr[3] = (x >> 0x18);
|
||||
}
|
||||
|
||||
static void write_u64_le(char *ptr, uint64_t x) {
|
||||
uint8_t *u8_ptr = (uint8_t*)ptr;
|
||||
u8_ptr[0] = (x >> 0x00);
|
||||
u8_ptr[1] = (x >> 0x08);
|
||||
u8_ptr[2] = (x >> 0x10);
|
||||
u8_ptr[3] = (x >> 0x18);
|
||||
u8_ptr[4] = (x >> 0x20);
|
||||
u8_ptr[5] = (x >> 0x28);
|
||||
u8_ptr[6] = (x >> 0x30);
|
||||
u8_ptr[7] = (x >> 0x38);
|
||||
}
|
||||
|
||||
static uint32_t read32_uleb128(const char *ptr, uint32_t *i) {
|
||||
uint32_t result = 0;
|
||||
uint32_t shift = 0;
|
||||
|
||||
for (;;) {
|
||||
uint32_t byte = ptr[*i];
|
||||
*i += 1;
|
||||
result |= ((byte & 0x7f) << shift);
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0) return result;
|
||||
if (shift >= 32) panic("read32_uleb128 failed");
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t read64_ileb128(const char *ptr, uint32_t *i) {
|
||||
int64_t result = 0;
|
||||
uint32_t shift = 0;
|
||||
|
||||
for (;;) {
|
||||
uint64_t byte = ptr[*i];
|
||||
*i += 1;
|
||||
result |= ((byte & 0x7f) << shift);
|
||||
shift += 7;
|
||||
if ((byte & 0x80) == 0) {
|
||||
if ((byte & 0x40) && (shift < 64)) {
|
||||
uint64_t extend = 0;
|
||||
result |= (~extend << shift);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (shift >= 64) panic("read64_ileb128 failed");
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t read32_ileb128(const char *ptr, uint32_t *i) {
|
||||
return read64_ileb128(ptr, i);
|
||||
}
|
||||
|
||||
static struct ByteSlice read_name(char *ptr, uint32_t *i) {
|
||||
uint32_t len = read32_uleb128(ptr, i);
|
||||
struct ByteSlice res;
|
||||
res.ptr = ptr + *i;
|
||||
res.len = len;
|
||||
*i += len;
|
||||
return res;
|
||||
}
|
||||
|
||||
enum Section {
|
||||
Section_custom,
|
||||
Section_type,
|
||||
Section_import,
|
||||
Section_function,
|
||||
Section_table,
|
||||
Section_memory,
|
||||
Section_global,
|
||||
Section_export,
|
||||
Section_start,
|
||||
Section_element,
|
||||
Section_code,
|
||||
Section_data,
|
||||
Section_data_count,
|
||||
};
|
||||
|
||||
enum Op {
|
||||
Op_unreachable,
|
||||
Op_br_void,
|
||||
Op_br_32,
|
||||
Op_br_64,
|
||||
Op_br_nez_void,
|
||||
Op_br_nez_32,
|
||||
Op_br_nez_64,
|
||||
Op_br_eqz_void,
|
||||
Op_br_eqz_32,
|
||||
Op_br_eqz_64,
|
||||
Op_br_table_void,
|
||||
Op_br_table_32,
|
||||
Op_br_table_64,
|
||||
Op_return_void,
|
||||
Op_return_32,
|
||||
Op_return_64,
|
||||
Op_call_import,
|
||||
Op_call_func,
|
||||
Op_call_indirect,
|
||||
Op_drop_32,
|
||||
Op_drop_64,
|
||||
Op_select_32,
|
||||
Op_select_64,
|
||||
Op_local_get_32,
|
||||
Op_local_get_64,
|
||||
Op_local_set_32,
|
||||
Op_local_set_64,
|
||||
Op_local_tee_32,
|
||||
Op_local_tee_64,
|
||||
Op_global_get_0_32,
|
||||
Op_global_get_32,
|
||||
Op_global_set_0_32,
|
||||
Op_global_set_32,
|
||||
Op_load_0_8,
|
||||
Op_load_8,
|
||||
Op_load_0_16,
|
||||
Op_load_16,
|
||||
Op_load_0_32,
|
||||
Op_load_32,
|
||||
Op_load_0_64,
|
||||
Op_load_64,
|
||||
Op_store_0_8,
|
||||
Op_store_8,
|
||||
Op_store_0_16,
|
||||
Op_store_16,
|
||||
Op_store_0_32,
|
||||
Op_store_32,
|
||||
Op_store_0_64,
|
||||
Op_store_64,
|
||||
Op_mem_size,
|
||||
Op_mem_grow,
|
||||
Op_const_0_32,
|
||||
Op_const_0_64,
|
||||
Op_const_1_32,
|
||||
Op_const_1_64,
|
||||
Op_const_32,
|
||||
Op_const_64,
|
||||
Op_const_umax_32,
|
||||
Op_const_umax_64,
|
||||
Op_eqz_32,
|
||||
Op_eq_32,
|
||||
Op_ne_32,
|
||||
Op_slt_32,
|
||||
Op_ult_32,
|
||||
Op_sgt_32,
|
||||
Op_ugt_32,
|
||||
Op_sle_32,
|
||||
Op_ule_32,
|
||||
Op_sge_32,
|
||||
Op_uge_32,
|
||||
Op_eqz_64,
|
||||
Op_eq_64,
|
||||
Op_ne_64,
|
||||
Op_slt_64,
|
||||
Op_ult_64,
|
||||
Op_sgt_64,
|
||||
Op_ugt_64,
|
||||
Op_sle_64,
|
||||
Op_ule_64,
|
||||
Op_sge_64,
|
||||
Op_uge_64,
|
||||
Op_feq_32,
|
||||
Op_fne_32,
|
||||
Op_flt_32,
|
||||
Op_fgt_32,
|
||||
Op_fle_32,
|
||||
Op_fge_32,
|
||||
Op_feq_64,
|
||||
Op_fne_64,
|
||||
Op_flt_64,
|
||||
Op_fgt_64,
|
||||
Op_fle_64,
|
||||
Op_fge_64,
|
||||
Op_clz_32,
|
||||
Op_ctz_32,
|
||||
Op_popcnt_32,
|
||||
Op_add_32,
|
||||
Op_sub_32,
|
||||
Op_mul_32,
|
||||
Op_sdiv_32,
|
||||
Op_udiv_32,
|
||||
Op_srem_32,
|
||||
Op_urem_32,
|
||||
Op_and_32,
|
||||
Op_or_32,
|
||||
Op_xor_32,
|
||||
Op_shl_32,
|
||||
Op_ashr_32,
|
||||
Op_lshr_32,
|
||||
Op_rol_32,
|
||||
Op_ror_32,
|
||||
Op_clz_64,
|
||||
Op_ctz_64,
|
||||
Op_popcnt_64,
|
||||
Op_add_64,
|
||||
Op_sub_64,
|
||||
Op_mul_64,
|
||||
Op_sdiv_64,
|
||||
Op_udiv_64,
|
||||
Op_srem_64,
|
||||
Op_urem_64,
|
||||
Op_and_64,
|
||||
Op_or_64,
|
||||
Op_xor_64,
|
||||
Op_shl_64,
|
||||
Op_ashr_64,
|
||||
Op_lshr_64,
|
||||
Op_rol_64,
|
||||
Op_ror_64,
|
||||
Op_fabs_32,
|
||||
Op_fneg_32,
|
||||
Op_ceil_32,
|
||||
Op_floor_32,
|
||||
Op_trunc_32,
|
||||
Op_nearest_32,
|
||||
Op_sqrt_32,
|
||||
Op_fadd_32,
|
||||
Op_fsub_32,
|
||||
Op_fmul_32,
|
||||
Op_fdiv_32,
|
||||
Op_fmin_32,
|
||||
Op_fmax_32,
|
||||
Op_copysign_32,
|
||||
Op_fabs_64,
|
||||
Op_fneg_64,
|
||||
Op_ceil_64,
|
||||
Op_floor_64,
|
||||
Op_trunc_64,
|
||||
Op_nearest_64,
|
||||
Op_sqrt_64,
|
||||
Op_fadd_64,
|
||||
Op_fsub_64,
|
||||
Op_fmul_64,
|
||||
Op_fdiv_64,
|
||||
Op_fmin_64,
|
||||
Op_fmax_64,
|
||||
Op_copysign_64,
|
||||
Op_ftos_32_32,
|
||||
Op_ftou_32_32,
|
||||
Op_ftos_32_64,
|
||||
Op_ftou_32_64,
|
||||
Op_sext_64_32,
|
||||
Op_ftos_64_32,
|
||||
Op_ftou_64_32,
|
||||
Op_ftos_64_64,
|
||||
Op_ftou_64_64,
|
||||
Op_stof_32_32,
|
||||
Op_utof_32_32,
|
||||
Op_stof_32_64,
|
||||
Op_utof_32_64,
|
||||
Op_ftof_32_64,
|
||||
Op_stof_64_32,
|
||||
Op_utof_64_32,
|
||||
Op_stof_64_64,
|
||||
Op_utof_64_64,
|
||||
Op_ftof_64_32,
|
||||
Op_sext8_32,
|
||||
Op_sext16_32,
|
||||
Op_sext8_64,
|
||||
Op_sext16_64,
|
||||
Op_sext32_64,
|
||||
Op_memcpy,
|
||||
Op_memset,
|
||||
|
||||
Op_wrap_32_64 = Op_drop_32,
|
||||
Op_zext_64_32 = Op_const_0_32,
|
||||
Op_last = Op_memset,
|
||||
};
|
||||
|
||||
enum WasmOp {
|
||||
WasmOp_unreachable = 0x00,
|
||||
WasmOp_nop = 0x01,
|
||||
WasmOp_block = 0x02,
|
||||
WasmOp_loop = 0x03,
|
||||
WasmOp_if = 0x04,
|
||||
WasmOp_else = 0x05,
|
||||
WasmOp_end = 0x0B,
|
||||
WasmOp_br = 0x0C,
|
||||
WasmOp_br_if = 0x0D,
|
||||
WasmOp_br_table = 0x0E,
|
||||
WasmOp_return = 0x0F,
|
||||
WasmOp_call = 0x10,
|
||||
WasmOp_call_indirect = 0x11,
|
||||
WasmOp_drop = 0x1A,
|
||||
WasmOp_select = 0x1B,
|
||||
WasmOp_local_get = 0x20,
|
||||
WasmOp_local_set = 0x21,
|
||||
WasmOp_local_tee = 0x22,
|
||||
WasmOp_global_get = 0x23,
|
||||
WasmOp_global_set = 0x24,
|
||||
WasmOp_i32_load = 0x28,
|
||||
WasmOp_i64_load = 0x29,
|
||||
WasmOp_f32_load = 0x2A,
|
||||
WasmOp_f64_load = 0x2B,
|
||||
WasmOp_i32_load8_s = 0x2C,
|
||||
WasmOp_i32_load8_u = 0x2D,
|
||||
WasmOp_i32_load16_s = 0x2E,
|
||||
WasmOp_i32_load16_u = 0x2F,
|
||||
WasmOp_i64_load8_s = 0x30,
|
||||
WasmOp_i64_load8_u = 0x31,
|
||||
WasmOp_i64_load16_s = 0x32,
|
||||
WasmOp_i64_load16_u = 0x33,
|
||||
WasmOp_i64_load32_s = 0x34,
|
||||
WasmOp_i64_load32_u = 0x35,
|
||||
WasmOp_i32_store = 0x36,
|
||||
WasmOp_i64_store = 0x37,
|
||||
WasmOp_f32_store = 0x38,
|
||||
WasmOp_f64_store = 0x39,
|
||||
WasmOp_i32_store8 = 0x3A,
|
||||
WasmOp_i32_store16 = 0x3B,
|
||||
WasmOp_i64_store8 = 0x3C,
|
||||
WasmOp_i64_store16 = 0x3D,
|
||||
WasmOp_i64_store32 = 0x3E,
|
||||
WasmOp_memory_size = 0x3F,
|
||||
WasmOp_memory_grow = 0x40,
|
||||
WasmOp_i32_const = 0x41,
|
||||
WasmOp_i64_const = 0x42,
|
||||
WasmOp_f32_const = 0x43,
|
||||
WasmOp_f64_const = 0x44,
|
||||
WasmOp_i32_eqz = 0x45,
|
||||
WasmOp_i32_eq = 0x46,
|
||||
WasmOp_i32_ne = 0x47,
|
||||
WasmOp_i32_lt_s = 0x48,
|
||||
WasmOp_i32_lt_u = 0x49,
|
||||
WasmOp_i32_gt_s = 0x4A,
|
||||
WasmOp_i32_gt_u = 0x4B,
|
||||
WasmOp_i32_le_s = 0x4C,
|
||||
WasmOp_i32_le_u = 0x4D,
|
||||
WasmOp_i32_ge_s = 0x4E,
|
||||
WasmOp_i32_ge_u = 0x4F,
|
||||
WasmOp_i64_eqz = 0x50,
|
||||
WasmOp_i64_eq = 0x51,
|
||||
WasmOp_i64_ne = 0x52,
|
||||
WasmOp_i64_lt_s = 0x53,
|
||||
WasmOp_i64_lt_u = 0x54,
|
||||
WasmOp_i64_gt_s = 0x55,
|
||||
WasmOp_i64_gt_u = 0x56,
|
||||
WasmOp_i64_le_s = 0x57,
|
||||
WasmOp_i64_le_u = 0x58,
|
||||
WasmOp_i64_ge_s = 0x59,
|
||||
WasmOp_i64_ge_u = 0x5A,
|
||||
WasmOp_f32_eq = 0x5B,
|
||||
WasmOp_f32_ne = 0x5C,
|
||||
WasmOp_f32_lt = 0x5D,
|
||||
WasmOp_f32_gt = 0x5E,
|
||||
WasmOp_f32_le = 0x5F,
|
||||
WasmOp_f32_ge = 0x60,
|
||||
WasmOp_f64_eq = 0x61,
|
||||
WasmOp_f64_ne = 0x62,
|
||||
WasmOp_f64_lt = 0x63,
|
||||
WasmOp_f64_gt = 0x64,
|
||||
WasmOp_f64_le = 0x65,
|
||||
WasmOp_f64_ge = 0x66,
|
||||
WasmOp_i32_clz = 0x67,
|
||||
WasmOp_i32_ctz = 0x68,
|
||||
WasmOp_i32_popcnt = 0x69,
|
||||
WasmOp_i32_add = 0x6A,
|
||||
WasmOp_i32_sub = 0x6B,
|
||||
WasmOp_i32_mul = 0x6C,
|
||||
WasmOp_i32_div_s = 0x6D,
|
||||
WasmOp_i32_div_u = 0x6E,
|
||||
WasmOp_i32_rem_s = 0x6F,
|
||||
WasmOp_i32_rem_u = 0x70,
|
||||
WasmOp_i32_and = 0x71,
|
||||
WasmOp_i32_or = 0x72,
|
||||
WasmOp_i32_xor = 0x73,
|
||||
WasmOp_i32_shl = 0x74,
|
||||
WasmOp_i32_shr_s = 0x75,
|
||||
WasmOp_i32_shr_u = 0x76,
|
||||
WasmOp_i32_rotl = 0x77,
|
||||
WasmOp_i32_rotr = 0x78,
|
||||
WasmOp_i64_clz = 0x79,
|
||||
WasmOp_i64_ctz = 0x7A,
|
||||
WasmOp_i64_popcnt = 0x7B,
|
||||
WasmOp_i64_add = 0x7C,
|
||||
WasmOp_i64_sub = 0x7D,
|
||||
WasmOp_i64_mul = 0x7E,
|
||||
WasmOp_i64_div_s = 0x7F,
|
||||
WasmOp_i64_div_u = 0x80,
|
||||
WasmOp_i64_rem_s = 0x81,
|
||||
WasmOp_i64_rem_u = 0x82,
|
||||
WasmOp_i64_and = 0x83,
|
||||
WasmOp_i64_or = 0x84,
|
||||
WasmOp_i64_xor = 0x85,
|
||||
WasmOp_i64_shl = 0x86,
|
||||
WasmOp_i64_shr_s = 0x87,
|
||||
WasmOp_i64_shr_u = 0x88,
|
||||
WasmOp_i64_rotl = 0x89,
|
||||
WasmOp_i64_rotr = 0x8A,
|
||||
WasmOp_f32_abs = 0x8B,
|
||||
WasmOp_f32_neg = 0x8C,
|
||||
WasmOp_f32_ceil = 0x8D,
|
||||
WasmOp_f32_floor = 0x8E,
|
||||
WasmOp_f32_trunc = 0x8F,
|
||||
WasmOp_f32_nearest = 0x90,
|
||||
WasmOp_f32_sqrt = 0x91,
|
||||
WasmOp_f32_add = 0x92,
|
||||
WasmOp_f32_sub = 0x93,
|
||||
WasmOp_f32_mul = 0x94,
|
||||
WasmOp_f32_div = 0x95,
|
||||
WasmOp_f32_min = 0x96,
|
||||
WasmOp_f32_max = 0x97,
|
||||
WasmOp_f32_copysign = 0x98,
|
||||
WasmOp_f64_abs = 0x99,
|
||||
WasmOp_f64_neg = 0x9A,
|
||||
WasmOp_f64_ceil = 0x9B,
|
||||
WasmOp_f64_floor = 0x9C,
|
||||
WasmOp_f64_trunc = 0x9D,
|
||||
WasmOp_f64_nearest = 0x9E,
|
||||
WasmOp_f64_sqrt = 0x9F,
|
||||
WasmOp_f64_add = 0xA0,
|
||||
WasmOp_f64_sub = 0xA1,
|
||||
WasmOp_f64_mul = 0xA2,
|
||||
WasmOp_f64_div = 0xA3,
|
||||
WasmOp_f64_min = 0xA4,
|
||||
WasmOp_f64_max = 0xA5,
|
||||
WasmOp_f64_copysign = 0xA6,
|
||||
WasmOp_i32_wrap_i64 = 0xA7,
|
||||
WasmOp_i32_trunc_f32_s = 0xA8,
|
||||
WasmOp_i32_trunc_f32_u = 0xA9,
|
||||
WasmOp_i32_trunc_f64_s = 0xAA,
|
||||
WasmOp_i32_trunc_f64_u = 0xAB,
|
||||
WasmOp_i64_extend_i32_s = 0xAC,
|
||||
WasmOp_i64_extend_i32_u = 0xAD,
|
||||
WasmOp_i64_trunc_f32_s = 0xAE,
|
||||
WasmOp_i64_trunc_f32_u = 0xAF,
|
||||
WasmOp_i64_trunc_f64_s = 0xB0,
|
||||
WasmOp_i64_trunc_f64_u = 0xB1,
|
||||
WasmOp_f32_convert_i32_s = 0xB2,
|
||||
WasmOp_f32_convert_i32_u = 0xB3,
|
||||
WasmOp_f32_convert_i64_s = 0xB4,
|
||||
WasmOp_f32_convert_i64_u = 0xB5,
|
||||
WasmOp_f32_demote_f64 = 0xB6,
|
||||
WasmOp_f64_convert_i32_s = 0xB7,
|
||||
WasmOp_f64_convert_i32_u = 0xB8,
|
||||
WasmOp_f64_convert_i64_s = 0xB9,
|
||||
WasmOp_f64_convert_i64_u = 0xBA,
|
||||
WasmOp_f64_promote_f32 = 0xBB,
|
||||
WasmOp_i32_reinterpret_f32 = 0xBC,
|
||||
WasmOp_i64_reinterpret_f64 = 0xBD,
|
||||
WasmOp_f32_reinterpret_i32 = 0xBE,
|
||||
WasmOp_f64_reinterpret_i64 = 0xBF,
|
||||
WasmOp_i32_extend8_s = 0xC0,
|
||||
WasmOp_i32_extend16_s = 0xC1,
|
||||
WasmOp_i64_extend8_s = 0xC2,
|
||||
WasmOp_i64_extend16_s = 0xC3,
|
||||
WasmOp_i64_extend32_s = 0xC4,
|
||||
|
||||
WasmOp_prefixed = 0xFC,
|
||||
};
|
||||
|
||||
enum WasmPrefixedOp {
|
||||
WasmPrefixedOp_i32_trunc_sat_f32_s = 0x00,
|
||||
WasmPrefixedOp_i32_trunc_sat_f32_u = 0x01,
|
||||
WasmPrefixedOp_i32_trunc_sat_f64_s = 0x02,
|
||||
WasmPrefixedOp_i32_trunc_sat_f64_u = 0x03,
|
||||
WasmPrefixedOp_i64_trunc_sat_f32_s = 0x04,
|
||||
WasmPrefixedOp_i64_trunc_sat_f32_u = 0x05,
|
||||
WasmPrefixedOp_i64_trunc_sat_f64_s = 0x06,
|
||||
WasmPrefixedOp_i64_trunc_sat_f64_u = 0x07,
|
||||
WasmPrefixedOp_memory_init = 0x08,
|
||||
WasmPrefixedOp_data_drop = 0x09,
|
||||
WasmPrefixedOp_memory_copy = 0x0A,
|
||||
WasmPrefixedOp_memory_fill = 0x0B,
|
||||
WasmPrefixedOp_table_init = 0x0C,
|
||||
WasmPrefixedOp_elem_drop = 0x0D,
|
||||
WasmPrefixedOp_table_copy = 0x0E,
|
||||
WasmPrefixedOp_table_grow = 0x0F,
|
||||
WasmPrefixedOp_table_size = 0x10,
|
||||
WasmPrefixedOp_table_fill = 0x11,
|
||||
};
|
||||
|
||||
static const uint32_t wasm_page_size = 64 * 1024;
|
||||
|
||||
struct ProgramCounter {
|
||||
uint32_t opcode;
|
||||
uint32_t operand;
|
||||
};
|
||||
|
||||
struct TypeInfo {
|
||||
uint32_t param_count;
|
||||
// bitset with param_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit
|
||||
uint32_t param_types;
|
||||
uint32_t result_count;
|
||||
// bitset with result_count bits, indexed from lsb, 0 -> 32-bit, 1 -> 64-bit
|
||||
uint32_t result_types;
|
||||
};
|
||||
|
||||
struct Function {
|
||||
uint32_t id;
|
||||
// Index to start of code in opcodes/operands.
|
||||
struct ProgramCounter entry_pc;
|
||||
uint32_t type_idx;
|
||||
uint32_t locals_size;
|
||||
};
|
||||
|
||||
enum ImpMod {
|
||||
ImpMod_wasi_snapshot_preview1,
|
||||
};
|
||||
|
||||
enum ImpName {
|
||||
ImpName_args_get,
|
||||
ImpName_args_sizes_get,
|
||||
ImpName_clock_time_get,
|
||||
ImpName_debug,
|
||||
ImpName_debug_slice,
|
||||
ImpName_environ_get,
|
||||
ImpName_environ_sizes_get,
|
||||
ImpName_fd_close,
|
||||
ImpName_fd_fdstat_get,
|
||||
ImpName_fd_filestat_get,
|
||||
ImpName_fd_filestat_set_size,
|
||||
ImpName_fd_filestat_set_times,
|
||||
ImpName_fd_pread,
|
||||
ImpName_fd_prestat_dir_name,
|
||||
ImpName_fd_prestat_get,
|
||||
ImpName_fd_pwrite,
|
||||
ImpName_fd_read,
|
||||
ImpName_fd_readdir,
|
||||
ImpName_fd_write,
|
||||
ImpName_path_create_directory,
|
||||
ImpName_path_filestat_get,
|
||||
ImpName_path_open,
|
||||
ImpName_path_remove_directory,
|
||||
ImpName_path_rename,
|
||||
ImpName_path_unlink_file,
|
||||
ImpName_proc_exit,
|
||||
ImpName_random_get,
|
||||
};
|
||||
|
||||
struct Import {
|
||||
enum ImpMod mod;
|
||||
enum ImpName name;
|
||||
uint32_t type_idx;
|
||||
};
|
||||
|
||||
struct VirtualMachine {
|
||||
uint32_t *stack;
|
||||
/// Points to one after the last stack item.
|
||||
uint32_t stack_top;
|
||||
struct ProgramCounter pc;
|
||||
/// Actual memory usage of the WASI code. The capacity is max_memory.
|
||||
uint32_t memory_len;
|
||||
const char *mod_ptr;
|
||||
uint8_t *opcodes;
|
||||
uint32_t *operands;
|
||||
struct Function *functions;
|
||||
/// Type index to start of type in module_bytes.
|
||||
struct TypeInfo *types;
|
||||
uint64_t *globals;
|
||||
char *memory;
|
||||
struct Import *imports;
|
||||
uint32_t imports_len;
|
||||
const char **args;
|
||||
uint32_t *table;
|
||||
};
|
||||
|
||||
static int to_host_fd(int32_t wasi_fd) {
|
||||
const struct Preopen *preopen = find_preopen(wasi_fd);
|
||||
if (!preopen) return wasi_fd;
|
||||
return preopen->host_fd;
|
||||
}
|
||||
|
||||
static enum wasi_errno_t to_wasi_err(int err) {
|
||||
switch (err) {
|
||||
case E2BIG: return WASI_E2BIG;
|
||||
case EACCES: return WASI_EACCES;
|
||||
case EADDRINUSE: return WASI_EADDRINUSE;
|
||||
case EADDRNOTAVAIL: return WASI_EADDRNOTAVAIL;
|
||||
case EAFNOSUPPORT: return WASI_EAFNOSUPPORT;
|
||||
case EAGAIN: return WASI_EAGAIN;
|
||||
case EALREADY: return WASI_EALREADY;
|
||||
case EBADF: return WASI_EBADF;
|
||||
case EBADMSG: return WASI_EBADMSG;
|
||||
case EBUSY: return WASI_EBUSY;
|
||||
case ECANCELED: return WASI_ECANCELED;
|
||||
case ECHILD: return WASI_ECHILD;
|
||||
case ECONNABORTED: return WASI_ECONNABORTED;
|
||||
case ECONNREFUSED: return WASI_ECONNREFUSED;
|
||||
case ECONNRESET: return WASI_ECONNRESET;
|
||||
case EDEADLK: return WASI_EDEADLK;
|
||||
case EDESTADDRREQ: return WASI_EDESTADDRREQ;
|
||||
case EDOM: return WASI_EDOM;
|
||||
case EDQUOT: return WASI_EDQUOT;
|
||||
case EEXIST: return WASI_EEXIST;
|
||||
case EFAULT: return WASI_EFAULT;
|
||||
case EFBIG: return WASI_EFBIG;
|
||||
case EHOSTUNREACH: return WASI_EHOSTUNREACH;
|
||||
case EIDRM: return WASI_EIDRM;
|
||||
case EILSEQ: return WASI_EILSEQ;
|
||||
case EINPROGRESS: return WASI_EINPROGRESS;
|
||||
case EINTR: return WASI_EINTR;
|
||||
case EINVAL: return WASI_EINVAL;
|
||||
case EIO: return WASI_EIO;
|
||||
case EISCONN: return WASI_EISCONN;
|
||||
case EISDIR: return WASI_EISDIR;
|
||||
case ELOOP: return WASI_ELOOP;
|
||||
case EMFILE: return WASI_EMFILE;
|
||||
case EMLINK: return WASI_EMLINK;
|
||||
case EMSGSIZE: return WASI_EMSGSIZE;
|
||||
case EMULTIHOP: return WASI_EMULTIHOP;
|
||||
case ENAMETOOLONG: return WASI_ENAMETOOLONG;
|
||||
case ENETDOWN: return WASI_ENETDOWN;
|
||||
case ENETRESET: return WASI_ENETRESET;
|
||||
case ENETUNREACH: return WASI_ENETUNREACH;
|
||||
case ENFILE: return WASI_ENFILE;
|
||||
case ENOBUFS: return WASI_ENOBUFS;
|
||||
case ENODEV: return WASI_ENODEV;
|
||||
case ENOENT: return WASI_ENOENT;
|
||||
case ENOEXEC: return WASI_ENOEXEC;
|
||||
case ENOLCK: return WASI_ENOLCK;
|
||||
case ENOLINK: return WASI_ENOLINK;
|
||||
case ENOMEM: return WASI_ENOMEM;
|
||||
case ENOMSG: return WASI_ENOMSG;
|
||||
case ENOPROTOOPT: return WASI_ENOPROTOOPT;
|
||||
case ENOSPC: return WASI_ENOSPC;
|
||||
case ENOSYS: return WASI_ENOSYS;
|
||||
case ENOTCONN: return WASI_ENOTCONN;
|
||||
case ENOTDIR: return WASI_ENOTDIR;
|
||||
case ENOTEMPTY: return WASI_ENOTEMPTY;
|
||||
case ENOTRECOVERABLE: return WASI_ENOTRECOVERABLE;
|
||||
case ENOTSOCK: return WASI_ENOTSOCK;
|
||||
case EOPNOTSUPP: return WASI_EOPNOTSUPP;
|
||||
case ENOTTY: return WASI_ENOTTY;
|
||||
case ENXIO: return WASI_ENXIO;
|
||||
case EOVERFLOW: return WASI_EOVERFLOW;
|
||||
case EOWNERDEAD: return WASI_EOWNERDEAD;
|
||||
case EPERM: return WASI_EPERM;
|
||||
case EPIPE: return WASI_EPIPE;
|
||||
case EPROTO: return WASI_EPROTO;
|
||||
case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT;
|
||||
case EPROTOTYPE: return WASI_EPROTOTYPE;
|
||||
case ERANGE: return WASI_ERANGE;
|
||||
case EROFS: return WASI_EROFS;
|
||||
case ESPIPE: return WASI_ESPIPE;
|
||||
case ESRCH: return WASI_ESRCH;
|
||||
case ESTALE: return WASI_ESTALE;
|
||||
case ETIMEDOUT: return WASI_ETIMEDOUT;
|
||||
case ETXTBSY: return WASI_ETXTBSY;
|
||||
case EXDEV: return WASI_EXDEV;
|
||||
default:
|
||||
fprintf(stderr, "unexpected errno: %s\n", strerror(err));
|
||||
abort();
|
||||
};
|
||||
}
|
||||
|
||||
enum wasi_filetype_t {
|
||||
wasi_filetype_t_UNKNOWN,
|
||||
wasi_filetype_t_BLOCK_DEVICE,
|
||||
wasi_filetype_t_CHARACTER_DEVICE,
|
||||
wasi_filetype_t_DIRECTORY,
|
||||
wasi_filetype_t_REGULAR_FILE,
|
||||
wasi_filetype_t_SOCKET_DGRAM,
|
||||
wasi_filetype_t_SOCKET_STREAM,
|
||||
wasi_filetype_t_SYMBOLIC_LINK,
|
||||
};
|
||||
|
||||
static const uint16_t WASI_O_CREAT = 0x0001;
|
||||
static const uint16_t WASI_O_DIRECTORY = 0x0002;
|
||||
static const uint16_t WASI_O_EXCL = 0x0004;
|
||||
static const uint16_t WASI_O_TRUNC = 0x0008;
|
||||
|
||||
static const uint16_t WASI_FDFLAG_APPEND = 0x0001;
|
||||
static const uint16_t WASI_FDFLAG_DSYNC = 0x0002;
|
||||
static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004;
|
||||
static const uint16_t WASI_FDFLAG_SYNC = 0x0010;
|
||||
|
||||
static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull;
|
||||
static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull;
|
||||
|
||||
static enum wasi_filetype_t to_wasi_filetype(mode_t st_mode) {
|
||||
switch (st_mode & S_IFMT) {
|
||||
case S_IFBLK:
|
||||
return wasi_filetype_t_BLOCK_DEVICE;
|
||||
case S_IFCHR:
|
||||
return wasi_filetype_t_CHARACTER_DEVICE;
|
||||
case S_IFDIR:
|
||||
return wasi_filetype_t_DIRECTORY;
|
||||
case S_IFLNK:
|
||||
return wasi_filetype_t_SYMBOLIC_LINK;
|
||||
case S_IFREG:
|
||||
return wasi_filetype_t_REGULAR_FILE;
|
||||
default:
|
||||
return wasi_filetype_t_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t to_wasi_timestamp(struct timespec ts) {
|
||||
return ts.tv_sec * 1000000000ull + ts.tv_nsec;
|
||||
}
|
||||
|
||||
/// const filestat_t = extern struct {
|
||||
/// dev: device_t, u64
|
||||
/// ino: inode_t, u64
|
||||
/// filetype: filetype_t, u8
|
||||
/// nlink: linkcount_t, u64
|
||||
/// size: filesize_t, u64
|
||||
/// atim: timestamp_t, u64
|
||||
/// mtim: timestamp_t, u64
|
||||
/// ctim: timestamp_t, u64
|
||||
/// };
|
||||
static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm,
|
||||
uint32_t buf, struct stat st)
|
||||
{
|
||||
write_u64_le(vm->memory + buf + 0x00, 0); // device
|
||||
write_u64_le(vm->memory + buf + 0x08, st.st_ino);
|
||||
write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode));
|
||||
write_u64_le(vm->memory + buf + 0x18, 1); // nlink
|
||||
write_u64_le(vm->memory + buf + 0x20, st.st_size);
|
||||
#if defined(__APPLE__)
|
||||
write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atimespec));
|
||||
write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtimespec));
|
||||
write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctimespec));
|
||||
#else
|
||||
write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim));
|
||||
write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim));
|
||||
write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim));
|
||||
#endif
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
|
||||
static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm,
|
||||
uint32_t argc, uint32_t argv_buf_size)
|
||||
{
|
||||
uint32_t args_len = 0;
|
||||
size_t buf_size = 0;
|
||||
while (vm->args[args_len]) {
|
||||
buf_size += strlen(vm->args[args_len]) + 1;
|
||||
args_len += 1;
|
||||
}
|
||||
write_u32_le(vm->memory + argc, args_len);
|
||||
write_u32_le(vm->memory + argv_buf_size, buf_size);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t;
|
||||
static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm,
|
||||
uint32_t argv, uint32_t argv_buf)
|
||||
{
|
||||
uint32_t argv_buf_i = 0;
|
||||
uint32_t arg_i = 0;
|
||||
for (;; arg_i += 1) {
|
||||
const char *arg = vm->args[arg_i];
|
||||
if (!arg) break;
|
||||
// Write the arg to the buffer.
|
||||
uint32_t argv_ptr = argv_buf + argv_buf_i;
|
||||
uint32_t arg_len = strlen(arg) + 1;
|
||||
memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len);
|
||||
argv_buf_i += arg_len;
|
||||
|
||||
write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr);
|
||||
}
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn random_get(buf: [*]u8, buf_len: usize) errno_t;
|
||||
static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm,
|
||||
uint32_t buf, uint32_t buf_len)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) {
|
||||
panic("getrandom failed");
|
||||
}
|
||||
#else
|
||||
for (uint32_t i = 0; i < buf_len; i += 1) {
|
||||
vm->memory[buf + i] = rand();
|
||||
}
|
||||
#endif
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
|
||||
/// const prestat_t = extern struct {
|
||||
/// pr_type: u8,
|
||||
/// u: usize,
|
||||
/// };
|
||||
static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm,
|
||||
int32_t fd, uint32_t buf)
|
||||
{
|
||||
const struct Preopen *preopen = find_preopen(fd);
|
||||
if (!preopen) return WASI_EBADF;
|
||||
write_u32_le(vm->memory + buf + 0, 0);
|
||||
write_u32_le(vm->memory + buf + 4, preopen->name_len);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
|
||||
static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm,
|
||||
int32_t fd, uint32_t path, uint32_t path_len)
|
||||
{
|
||||
const struct Preopen *preopen = find_preopen(fd);
|
||||
if (!preopen) return WASI_EBADF;
|
||||
if (path_len != preopen->name_len)
|
||||
panic("wasi_fd_prestat_dir_name expects correct name_len");
|
||||
memcpy(vm->memory + path, preopen->name, path_len);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn fd_close(fd: fd_t) errno_t;
|
||||
static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) {
|
||||
int host_fd = to_host_fd(fd);
|
||||
close(host_fd);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static enum wasi_errno_t wasi_fd_read(
|
||||
struct VirtualMachine *vm,
|
||||
int32_t fd,
|
||||
uint32_t iovs, // [*]const iovec_t
|
||||
uint32_t iovs_len, // usize
|
||||
uint32_t nread // *usize
|
||||
) {
|
||||
int host_fd = to_host_fd(fd);
|
||||
uint32_t i = 0;
|
||||
size_t total_read = 0;
|
||||
for (; i < iovs_len; i += 1) {
|
||||
uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
|
||||
uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
|
||||
ssize_t amt_read = read(host_fd, vm->memory + ptr, len);
|
||||
if (amt_read < 0) return to_wasi_err(errno);
|
||||
total_read += amt_read;
|
||||
if (amt_read != len) break;
|
||||
}
|
||||
write_u32_le(vm->memory + nread, total_read);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
|
||||
/// const ciovec_t = extern struct {
|
||||
/// base: [*]const u8,
|
||||
/// len: usize,
|
||||
/// };
|
||||
static enum wasi_errno_t wasi_fd_write(struct VirtualMachine *vm,
|
||||
int32_t fd, uint32_t iovs, uint32_t iovs_len, uint32_t nwritten)
|
||||
{
|
||||
int host_fd = to_host_fd(fd);
|
||||
size_t total_written = 0;
|
||||
for (uint32_t i = 0; i < iovs_len; i += 1) {
|
||||
uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
|
||||
uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
|
||||
ssize_t written = write(host_fd, vm->memory + ptr, len);
|
||||
if (written < 0) return to_wasi_err(errno);
|
||||
total_written += written;
|
||||
if (written != len) break;
|
||||
}
|
||||
write_u32_le(vm->memory + nwritten, total_written);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static enum wasi_errno_t wasi_fd_pwrite(
|
||||
struct VirtualMachine *vm,
|
||||
int32_t fd,
|
||||
uint32_t iovs, // [*]const ciovec_t
|
||||
uint32_t iovs_len, // usize
|
||||
uint64_t offset, // wasi.filesize_t,
|
||||
uint32_t written_ptr // *usize
|
||||
) {
|
||||
int host_fd = to_host_fd(fd);
|
||||
uint32_t i = 0;
|
||||
size_t written = 0;
|
||||
for (; i < iovs_len; i += 1) {
|
||||
uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
|
||||
uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
|
||||
ssize_t w = pwrite(host_fd, vm->memory + ptr, len, offset + written);
|
||||
if (w < 0) return to_wasi_err(errno);
|
||||
written += w;
|
||||
if (w != len) break;
|
||||
}
|
||||
write_u32_le(vm->memory + written_ptr, written);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
///extern fn path_open(
|
||||
/// dirfd: fd_t,
|
||||
/// dirflags: lookupflags_t,
|
||||
/// path: [*]const u8,
|
||||
/// path_len: usize,
|
||||
/// oflags: oflags_t,
|
||||
/// fs_rights_base: rights_t,
|
||||
/// fs_rights_inheriting: rights_t,
|
||||
/// fs_flags: fdflags_t,
|
||||
/// fd: *fd_t,
|
||||
///) errno_t;
|
||||
static enum wasi_errno_t wasi_path_open(
|
||||
struct VirtualMachine *vm,
|
||||
int32_t dirfd,
|
||||
uint32_t dirflags, // wasi.lookupflags_t,
|
||||
uint32_t path,
|
||||
uint32_t path_len,
|
||||
uint16_t oflags, // wasi.oflags_t,
|
||||
uint64_t fs_rights_base, // wasi.rights_t,
|
||||
uint64_t fs_rights_inheriting, // wasi.rights_t,
|
||||
uint16_t fs_flags, // wasi.fdflags_t,
|
||||
uint32_t fd
|
||||
) {
|
||||
char sub_path[PATH_MAX];
|
||||
memcpy(sub_path, vm->memory + path, path_len);
|
||||
sub_path[path_len] = 0;
|
||||
|
||||
int host_fd = to_host_fd(dirfd);
|
||||
uint32_t flags =
|
||||
(((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) |
|
||||
(((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) |
|
||||
(((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) |
|
||||
(((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) |
|
||||
(((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) |
|
||||
(((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) |
|
||||
(((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) |
|
||||
(((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0);
|
||||
|
||||
if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) &&
|
||||
((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0))
|
||||
{
|
||||
flags |= O_RDWR;
|
||||
} else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) {
|
||||
flags |= O_WRONLY;
|
||||
} else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) {
|
||||
flags |= O_RDONLY; // no-op because O_RDONLY is 0
|
||||
}
|
||||
mode_t mode = 0644;
|
||||
int res_fd = openat(host_fd, sub_path, flags, mode);
|
||||
if (res_fd == -1) return to_wasi_err(errno);
|
||||
write_u32_le(vm->memory + fd, res_fd);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static enum wasi_errno_t wasi_path_filestat_get(
|
||||
struct VirtualMachine *vm,
|
||||
int32_t fd,
|
||||
uint32_t flags, // wasi.lookupflags_t,
|
||||
uint32_t path, // [*]const u8
|
||||
uint32_t path_len, // usize
|
||||
uint32_t buf // *filestat_t
|
||||
) {
|
||||
char sub_path[PATH_MAX];
|
||||
memcpy(sub_path, vm->memory + path, path_len);
|
||||
sub_path[path_len] = 0;
|
||||
|
||||
int host_fd = to_host_fd(fd);
|
||||
struct stat st;
|
||||
if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno);
|
||||
return finish_wasi_stat(vm, buf, st);
|
||||
}
|
||||
|
||||
/// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
|
||||
static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm,
|
||||
int32_t wasi_fd, uint32_t path, uint32_t path_len)
|
||||
{
|
||||
char sub_path[PATH_MAX];
|
||||
memcpy(sub_path, vm->memory + path, path_len);
|
||||
sub_path[path_len] = 0;
|
||||
|
||||
int host_fd = to_host_fd(wasi_fd);
|
||||
if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
static enum wasi_errno_t wasi_path_rename(
|
||||
struct VirtualMachine *vm,
|
||||
int32_t old_fd,
|
||||
uint32_t old_path_ptr, // [*]const u8
|
||||
uint32_t old_path_len, // usize
|
||||
int32_t new_fd,
|
||||
uint32_t new_path_ptr, // [*]const u8
|
||||
uint32_t new_path_len // usize
|
||||
) {
|
||||
char old_path[PATH_MAX];
|
||||
memcpy(old_path, vm->memory + old_path_ptr, old_path_len);
|
||||
old_path[old_path_len] = 0;
|
||||
|
||||
char new_path[PATH_MAX];
|
||||
memcpy(new_path, vm->memory + new_path_ptr, new_path_len);
|
||||
new_path[new_path_len] = 0;
|
||||
|
||||
int old_host_fd = to_host_fd(old_fd);
|
||||
int new_host_fd = to_host_fd(new_fd);
|
||||
if (renameat(old_host_fd, old_path, new_host_fd, new_path) == -1) return to_wasi_err(errno);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
|
||||
static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
|
||||
int host_fd = to_host_fd(fd);
|
||||
struct stat st;
|
||||
if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
|
||||
return finish_wasi_stat(vm, buf, st);
|
||||
}
|
||||
|
||||
static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm,
|
||||
int32_t fd, uint64_t size)
|
||||
{
|
||||
int host_fd = to_host_fd(fd);
|
||||
if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// pub extern "wasi_snapshot_preview1" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
|
||||
/// pub const fdstat_t = extern struct {
|
||||
/// fs_filetype: filetype_t, u8
|
||||
/// fs_flags: fdflags_t, u16
|
||||
/// fs_rights_base: rights_t, u64
|
||||
/// fs_rights_inheriting: rights_t, u64
|
||||
/// };
|
||||
static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
|
||||
int host_fd = to_host_fd(fd);
|
||||
struct stat st;
|
||||
if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
|
||||
write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode));
|
||||
write_u16_le(vm->memory + buf + 0x02, 0); // flags
|
||||
write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base
|
||||
write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
/// extern fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
|
||||
static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm,
|
||||
uint32_t clock_id, uint64_t precision, uint32_t timestamp)
|
||||
{
|
||||
if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC");
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno);
|
||||
uint64_t wasi_ts = to_wasi_timestamp(ts);
|
||||
write_u64_le(vm->memory + timestamp, wasi_ts);
|
||||
return WASI_ESUCCESS;
|
||||
}
|
||||
|
||||
///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void;
|
||||
void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) {
|
||||
fprintf(stderr, "wasi_debug: '%s' number=%" PRIu64 " %" PRIx64 "\n", vm->memory + text, n, n);
|
||||
}
|
||||
|
||||
/// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void;
|
||||
void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) {
|
||||
fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr);
|
||||
}
|
||||
|
||||
enum StackType {
|
||||
ST_32,
|
||||
ST_64,
|
||||
};
|
||||
|
||||
struct Label {
|
||||
enum WasmOp opcode;
|
||||
uint32_t stack_index;
|
||||
uint32_t stack_offset;
|
||||
struct TypeInfo type_info;
|
||||
// this is a UINT32_MAX terminated linked list that is stored in the operands array
|
||||
uint32_t ref_list;
|
||||
union {
|
||||
struct ProgramCounter loop_pc;
|
||||
uint32_t else_ref;
|
||||
} extra;
|
||||
};
|
||||
|
||||
static uint32_t Label_operandCount(const struct Label *label) {
|
||||
if (label->opcode == WasmOp_loop) {
|
||||
return label->type_info.param_count;
|
||||
} else {
|
||||
return label->type_info.result_count;
|
||||
}
|
||||
}
|
||||
|
||||
static enum StackType Label_operandType(const struct Label *label, uint32_t index) {
|
||||
if (label->opcode == WasmOp_loop) {
|
||||
return bs_isSet(&label->type_info.param_types, index);
|
||||
} else {
|
||||
return bs_isSet(&label->type_info.result_types, index);
|
||||
}
|
||||
}
|
||||
|
||||
#define max_stack_depth (1 << 12)
|
||||
|
||||
struct StackInfo {
|
||||
uint32_t top_index;
|
||||
uint32_t top_offset;
|
||||
uint32_t types[max_stack_depth >> 5];
|
||||
uint32_t offsets[max_stack_depth];
|
||||
};
|
||||
|
||||
static enum StackType si_top(const struct StackInfo *si) {
|
||||
return bs_isSet(si->types, si->top_index - 1);
|
||||
}
|
||||
|
||||
static enum StackType si_local(const struct StackInfo *si, uint32_t local_idx) {
|
||||
return bs_isSet(si->types, local_idx);
|
||||
}
|
||||
|
||||
static void si_push(struct StackInfo *si, enum StackType entry_type) {
|
||||
bs_setValue(si->types, si->top_index, entry_type);
|
||||
si->offsets[si->top_index] = si->top_offset;
|
||||
si->top_index += 1;
|
||||
si->top_offset += 1 + entry_type;
|
||||
}
|
||||
|
||||
static void si_pop(struct StackInfo *si, enum StackType entry_type) {
|
||||
assert(si_top(si) == entry_type);
|
||||
si->top_index -= 1;
|
||||
si->top_offset -= 1 + entry_type;
|
||||
assert(si->top_offset == si->offsets[si->top_index]);
|
||||
}
|
||||
|
||||
static void vm_decodeCode(struct VirtualMachine *vm, struct TypeInfo *func_type_info,
|
||||
uint32_t *code_i, struct ProgramCounter *pc, struct StackInfo *stack)
|
||||
{
|
||||
const char *mod_ptr = vm->mod_ptr;
|
||||
uint8_t *opcodes = vm->opcodes;
|
||||
uint32_t *operands = vm->operands;
|
||||
|
||||
// push return address
|
||||
uint32_t frame_size = stack->top_offset;
|
||||
si_push(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
|
||||
uint32_t unreachable_depth = 0;
|
||||
uint32_t label_i = 0;
|
||||
static struct Label labels[1 << 9];
|
||||
#ifndef NDEBUG
|
||||
memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version
|
||||
#endif
|
||||
labels[label_i].opcode = WasmOp_block;
|
||||
labels[label_i].stack_index = stack->top_index;
|
||||
labels[label_i].stack_offset = stack->top_offset;
|
||||
labels[label_i].type_info = *func_type_info;
|
||||
labels[label_i].ref_list = UINT32_MAX;
|
||||
|
||||
enum {
|
||||
State_default,
|
||||
State_bool_not,
|
||||
} state = State_default;
|
||||
|
||||
for (;;) {
|
||||
assert(stack->top_index >= labels[0].stack_index);
|
||||
assert(stack->top_offset >= labels[0].stack_offset);
|
||||
enum WasmOp opcode = (uint8_t)mod_ptr[*code_i];
|
||||
*code_i += 1;
|
||||
enum WasmPrefixedOp prefixed_opcode;
|
||||
if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i);
|
||||
|
||||
//fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand);
|
||||
//struct ProgramCounter old_pc = *pc;
|
||||
|
||||
if (unreachable_depth == 0)
|
||||
switch (opcode) {
|
||||
case WasmOp_unreachable:
|
||||
case WasmOp_nop:
|
||||
case WasmOp_block:
|
||||
case WasmOp_loop:
|
||||
case WasmOp_else:
|
||||
case WasmOp_end:
|
||||
case WasmOp_br:
|
||||
case WasmOp_return:
|
||||
case WasmOp_call:
|
||||
case WasmOp_local_get:
|
||||
case WasmOp_local_set:
|
||||
case WasmOp_local_tee:
|
||||
case WasmOp_global_get:
|
||||
case WasmOp_global_set:
|
||||
case WasmOp_drop:
|
||||
case WasmOp_select:
|
||||
break; // handled manually below
|
||||
|
||||
case WasmOp_if:
|
||||
case WasmOp_br_if:
|
||||
case WasmOp_br_table:
|
||||
case WasmOp_call_indirect:
|
||||
si_pop(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_memory_size:
|
||||
case WasmOp_i32_const:
|
||||
case WasmOp_f32_const:
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_const:
|
||||
case WasmOp_f64_const:
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmOp_i32_load:
|
||||
case WasmOp_f32_load:
|
||||
case WasmOp_i32_load8_s:
|
||||
case WasmOp_i32_load8_u:
|
||||
case WasmOp_i32_load16_s:
|
||||
case WasmOp_i32_load16_u:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_load:
|
||||
case WasmOp_f64_load:
|
||||
case WasmOp_i64_load8_s:
|
||||
case WasmOp_i64_load8_u:
|
||||
case WasmOp_i64_load16_s:
|
||||
case WasmOp_i64_load16_u:
|
||||
case WasmOp_i64_load32_s:
|
||||
case WasmOp_i64_load32_u:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmOp_memory_grow:
|
||||
case WasmOp_i32_eqz:
|
||||
case WasmOp_i32_clz:
|
||||
case WasmOp_i32_ctz:
|
||||
case WasmOp_i32_popcnt:
|
||||
case WasmOp_f32_abs:
|
||||
case WasmOp_f32_neg:
|
||||
case WasmOp_f32_ceil:
|
||||
case WasmOp_f32_floor:
|
||||
case WasmOp_f32_trunc:
|
||||
case WasmOp_f32_nearest:
|
||||
case WasmOp_f32_sqrt:
|
||||
case WasmOp_i32_trunc_f32_s:
|
||||
case WasmOp_i32_trunc_f32_u:
|
||||
case WasmOp_f32_convert_i32_s:
|
||||
case WasmOp_f32_convert_i32_u:
|
||||
case WasmOp_i32_reinterpret_f32:
|
||||
case WasmOp_f32_reinterpret_i32:
|
||||
case WasmOp_i32_extend8_s:
|
||||
case WasmOp_i32_extend16_s:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_eqz:
|
||||
case WasmOp_i32_wrap_i64:
|
||||
case WasmOp_i32_trunc_f64_s:
|
||||
case WasmOp_i32_trunc_f64_u:
|
||||
case WasmOp_f32_convert_i64_s:
|
||||
case WasmOp_f32_convert_i64_u:
|
||||
case WasmOp_f32_demote_f64:
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_clz:
|
||||
case WasmOp_i64_ctz:
|
||||
case WasmOp_i64_popcnt:
|
||||
case WasmOp_f64_abs:
|
||||
case WasmOp_f64_neg:
|
||||
case WasmOp_f64_ceil:
|
||||
case WasmOp_f64_floor:
|
||||
case WasmOp_f64_trunc:
|
||||
case WasmOp_f64_nearest:
|
||||
case WasmOp_f64_sqrt:
|
||||
case WasmOp_i64_trunc_f64_s:
|
||||
case WasmOp_i64_trunc_f64_u:
|
||||
case WasmOp_f64_convert_i64_s:
|
||||
case WasmOp_f64_convert_i64_u:
|
||||
case WasmOp_i64_reinterpret_f64:
|
||||
case WasmOp_f64_reinterpret_i64:
|
||||
case WasmOp_i64_extend8_s:
|
||||
case WasmOp_i64_extend16_s:
|
||||
case WasmOp_i64_extend32_s:
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_extend_i32_s:
|
||||
case WasmOp_i64_extend_i32_u:
|
||||
case WasmOp_i64_trunc_f32_s:
|
||||
case WasmOp_i64_trunc_f32_u:
|
||||
case WasmOp_f64_convert_i32_s:
|
||||
case WasmOp_f64_convert_i32_u:
|
||||
case WasmOp_f64_promote_f32:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmOp_i32_store:
|
||||
case WasmOp_f32_store:
|
||||
case WasmOp_i32_store8:
|
||||
case WasmOp_i32_store16:
|
||||
si_pop(stack, ST_32);
|
||||
si_pop(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_store:
|
||||
case WasmOp_f64_store:
|
||||
case WasmOp_i64_store8:
|
||||
case WasmOp_i64_store16:
|
||||
case WasmOp_i64_store32:
|
||||
si_pop(stack, ST_64);
|
||||
si_pop(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i32_eq:
|
||||
case WasmOp_i32_ne:
|
||||
case WasmOp_i32_lt_s:
|
||||
case WasmOp_i32_lt_u:
|
||||
case WasmOp_i32_gt_s:
|
||||
case WasmOp_i32_gt_u:
|
||||
case WasmOp_i32_le_s:
|
||||
case WasmOp_i32_le_u:
|
||||
case WasmOp_i32_ge_s:
|
||||
case WasmOp_i32_ge_u:
|
||||
case WasmOp_f32_eq:
|
||||
case WasmOp_f32_ne:
|
||||
case WasmOp_f32_lt:
|
||||
case WasmOp_f32_gt:
|
||||
case WasmOp_f32_le:
|
||||
case WasmOp_f32_ge:
|
||||
si_pop(stack, ST_32);
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_eq:
|
||||
case WasmOp_i64_ne:
|
||||
case WasmOp_i64_lt_s:
|
||||
case WasmOp_i64_lt_u:
|
||||
case WasmOp_i64_gt_s:
|
||||
case WasmOp_i64_gt_u:
|
||||
case WasmOp_i64_le_s:
|
||||
case WasmOp_i64_le_u:
|
||||
case WasmOp_i64_ge_s:
|
||||
case WasmOp_i64_ge_u:
|
||||
case WasmOp_f64_eq:
|
||||
case WasmOp_f64_ne:
|
||||
case WasmOp_f64_lt:
|
||||
case WasmOp_f64_gt:
|
||||
case WasmOp_f64_le:
|
||||
case WasmOp_f64_ge:
|
||||
si_pop(stack, ST_64);
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i32_add:
|
||||
case WasmOp_i32_sub:
|
||||
case WasmOp_i32_mul:
|
||||
case WasmOp_i32_div_s:
|
||||
case WasmOp_i32_div_u:
|
||||
case WasmOp_i32_rem_s:
|
||||
case WasmOp_i32_rem_u:
|
||||
case WasmOp_i32_and:
|
||||
case WasmOp_i32_or:
|
||||
case WasmOp_i32_xor:
|
||||
case WasmOp_i32_shl:
|
||||
case WasmOp_i32_shr_s:
|
||||
case WasmOp_i32_shr_u:
|
||||
case WasmOp_i32_rotl:
|
||||
case WasmOp_i32_rotr:
|
||||
case WasmOp_f32_add:
|
||||
case WasmOp_f32_sub:
|
||||
case WasmOp_f32_mul:
|
||||
case WasmOp_f32_div:
|
||||
case WasmOp_f32_min:
|
||||
case WasmOp_f32_max:
|
||||
case WasmOp_f32_copysign:
|
||||
si_pop(stack, ST_32);
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmOp_i64_add:
|
||||
case WasmOp_i64_sub:
|
||||
case WasmOp_i64_mul:
|
||||
case WasmOp_i64_div_s:
|
||||
case WasmOp_i64_div_u:
|
||||
case WasmOp_i64_rem_s:
|
||||
case WasmOp_i64_rem_u:
|
||||
case WasmOp_i64_and:
|
||||
case WasmOp_i64_or:
|
||||
case WasmOp_i64_xor:
|
||||
case WasmOp_i64_shl:
|
||||
case WasmOp_i64_shr_s:
|
||||
case WasmOp_i64_shr_u:
|
||||
case WasmOp_i64_rotl:
|
||||
case WasmOp_i64_rotr:
|
||||
case WasmOp_f64_add:
|
||||
case WasmOp_f64_sub:
|
||||
case WasmOp_f64_mul:
|
||||
case WasmOp_f64_div:
|
||||
case WasmOp_f64_min:
|
||||
case WasmOp_f64_max:
|
||||
case WasmOp_f64_copysign:
|
||||
si_pop(stack, ST_64);
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmOp_prefixed:
|
||||
switch (prefixed_opcode) {
|
||||
case WasmPrefixedOp_i32_trunc_sat_f32_s:
|
||||
case WasmPrefixedOp_i32_trunc_sat_f32_u:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_i32_trunc_sat_f64_s:
|
||||
case WasmPrefixedOp_i32_trunc_sat_f64_u:
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_i64_trunc_sat_f32_s:
|
||||
case WasmPrefixedOp_i64_trunc_sat_f32_u:
|
||||
si_pop(stack, ST_32);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_i64_trunc_sat_f64_s:
|
||||
case WasmPrefixedOp_i64_trunc_sat_f64_u:
|
||||
si_pop(stack, ST_64);
|
||||
si_push(stack, ST_64);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_memory_init:
|
||||
case WasmPrefixedOp_memory_copy:
|
||||
case WasmPrefixedOp_memory_fill:
|
||||
case WasmPrefixedOp_table_init:
|
||||
case WasmPrefixedOp_table_copy:
|
||||
si_pop(stack, ST_32);
|
||||
si_pop(stack, ST_32);
|
||||
si_pop(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_table_fill:
|
||||
si_pop(stack, ST_32);
|
||||
panic("si_pop(stack, unreachable);");
|
||||
si_pop(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_data_drop:
|
||||
case WasmPrefixedOp_elem_drop:
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_table_grow:
|
||||
si_pop(stack, ST_32);
|
||||
panic("si_pop(stack, unreachable);");
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_table_size:
|
||||
si_push(stack, ST_32);
|
||||
break;
|
||||
|
||||
default: panic("unexpected prefixed opcode");
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
switch (opcode) {
|
||||
case WasmOp_unreachable:
|
||||
if (unreachable_depth == 0) {
|
||||
opcodes[pc->opcode] = Op_unreachable;
|
||||
pc->opcode += 1;
|
||||
unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_nop:
|
||||
case WasmOp_i32_reinterpret_f32:
|
||||
case WasmOp_i64_reinterpret_f64:
|
||||
case WasmOp_f32_reinterpret_i32:
|
||||
case WasmOp_f64_reinterpret_i64:
|
||||
break;
|
||||
|
||||
case WasmOp_block:
|
||||
case WasmOp_loop:
|
||||
case WasmOp_if:
|
||||
{
|
||||
int64_t block_type = read64_ileb128(mod_ptr, code_i);
|
||||
if (unreachable_depth == 0) {
|
||||
label_i += 1;
|
||||
struct Label *label = &labels[label_i];
|
||||
label->opcode = opcode;
|
||||
if (block_type < 0) {
|
||||
label->type_info.param_count = 0;
|
||||
label->type_info.param_types = 0;
|
||||
label->type_info.result_count = block_type != -0x40;
|
||||
switch (block_type) {
|
||||
case -0x40:
|
||||
case -1:
|
||||
case -3:
|
||||
label->type_info.result_types = 0;
|
||||
break;
|
||||
case -2:
|
||||
case -4:
|
||||
label->type_info.result_types = UINT32_MAX;
|
||||
break;
|
||||
default: panic("unexpected param type");
|
||||
}
|
||||
} else label->type_info = vm->types[block_type];
|
||||
|
||||
uint32_t param_i = label->type_info.param_count;
|
||||
while (param_i > 0) {
|
||||
param_i -= 1;
|
||||
si_pop(stack, bs_isSet(&label->type_info.param_types, param_i));
|
||||
}
|
||||
label->stack_index = stack->top_index;
|
||||
label->stack_offset = stack->top_offset;
|
||||
label->ref_list = UINT32_MAX;
|
||||
for (; param_i < label->type_info.param_count; param_i += 1)
|
||||
si_push(stack, bs_isSet(&label->type_info.param_types, param_i));
|
||||
|
||||
switch (opcode) {
|
||||
case WasmOp_block:
|
||||
break;
|
||||
|
||||
case WasmOp_loop:
|
||||
label->extra.loop_pc = *pc;
|
||||
break;
|
||||
|
||||
case WasmOp_if:
|
||||
if (state == State_bool_not) {
|
||||
pc->opcode -= 1;
|
||||
opcodes[pc->opcode] = Op_br_nez_void;
|
||||
} else opcodes[pc->opcode] = Op_br_eqz_void;
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand] = 0;
|
||||
label->extra.else_ref = pc->operand + 1;
|
||||
pc->operand += 3;
|
||||
break;
|
||||
|
||||
default: panic("unexpected label opcode");
|
||||
}
|
||||
} else unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_else:
|
||||
if (unreachable_depth <= 1) {
|
||||
struct Label *label = &labels[label_i];
|
||||
assert(label->opcode == WasmOp_if);
|
||||
label->opcode = WasmOp_else;
|
||||
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t operand_count = Label_operandCount(label);
|
||||
for (uint32_t operand_i = operand_count; operand_i > 0; ) {
|
||||
operand_i -= 1;
|
||||
si_pop(stack, Label_operandType(label, operand_i));
|
||||
}
|
||||
assert(stack->top_index == label->stack_index);
|
||||
assert(stack->top_offset == label->stack_offset);
|
||||
|
||||
switch (operand_count) {
|
||||
case 0:
|
||||
opcodes[pc->opcode] = Op_br_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//fprintf(stderr, "label_i=%u operand_type=%d\n",
|
||||
// label_i, Label_operandType(label, 0));
|
||||
switch (Label_operandType(label, 0)) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_br_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_br_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
|
||||
operands[pc->operand + 1] = label->ref_list;
|
||||
label->ref_list = pc->operand + 1;
|
||||
pc->operand += 3;
|
||||
} else unreachable_depth = 0;
|
||||
|
||||
operands[label->extra.else_ref + 0] = pc->opcode;
|
||||
operands[label->extra.else_ref + 1] = pc->operand;
|
||||
for (uint32_t param_i = 0; param_i < label->type_info.param_count; param_i += 1)
|
||||
si_push(stack, bs_isSet(&label->type_info.param_types, param_i));
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_end:
|
||||
if (unreachable_depth <= 1) {
|
||||
struct Label *label = &labels[label_i];
|
||||
struct ProgramCounter *target_pc = (label->opcode == WasmOp_loop) ? &label->extra.loop_pc : pc;
|
||||
if (label->opcode == WasmOp_if) {
|
||||
operands[label->extra.else_ref + 0] = target_pc->opcode;
|
||||
operands[label->extra.else_ref + 1] = target_pc->operand;
|
||||
}
|
||||
uint32_t ref = label->ref_list;
|
||||
while (ref != UINT32_MAX) {
|
||||
uint32_t next_ref = operands[ref];
|
||||
operands[ref + 0] = target_pc->opcode;
|
||||
operands[ref + 1] = target_pc->operand;
|
||||
ref = next_ref;
|
||||
}
|
||||
|
||||
if (unreachable_depth == 0) {
|
||||
for (uint32_t result_i = label->type_info.result_count; result_i > 0; ) {
|
||||
result_i -= 1;
|
||||
si_pop(stack, bs_isSet(&label->type_info.result_types, result_i));
|
||||
}
|
||||
} else unreachable_depth = 0;
|
||||
|
||||
if (label_i == 0) {
|
||||
assert(stack->top_index == label->stack_index);
|
||||
assert(stack->top_offset == label->stack_offset);
|
||||
|
||||
switch (labels[0].type_info.result_count) {
|
||||
case 0:
|
||||
opcodes[pc->opcode] = Op_return_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_return_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_return_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset;
|
||||
operands[pc->operand + 1] = frame_size;
|
||||
pc->operand += 2;
|
||||
return;
|
||||
}
|
||||
label_i -= 1;
|
||||
|
||||
stack->top_index = label->stack_index;
|
||||
stack->top_offset = label->stack_offset;
|
||||
for (uint32_t result_i = 0; result_i < label->type_info.result_count; result_i += 1)
|
||||
si_push(stack, bs_isSet(&label->type_info.result_types, result_i));
|
||||
} else unreachable_depth -= 1;
|
||||
break;
|
||||
|
||||
case WasmOp_br:
|
||||
case WasmOp_br_if:
|
||||
{
|
||||
uint32_t label_idx = read32_uleb128(mod_ptr, code_i);
|
||||
if (unreachable_depth == 0) {
|
||||
struct Label *label = &labels[label_i - label_idx];
|
||||
uint32_t operand_count = Label_operandCount(label);
|
||||
uint32_t operand_i = operand_count;
|
||||
while (operand_i > 0) {
|
||||
operand_i -= 1;
|
||||
si_pop(stack, Label_operandType(label, operand_i));
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case WasmOp_br:
|
||||
switch (operand_count) {
|
||||
case 0:
|
||||
opcodes[pc->opcode] = Op_br_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (Label_operandType(label, 0)) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_br_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_br_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_br_if:
|
||||
switch (operand_count) {
|
||||
case 0:
|
||||
if (state == State_bool_not) {
|
||||
pc->opcode -= 1;
|
||||
opcodes[pc->opcode] = Op_br_eqz_void;
|
||||
} else opcodes[pc->opcode] = Op_br_nez_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (Label_operandType(label, 0)) {
|
||||
case ST_32:
|
||||
if (state == State_bool_not) {
|
||||
pc->opcode -= 1;
|
||||
opcodes[pc->opcode] = Op_br_eqz_32;
|
||||
} else opcodes[pc->opcode] = Op_br_nez_32;
|
||||
break;
|
||||
|
||||
case ST_64:
|
||||
if (state == State_bool_not) {
|
||||
pc->opcode -= 1;
|
||||
opcodes[pc->opcode] = Op_br_eqz_64;
|
||||
} else opcodes[pc->opcode] = Op_br_nez_64;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
|
||||
operands[pc->operand + 1] = label->ref_list;
|
||||
label->ref_list = pc->operand + 1;
|
||||
pc->operand += 3;
|
||||
|
||||
switch (opcode) {
|
||||
case WasmOp_br:
|
||||
unreachable_depth += 1;
|
||||
break;
|
||||
|
||||
case WasmOp_br_if:
|
||||
for (; operand_i < operand_count; operand_i += 1)
|
||||
si_push(stack, Label_operandType(label, operand_i));
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_br_table:
|
||||
{
|
||||
uint32_t labels_len = read32_uleb128(mod_ptr, code_i);
|
||||
for (uint32_t i = 0; i <= labels_len; i += 1) {
|
||||
uint32_t label_idx = read32_uleb128(mod_ptr, code_i);
|
||||
if (unreachable_depth != 0) continue;
|
||||
struct Label *label = &labels[label_i - label_idx];
|
||||
if (i == 0) {
|
||||
uint32_t operand_count = Label_operandCount(label);
|
||||
for (uint32_t operand_i = operand_count; operand_i > 0; ) {
|
||||
operand_i -= 1;
|
||||
si_pop(stack, Label_operandType(label, operand_i));
|
||||
}
|
||||
|
||||
switch (operand_count) {
|
||||
case 0:
|
||||
opcodes[pc->opcode] = Op_br_table_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (Label_operandType(label, 0)) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_br_table_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_br_table_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand] = labels_len;
|
||||
pc->operand += 1;
|
||||
}
|
||||
operands[pc->operand + 0] = stack->top_offset - label->stack_offset;
|
||||
operands[pc->operand + 1] = label->ref_list;
|
||||
label->ref_list = pc->operand + 1;
|
||||
pc->operand += 3;
|
||||
}
|
||||
if (unreachable_depth == 0) unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_return:
|
||||
if (unreachable_depth == 0) {
|
||||
for (uint32_t result_i = labels[0].type_info.result_count; result_i > 0; ) {
|
||||
result_i -= 1;
|
||||
si_pop(stack, bs_isSet(&labels[0].type_info.result_types, result_i));
|
||||
}
|
||||
|
||||
switch (labels[0].type_info.result_count) {
|
||||
case 0:
|
||||
opcodes[pc->opcode] = Op_return_void;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch ((enum StackType)bs_isSet(&labels[0].type_info.result_types, 0)) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_return_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_return_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected operand count");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand + 0] = stack->top_offset - labels[0].stack_offset;
|
||||
operands[pc->operand + 1] = frame_size;
|
||||
pc->operand += 2;
|
||||
unreachable_depth += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_call:
|
||||
{
|
||||
uint32_t fn_id = read32_uleb128(mod_ptr, code_i);
|
||||
if (unreachable_depth == 0) {
|
||||
uint32_t type_idx;
|
||||
if (fn_id < vm->imports_len) {
|
||||
opcodes[pc->opcode + 0] = Op_call_import;
|
||||
opcodes[pc->opcode + 1] = fn_id;
|
||||
pc->opcode += 2;
|
||||
type_idx = vm->imports[fn_id].type_idx;
|
||||
} else {
|
||||
uint32_t fn_idx = fn_id - vm->imports_len;
|
||||
opcodes[pc->opcode] = Op_call_func;
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand] = fn_idx;
|
||||
pc->operand += 1;
|
||||
type_idx = vm->functions[fn_idx].type_idx;
|
||||
}
|
||||
struct TypeInfo *type_info = &vm->types[type_idx];
|
||||
|
||||
for (uint32_t param_i = type_info->param_count; param_i > 0; ) {
|
||||
param_i -= 1;
|
||||
si_pop(stack, bs_isSet(&type_info->param_types, param_i));
|
||||
}
|
||||
for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1)
|
||||
si_push(stack, bs_isSet(&type_info->result_types, result_i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_call_indirect:
|
||||
{
|
||||
uint32_t type_idx = read32_uleb128(mod_ptr, code_i);
|
||||
if (read32_uleb128(mod_ptr, code_i) != 0) panic("unexpected table index");
|
||||
if (unreachable_depth == 0) {
|
||||
opcodes[pc->opcode] = Op_call_indirect;
|
||||
pc->opcode += 1;
|
||||
|
||||
struct TypeInfo *type_info = &vm->types[type_idx];
|
||||
for (uint32_t param_i = type_info->param_count; param_i > 0; ) {
|
||||
param_i -= 1;
|
||||
si_pop(stack, bs_isSet(&type_info->param_types, param_i));
|
||||
}
|
||||
for (uint32_t result_i = 0; result_i < type_info->result_count; result_i += 1)
|
||||
si_push(stack, bs_isSet(&type_info->result_types, result_i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_select:
|
||||
case WasmOp_drop:
|
||||
if (unreachable_depth == 0) {
|
||||
if (opcode == WasmOp_select) si_pop(stack, ST_32);
|
||||
enum StackType operand_type = si_top(stack);
|
||||
si_pop(stack, operand_type);
|
||||
if (opcode == WasmOp_select) {
|
||||
si_pop(stack, operand_type);
|
||||
si_push(stack, operand_type);
|
||||
}
|
||||
switch (opcode) {
|
||||
case WasmOp_select:
|
||||
switch (operand_type) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_select_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_select_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_drop:
|
||||
switch (operand_type) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_drop_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_drop_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_local_get:
|
||||
case WasmOp_local_set:
|
||||
case WasmOp_local_tee:
|
||||
{
|
||||
uint32_t local_idx = read32_uleb128(mod_ptr, code_i);
|
||||
if (unreachable_depth == 0) {
|
||||
enum StackType local_type = si_local(stack, local_idx);
|
||||
switch (opcode) {
|
||||
case WasmOp_local_get:
|
||||
switch (local_type) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_local_get_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_local_get_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_local_set:
|
||||
switch (local_type) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_local_set_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_local_set_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_local_tee:
|
||||
switch (local_type) {
|
||||
case ST_32: opcodes[pc->opcode] = Op_local_tee_32; break;
|
||||
case ST_64: opcodes[pc->opcode] = Op_local_tee_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
operands[pc->operand] = stack->top_offset - stack->offsets[local_idx];
|
||||
pc->operand += 1;
|
||||
switch (opcode) {
|
||||
case WasmOp_local_get:
|
||||
si_push(stack, local_type);
|
||||
break;
|
||||
|
||||
case WasmOp_local_set:
|
||||
si_pop(stack, local_type);
|
||||
break;
|
||||
|
||||
case WasmOp_local_tee:
|
||||
si_pop(stack, local_type);
|
||||
si_push(stack, local_type);
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_global_get:
|
||||
case WasmOp_global_set:
|
||||
{
|
||||
uint32_t global_idx = read32_uleb128(mod_ptr, code_i);
|
||||
if (unreachable_depth == 0) {
|
||||
enum StackType global_type = ST_32; // all globals assumed to be 32-bit
|
||||
switch (opcode) {
|
||||
case WasmOp_global_get:
|
||||
switch (global_idx) {
|
||||
case 0: opcodes[pc->opcode] = Op_global_get_0_32; break;
|
||||
default: opcodes[pc->opcode] = Op_global_get_32; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_global_set:
|
||||
switch (global_idx) {
|
||||
case 0: opcodes[pc->opcode] = Op_global_set_0_32; break;
|
||||
default: opcodes[pc->opcode] = Op_global_set_32; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
if (global_idx != 0) {
|
||||
operands[pc->operand] = global_idx;
|
||||
pc->operand += 1;
|
||||
}
|
||||
switch (opcode) {
|
||||
case WasmOp_global_get:
|
||||
si_push(stack, global_type);
|
||||
break;
|
||||
|
||||
case WasmOp_global_set:
|
||||
si_pop(stack, global_type);
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_load:
|
||||
case WasmOp_i64_load:
|
||||
case WasmOp_f32_load:
|
||||
case WasmOp_f64_load:
|
||||
case WasmOp_i32_load8_s:
|
||||
case WasmOp_i32_load8_u:
|
||||
case WasmOp_i32_load16_s:
|
||||
case WasmOp_i32_load16_u:
|
||||
case WasmOp_i64_load8_s:
|
||||
case WasmOp_i64_load8_u:
|
||||
case WasmOp_i64_load16_s:
|
||||
case WasmOp_i64_load16_u:
|
||||
case WasmOp_i64_load32_s:
|
||||
case WasmOp_i64_load32_u:
|
||||
case WasmOp_i32_store:
|
||||
case WasmOp_i64_store:
|
||||
case WasmOp_f32_store:
|
||||
case WasmOp_f64_store:
|
||||
case WasmOp_i32_store8:
|
||||
case WasmOp_i32_store16:
|
||||
case WasmOp_i64_store8:
|
||||
case WasmOp_i64_store16:
|
||||
case WasmOp_i64_store32:
|
||||
{
|
||||
uint32_t alignment = read32_uleb128(mod_ptr, code_i);
|
||||
uint32_t offset = read32_uleb128(mod_ptr, code_i);
|
||||
(void)alignment;
|
||||
if (unreachable_depth == 0) {
|
||||
switch (opcode) {
|
||||
default: break;
|
||||
|
||||
case WasmOp_i64_store8: case WasmOp_i64_store16: case WasmOp_i64_store32:
|
||||
opcodes[pc->opcode] = Op_drop_32;
|
||||
pc->opcode += 1;
|
||||
break;
|
||||
}
|
||||
switch (opcode) {
|
||||
case WasmOp_i32_load8_s: case WasmOp_i32_load8_u:
|
||||
case WasmOp_i64_load8_s: case WasmOp_i64_load8_u:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_load_0_8; break;
|
||||
default: opcodes[pc->opcode] = Op_load_8; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_load16_s: case WasmOp_i32_load16_u:
|
||||
case WasmOp_i64_load16_s: case WasmOp_i64_load16_u:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_load_0_16; break;
|
||||
default: opcodes[pc->opcode] = Op_load_16; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_load: case WasmOp_f32_load:
|
||||
case WasmOp_i64_load32_s: case WasmOp_i64_load32_u:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_load_0_32; break;
|
||||
default: opcodes[pc->opcode] = Op_load_32; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i64_load: case WasmOp_f64_load:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_load_0_64; break;
|
||||
default: opcodes[pc->opcode] = Op_load_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_store8: case WasmOp_i64_store8:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_store_0_8; break;
|
||||
default: opcodes[pc->opcode] = Op_store_8; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_store16: case WasmOp_i64_store16:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_store_0_16; break;
|
||||
default: opcodes[pc->opcode] = Op_store_16; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_store: case WasmOp_f32_store: case WasmOp_i64_store32:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_store_0_32; break;
|
||||
default: opcodes[pc->opcode] = Op_store_32; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i64_store: case WasmOp_f64_store:
|
||||
switch (offset) {
|
||||
case 0: opcodes[pc->opcode] = Op_store_0_64; break;
|
||||
default: opcodes[pc->opcode] = Op_store_64; break;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
switch (offset) {
|
||||
case 0: break;
|
||||
|
||||
default:
|
||||
operands[pc->operand] = offset;
|
||||
pc->operand += 1;
|
||||
break;
|
||||
}
|
||||
switch (opcode) {
|
||||
default: break;
|
||||
|
||||
case WasmOp_i32_load8_s: case WasmOp_i64_load8_s:
|
||||
opcodes[pc->opcode] = Op_sext8_32;
|
||||
pc->opcode += 1;
|
||||
break;
|
||||
|
||||
case WasmOp_i32_load16_s: case WasmOp_i64_load16_s:
|
||||
opcodes[pc->opcode] = Op_sext16_32;
|
||||
pc->opcode += 1;
|
||||
break;
|
||||
}
|
||||
switch (opcode) {
|
||||
default: break;
|
||||
|
||||
case WasmOp_i64_load8_s: case WasmOp_i64_load16_s: case WasmOp_i64_load32_s:
|
||||
opcodes[pc->opcode] = Op_sext_64_32;
|
||||
pc->opcode += 1;
|
||||
break;
|
||||
|
||||
case WasmOp_i64_load8_u: case WasmOp_i64_load16_u: case WasmOp_i64_load32_u:
|
||||
opcodes[pc->opcode] = Op_zext_64_32;
|
||||
pc->opcode += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_memory_size:
|
||||
case WasmOp_memory_grow:
|
||||
{
|
||||
if (mod_ptr[*code_i] != 0) panic("unexpected memory index");
|
||||
*code_i += 1;
|
||||
if (unreachable_depth == 0) {
|
||||
switch (opcode) {
|
||||
case WasmOp_memory_size: opcodes[pc->opcode] = Op_mem_size; break;
|
||||
case WasmOp_memory_grow: opcodes[pc->opcode] = Op_mem_grow; break;
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i32_const:
|
||||
case WasmOp_f32_const:
|
||||
{
|
||||
uint32_t value;
|
||||
switch (opcode) {
|
||||
case WasmOp_i32_const: value = read32_ileb128(mod_ptr, code_i); break;
|
||||
|
||||
case WasmOp_f32_const:
|
||||
value = read_u32_le(&mod_ptr[*code_i]);
|
||||
*code_i += sizeof(value);
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
if (unreachable_depth == 0) {
|
||||
switch (value) {
|
||||
case 0: opcodes[pc->opcode] = Op_const_0_32; break;
|
||||
case 1: opcodes[pc->opcode] = Op_const_1_32; break;
|
||||
|
||||
default:
|
||||
opcodes[pc->opcode] = Op_const_32;
|
||||
operands[pc->operand] = value;
|
||||
pc->operand += 1;
|
||||
break;
|
||||
|
||||
case UINT32_MAX: opcodes[pc->opcode] = Op_const_umax_32; break;
|
||||
}
|
||||
pc->opcode += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_i64_const:
|
||||
case WasmOp_f64_const:
|
||||
{
|
||||
uint64_t value;
|
||||
switch (opcode) {
|
||||
case WasmOp_i64_const: value = read64_ileb128(mod_ptr, code_i); break;
|
||||
|
||||
case WasmOp_f64_const:
|
||||
value = read_u64_le(&mod_ptr[*code_i]);
|
||||
*code_i += sizeof(value);
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
|
||||
if (unreachable_depth == 0) {
|
||||
switch (value) {
|
||||
case 0: opcodes[pc->opcode] = Op_const_0_64; break;
|
||||
case 1: opcodes[pc->opcode] = Op_const_1_64; break;
|
||||
|
||||
default:
|
||||
opcodes[pc->opcode] = Op_const_64;
|
||||
operands[pc->operand + 0] = (uint32_t)(value >> 0);
|
||||
operands[pc->operand + 1] = (uint32_t)(value >> 32);
|
||||
pc->operand += 2;
|
||||
break;
|
||||
|
||||
case UINT64_MAX: opcodes[pc->opcode] = Op_const_umax_64; break;
|
||||
}
|
||||
pc->opcode += 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (unreachable_depth == 0) {
|
||||
switch (opcode) {
|
||||
case WasmOp_i32_eqz: opcodes[pc->opcode] = Op_eqz_32; break;
|
||||
case WasmOp_i32_eq: opcodes[pc->opcode] = Op_eq_32; break;
|
||||
case WasmOp_i32_ne: opcodes[pc->opcode] = Op_ne_32; break;
|
||||
case WasmOp_i32_lt_s: opcodes[pc->opcode] = Op_slt_32; break;
|
||||
case WasmOp_i32_lt_u: opcodes[pc->opcode] = Op_ult_32; break;
|
||||
case WasmOp_i32_gt_s: opcodes[pc->opcode] = Op_sgt_32; break;
|
||||
case WasmOp_i32_gt_u: opcodes[pc->opcode] = Op_ugt_32; break;
|
||||
case WasmOp_i32_le_s: opcodes[pc->opcode] = Op_sle_32; break;
|
||||
case WasmOp_i32_le_u: opcodes[pc->opcode] = Op_ule_32; break;
|
||||
case WasmOp_i32_ge_s: opcodes[pc->opcode] = Op_sge_32; break;
|
||||
case WasmOp_i32_ge_u: opcodes[pc->opcode] = Op_uge_32; break;
|
||||
case WasmOp_i64_eqz: opcodes[pc->opcode] = Op_eqz_64; break;
|
||||
case WasmOp_i64_eq: opcodes[pc->opcode] = Op_eq_64; break;
|
||||
case WasmOp_i64_ne: opcodes[pc->opcode] = Op_ne_64; break;
|
||||
case WasmOp_i64_lt_s: opcodes[pc->opcode] = Op_slt_64; break;
|
||||
case WasmOp_i64_lt_u: opcodes[pc->opcode] = Op_ult_64; break;
|
||||
case WasmOp_i64_gt_s: opcodes[pc->opcode] = Op_sgt_64; break;
|
||||
case WasmOp_i64_gt_u: opcodes[pc->opcode] = Op_ugt_64; break;
|
||||
case WasmOp_i64_le_s: opcodes[pc->opcode] = Op_sle_64; break;
|
||||
case WasmOp_i64_le_u: opcodes[pc->opcode] = Op_ule_64; break;
|
||||
case WasmOp_i64_ge_s: opcodes[pc->opcode] = Op_sge_64; break;
|
||||
case WasmOp_i64_ge_u: opcodes[pc->opcode] = Op_uge_64; break;
|
||||
case WasmOp_f32_eq: opcodes[pc->opcode] = Op_feq_32; break;
|
||||
case WasmOp_f32_ne: opcodes[pc->opcode] = Op_fne_32; break;
|
||||
case WasmOp_f32_lt: opcodes[pc->opcode] = Op_flt_32; break;
|
||||
case WasmOp_f32_gt: opcodes[pc->opcode] = Op_fgt_32; break;
|
||||
case WasmOp_f32_le: opcodes[pc->opcode] = Op_fle_32; break;
|
||||
case WasmOp_f32_ge: opcodes[pc->opcode] = Op_fge_32; break;
|
||||
case WasmOp_f64_eq: opcodes[pc->opcode] = Op_feq_64; break;
|
||||
case WasmOp_f64_ne: opcodes[pc->opcode] = Op_fne_64; break;
|
||||
case WasmOp_f64_lt: opcodes[pc->opcode] = Op_flt_64; break;
|
||||
case WasmOp_f64_gt: opcodes[pc->opcode] = Op_fgt_64; break;
|
||||
case WasmOp_f64_le: opcodes[pc->opcode] = Op_fle_64; break;
|
||||
case WasmOp_f64_ge: opcodes[pc->opcode] = Op_fge_64; break;
|
||||
case WasmOp_i32_clz: opcodes[pc->opcode] = Op_clz_32; break;
|
||||
case WasmOp_i32_ctz: opcodes[pc->opcode] = Op_ctz_32; break;
|
||||
case WasmOp_i32_popcnt: opcodes[pc->opcode] = Op_popcnt_32; break;
|
||||
case WasmOp_i32_add: opcodes[pc->opcode] = Op_add_32; break;
|
||||
case WasmOp_i32_sub: opcodes[pc->opcode] = Op_sub_32; break;
|
||||
case WasmOp_i32_mul: opcodes[pc->opcode] = Op_mul_32; break;
|
||||
case WasmOp_i32_div_s: opcodes[pc->opcode] = Op_sdiv_32; break;
|
||||
case WasmOp_i32_div_u: opcodes[pc->opcode] = Op_udiv_32; break;
|
||||
case WasmOp_i32_rem_s: opcodes[pc->opcode] = Op_srem_32; break;
|
||||
case WasmOp_i32_rem_u: opcodes[pc->opcode] = Op_urem_32; break;
|
||||
case WasmOp_i32_and: opcodes[pc->opcode] = Op_and_32; break;
|
||||
case WasmOp_i32_or: opcodes[pc->opcode] = Op_or_32; break;
|
||||
case WasmOp_i32_xor: opcodes[pc->opcode] = Op_xor_32; break;
|
||||
case WasmOp_i32_shl: opcodes[pc->opcode] = Op_shl_32; break;
|
||||
case WasmOp_i32_shr_s: opcodes[pc->opcode] = Op_ashr_32; break;
|
||||
case WasmOp_i32_shr_u: opcodes[pc->opcode] = Op_lshr_32; break;
|
||||
case WasmOp_i32_rotl: opcodes[pc->opcode] = Op_rol_32; break;
|
||||
case WasmOp_i32_rotr: opcodes[pc->opcode] = Op_ror_32; break;
|
||||
case WasmOp_i64_clz: opcodes[pc->opcode] = Op_clz_64; break;
|
||||
case WasmOp_i64_ctz: opcodes[pc->opcode] = Op_ctz_64; break;
|
||||
case WasmOp_i64_popcnt: opcodes[pc->opcode] = Op_popcnt_64; break;
|
||||
case WasmOp_i64_add: opcodes[pc->opcode] = Op_add_64; break;
|
||||
case WasmOp_i64_sub: opcodes[pc->opcode] = Op_sub_64; break;
|
||||
case WasmOp_i64_mul: opcodes[pc->opcode] = Op_mul_64; break;
|
||||
case WasmOp_i64_div_s: opcodes[pc->opcode] = Op_sdiv_64; break;
|
||||
case WasmOp_i64_div_u: opcodes[pc->opcode] = Op_udiv_64; break;
|
||||
case WasmOp_i64_rem_s: opcodes[pc->opcode] = Op_srem_64; break;
|
||||
case WasmOp_i64_rem_u: opcodes[pc->opcode] = Op_urem_64; break;
|
||||
case WasmOp_i64_and: opcodes[pc->opcode] = Op_and_64; break;
|
||||
case WasmOp_i64_or: opcodes[pc->opcode] = Op_or_64; break;
|
||||
case WasmOp_i64_xor: opcodes[pc->opcode] = Op_xor_64; break;
|
||||
case WasmOp_i64_shl: opcodes[pc->opcode] = Op_shl_64; break;
|
||||
case WasmOp_i64_shr_s: opcodes[pc->opcode] = Op_ashr_64; break;
|
||||
case WasmOp_i64_shr_u: opcodes[pc->opcode] = Op_lshr_64; break;
|
||||
case WasmOp_i64_rotl: opcodes[pc->opcode] = Op_rol_64; break;
|
||||
case WasmOp_i64_rotr: opcodes[pc->opcode] = Op_ror_64; break;
|
||||
case WasmOp_f32_abs: opcodes[pc->opcode] = Op_fabs_32; break;
|
||||
case WasmOp_f32_neg: opcodes[pc->opcode] = Op_fneg_32; break;
|
||||
case WasmOp_f32_ceil: opcodes[pc->opcode] = Op_ceil_32; break;
|
||||
case WasmOp_f32_floor: opcodes[pc->opcode] = Op_floor_32; break;
|
||||
case WasmOp_f32_trunc: opcodes[pc->opcode] = Op_trunc_32; break;
|
||||
case WasmOp_f32_nearest: opcodes[pc->opcode] = Op_nearest_32; break;
|
||||
case WasmOp_f32_sqrt: opcodes[pc->opcode] = Op_sqrt_32; break;
|
||||
case WasmOp_f32_add: opcodes[pc->opcode] = Op_fadd_32; break;
|
||||
case WasmOp_f32_sub: opcodes[pc->opcode] = Op_fsub_32; break;
|
||||
case WasmOp_f32_mul: opcodes[pc->opcode] = Op_fmul_32; break;
|
||||
case WasmOp_f32_div: opcodes[pc->opcode] = Op_fdiv_32; break;
|
||||
case WasmOp_f32_min: opcodes[pc->opcode] = Op_fmin_32; break;
|
||||
case WasmOp_f32_max: opcodes[pc->opcode] = Op_fmax_32; break;
|
||||
case WasmOp_f32_copysign: opcodes[pc->opcode] = Op_copysign_32; break;
|
||||
case WasmOp_f64_abs: opcodes[pc->opcode] = Op_fabs_64; break;
|
||||
case WasmOp_f64_neg: opcodes[pc->opcode] = Op_fneg_64; break;
|
||||
case WasmOp_f64_ceil: opcodes[pc->opcode] = Op_ceil_64; break;
|
||||
case WasmOp_f64_floor: opcodes[pc->opcode] = Op_floor_64; break;
|
||||
case WasmOp_f64_trunc: opcodes[pc->opcode] = Op_trunc_64; break;
|
||||
case WasmOp_f64_nearest: opcodes[pc->opcode] = Op_nearest_64; break;
|
||||
case WasmOp_f64_sqrt: opcodes[pc->opcode] = Op_sqrt_64; break;
|
||||
case WasmOp_f64_add: opcodes[pc->opcode] = Op_fadd_64; break;
|
||||
case WasmOp_f64_sub: opcodes[pc->opcode] = Op_fsub_64; break;
|
||||
case WasmOp_f64_mul: opcodes[pc->opcode] = Op_fmul_64; break;
|
||||
case WasmOp_f64_div: opcodes[pc->opcode] = Op_fdiv_64; break;
|
||||
case WasmOp_f64_min: opcodes[pc->opcode] = Op_fmin_64; break;
|
||||
case WasmOp_f64_max: opcodes[pc->opcode] = Op_fmax_64; break;
|
||||
case WasmOp_f64_copysign: opcodes[pc->opcode] = Op_copysign_64; break;
|
||||
case WasmOp_i32_wrap_i64: opcodes[pc->opcode] = Op_wrap_32_64; break;
|
||||
case WasmOp_i32_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_32_32; break;
|
||||
case WasmOp_i32_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_32_32; break;
|
||||
case WasmOp_i32_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_32_64; break;
|
||||
case WasmOp_i32_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_32_64; break;
|
||||
case WasmOp_i64_extend_i32_s: opcodes[pc->opcode] = Op_sext_64_32; break;
|
||||
case WasmOp_i64_extend_i32_u: opcodes[pc->opcode] = Op_zext_64_32; break;
|
||||
case WasmOp_i64_trunc_f32_s: opcodes[pc->opcode] = Op_ftos_64_32; break;
|
||||
case WasmOp_i64_trunc_f32_u: opcodes[pc->opcode] = Op_ftou_64_32; break;
|
||||
case WasmOp_i64_trunc_f64_s: opcodes[pc->opcode] = Op_ftos_64_64; break;
|
||||
case WasmOp_i64_trunc_f64_u: opcodes[pc->opcode] = Op_ftou_64_64; break;
|
||||
case WasmOp_f32_convert_i32_s: opcodes[pc->opcode] = Op_stof_32_32; break;
|
||||
case WasmOp_f32_convert_i32_u: opcodes[pc->opcode] = Op_utof_32_32; break;
|
||||
case WasmOp_f32_convert_i64_s: opcodes[pc->opcode] = Op_stof_32_64; break;
|
||||
case WasmOp_f32_convert_i64_u: opcodes[pc->opcode] = Op_utof_32_64; break;
|
||||
case WasmOp_f32_demote_f64: opcodes[pc->opcode] = Op_ftof_32_64; break;
|
||||
case WasmOp_f64_convert_i32_s: opcodes[pc->opcode] = Op_stof_64_32; break;
|
||||
case WasmOp_f64_convert_i32_u: opcodes[pc->opcode] = Op_utof_64_32; break;
|
||||
case WasmOp_f64_convert_i64_s: opcodes[pc->opcode] = Op_stof_64_64; break;
|
||||
case WasmOp_f64_convert_i64_u: opcodes[pc->opcode] = Op_utof_64_64; break;
|
||||
case WasmOp_f64_promote_f32: opcodes[pc->opcode] = Op_ftof_64_32; break;
|
||||
case WasmOp_i32_extend8_s: opcodes[pc->opcode] = Op_sext8_32; break;
|
||||
case WasmOp_i32_extend16_s: opcodes[pc->opcode] = Op_sext16_32; break;
|
||||
case WasmOp_i64_extend8_s: opcodes[pc->opcode] = Op_sext8_64; break;
|
||||
case WasmOp_i64_extend16_s: opcodes[pc->opcode] = Op_sext16_64; break;
|
||||
case WasmOp_i64_extend32_s: opcodes[pc->opcode] = Op_sext32_64; break;
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
pc->opcode += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmOp_prefixed:
|
||||
switch (prefixed_opcode) {
|
||||
case WasmPrefixedOp_memory_copy:
|
||||
if (mod_ptr[*code_i + 0] != 0 || mod_ptr[*code_i + 1] != 0)
|
||||
panic("unexpected memory index");
|
||||
*code_i += 2;
|
||||
if (unreachable_depth == 0) {
|
||||
opcodes[pc->opcode] = Op_memcpy;
|
||||
pc->opcode += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WasmPrefixedOp_memory_fill:
|
||||
if (mod_ptr[*code_i] != 0) panic("unexpected memory index");
|
||||
*code_i += 1;
|
||||
if (unreachable_depth == 0) {
|
||||
opcodes[pc->opcode] = Op_memset;
|
||||
pc->opcode += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default: panic("unexpected opcode");
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (opcode) {
|
||||
default: state = State_default; break;
|
||||
case WasmOp_i32_eqz: state = State_bool_not; break;
|
||||
}
|
||||
|
||||
//for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) {
|
||||
// fprintf(stderr, "decoded opcode[%u] = %u\n", i, opcodes[i]);
|
||||
//}
|
||||
//for (uint32_t i = old_pc.operand; i < pc->operand; i += 1) {
|
||||
// fprintf(stderr, "decoded operand[%u] = %u\n", i, operands[i]);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
static void vm_push_u32(struct VirtualMachine *vm, uint32_t value) {
|
||||
vm->stack[vm->stack_top + 0] = value;
|
||||
vm->stack_top += 1;
|
||||
}
|
||||
|
||||
static void vm_push_i32(struct VirtualMachine *vm, int32_t value) {
|
||||
vm_push_u32(vm, (uint32_t)value);
|
||||
}
|
||||
|
||||
static void vm_push_u64(struct VirtualMachine *vm, uint64_t value) {
|
||||
vm->stack[vm->stack_top + 0] = (uint32_t)(value >> 0);
|
||||
vm->stack[vm->stack_top + 1] = (uint32_t)(value >> 32);
|
||||
vm->stack_top += 2;
|
||||
}
|
||||
|
||||
static void vm_push_i64(struct VirtualMachine *vm, int64_t value) {
|
||||
vm_push_u64(vm, (uint64_t)value);
|
||||
}
|
||||
|
||||
static void vm_push_f32(struct VirtualMachine *vm, float value) {
|
||||
uint32_t integer;
|
||||
memcpy(&integer, &value, sizeof(integer));
|
||||
vm_push_u32(vm, integer);
|
||||
}
|
||||
|
||||
static void vm_push_f64(struct VirtualMachine *vm, double value) {
|
||||
uint64_t integer;
|
||||
memcpy(&integer, &value, sizeof(integer));
|
||||
vm_push_u64(vm, integer);
|
||||
}
|
||||
|
||||
static uint32_t vm_pop_u32(struct VirtualMachine *vm) {
|
||||
vm->stack_top -= 1;
|
||||
return vm->stack[vm->stack_top + 0];
|
||||
}
|
||||
|
||||
static int32_t vm_pop_i32(struct VirtualMachine *vm) {
|
||||
return (int32_t)vm_pop_u32(vm);
|
||||
}
|
||||
|
||||
static uint64_t vm_pop_u64(struct VirtualMachine *vm) {
|
||||
vm->stack_top -= 2;
|
||||
return vm->stack[vm->stack_top + 0] | (uint64_t)vm->stack[vm->stack_top + 1] << 32;
|
||||
}
|
||||
|
||||
static int64_t vm_pop_i64(struct VirtualMachine *vm) {
|
||||
return (int64_t)vm_pop_u64(vm);
|
||||
}
|
||||
|
||||
static float vm_pop_f32(struct VirtualMachine *vm) {
|
||||
uint32_t integer = vm_pop_u32(vm);
|
||||
float result;
|
||||
memcpy(&result, &integer, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static double vm_pop_f64(struct VirtualMachine *vm) {
|
||||
uint64_t integer = vm_pop_u64(vm);
|
||||
double result;
|
||||
memcpy(&result, &integer, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
static void vm_callImport(struct VirtualMachine *vm, const struct Import *import) {
|
||||
switch (import->mod) {
|
||||
case ImpMod_wasi_snapshot_preview1: switch (import->name) {
|
||||
case ImpName_fd_prestat_get:
|
||||
{
|
||||
uint32_t buf = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_prestat_get(vm, fd, buf));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_prestat_dir_name:
|
||||
{
|
||||
uint32_t path_len = vm_pop_u32(vm);
|
||||
uint32_t path = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_prestat_dir_name(vm, fd, path, path_len));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_close:
|
||||
{
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_close(vm, fd));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_read:
|
||||
{
|
||||
uint32_t nread = vm_pop_u32(vm);
|
||||
uint32_t iovs_len = vm_pop_u32(vm);
|
||||
uint32_t iovs = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_read(vm, fd, iovs, iovs_len, nread));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_filestat_get:
|
||||
{
|
||||
uint32_t buf = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_filestat_get(vm, fd, buf));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_filestat_set_size:
|
||||
{
|
||||
uint64_t size = vm_pop_u64(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_filestat_set_size(vm, fd, size));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_filestat_set_times:
|
||||
{
|
||||
panic("unexpected call to fd_filestat_set_times");
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_fdstat_get:
|
||||
{
|
||||
uint32_t buf = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_fdstat_get(vm, fd, buf));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_readdir:
|
||||
{
|
||||
panic("unexpected call to fd_readdir");
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_write:
|
||||
{
|
||||
uint32_t nwritten = vm_pop_u32(vm);
|
||||
uint32_t iovs_len = vm_pop_u32(vm);
|
||||
uint32_t iovs = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_write(vm, fd, iovs, iovs_len, nwritten));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_pwrite:
|
||||
{
|
||||
uint32_t nwritten = vm_pop_u32(vm);
|
||||
uint64_t offset = vm_pop_u64(vm);
|
||||
uint32_t iovs_len = vm_pop_u32(vm);
|
||||
uint32_t iovs = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_fd_pwrite(vm, fd, iovs, iovs_len, offset, nwritten));
|
||||
}
|
||||
break;
|
||||
case ImpName_proc_exit:
|
||||
{
|
||||
uint32_t code = vm_pop_u32(vm);
|
||||
exit(code);
|
||||
}
|
||||
break;
|
||||
case ImpName_args_sizes_get:
|
||||
{
|
||||
uint32_t argv_buf_size = vm_pop_u32(vm);
|
||||
uint32_t argc = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, wasi_args_sizes_get(vm, argc, argv_buf_size));
|
||||
}
|
||||
break;
|
||||
case ImpName_args_get:
|
||||
{
|
||||
uint32_t argv_buf = vm_pop_u32(vm);
|
||||
uint32_t argv = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, wasi_args_get(vm, argv, argv_buf));
|
||||
}
|
||||
break;
|
||||
case ImpName_random_get:
|
||||
{
|
||||
uint32_t buf_len = vm_pop_u32(vm);
|
||||
uint32_t buf = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, wasi_random_get(vm, buf, buf_len));
|
||||
}
|
||||
break;
|
||||
case ImpName_environ_sizes_get:
|
||||
{
|
||||
panic("unexpected call to environ_sizes_get");
|
||||
}
|
||||
break;
|
||||
case ImpName_environ_get:
|
||||
{
|
||||
panic("unexpected call to environ_get");
|
||||
}
|
||||
break;
|
||||
case ImpName_path_filestat_get:
|
||||
{
|
||||
uint32_t buf = vm_pop_u32(vm);
|
||||
uint32_t path_len = vm_pop_u32(vm);
|
||||
uint32_t path = vm_pop_u32(vm);
|
||||
uint32_t flags = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_path_filestat_get(vm, fd, flags, path, path_len, buf));
|
||||
}
|
||||
break;
|
||||
case ImpName_path_create_directory:
|
||||
{
|
||||
uint32_t path_len = vm_pop_u32(vm);
|
||||
uint32_t path = vm_pop_u32(vm);
|
||||
int32_t fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_path_create_directory(vm, fd, path, path_len));
|
||||
}
|
||||
break;
|
||||
case ImpName_path_rename:
|
||||
{
|
||||
uint32_t new_path_len = vm_pop_u32(vm);
|
||||
uint32_t new_path = vm_pop_u32(vm);
|
||||
int32_t new_fd = vm_pop_i32(vm);
|
||||
uint32_t old_path_len = vm_pop_u32(vm);
|
||||
uint32_t old_path = vm_pop_u32(vm);
|
||||
int32_t old_fd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_path_rename(
|
||||
vm,
|
||||
old_fd,
|
||||
old_path,
|
||||
old_path_len,
|
||||
new_fd,
|
||||
new_path,
|
||||
new_path_len
|
||||
));
|
||||
}
|
||||
break;
|
||||
case ImpName_path_open:
|
||||
{
|
||||
uint32_t fd = vm_pop_u32(vm);
|
||||
uint32_t fs_flags = vm_pop_u32(vm);
|
||||
uint64_t fs_rights_inheriting = vm_pop_u64(vm);
|
||||
uint64_t fs_rights_base = vm_pop_u64(vm);
|
||||
uint32_t oflags = vm_pop_u32(vm);
|
||||
uint32_t path_len = vm_pop_u32(vm);
|
||||
uint32_t path = vm_pop_u32(vm);
|
||||
uint32_t dirflags = vm_pop_u32(vm);
|
||||
int32_t dirfd = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, wasi_path_open(
|
||||
vm,
|
||||
dirfd,
|
||||
dirflags,
|
||||
path,
|
||||
path_len,
|
||||
oflags,
|
||||
fs_rights_base,
|
||||
fs_rights_inheriting,
|
||||
fs_flags,
|
||||
fd
|
||||
));
|
||||
}
|
||||
break;
|
||||
case ImpName_path_remove_directory:
|
||||
{
|
||||
panic("unexpected call to path_remove_directory");
|
||||
}
|
||||
break;
|
||||
case ImpName_path_unlink_file:
|
||||
{
|
||||
panic("unexpected call to path_unlink_file");
|
||||
}
|
||||
break;
|
||||
case ImpName_clock_time_get:
|
||||
{
|
||||
uint32_t timestamp = vm_pop_u32(vm);
|
||||
uint64_t precision = vm_pop_u64(vm);
|
||||
uint32_t clock_id = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, wasi_clock_time_get(vm, clock_id, precision, timestamp));
|
||||
}
|
||||
break;
|
||||
case ImpName_fd_pread:
|
||||
{
|
||||
panic("unexpected call to fd_pread");
|
||||
}
|
||||
break;
|
||||
case ImpName_debug:
|
||||
{
|
||||
uint64_t number = vm_pop_u64(vm);
|
||||
uint32_t text = vm_pop_u32(vm);
|
||||
wasi_debug(vm, text, number);
|
||||
}
|
||||
break;
|
||||
case ImpName_debug_slice:
|
||||
{
|
||||
uint32_t len = vm_pop_u32(vm);
|
||||
uint32_t ptr = vm_pop_u32(vm);
|
||||
wasi_debug_slice(vm, ptr, len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void vm_call(struct VirtualMachine *vm, const struct Function *func) {
|
||||
//struct TypeInfo *type_info = &vm->types[func->type_idx];
|
||||
//fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_size: %u\n",
|
||||
// func->id, type_info->param_count, type_info->result_count, func->locals_size);
|
||||
|
||||
// Push zeroed locals to stack
|
||||
memset(&vm->stack[vm->stack_top], 0, func->locals_size * sizeof(uint32_t));
|
||||
vm->stack_top += func->locals_size;
|
||||
|
||||
vm_push_u32(vm, vm->pc.opcode);
|
||||
vm_push_u32(vm, vm->pc.operand);
|
||||
|
||||
vm->pc = func->entry_pc;
|
||||
}
|
||||
|
||||
static void vm_br_void(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand];
|
||||
|
||||
vm->stack_top -= stack_adjust;
|
||||
|
||||
vm->pc.opcode = vm->operands[vm->pc.operand + 1];
|
||||
vm->pc.operand = vm->operands[vm->pc.operand + 2];
|
||||
}
|
||||
|
||||
static void vm_br_u32(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand];
|
||||
|
||||
uint32_t result = vm_pop_u32(vm);
|
||||
vm->stack_top -= stack_adjust;
|
||||
vm_push_u32(vm, result);
|
||||
|
||||
vm->pc.opcode = vm->operands[vm->pc.operand + 1];
|
||||
vm->pc.operand = vm->operands[vm->pc.operand + 2];
|
||||
}
|
||||
|
||||
static void vm_br_u64(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand];
|
||||
|
||||
uint64_t result = vm_pop_u64(vm);
|
||||
vm->stack_top -= stack_adjust;
|
||||
vm_push_u64(vm, result);
|
||||
|
||||
vm->pc.opcode = vm->operands[vm->pc.operand + 1];
|
||||
vm->pc.operand = vm->operands[vm->pc.operand + 2];
|
||||
}
|
||||
|
||||
static void vm_return_void(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
|
||||
uint32_t frame_size = vm->operands[vm->pc.operand + 1];
|
||||
|
||||
vm->stack_top -= stack_adjust;
|
||||
vm->pc.operand = vm_pop_u32(vm);
|
||||
vm->pc.opcode = vm_pop_u32(vm);
|
||||
|
||||
vm->stack_top -= frame_size;
|
||||
}
|
||||
|
||||
static void vm_return_u32(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
|
||||
uint32_t frame_size = vm->operands[vm->pc.operand + 1];
|
||||
|
||||
uint32_t result = vm_pop_u32(vm);
|
||||
|
||||
vm->stack_top -= stack_adjust;
|
||||
vm->pc.operand = vm_pop_u32(vm);
|
||||
vm->pc.opcode = vm_pop_u32(vm);
|
||||
|
||||
vm->stack_top -= frame_size;
|
||||
vm_push_u32(vm, result);
|
||||
}
|
||||
|
||||
static void vm_return_u64(struct VirtualMachine *vm) {
|
||||
uint32_t stack_adjust = vm->operands[vm->pc.operand + 0];
|
||||
uint32_t frame_size = vm->operands[vm->pc.operand + 1];
|
||||
|
||||
uint64_t result = vm_pop_u64(vm);
|
||||
|
||||
vm->stack_top -= stack_adjust;
|
||||
vm->pc.operand = vm_pop_u32(vm);
|
||||
vm->pc.opcode = vm_pop_u32(vm);
|
||||
|
||||
vm->stack_top -= frame_size;
|
||||
vm_push_u64(vm, result);
|
||||
}
|
||||
|
||||
static void vm_run(struct VirtualMachine *vm) {
|
||||
uint8_t *opcodes = vm->opcodes;
|
||||
uint32_t *operands = vm->operands;
|
||||
struct ProgramCounter *pc = &vm->pc;
|
||||
uint32_t global_0 = vm->globals[0];
|
||||
for (;;) {
|
||||
enum Op op = opcodes[pc->opcode];
|
||||
//fprintf(stderr, "stack[%u:%u]=%x:%x pc=%x:%x op=%u\n",
|
||||
// vm->stack_top - 2, vm->stack_top - 1,
|
||||
// vm->stack[vm->stack_top - 2], vm->stack[vm->stack_top - 1],
|
||||
// pc->opcode, pc->operand, op);
|
||||
pc->opcode += 1;
|
||||
switch (op) {
|
||||
case Op_unreachable:
|
||||
panic("unreachable reached");
|
||||
case Op_br_void:
|
||||
vm_br_void(vm);
|
||||
break;
|
||||
case Op_br_32:
|
||||
vm_br_u32(vm);
|
||||
break;
|
||||
case Op_br_64:
|
||||
vm_br_u64(vm);
|
||||
break;
|
||||
case Op_br_nez_void:
|
||||
if (vm_pop_u32(vm) != 0) {
|
||||
vm_br_void(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_nez_32:
|
||||
if (vm_pop_u32(vm) != 0) {
|
||||
vm_br_u32(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_nez_64:
|
||||
if (vm_pop_u32(vm) != 0) {
|
||||
vm_br_u64(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_eqz_void:
|
||||
if (vm_pop_u32(vm) == 0) {
|
||||
vm_br_void(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_eqz_32:
|
||||
if (vm_pop_u32(vm) == 0) {
|
||||
vm_br_u32(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_eqz_64:
|
||||
if (vm_pop_u32(vm) == 0) {
|
||||
vm_br_u64(vm);
|
||||
} else {
|
||||
pc->operand += 3;
|
||||
}
|
||||
break;
|
||||
case Op_br_table_void:
|
||||
{
|
||||
uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
|
||||
pc->operand += 1 + index * 3;
|
||||
vm_br_void(vm);
|
||||
}
|
||||
break;
|
||||
case Op_br_table_32:
|
||||
{
|
||||
uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
|
||||
pc->operand += 1 + index * 3;
|
||||
vm_br_u32(vm);
|
||||
}
|
||||
break;
|
||||
case Op_br_table_64:
|
||||
{
|
||||
uint32_t index = min_u32(vm_pop_u32(vm), operands[pc->operand]);
|
||||
pc->operand += 1 + index * 3;
|
||||
vm_br_u64(vm);
|
||||
}
|
||||
break;
|
||||
case Op_return_void:
|
||||
vm_return_void(vm);
|
||||
break;
|
||||
case Op_return_32:
|
||||
vm_return_u32(vm);
|
||||
break;
|
||||
case Op_return_64:
|
||||
vm_return_u64(vm);
|
||||
break;
|
||||
case Op_call_import:
|
||||
{
|
||||
uint8_t import_idx = opcodes[pc->opcode];
|
||||
pc->opcode += 1;
|
||||
vm_callImport(vm, &vm->imports[import_idx]);
|
||||
}
|
||||
break;
|
||||
case Op_call_func:
|
||||
{
|
||||
uint32_t func_idx = operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_call(vm, &vm->functions[func_idx]);
|
||||
}
|
||||
break;
|
||||
case Op_call_indirect:
|
||||
{
|
||||
uint32_t fn_id = vm->table[vm_pop_u32(vm)];
|
||||
if (fn_id < vm->imports_len)
|
||||
vm_callImport(vm, &vm->imports[fn_id]);
|
||||
else
|
||||
vm_call(vm, &vm->functions[fn_id - vm->imports_len]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_drop_32:
|
||||
vm->stack_top -= 1;
|
||||
break;
|
||||
case Op_drop_64:
|
||||
vm->stack_top -= 2;
|
||||
break;
|
||||
case Op_select_32:
|
||||
{
|
||||
uint32_t c = vm_pop_u32(vm);
|
||||
uint32_t b = vm_pop_u32(vm);
|
||||
uint32_t a = vm_pop_u32(vm);
|
||||
uint32_t result = (c != 0) ? a : b;
|
||||
vm_push_u32(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_select_64:
|
||||
{
|
||||
uint32_t c = vm_pop_u32(vm);
|
||||
uint64_t b = vm_pop_u64(vm);
|
||||
uint64_t a = vm_pop_u64(vm);
|
||||
uint64_t result = (c != 0) ? a : b;
|
||||
vm_push_u64(vm, result);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_local_get_32:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
vm_push_u32(vm, *local);
|
||||
}
|
||||
break;
|
||||
case Op_local_get_64:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
vm_push_u64(vm, local[0] | (uint64_t)local[1] << 32);
|
||||
}
|
||||
break;
|
||||
case Op_local_set_32:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
*local = vm_pop_u32(vm);
|
||||
}
|
||||
break;
|
||||
case Op_local_set_64:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
uint64_t value = vm_pop_u64(vm);
|
||||
local[0] = (uint32_t)(value >> 0);
|
||||
local[1] = (uint32_t)(value >> 32);
|
||||
}
|
||||
break;
|
||||
case Op_local_tee_32:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
*local = vm->stack[vm->stack_top - 1];
|
||||
}
|
||||
break;
|
||||
case Op_local_tee_64:
|
||||
{
|
||||
uint32_t *local = &vm->stack[vm->stack_top - operands[pc->operand]];
|
||||
pc->operand += 1;
|
||||
local[0] = vm->stack[vm->stack_top - 2];
|
||||
local[1] = vm->stack[vm->stack_top - 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_global_get_0_32:
|
||||
vm_push_u32(vm, global_0);
|
||||
break;
|
||||
case Op_global_get_32:
|
||||
{
|
||||
uint32_t idx = operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_u32(vm, vm->globals[idx]);
|
||||
}
|
||||
break;
|
||||
case Op_global_set_0_32:
|
||||
global_0 = vm_pop_u32(vm);
|
||||
break;
|
||||
case Op_global_set_32:
|
||||
{
|
||||
uint32_t idx = operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm->globals[idx] = vm_pop_u32(vm);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_load_0_8:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, (uint8_t)vm->memory[address]);
|
||||
}
|
||||
break;
|
||||
case Op_load_8:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_u32(vm, (uint8_t)vm->memory[address]);
|
||||
}
|
||||
break;
|
||||
case Op_load_0_16:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, read_u16_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_load_16:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_u32(vm, read_u16_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_load_0_32:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, read_u32_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_load_32:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_u32(vm, read_u32_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_load_0_64:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
vm_push_u64(vm, read_u64_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_load_64:
|
||||
{
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_u64(vm, read_u64_le(&vm->memory[address]));
|
||||
}
|
||||
break;
|
||||
case Op_store_0_8:
|
||||
{
|
||||
uint8_t value = (uint8_t)vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
vm->memory[address] = value;
|
||||
}
|
||||
break;
|
||||
case Op_store_8:
|
||||
{
|
||||
uint8_t value = (uint8_t)vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm->memory[address] = value;
|
||||
}
|
||||
break;
|
||||
case Op_store_0_16:
|
||||
{
|
||||
uint16_t value = (uint16_t)vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
write_u16_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_store_16:
|
||||
{
|
||||
uint16_t value = (uint16_t)vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
write_u16_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_store_0_32:
|
||||
{
|
||||
uint32_t value = vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
write_u32_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_store_32:
|
||||
{
|
||||
uint32_t value = vm_pop_u32(vm);
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
write_u32_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_store_0_64:
|
||||
{
|
||||
uint64_t value = vm_pop_u64(vm);
|
||||
uint32_t address = vm_pop_u32(vm);
|
||||
write_u64_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_store_64:
|
||||
{
|
||||
uint64_t value = vm_pop_u64(vm);
|
||||
uint32_t address = vm_pop_u32(vm) + operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
write_u64_le(&vm->memory[address], value);
|
||||
}
|
||||
break;
|
||||
case Op_mem_size:
|
||||
vm_push_u32(vm, vm->memory_len / wasm_page_size);
|
||||
break;
|
||||
case Op_mem_grow:
|
||||
{
|
||||
uint32_t page_count = vm_pop_u32(vm);
|
||||
uint32_t old_page_count = vm->memory_len / wasm_page_size;
|
||||
uint32_t new_len = vm->memory_len + page_count * wasm_page_size;
|
||||
if (new_len > max_memory) {
|
||||
vm_push_i32(vm, -1);
|
||||
} else {
|
||||
vm->memory_len = new_len;
|
||||
vm_push_u32(vm, old_page_count);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_const_0_32:
|
||||
vm_push_i32(vm, 0);
|
||||
break;
|
||||
case Op_const_0_64:
|
||||
vm_push_i64(vm, 0);
|
||||
break;
|
||||
case Op_const_1_32:
|
||||
vm_push_i32(vm, 1);
|
||||
break;
|
||||
case Op_const_1_64:
|
||||
vm_push_i64(vm, 1);
|
||||
break;
|
||||
case Op_const_32:
|
||||
{
|
||||
uint32_t value = operands[pc->operand];
|
||||
pc->operand += 1;
|
||||
vm_push_i32(vm, value);
|
||||
}
|
||||
break;
|
||||
case Op_const_64:
|
||||
{
|
||||
uint64_t value = ((uint64_t)operands[pc->operand]) |
|
||||
(((uint64_t)operands[pc->operand + 1]) << 32);
|
||||
pc->operand += 2;
|
||||
vm_push_i64(vm, value);
|
||||
}
|
||||
break;
|
||||
case Op_const_umax_32:
|
||||
vm_push_i32(vm, -1);
|
||||
break;
|
||||
case Op_const_umax_64:
|
||||
vm_push_i64(vm, -1);
|
||||
break;
|
||||
|
||||
case Op_eqz_32:
|
||||
{
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs == 0);
|
||||
}
|
||||
break;
|
||||
case Op_eq_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs == rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ne_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs != rhs);
|
||||
}
|
||||
break;
|
||||
case Op_slt_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, lhs < rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ult_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs < rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sgt_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ugt_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sle_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ule_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sge_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_uge_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_eqz_64:
|
||||
{
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs == 0);
|
||||
}
|
||||
break;
|
||||
case Op_eq_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs == rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ne_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs != rhs);
|
||||
}
|
||||
break;
|
||||
case Op_slt_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_u32(vm, lhs < rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ult_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs < rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sgt_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ugt_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sle_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_ule_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sge_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_uge_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_feq_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs == rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fne_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs != rhs);
|
||||
}
|
||||
break;
|
||||
case Op_flt_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs < rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fgt_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fle_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fge_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_feq_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs == rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fne_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs != rhs);
|
||||
}
|
||||
break;
|
||||
case Op_flt_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fgt_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs > rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fle_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs <= rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fge_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_u32(vm, lhs >= rhs);
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_clz_32:
|
||||
{
|
||||
uint32_t operand = vm_pop_u32(vm);
|
||||
uint32_t result = (operand == 0) ? 32 : __builtin_clz(operand);
|
||||
vm_push_u32(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_ctz_32:
|
||||
{
|
||||
uint32_t operand = vm_pop_u32(vm);
|
||||
uint32_t result = (operand == 0) ? 32 : __builtin_ctz(operand);
|
||||
vm_push_u32(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_popcnt_32:
|
||||
{
|
||||
uint32_t operand = vm_pop_u32(vm);
|
||||
uint32_t result = __builtin_popcount(operand);
|
||||
vm_push_u32(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_add_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs + rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sub_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs - rhs);
|
||||
}
|
||||
break;
|
||||
case Op_mul_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs * rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sdiv_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_i32(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_udiv_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_srem_32:
|
||||
{
|
||||
int32_t rhs = vm_pop_i32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_i32(vm, lhs % rhs);
|
||||
}
|
||||
break;
|
||||
case Op_urem_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs % rhs);
|
||||
}
|
||||
break;
|
||||
case Op_and_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs & rhs);
|
||||
}
|
||||
break;
|
||||
case Op_or_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs | rhs);
|
||||
}
|
||||
break;
|
||||
case Op_xor_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs ^ rhs);
|
||||
}
|
||||
break;
|
||||
case Op_shl_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs << (rhs & 0x1f));
|
||||
}
|
||||
break;
|
||||
case Op_ashr_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
int32_t lhs = vm_pop_i32(vm);
|
||||
vm_push_i32(vm, lhs >> (rhs & 0x1f));
|
||||
}
|
||||
break;
|
||||
case Op_lshr_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, lhs >> (rhs & 0x1f));
|
||||
}
|
||||
break;
|
||||
case Op_rol_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, rotl32(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_ror_32:
|
||||
{
|
||||
uint32_t rhs = vm_pop_u32(vm);
|
||||
uint32_t lhs = vm_pop_u32(vm);
|
||||
vm_push_u32(vm, rotr32(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_clz_64:
|
||||
{
|
||||
uint64_t operand = vm_pop_u64(vm);
|
||||
uint64_t result = (operand == 0) ? 64 : __builtin_clzll(operand);
|
||||
vm_push_u64(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_ctz_64:
|
||||
{
|
||||
uint64_t operand = vm_pop_u64(vm);
|
||||
uint64_t result = (operand == 0) ? 64 : __builtin_ctzll(operand);
|
||||
vm_push_u64(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_popcnt_64:
|
||||
{
|
||||
uint64_t operand = vm_pop_u64(vm);
|
||||
uint64_t result = __builtin_popcountll(operand);
|
||||
vm_push_u64(vm, result);
|
||||
}
|
||||
break;
|
||||
case Op_add_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs + rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sub_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs - rhs);
|
||||
}
|
||||
break;
|
||||
case Op_mul_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs * rhs);
|
||||
}
|
||||
break;
|
||||
case Op_sdiv_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_i64(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_udiv_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_srem_64:
|
||||
{
|
||||
int64_t rhs = vm_pop_i64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_i64(vm, lhs % rhs);
|
||||
}
|
||||
break;
|
||||
case Op_urem_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs % rhs);
|
||||
}
|
||||
break;
|
||||
case Op_and_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs & rhs);
|
||||
}
|
||||
break;
|
||||
case Op_or_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs | rhs);
|
||||
}
|
||||
break;
|
||||
case Op_xor_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs ^ rhs);
|
||||
}
|
||||
break;
|
||||
case Op_shl_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs << (rhs & 0x3f));
|
||||
}
|
||||
break;
|
||||
case Op_ashr_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
int64_t lhs = vm_pop_i64(vm);
|
||||
vm_push_i64(vm, lhs >> (rhs & 0x3f));
|
||||
}
|
||||
break;
|
||||
case Op_lshr_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, lhs >> (rhs & 0x3f));
|
||||
}
|
||||
break;
|
||||
case Op_rol_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, rotl64(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_ror_64:
|
||||
{
|
||||
uint64_t rhs = vm_pop_u64(vm);
|
||||
uint64_t lhs = vm_pop_u64(vm);
|
||||
vm_push_u64(vm, rotr64(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_fabs_32:
|
||||
vm_push_f32(vm, fabsf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_fneg_32:
|
||||
vm_push_f32(vm, -vm_pop_f32(vm));
|
||||
break;
|
||||
case Op_ceil_32:
|
||||
vm_push_f32(vm, ceilf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_floor_32:
|
||||
vm_push_f32(vm, floorf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_trunc_32:
|
||||
vm_push_f32(vm, truncf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_nearest_32:
|
||||
vm_push_f32(vm, roundf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_sqrt_32:
|
||||
vm_push_f32(vm, sqrtf(vm_pop_f32(vm)));
|
||||
break;
|
||||
case Op_fadd_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, lhs + rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fsub_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, lhs - rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fmul_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, lhs * rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fdiv_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fmin_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, fminf(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_fmax_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, fmaxf(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_copysign_32:
|
||||
{
|
||||
float rhs = vm_pop_f32(vm);
|
||||
float lhs = vm_pop_f32(vm);
|
||||
vm_push_f32(vm, copysignf(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_fabs_64:
|
||||
vm_push_f64(vm, fabs(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_fneg_64:
|
||||
vm_push_f64(vm, -vm_pop_f64(vm));
|
||||
break;
|
||||
case Op_ceil_64:
|
||||
vm_push_f64(vm, ceil(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_floor_64:
|
||||
vm_push_f64(vm, floor(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_trunc_64:
|
||||
vm_push_f64(vm, trunc(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_nearest_64:
|
||||
vm_push_f64(vm, round(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_sqrt_64:
|
||||
vm_push_f64(vm, sqrt(vm_pop_f64(vm)));
|
||||
break;
|
||||
case Op_fadd_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, lhs + rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fsub_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, lhs - rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fmul_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, lhs * rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fdiv_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, lhs / rhs);
|
||||
}
|
||||
break;
|
||||
case Op_fmin_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, fmin(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_fmax_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, fmax(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
case Op_copysign_64:
|
||||
{
|
||||
double rhs = vm_pop_f64(vm);
|
||||
double lhs = vm_pop_f64(vm);
|
||||
vm_push_f64(vm, copysign(lhs, rhs));
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_ftos_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break;
|
||||
case Op_ftou_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break;
|
||||
case Op_ftos_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break;
|
||||
case Op_ftou_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break;
|
||||
case Op_sext_64_32: vm_push_i64(vm, vm_pop_i32(vm)); break;
|
||||
case Op_ftos_64_32: vm_push_i64(vm, (int64_t)vm_pop_f32(vm)); break;
|
||||
case Op_ftou_64_32: vm_push_u64(vm, (uint64_t)vm_pop_f32(vm)); break;
|
||||
case Op_ftos_64_64: vm_push_i64(vm, (int64_t)vm_pop_f64(vm)); break;
|
||||
case Op_ftou_64_64: vm_push_u64(vm, (uint64_t)vm_pop_f64(vm)); break;
|
||||
case Op_stof_32_32: vm_push_f32(vm, (float)vm_pop_i32(vm)); break;
|
||||
case Op_utof_32_32: vm_push_f32(vm, (float)vm_pop_u32(vm)); break;
|
||||
case Op_stof_32_64: vm_push_f32(vm, (float)vm_pop_i64(vm)); break;
|
||||
case Op_utof_32_64: vm_push_f32(vm, (float)vm_pop_u64(vm)); break;
|
||||
case Op_ftof_32_64: vm_push_f32(vm, (float)vm_pop_f64(vm)); break;
|
||||
case Op_stof_64_32: vm_push_f64(vm, (double)vm_pop_i32(vm)); break;
|
||||
case Op_utof_64_32: vm_push_f64(vm, (double)vm_pop_u32(vm)); break;
|
||||
case Op_stof_64_64: vm_push_f64(vm, (double)vm_pop_i64(vm)); break;
|
||||
case Op_utof_64_64: vm_push_f64(vm, (double)vm_pop_u64(vm)); break;
|
||||
case Op_ftof_64_32: vm_push_f64(vm, (double)vm_pop_f32(vm)); break;
|
||||
case Op_sext8_32: vm_push_i32(vm, (int8_t)vm_pop_i32(vm)); break;
|
||||
case Op_sext16_32: vm_push_i32(vm, (int16_t)vm_pop_i32(vm)); break;
|
||||
case Op_sext8_64: vm_push_i64(vm, (int8_t)vm_pop_i64(vm)); break;
|
||||
case Op_sext16_64: vm_push_i64(vm, (int16_t)vm_pop_i64(vm)); break;
|
||||
case Op_sext32_64: vm_push_i64(vm, (int32_t)vm_pop_i64(vm)); break;
|
||||
|
||||
case Op_memcpy:
|
||||
{
|
||||
uint32_t n = vm_pop_u32(vm);
|
||||
uint32_t src = vm_pop_u32(vm);
|
||||
uint32_t dest = vm_pop_u32(vm);
|
||||
assert(dest + n <= vm->memory_len);
|
||||
assert(src + n <= vm->memory_len);
|
||||
assert(src + n <= dest || dest + n <= src); // overlapping
|
||||
memcpy(vm->memory + dest, vm->memory + src, n);
|
||||
}
|
||||
break;
|
||||
case Op_memset:
|
||||
{
|
||||
uint32_t n = vm_pop_u32(vm);
|
||||
uint8_t value = (uint8_t)vm_pop_u32(vm);
|
||||
uint32_t dest = vm_pop_u32(vm);
|
||||
assert(dest + n <= vm->memory_len);
|
||||
memset(vm->memory + dest, value, n);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static size_t common_prefix(const char *a, const char *b) {
|
||||
size_t i = 0;
|
||||
for (; a[i] == b[i]; i += 1) {}
|
||||
return i;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
|
||||
const char *zig_lib_dir_path = argv[1];
|
||||
const char *cmake_binary_dir_path = argv[2];
|
||||
const char *root_name = argv[3];
|
||||
size_t argv_i = 4;
|
||||
const char *wasm_file = argv[argv_i];
|
||||
|
||||
size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path);
|
||||
const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len;
|
||||
|
||||
size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path);
|
||||
|
||||
const char *new_argv[30];
|
||||
char new_argv_buf[PATH_MAX + 1024];
|
||||
uint32_t new_argv_i = 0;
|
||||
uint32_t new_argv_buf_i = 0;
|
||||
|
||||
int cache_dir = -1;
|
||||
{
|
||||
char cache_dir_buf[PATH_MAX * 2];
|
||||
size_t i = 0;
|
||||
size_t cmake_binary_dir_path_len = strlen(cmake_binary_dir_path);
|
||||
|
||||
memcpy(cache_dir_buf + i, cmake_binary_dir_path, cmake_binary_dir_path_len);
|
||||
i += cmake_binary_dir_path_len;
|
||||
|
||||
cache_dir_buf[i] = '/';
|
||||
i += 1;
|
||||
|
||||
memcpy(cache_dir_buf + i, "zig1-cache", strlen("zig1-cache"));
|
||||
i += strlen("zig1-cache");
|
||||
|
||||
cache_dir_buf[i] = 0;
|
||||
|
||||
mkdir(cache_dir_buf, 0777);
|
||||
cache_dir = err_wrap("opening cache dir",
|
||||
open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC));
|
||||
}
|
||||
|
||||
// Construct a new argv for the WASI code which has absolute paths
|
||||
// converted to relative paths, and has the target and terminal status
|
||||
// autodetected.
|
||||
|
||||
// wasm file path
|
||||
new_argv[new_argv_i] = argv[argv_i];
|
||||
new_argv_i += 1;
|
||||
argv_i += 1;
|
||||
|
||||
for (; argv[argv_i]; argv_i += 1) {
|
||||
new_argv[new_argv_i] = argv[argv_i];
|
||||
new_argv_i += 1;
|
||||
}
|
||||
|
||||
{
|
||||
new_argv[new_argv_i] = "--name";
|
||||
new_argv_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = root_name;
|
||||
new_argv_i += 1;
|
||||
|
||||
char *emit_bin_arg = new_argv_buf + new_argv_buf_i;
|
||||
memcpy(new_argv_buf + new_argv_buf_i, "-femit-bin=", strlen("-femit-bin="));
|
||||
new_argv_buf_i += strlen("-femit-bin=");
|
||||
memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
|
||||
new_argv_buf_i += rel_cmake_bin_path_len;
|
||||
new_argv_buf[new_argv_buf_i] = '/';
|
||||
new_argv_buf_i += 1;
|
||||
memcpy(new_argv_buf + new_argv_buf_i, root_name, strlen(root_name));
|
||||
new_argv_buf_i += strlen(root_name);
|
||||
memcpy(new_argv_buf + new_argv_buf_i, ".c", 3);
|
||||
new_argv_buf_i += 3;
|
||||
|
||||
new_argv[new_argv_i] = emit_bin_arg;
|
||||
new_argv_i += 1;
|
||||
}
|
||||
|
||||
{
|
||||
new_argv[new_argv_i] = "--pkg-begin";
|
||||
new_argv_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = "build_options";
|
||||
new_argv_i += 1;
|
||||
|
||||
char *build_options_path = new_argv_buf + new_argv_buf_i;
|
||||
memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
|
||||
new_argv_buf_i += rel_cmake_bin_path_len;
|
||||
new_argv_buf[new_argv_buf_i] = '/';
|
||||
new_argv_buf_i += 1;
|
||||
memcpy(new_argv_buf + new_argv_buf_i, "config.zig", strlen("config.zig"));
|
||||
new_argv_buf_i += strlen("config.zig");
|
||||
new_argv_buf[new_argv_buf_i] = 0;
|
||||
new_argv_buf_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = build_options_path;
|
||||
new_argv_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = "--pkg-end";
|
||||
new_argv_i += 1;
|
||||
}
|
||||
|
||||
{
|
||||
new_argv[new_argv_i] = "-target";
|
||||
new_argv_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = ZIG_TRIPLE_ARCH "-" ZIG_TRIPLE_OS;
|
||||
new_argv_i += 1;
|
||||
}
|
||||
|
||||
if (isatty(STDERR_FILENO) != 0) {
|
||||
new_argv[new_argv_i] = "--color";
|
||||
new_argv_i += 1;
|
||||
|
||||
new_argv[new_argv_i] = "on";
|
||||
new_argv_i += 1;
|
||||
}
|
||||
|
||||
new_argv[new_argv_i] = NULL;
|
||||
|
||||
const struct ByteSlice compressed_bytes = read_file_alloc(wasm_file);
|
||||
|
||||
const size_t max_uncompressed_size = 2500000;
|
||||
char *mod_ptr = arena_alloc(max_uncompressed_size);
|
||||
size_t mod_len = ZSTD_decompress(mod_ptr, max_uncompressed_size,
|
||||
compressed_bytes.ptr, compressed_bytes.len);
|
||||
|
||||
int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC));
|
||||
int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC));
|
||||
|
||||
add_preopen(0, "stdin", STDIN_FILENO);
|
||||
add_preopen(1, "stdout", STDOUT_FILENO);
|
||||
add_preopen(2, "stderr", STDERR_FILENO);
|
||||
add_preopen(3, ".", cwd);
|
||||
add_preopen(4, "/cache", cache_dir);
|
||||
add_preopen(5, "/lib", zig_lib_dir);
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
if (mod_ptr[0] != 0 || mod_ptr[1] != 'a' || mod_ptr[2] != 's' || mod_ptr[3] != 'm') {
|
||||
panic("bad magic");
|
||||
}
|
||||
i += 4;
|
||||
|
||||
uint32_t version = read_u32_le(mod_ptr + i);
|
||||
i += 4;
|
||||
if (version != 1) panic("bad wasm version");
|
||||
|
||||
uint32_t section_starts[13];
|
||||
memset(§ion_starts, 0, sizeof(uint32_t) * 13);
|
||||
|
||||
while (i < mod_len) {
|
||||
uint8_t section_id = mod_ptr[i];
|
||||
i += 1;
|
||||
uint32_t section_len = read32_uleb128(mod_ptr, &i);
|
||||
section_starts[section_id] = i;
|
||||
i += section_len;
|
||||
}
|
||||
|
||||
// Map type indexes to offsets into the module.
|
||||
struct TypeInfo *types;
|
||||
{
|
||||
i = section_starts[Section_type];
|
||||
uint32_t types_len = read32_uleb128(mod_ptr, &i);
|
||||
types = arena_alloc(sizeof(struct TypeInfo) * types_len);
|
||||
for (size_t type_i = 0; type_i < types_len; type_i += 1) {
|
||||
struct TypeInfo *info = &types[type_i];
|
||||
if (mod_ptr[i] != 0x60) panic("bad type byte");
|
||||
i += 1;
|
||||
|
||||
info->param_count = read32_uleb128(mod_ptr, &i);
|
||||
if (info->param_count > 32) panic("found a type with over 32 parameters");
|
||||
info->param_types = 0;
|
||||
for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) {
|
||||
int64_t param_type = read64_ileb128(mod_ptr, &i);
|
||||
switch (param_type) {
|
||||
case -1: case -3: bs_unset(&info->param_types, param_i); break;
|
||||
case -2: case -4: bs_set(&info->param_types, param_i); break;
|
||||
default: panic("unexpected param type");
|
||||
}
|
||||
}
|
||||
|
||||
info->result_count = read32_uleb128(mod_ptr, &i);
|
||||
info->result_types = 0;
|
||||
for (uint32_t result_i = 0; result_i < info->result_count; result_i += 1) {
|
||||
int64_t result_type = read64_ileb128(mod_ptr, &i);
|
||||
switch (result_type) {
|
||||
case -1: case -3: bs_unset(&info->result_types, result_i); break;
|
||||
case -2: case -4: bs_set(&info->result_types, result_i); break;
|
||||
default: panic("unexpected result type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Count the imported functions so we can correct function references.
|
||||
struct Import *imports;
|
||||
uint32_t imports_len;
|
||||
{
|
||||
i = section_starts[Section_import];
|
||||
imports_len = read32_uleb128(mod_ptr, &i);
|
||||
imports = arena_alloc(sizeof(struct Import) * imports_len);
|
||||
for (size_t imp_i = 0; imp_i < imports_len; imp_i += 1) {
|
||||
struct Import *imp = &imports[imp_i];
|
||||
|
||||
struct ByteSlice mod_name = read_name(mod_ptr, &i);
|
||||
if (mod_name.len == strlen("wasi_snapshot_preview1") &&
|
||||
memcmp(mod_name.ptr, "wasi_snapshot_preview1", mod_name.len) == 0) {
|
||||
imp->mod = ImpMod_wasi_snapshot_preview1;
|
||||
} else panic("unknown import module");
|
||||
|
||||
struct ByteSlice sym_name = read_name(mod_ptr, &i);
|
||||
if (sym_name.len == strlen("args_get") &&
|
||||
memcmp(sym_name.ptr, "args_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_args_get;
|
||||
} else if (sym_name.len == strlen("args_sizes_get") &&
|
||||
memcmp(sym_name.ptr, "args_sizes_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_args_sizes_get;
|
||||
} else if (sym_name.len == strlen("clock_time_get") &&
|
||||
memcmp(sym_name.ptr, "clock_time_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_clock_time_get;
|
||||
} else if (sym_name.len == strlen("debug") &&
|
||||
memcmp(sym_name.ptr, "debug", sym_name.len) == 0) {
|
||||
imp->name = ImpName_debug;
|
||||
} else if (sym_name.len == strlen("debug_slice") &&
|
||||
memcmp(sym_name.ptr, "debug_slice", sym_name.len) == 0) {
|
||||
imp->name = ImpName_debug_slice;
|
||||
} else if (sym_name.len == strlen("environ_get") &&
|
||||
memcmp(sym_name.ptr, "environ_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_environ_get;
|
||||
} else if (sym_name.len == strlen("environ_sizes_get") &&
|
||||
memcmp(sym_name.ptr, "environ_sizes_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_environ_sizes_get;
|
||||
} else if (sym_name.len == strlen("fd_close") &&
|
||||
memcmp(sym_name.ptr, "fd_close", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_close;
|
||||
} else if (sym_name.len == strlen("fd_fdstat_get") &&
|
||||
memcmp(sym_name.ptr, "fd_fdstat_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_fdstat_get;
|
||||
} else if (sym_name.len == strlen("fd_filestat_get") &&
|
||||
memcmp(sym_name.ptr, "fd_filestat_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_filestat_get;
|
||||
} else if (sym_name.len == strlen("fd_filestat_set_size") &&
|
||||
memcmp(sym_name.ptr, "fd_filestat_set_size", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_filestat_set_size;
|
||||
} else if (sym_name.len == strlen("fd_filestat_set_times") &&
|
||||
memcmp(sym_name.ptr, "fd_filestat_set_times", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_filestat_set_times;
|
||||
} else if (sym_name.len == strlen("fd_pread") &&
|
||||
memcmp(sym_name.ptr, "fd_pread", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_pread;
|
||||
} else if (sym_name.len == strlen("fd_prestat_dir_name") &&
|
||||
memcmp(sym_name.ptr, "fd_prestat_dir_name", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_prestat_dir_name;
|
||||
} else if (sym_name.len == strlen("fd_prestat_get") &&
|
||||
memcmp(sym_name.ptr, "fd_prestat_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_prestat_get;
|
||||
} else if (sym_name.len == strlen("fd_pwrite") &&
|
||||
memcmp(sym_name.ptr, "fd_pwrite", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_pwrite;
|
||||
} else if (sym_name.len == strlen("fd_read") &&
|
||||
memcmp(sym_name.ptr, "fd_read", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_read;
|
||||
} else if (sym_name.len == strlen("fd_readdir") &&
|
||||
memcmp(sym_name.ptr, "fd_readdir", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_readdir;
|
||||
} else if (sym_name.len == strlen("fd_write") &&
|
||||
memcmp(sym_name.ptr, "fd_write", sym_name.len) == 0) {
|
||||
imp->name = ImpName_fd_write;
|
||||
} else if (sym_name.len == strlen("path_create_directory") &&
|
||||
memcmp(sym_name.ptr, "path_create_directory", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_create_directory;
|
||||
} else if (sym_name.len == strlen("path_filestat_get") &&
|
||||
memcmp(sym_name.ptr, "path_filestat_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_filestat_get;
|
||||
} else if (sym_name.len == strlen("path_open") &&
|
||||
memcmp(sym_name.ptr, "path_open", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_open;
|
||||
} else if (sym_name.len == strlen("path_remove_directory") &&
|
||||
memcmp(sym_name.ptr, "path_remove_directory", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_remove_directory;
|
||||
} else if (sym_name.len == strlen("path_rename") &&
|
||||
memcmp(sym_name.ptr, "path_rename", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_rename;
|
||||
} else if (sym_name.len == strlen("path_unlink_file") &&
|
||||
memcmp(sym_name.ptr, "path_unlink_file", sym_name.len) == 0) {
|
||||
imp->name = ImpName_path_unlink_file;
|
||||
} else if (sym_name.len == strlen("proc_exit") &&
|
||||
memcmp(sym_name.ptr, "proc_exit", sym_name.len) == 0) {
|
||||
imp->name = ImpName_proc_exit;
|
||||
} else if (sym_name.len == strlen("random_get") &&
|
||||
memcmp(sym_name.ptr, "random_get", sym_name.len) == 0) {
|
||||
imp->name = ImpName_random_get;
|
||||
} else panic("unknown import name");
|
||||
|
||||
uint32_t desc = read32_uleb128(mod_ptr, &i);
|
||||
if (desc != 0) panic("external kind not function");
|
||||
imp->type_idx = read32_uleb128(mod_ptr, &i);
|
||||
}
|
||||
}
|
||||
|
||||
// Find _start in the exports
|
||||
uint32_t start_fn_idx;
|
||||
{
|
||||
i = section_starts[Section_export];
|
||||
uint32_t count = read32_uleb128(mod_ptr, &i);
|
||||
for (; count > 0; count -= 1) {
|
||||
struct ByteSlice name = read_name(mod_ptr, &i);
|
||||
uint32_t desc = read32_uleb128(mod_ptr, &i);
|
||||
start_fn_idx = read32_uleb128(mod_ptr, &i);
|
||||
if (desc == 0 && name.len == strlen("_start") &&
|
||||
memcmp(name.ptr, "_start", name.len) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count == 0) panic("_start symbol not found");
|
||||
}
|
||||
|
||||
// Map function indexes to offsets into the module and type index.
|
||||
struct Function *functions;
|
||||
uint32_t functions_len;
|
||||
{
|
||||
i = section_starts[Section_function];
|
||||
functions_len = read32_uleb128(mod_ptr, &i);
|
||||
functions = arena_alloc(sizeof(struct Function) * functions_len);
|
||||
for (size_t func_i = 0; func_i < functions_len; func_i += 1) {
|
||||
struct Function *func = &functions[func_i];
|
||||
func->id = imports_len + func_i;
|
||||
func->type_idx = read32_uleb128(mod_ptr, &i);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate and initialize globals.
|
||||
uint64_t *globals;
|
||||
{
|
||||
i = section_starts[Section_global];
|
||||
uint32_t globals_len = read32_uleb128(mod_ptr, &i);
|
||||
globals = arena_alloc(sizeof(uint64_t) * globals_len);
|
||||
for (size_t glob_i = 0; glob_i < globals_len; glob_i += 1) {
|
||||
uint64_t *global = &globals[glob_i];
|
||||
uint32_t content_type = read32_uleb128(mod_ptr, &i);
|
||||
uint32_t mutability = read32_uleb128(mod_ptr, &i);
|
||||
if (mutability != 1) panic("expected mutable global");
|
||||
if (content_type != 0x7f) panic("unexpected content type");
|
||||
uint8_t opcode = mod_ptr[i];
|
||||
i += 1;
|
||||
if (opcode != WasmOp_i32_const) panic("expected i32_const op");
|
||||
uint32_t init = read32_ileb128(mod_ptr, &i);
|
||||
*global = (uint32_t)init;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate and initialize memory.
|
||||
uint32_t memory_len;
|
||||
{
|
||||
i = section_starts[Section_memory];
|
||||
uint32_t memories_len = read32_uleb128(mod_ptr, &i);
|
||||
if (memories_len != 1) panic("unexpected memory count");
|
||||
uint32_t flags = read32_uleb128(mod_ptr, &i);
|
||||
(void)flags;
|
||||
memory_len = read32_uleb128(mod_ptr, &i) * wasm_page_size;
|
||||
|
||||
i = section_starts[Section_data];
|
||||
uint32_t datas_count = read32_uleb128(mod_ptr, &i);
|
||||
for (; datas_count > 0; datas_count -= 1) {
|
||||
uint32_t mode = read32_uleb128(mod_ptr, &i);
|
||||
if (mode != 0) panic("expected mode 0");
|
||||
enum WasmOp opcode = mod_ptr[i];
|
||||
i += 1;
|
||||
if (opcode != WasmOp_i32_const) panic("expected opcode i32_const");
|
||||
uint32_t offset = read32_uleb128(mod_ptr, &i);
|
||||
enum WasmOp end = mod_ptr[i];
|
||||
if (end != WasmOp_end) panic("expected end opcode");
|
||||
i += 1;
|
||||
uint32_t bytes_len = read32_uleb128(mod_ptr, &i);
|
||||
memcpy(memory + offset, mod_ptr + i, bytes_len);
|
||||
i += bytes_len;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *table = NULL;
|
||||
{
|
||||
i = section_starts[Section_table];
|
||||
uint32_t table_count = read32_uleb128(mod_ptr, &i);
|
||||
if (table_count > 1) {
|
||||
panic("expected only one table section");
|
||||
} else if (table_count == 1) {
|
||||
uint32_t element_type = read32_uleb128(mod_ptr, &i);
|
||||
(void)element_type;
|
||||
uint32_t has_max = read32_uleb128(mod_ptr, &i);
|
||||
if (has_max != 1) panic("expected has_max==1");
|
||||
uint32_t initial = read32_uleb128(mod_ptr, &i);
|
||||
(void)initial;
|
||||
uint32_t maximum = read32_uleb128(mod_ptr, &i);
|
||||
|
||||
i = section_starts[Section_element];
|
||||
uint32_t element_section_count = read32_uleb128(mod_ptr, &i);
|
||||
if (element_section_count != 1) panic("expected one element section");
|
||||
uint32_t flags = read32_uleb128(mod_ptr, &i);
|
||||
(void)flags;
|
||||
enum WasmOp opcode = mod_ptr[i];
|
||||
i += 1;
|
||||
if (opcode != WasmOp_i32_const) panic("expected op i32_const");
|
||||
uint32_t offset = read32_uleb128(mod_ptr, &i);
|
||||
enum WasmOp end = mod_ptr[i];
|
||||
if (end != WasmOp_end) panic("expected op end");
|
||||
i += 1;
|
||||
uint32_t elem_count = read32_uleb128(mod_ptr, &i);
|
||||
|
||||
table = arena_alloc(sizeof(uint32_t) * maximum);
|
||||
memset(table, 0, sizeof(uint32_t) * maximum);
|
||||
|
||||
for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) {
|
||||
table[elem_i + offset] = read32_uleb128(mod_ptr, &i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct VirtualMachine vm;
|
||||
#ifndef NDEBUG
|
||||
memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version
|
||||
#endif
|
||||
vm.stack = arena_alloc(sizeof(uint32_t) * 10000000),
|
||||
vm.mod_ptr = mod_ptr;
|
||||
vm.opcodes = arena_alloc(2000000);
|
||||
vm.operands = arena_alloc(sizeof(uint32_t) * 2000000);
|
||||
vm.stack_top = 0;
|
||||
vm.functions = functions;
|
||||
vm.types = types;
|
||||
vm.globals = globals;
|
||||
vm.memory = memory;
|
||||
vm.memory_len = memory_len;
|
||||
vm.imports = imports;
|
||||
vm.imports_len = imports_len;
|
||||
vm.args = new_argv;
|
||||
vm.table = table;
|
||||
|
||||
{
|
||||
uint32_t code_i = section_starts[Section_code];
|
||||
uint32_t codes_len = read32_uleb128(mod_ptr, &code_i);
|
||||
if (codes_len != functions_len) panic("code/function length mismatch");
|
||||
struct ProgramCounter pc;
|
||||
pc.opcode = 0;
|
||||
pc.operand = 0;
|
||||
struct StackInfo stack;
|
||||
for (uint32_t func_i = 0; func_i < functions_len; func_i += 1) {
|
||||
struct Function *func = &functions[func_i];
|
||||
uint32_t size = read32_uleb128(mod_ptr, &code_i);
|
||||
uint32_t code_begin = code_i;
|
||||
|
||||
stack.top_index = 0;
|
||||
stack.top_offset = 0;
|
||||
struct TypeInfo *type_info = &vm.types[func->type_idx];
|
||||
for (uint32_t param_i = 0; param_i < type_info->param_count; param_i += 1)
|
||||
si_push(&stack, bs_isSet(&type_info->param_types, param_i));
|
||||
uint32_t params_size = stack.top_offset;
|
||||
|
||||
for (uint32_t local_sets_count = read32_uleb128(mod_ptr, &code_i);
|
||||
local_sets_count > 0; local_sets_count -= 1)
|
||||
{
|
||||
uint32_t local_set_count = read32_uleb128(mod_ptr, &code_i);
|
||||
enum StackType local_type;
|
||||
switch (read64_ileb128(mod_ptr, &code_i)) {
|
||||
case -1: case -3: local_type = ST_32; break;
|
||||
case -2: case -4: local_type = ST_64; break;
|
||||
default: panic("unexpected local type");
|
||||
}
|
||||
for (; local_set_count > 0; local_set_count -= 1)
|
||||
si_push(&stack, local_type);
|
||||
}
|
||||
func->locals_size = stack.top_offset - params_size;
|
||||
|
||||
func->entry_pc = pc;
|
||||
//fprintf(stderr, "decoding func id %u with pc %u:%u\n", func->id, pc.opcode, pc.operand);
|
||||
vm_decodeCode(&vm, type_info, &code_i, &pc, &stack);
|
||||
if (code_i != code_begin + size) panic("bad code size");
|
||||
}
|
||||
//fprintf(stderr, "%u opcodes\n%u operands\n", pc.opcode, pc.operand);
|
||||
}
|
||||
|
||||
vm_call(&vm, &vm.functions[start_fn_idx - imports_len]);
|
||||
vm_run(&vm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user