mirror of
https://github.com/ziglang/zig.git
synced 2024-11-13 23:52:57 +00:00
use zig-wasm2c for bootstrapping
This commit is contained in:
parent
a63305bc50
commit
1263346774
@ -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(
|
||||
|
164
stage1/FuncGen.h
Normal file
164
stage1/FuncGen.h
Normal file
@ -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 */
|
241
stage1/InputStream.h
Normal file
241
stage1/InputStream.h
Normal file
@ -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 */
|
12
stage1/panic.h
Normal file
12
stage1/panic.h
Normal file
@ -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
stage1/wasi.c
Normal file
948
stage1/wasi.c
Normal file
@ -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
stage1/wasm.h
Normal file
280
stage1/wasm.h
Normal file
@ -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
stage1/wasm2c.c
Normal file
2520
stage1/wasm2c.c
Normal file
File diff suppressed because it is too large
Load Diff
4567
stage1/zig1.c
4567
stage1/zig1.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user