diff options
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | src/c-writer.cc | 247 | ||||
-rw-r--r-- | src/prebuilt/wasm2c.include.c | 153 | ||||
-rw-r--r-- | src/prebuilt/wasm2c.include.h | 91 | ||||
-rw-r--r-- | src/wasm2c.c.tmpl | 149 | ||||
-rw-r--r-- | src/wasm2c.h.tmpl | 87 | ||||
-rwxr-xr-x | src/wasm2c_tmpl.py | 80 |
7 files changed, 575 insertions, 241 deletions
@@ -146,6 +146,15 @@ update-re2c: src/prebuilt/wast-lexer-gen.cc src/prebuilt/wast-lexer-gen.cc: src/wast-lexer.cc re2c -W -Werror --no-generation-date -bc8 -o $@ $< +.PHONY: update-wasm2c +update-wasm2c: src/prebuilt/wasm2c.include.c src/prebuilt/wasm2c.include.h + +src/prebuilt/wasm2c.include.c: src/wasm2c.c.tmpl + src/wasm2c_tmpl.py -o $@ $< + +src/prebuilt/wasm2c.include.h: src/wasm2c.h.tmpl + src/wasm2c_tmpl.py -o $@ $< + # running CMake $(foreach CONFIG,$(CONFIGS), \ $(foreach COMPILER,$(COMPILERS), \ diff --git a/src/c-writer.cc b/src/c-writer.cc index 64b6f539..2d10dc81 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -384,248 +384,13 @@ static const char* s_global_symbols[] = { }; -static const char s_header_top[] = - R"( -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef WASM_RT_INCLUDED_ -#define WASM_RT_INCLUDED_ - -#include <stdint.h> - -#ifndef WASM_RT_MAX_CALL_STACK_DEPTH -#define WASM_RT_MAX_CALL_STACK_DEPTH 500 -#endif - -#ifndef WASM_RT_MODULE_PREFIX -#define WASM_RT_MODULE_PREFIX -#endif - -#define WASM_RT_PASTE_(x, y) x ## y -#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y) -#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x) - -#define WASM_RT_DEFINE_EXTERNAL(decl, target) decl = ⌖ - -/* TODO(binji): only use stdint.h types in header */ -typedef uint8_t u8; -typedef int8_t s8; -typedef uint16_t u16; -typedef int16_t s16; -typedef uint32_t u32; -typedef int32_t s32; -typedef uint64_t u64; -typedef int64_t s64; -typedef float f32; -typedef double f64; - -typedef enum { - WASM_RT_TRAP_NONE, - WASM_RT_TRAP_OOB, - WASM_RT_TRAP_INT_OVERFLOW, - WASM_RT_TRAP_DIV_BY_ZERO, - WASM_RT_TRAP_INVALID_CONVERSION, - WASM_RT_TRAP_UNREACHABLE, - WASM_RT_TRAP_CALL_INDIRECT, - WASM_RT_TRAP_EXHAUSTION, -} wasm_rt_trap_t; - -typedef enum { - WASM_RT_I32, - WASM_RT_I64, - WASM_RT_F32, - WASM_RT_F64, -} wasm_rt_type_t; - -typedef void (*wasm_rt_anyfunc_t)(void); - -typedef struct { - uint32_t func_type; - wasm_rt_anyfunc_t func; -} wasm_rt_elem_t; - -typedef struct { - uint8_t* data; - uint32_t pages, max_pages; - uint32_t size; -} wasm_rt_memory_t; - -typedef struct { - wasm_rt_elem_t* data; - uint32_t max_size; - uint32_t size; -} wasm_rt_table_t; - -extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn)); -extern uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...); -extern void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages); -extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages); -extern void wasm_rt_allocate_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements); -extern uint32_t wasm_rt_call_stack_depth; - -#endif /* WASM_RT_INCLUDED_ */ - -extern void WASM_RT_ADD_PREFIX(init)(void); -)"; - -static const char s_header_bottom[] = R"( -#ifdef __cplusplus -} -#endif -)"; - -static const char s_source_includes[] = R"(#include <assert.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> -)"; - -static const char s_source_declarations[] = R"( -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#define LIKELY(x) __builtin_expect(!!(x), 1) - -#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) - -#define FUNC_PROLOGUE \ - if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \ - TRAP(EXHAUSTION) - -#define FUNC_EPILOGUE --wasm_rt_call_stack_depth - -#define UNREACHABLE TRAP(UNREACHABLE) - -#define CALL_INDIRECT(table, t, ft, x, ...) \ - (LIKELY((x) < table.size && table.data[x].func && \ - table.data[x].func_type == func_types[ft]) \ - ? ((t)table.data[x].func)(__VA_ARGS__) \ - : TRAP(CALL_INDIRECT)) - -#define MEMCHECK(mem, a, t) \ - if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB) - -#define DEFINE_LOAD(name, t1, t2, t3) \ - static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \ - MEMCHECK(mem, addr, t1); \ - t1 result; \ - memcpy(&result, &mem->data[addr], sizeof(t1)); \ - return (t3)(t2)result; \ - } - -#define DEFINE_STORE(name, t1, t2) \ - static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \ - MEMCHECK(mem, addr, t1); \ - t1 wrapped = (t1)value; \ - memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \ - } - -DEFINE_LOAD(i32_load, u32, u32, u32); -DEFINE_LOAD(i64_load, u64, u64, u64); -DEFINE_LOAD(f32_load, f32, f32, f32); -DEFINE_LOAD(f64_load, f64, f64, f64); -DEFINE_LOAD(i32_load8_s, s8, s32, u32); -DEFINE_LOAD(i64_load8_s, s8, s64, u64); -DEFINE_LOAD(i32_load8_u, u8, u32, u32); -DEFINE_LOAD(i64_load8_u, u8, u64, u64); -DEFINE_LOAD(i32_load16_s, s16, s32, u32); -DEFINE_LOAD(i64_load16_s, s16, s64, u64); -DEFINE_LOAD(i32_load16_u, u16, u32, u32); -DEFINE_LOAD(i64_load16_u, u16, u64, u64); -DEFINE_LOAD(i64_load32_s, s32, s64, u64); -DEFINE_LOAD(i64_load32_u, u32, u64, u64); -DEFINE_STORE(i32_store, u32, u32); -DEFINE_STORE(i64_store, u64, u64); -DEFINE_STORE(f32_store, f32, f32); -DEFINE_STORE(f64_store, f64, f64); -DEFINE_STORE(i32_store8, u8, u32); -DEFINE_STORE(i32_store16, u16, u32); -DEFINE_STORE(i64_store8, u8, u64); -DEFINE_STORE(i64_store16, u16, u64); -DEFINE_STORE(i64_store32, u32, u64); - -#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32) -#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64) -#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32) -#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64) -#define I32_POPCNT(x) (__builtin_popcount(x)) -#define I64_POPCNT(x) (__builtin_popcountll(x)) - -#define DIV_S(ut, min, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ - : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \ - : (ut)((x) / (y))) - -#define REM_S(ut, min, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ - : (UNLIKELY((x) == min && (y) == -1)) ? 0 \ - : (ut)((x) % (y))) - -#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y) -#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y) -#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y) -#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y) - -#define DIVREM_U(op, x, y) \ - ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y))) - -#define DIV_U(x, y) DIVREM_U(/, x, y) -#define REM_U(x, y) DIVREM_U(%, x, y) - -#define ROTL(x, y, mask) \ - (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask)))) -#define ROTR(x, y, mask) \ - (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask)))) - -#define I32_ROTL(x, y) ROTL(x, y, 31) -#define I64_ROTL(x, y) ROTL(x, y, 63) -#define I32_ROTR(x, y) ROTR(x, y, 31) -#define I64_ROTR(x, y) ROTR(x, y, 63) - -#define FMIN(x, y) \ - ((UNLIKELY((x) != (x))) ? NAN \ - : (UNLIKELY((y) != (y))) ? NAN \ - : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \ - : (x < y) ? x : y) - -#define FMAX(x, y) \ - ((UNLIKELY((x) != (x))) ? NAN \ - : (UNLIKELY((y) != (y))) ? NAN \ - : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \ - : (x > y) ? x : y) - -#define TRUNC_S(ut, st, ft, min, max, maxop, x) \ - ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ - : (UNLIKELY((x) < (ft)(min) || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ - : (ut)(st)(x)) - -#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, INT32_MIN, INT32_MAX, >=, x) -#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, INT64_MIN, INT64_MAX, >=, x) -#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, INT32_MIN, INT32_MAX, >, x) -#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, INT64_MIN, INT64_MAX, >=, x) - -#define TRUNC_U(ut, ft, max, maxop, x) \ - ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ - : (UNLIKELY((x) <= (ft)-1 || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ - : (ut)(x)) - -#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, UINT32_MAX, >=, x) -#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, UINT64_MAX, >=, x) -#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, UINT32_MAX, >, x) -#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, UINT64_MAX, >=, x) - -#define DEFINE_REINTERPRET(name, t1, t2) \ - static inline t2 name(t1 x) { \ - t2 result; \ - memcpy(&result, &x, sizeof(result)); \ - return result; \ - } +#define SECTION_NAME(x) s_header_##x +#include "src/prebuilt/wasm2c.include.h" +#undef SECTION_NAME -DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32) -DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32) -DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64) -DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64) -)"; +#define SECTION_NAME(x) s_source_##x +#include "src/prebuilt/wasm2c.include.c" +#undef SECTION_NAME size_t CWriter::MarkTypeStack() const { return type_stack_.size(); diff --git a/src/prebuilt/wasm2c.include.c b/src/prebuilt/wasm2c.include.c new file mode 100644 index 00000000..f970cd74 --- /dev/null +++ b/src/prebuilt/wasm2c.include.c @@ -0,0 +1,153 @@ +/* Generated from 'wasm2c.c.tmpl' by wasm2c_tmpl.py, do not edit! */ +const char SECTION_NAME(includes)[] = +"#include <assert.h>\n" +"#include <math.h>\n" +"#include <stdlib.h>\n" +"#include <string.h>\n" +; + +const char SECTION_NAME(declarations)[] = +"#define UNLIKELY(x) __builtin_expect(!!(x), 0)\n" +"#define LIKELY(x) __builtin_expect(!!(x), 1)\n" +"\n" +"#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)\n" +"\n" +"#define FUNC_PROLOGUE \\\n" +" if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \\\n" +" TRAP(EXHAUSTION)\n" +"\n" +"#define FUNC_EPILOGUE --wasm_rt_call_stack_depth\n" +"\n" +"#define UNREACHABLE TRAP(UNREACHABLE)\n" +"\n" +"#define CALL_INDIRECT(table, t, ft, x, ...) \\\n" +" (LIKELY((x) < table.size && table.data[x].func && \\\n" +" table.data[x].func_type == func_types[ft]) \\\n" +" ? ((t)table.data[x].func)(__VA_ARGS__) \\\n" +" : TRAP(CALL_INDIRECT))\n" +"\n" +"#define MEMCHECK(mem, a, t) \\\n" +" if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)\n" +"\n" +"#define DEFINE_LOAD(name, t1, t2, t3) \\\n" +" static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \\\n" +" MEMCHECK(mem, addr, t1); \\\n" +" t1 result; \\\n" +" memcpy(&result, &mem->data[addr], sizeof(t1)); \\\n" +" return (t3)(t2)result; \\\n" +" }\n" +"\n" +"#define DEFINE_STORE(name, t1, t2) \\\n" +" static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \\\n" +" MEMCHECK(mem, addr, t1); \\\n" +" t1 wrapped = (t1)value; \\\n" +" memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \\\n" +" }\n" +"\n" +"DEFINE_LOAD(i32_load, u32, u32, u32);\n" +"DEFINE_LOAD(i64_load, u64, u64, u64);\n" +"DEFINE_LOAD(f32_load, f32, f32, f32);\n" +"DEFINE_LOAD(f64_load, f64, f64, f64);\n" +"DEFINE_LOAD(i32_load8_s, s8, s32, u32);\n" +"DEFINE_LOAD(i64_load8_s, s8, s64, u64);\n" +"DEFINE_LOAD(i32_load8_u, u8, u32, u32);\n" +"DEFINE_LOAD(i64_load8_u, u8, u64, u64);\n" +"DEFINE_LOAD(i32_load16_s, s16, s32, u32);\n" +"DEFINE_LOAD(i64_load16_s, s16, s64, u64);\n" +"DEFINE_LOAD(i32_load16_u, u16, u32, u32);\n" +"DEFINE_LOAD(i64_load16_u, u16, u64, u64);\n" +"DEFINE_LOAD(i64_load32_s, s32, s64, u64);\n" +"DEFINE_LOAD(i64_load32_u, u32, u64, u64);\n" +"DEFINE_STORE(i32_store, u32, u32);\n" +"DEFINE_STORE(i64_store, u64, u64);\n" +"DEFINE_STORE(f32_store, f32, f32);\n" +"DEFINE_STORE(f64_store, f64, f64);\n" +"DEFINE_STORE(i32_store8, u8, u32);\n" +"DEFINE_STORE(i32_store16, u16, u32);\n" +"DEFINE_STORE(i64_store8, u8, u64);\n" +"DEFINE_STORE(i64_store16, u16, u64);\n" +"DEFINE_STORE(i64_store32, u32, u64);\n" +"\n" +"#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32)\n" +"#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64)\n" +"#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32)\n" +"#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64)\n" +"#define I32_POPCNT(x) (__builtin_popcount(x))\n" +"#define I64_POPCNT(x) (__builtin_popcountll(x))\n" +"\n" +"#define DIV_S(ut, min, x, y) \\\n" +" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n" +" : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \\\n" +" : (ut)((x) / (y)))\n" +"\n" +"#define REM_S(ut, min, x, y) \\\n" +" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n" +" : (UNLIKELY((x) == min && (y) == -1)) ? 0 \\\n" +" : (ut)((x) % (y)))\n" +"\n" +"#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y)\n" +"#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y)\n" +"#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y)\n" +"#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y)\n" +"\n" +"#define DIVREM_U(op, x, y) \\\n" +" ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y)))\n" +"\n" +"#define DIV_U(x, y) DIVREM_U(/, x, y)\n" +"#define REM_U(x, y) DIVREM_U(%, x, y)\n" +"\n" +"#define ROTL(x, y, mask) \\\n" +" (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask))))\n" +"#define ROTR(x, y, mask) \\\n" +" (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask))))\n" +"\n" +"#define I32_ROTL(x, y) ROTL(x, y, 31)\n" +"#define I64_ROTL(x, y) ROTL(x, y, 63)\n" +"#define I32_ROTR(x, y) ROTR(x, y, 31)\n" +"#define I64_ROTR(x, y) ROTR(x, y, 63)\n" +"\n" +"#define FMIN(x, y) \\\n" +" ((UNLIKELY((x) != (x))) ? NAN \\\n" +" : (UNLIKELY((y) != (y))) ? NAN \\\n" +" : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \\\n" +" : (x < y) ? x : y)\n" +"\n" +"#define FMAX(x, y) \\\n" +" ((UNLIKELY((x) != (x))) ? NAN \\\n" +" : (UNLIKELY((y) != (y))) ? NAN \\\n" +" : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \\\n" +" : (x > y) ? x : y)\n" +"\n" +"#define TRUNC_S(ut, st, ft, min, max, maxop, x) \\\n" +" ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n" +" : (UNLIKELY((x) < (ft)(min) || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \\\n" +" : (ut)(st)(x))\n" +"\n" +"#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, INT32_MIN, INT32_MAX, >=, x)\n" +"#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, INT64_MIN, INT64_MAX, >=, x)\n" +"#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, INT32_MIN, INT32_MAX, >, x)\n" +"#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, INT64_MIN, INT64_MAX, >=, x)\n" +"\n" +"#define TRUNC_U(ut, ft, max, maxop, x) \\\n" +" ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n" +" : (UNLIKELY((x) <= (ft)-1 || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \\\n" +" : (ut)(x))\n" +"\n" +"#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, UINT32_MAX, >=, x)\n" +"#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, UINT64_MAX, >=, x)\n" +"#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, UINT32_MAX, >, x)\n" +"#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, UINT64_MAX, >=, x)\n" +"\n" +"#define DEFINE_REINTERPRET(name, t1, t2) \\\n" +" static inline t2 name(t1 x) { \\\n" +" t2 result; \\\n" +" memcpy(&result, &x, sizeof(result)); \\\n" +" return result; \\\n" +" }\n" +"\n" +"DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32)\n" +"DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32)\n" +"DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64)\n" +"DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64)\n" +"\n" +; diff --git a/src/prebuilt/wasm2c.include.h b/src/prebuilt/wasm2c.include.h new file mode 100644 index 00000000..d5ada500 --- /dev/null +++ b/src/prebuilt/wasm2c.include.h @@ -0,0 +1,91 @@ +/* Generated from 'wasm2c.h.tmpl' by wasm2c_tmpl.py, do not edit! */ +const char SECTION_NAME(top)[] = +"#ifdef __cplusplus\n" +"extern \"C\" {\n" +"#endif\n" +"\n" +"#ifndef WASM_RT_INCLUDED_\n" +"#define WASM_RT_INCLUDED_\n" +"\n" +"#include <stdint.h>\n" +"\n" +"#ifndef WASM_RT_MAX_CALL_STACK_DEPTH\n" +"#define WASM_RT_MAX_CALL_STACK_DEPTH 500\n" +"#endif\n" +"\n" +"#ifndef WASM_RT_MODULE_PREFIX\n" +"#define WASM_RT_MODULE_PREFIX\n" +"#endif\n" +"\n" +"#define WASM_RT_PASTE_(x, y) x ## y\n" +"#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)\n" +"#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)\n" +"\n" +"#define WASM_RT_DEFINE_EXTERNAL(decl, target) decl = ⌖\n" +"\n" +"/* TODO(binji): only use stdint.h types in header */\n" +"typedef uint8_t u8;\n" +"typedef int8_t s8;\n" +"typedef uint16_t u16;\n" +"typedef int16_t s16;\n" +"typedef uint32_t u32;\n" +"typedef int32_t s32;\n" +"typedef uint64_t u64;\n" +"typedef int64_t s64;\n" +"typedef float f32;\n" +"typedef double f64;\n" +"\n" +"typedef enum {\n" +" WASM_RT_TRAP_NONE,\n" +" WASM_RT_TRAP_OOB,\n" +" WASM_RT_TRAP_INT_OVERFLOW,\n" +" WASM_RT_TRAP_DIV_BY_ZERO,\n" +" WASM_RT_TRAP_INVALID_CONVERSION,\n" +" WASM_RT_TRAP_UNREACHABLE,\n" +" WASM_RT_TRAP_CALL_INDIRECT,\n" +" WASM_RT_TRAP_EXHAUSTION,\n" +"} wasm_rt_trap_t;\n" +"\n" +"typedef enum {\n" +" WASM_RT_I32,\n" +" WASM_RT_I64,\n" +" WASM_RT_F32,\n" +" WASM_RT_F64,\n" +"} wasm_rt_type_t;\n" +"\n" +"typedef void (*wasm_rt_anyfunc_t)(void);\n" +"\n" +"typedef struct {\n" +" uint32_t func_type;\n" +" wasm_rt_anyfunc_t func;\n" +"} wasm_rt_elem_t;\n" +"\n" +"typedef struct {\n" +" uint8_t* data;\n" +" uint32_t pages, max_pages;\n" +" uint32_t size;\n" +"} wasm_rt_memory_t;\n" +"\n" +"typedef struct {\n" +" wasm_rt_elem_t* data;\n" +" uint32_t max_size;\n" +" uint32_t size;\n" +"} wasm_rt_table_t;\n" +"\n" +"extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));\n" +"extern uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...);\n" +"extern void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages);\n" +"extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages);\n" +"extern void wasm_rt_allocate_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements);\n" +"extern uint32_t wasm_rt_call_stack_depth;\n" +"\n" +"#endif /* WASM_RT_INCLUDED_ */\n" +"\n" +"extern void WASM_RT_ADD_PREFIX(init)(void);\n" +; + +const char SECTION_NAME(bottom)[] = +"#ifdef __cplusplus\n" +"}\n" +"#endif\n" +; diff --git a/src/wasm2c.c.tmpl b/src/wasm2c.c.tmpl new file mode 100644 index 00000000..baf8bd84 --- /dev/null +++ b/src/wasm2c.c.tmpl @@ -0,0 +1,149 @@ +%%includes +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +%%declarations +#define UNLIKELY(x) __builtin_expect(!!(x), 0) +#define LIKELY(x) __builtin_expect(!!(x), 1) + +#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) + +#define FUNC_PROLOGUE \ + if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \ + TRAP(EXHAUSTION) + +#define FUNC_EPILOGUE --wasm_rt_call_stack_depth + +#define UNREACHABLE TRAP(UNREACHABLE) + +#define CALL_INDIRECT(table, t, ft, x, ...) \ + (LIKELY((x) < table.size && table.data[x].func && \ + table.data[x].func_type == func_types[ft]) \ + ? ((t)table.data[x].func)(__VA_ARGS__) \ + : TRAP(CALL_INDIRECT)) + +#define MEMCHECK(mem, a, t) \ + if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB) + +#define DEFINE_LOAD(name, t1, t2, t3) \ + static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \ + MEMCHECK(mem, addr, t1); \ + t1 result; \ + memcpy(&result, &mem->data[addr], sizeof(t1)); \ + return (t3)(t2)result; \ + } + +#define DEFINE_STORE(name, t1, t2) \ + static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \ + MEMCHECK(mem, addr, t1); \ + t1 wrapped = (t1)value; \ + memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \ + } + +DEFINE_LOAD(i32_load, u32, u32, u32); +DEFINE_LOAD(i64_load, u64, u64, u64); +DEFINE_LOAD(f32_load, f32, f32, f32); +DEFINE_LOAD(f64_load, f64, f64, f64); +DEFINE_LOAD(i32_load8_s, s8, s32, u32); +DEFINE_LOAD(i64_load8_s, s8, s64, u64); +DEFINE_LOAD(i32_load8_u, u8, u32, u32); +DEFINE_LOAD(i64_load8_u, u8, u64, u64); +DEFINE_LOAD(i32_load16_s, s16, s32, u32); +DEFINE_LOAD(i64_load16_s, s16, s64, u64); +DEFINE_LOAD(i32_load16_u, u16, u32, u32); +DEFINE_LOAD(i64_load16_u, u16, u64, u64); +DEFINE_LOAD(i64_load32_s, s32, s64, u64); +DEFINE_LOAD(i64_load32_u, u32, u64, u64); +DEFINE_STORE(i32_store, u32, u32); +DEFINE_STORE(i64_store, u64, u64); +DEFINE_STORE(f32_store, f32, f32); +DEFINE_STORE(f64_store, f64, f64); +DEFINE_STORE(i32_store8, u8, u32); +DEFINE_STORE(i32_store16, u16, u32); +DEFINE_STORE(i64_store8, u8, u64); +DEFINE_STORE(i64_store16, u16, u64); +DEFINE_STORE(i64_store32, u32, u64); + +#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32) +#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64) +#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32) +#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64) +#define I32_POPCNT(x) (__builtin_popcount(x)) +#define I64_POPCNT(x) (__builtin_popcountll(x)) + +#define DIV_S(ut, min, x, y) \ + ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ + : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \ + : (ut)((x) / (y))) + +#define REM_S(ut, min, x, y) \ + ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ + : (UNLIKELY((x) == min && (y) == -1)) ? 0 \ + : (ut)((x) % (y))) + +#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y) +#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y) +#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y) +#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y) + +#define DIVREM_U(op, x, y) \ + ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y))) + +#define DIV_U(x, y) DIVREM_U(/, x, y) +#define REM_U(x, y) DIVREM_U(%, x, y) + +#define ROTL(x, y, mask) \ + (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask)))) +#define ROTR(x, y, mask) \ + (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask)))) + +#define I32_ROTL(x, y) ROTL(x, y, 31) +#define I64_ROTL(x, y) ROTL(x, y, 63) +#define I32_ROTR(x, y) ROTR(x, y, 31) +#define I64_ROTR(x, y) ROTR(x, y, 63) + +#define FMIN(x, y) \ + ((UNLIKELY((x) != (x))) ? NAN \ + : (UNLIKELY((y) != (y))) ? NAN \ + : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \ + : (x < y) ? x : y) + +#define FMAX(x, y) \ + ((UNLIKELY((x) != (x))) ? NAN \ + : (UNLIKELY((y) != (y))) ? NAN \ + : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \ + : (x > y) ? x : y) + +#define TRUNC_S(ut, st, ft, min, max, maxop, x) \ + ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ + : (UNLIKELY((x) < (ft)(min) || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ + : (ut)(st)(x)) + +#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, INT32_MIN, INT32_MAX, >=, x) +#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, INT64_MIN, INT64_MAX, >=, x) +#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, INT32_MIN, INT32_MAX, >, x) +#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, INT64_MIN, INT64_MAX, >=, x) + +#define TRUNC_U(ut, ft, max, maxop, x) \ + ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ + : (UNLIKELY((x) <= (ft)-1 || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ + : (ut)(x)) + +#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, UINT32_MAX, >=, x) +#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, UINT64_MAX, >=, x) +#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, UINT32_MAX, >, x) +#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, UINT64_MAX, >=, x) + +#define DEFINE_REINTERPRET(name, t1, t2) \ + static inline t2 name(t1 x) { \ + t2 result; \ + memcpy(&result, &x, sizeof(result)); \ + return result; \ + } + +DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32) +DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32) +DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64) +DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64) + diff --git a/src/wasm2c.h.tmpl b/src/wasm2c.h.tmpl new file mode 100644 index 00000000..24b1af23 --- /dev/null +++ b/src/wasm2c.h.tmpl @@ -0,0 +1,87 @@ +%%top +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WASM_RT_INCLUDED_ +#define WASM_RT_INCLUDED_ + +#include <stdint.h> + +#ifndef WASM_RT_MAX_CALL_STACK_DEPTH +#define WASM_RT_MAX_CALL_STACK_DEPTH 500 +#endif + +#ifndef WASM_RT_MODULE_PREFIX +#define WASM_RT_MODULE_PREFIX +#endif + +#define WASM_RT_PASTE_(x, y) x ## y +#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y) +#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x) + +#define WASM_RT_DEFINE_EXTERNAL(decl, target) decl = ⌖ + +/* TODO(binji): only use stdint.h types in header */ +typedef uint8_t u8; +typedef int8_t s8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef int32_t s32; +typedef uint64_t u64; +typedef int64_t s64; +typedef float f32; +typedef double f64; + +typedef enum { + WASM_RT_TRAP_NONE, + WASM_RT_TRAP_OOB, + WASM_RT_TRAP_INT_OVERFLOW, + WASM_RT_TRAP_DIV_BY_ZERO, + WASM_RT_TRAP_INVALID_CONVERSION, + WASM_RT_TRAP_UNREACHABLE, + WASM_RT_TRAP_CALL_INDIRECT, + WASM_RT_TRAP_EXHAUSTION, +} wasm_rt_trap_t; + +typedef enum { + WASM_RT_I32, + WASM_RT_I64, + WASM_RT_F32, + WASM_RT_F64, +} wasm_rt_type_t; + +typedef void (*wasm_rt_anyfunc_t)(void); + +typedef struct { + uint32_t func_type; + wasm_rt_anyfunc_t func; +} wasm_rt_elem_t; + +typedef struct { + uint8_t* data; + uint32_t pages, max_pages; + uint32_t size; +} wasm_rt_memory_t; + +typedef struct { + wasm_rt_elem_t* data; + uint32_t max_size; + uint32_t size; +} wasm_rt_table_t; + +extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn)); +extern uint32_t wasm_rt_register_func_type(uint32_t params, uint32_t results, ...); +extern void wasm_rt_allocate_memory(wasm_rt_memory_t*, uint32_t initial_pages, uint32_t max_pages); +extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages); +extern void wasm_rt_allocate_table(wasm_rt_table_t*, uint32_t elements, uint32_t max_elements); +extern uint32_t wasm_rt_call_stack_depth; + +#endif /* WASM_RT_INCLUDED_ */ + +extern void WASM_RT_ADD_PREFIX(init)(void); +%%bottom +#ifdef __cplusplus +} +#endif diff --git a/src/wasm2c_tmpl.py b/src/wasm2c_tmpl.py new file mode 100755 index 00000000..d43c2065 --- /dev/null +++ b/src/wasm2c_tmpl.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# +# Copyright 2018 WebAssembly Community Group participants +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from __future__ import print_function +import argparse +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO +import os +import sys + +def EscapeCString(s): + out = '' + for b in bytearray(s.encode('utf-8')): + if b in (34, 92): + # " or \ + out += '\\' + chr(b) + elif b == 10: + # newline + out += '\\n' + elif 32 <= b <= 127: + # printable char + out += chr(b) + else: + # non-printable; write as \xab + out += '\\x%02x' % b + + return out + + +def main(args): + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument('-o', '--output', metavar='PATH', + help='output file.') + arg_parser.add_argument('file', help='input file.') + options = arg_parser.parse_args(args) + + section_name = None + output = StringIO() + + output.write('/* Generated from \'%s\' by wasm2c_tmpl.py, do not edit! */\n' % + os.path.basename(options.file)) + + with open(options.file) as f: + for line in f.readlines(): + if line.startswith('%%'): + if section_name is not None: + output.write(';\n\n'); + section_name = line[2:-1] + output.write('const char SECTION_NAME(%s)[] =\n' % section_name) + else: + output.write('"%s"\n' % EscapeCString(line)) + + output.write(';\n'); + if options.output: + with open(options.output, 'w') as outf: + outf.write(output.getvalue()) + else: + sys.stdout.write(output.getvalue()) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) |