summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--src/c-writer.cc247
-rw-r--r--src/prebuilt/wasm2c.include.c153
-rw-r--r--src/prebuilt/wasm2c.include.h91
-rw-r--r--src/wasm2c.c.tmpl149
-rw-r--r--src/wasm2c.h.tmpl87
-rwxr-xr-xsrc/wasm2c_tmpl.py80
7 files changed, 575 insertions, 241 deletions
diff --git a/Makefile b/Makefile
index 2ed3c773..a40d44fd 100644
--- a/Makefile
+++ b/Makefile
@@ -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 = &target;
-
-/* 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 = &target;\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 = &target;
+
+/* 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:]))