summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/c-writer.cc12
-rw-r--r--src/prebuilt/wasm2c.include.c128
-rw-r--r--src/wasm2c.c.tmpl128
-rwxr-xr-xtest/run-spec-wasm2c.py62
-rwxr-xr-xtest/run-tests.py4
-rw-r--r--test/spec-wasm2c-prefix.c4
-rw-r--r--test/utils.py7
-rw-r--r--wasm2c/examples/fac/Makefile2
-rw-r--r--wasm2c/examples/fac/fac.c127
-rw-r--r--wasm2c/examples/rot13/Makefile2
-rw-r--r--wasm2c/wasm-rt-impl.c140
-rw-r--r--wasm2c/wasm-rt.h44
12 files changed, 544 insertions, 116 deletions
diff --git a/src/c-writer.cc b/src/c-writer.cc
index de34cb61..e2bef4a3 100644
--- a/src/c-writer.cc
+++ b/src/c-writer.cc
@@ -2214,11 +2214,11 @@ void CWriter::Write(const UnaryExpr& expr) {
break;
case Opcode::F32Abs:
- WriteSimpleUnaryExpr(expr.opcode, "fabsf");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_fabsf");
break;
case Opcode::F64Abs:
- WriteSimpleUnaryExpr(expr.opcode, "fabs");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_fabs");
break;
case Opcode::F32Sqrt:
@@ -2246,19 +2246,19 @@ void CWriter::Write(const UnaryExpr& expr) {
break;
case Opcode::F32Trunc:
- WriteSimpleUnaryExpr(expr.opcode, "truncf");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_truncf");
break;
case Opcode::F64Trunc:
- WriteSimpleUnaryExpr(expr.opcode, "trunc");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_trunc");
break;
case Opcode::F32Nearest:
- WriteSimpleUnaryExpr(expr.opcode, "nearbyintf");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_nearbyintf");
break;
case Opcode::F64Nearest:
- WriteSimpleUnaryExpr(expr.opcode, "nearbyint");
+ WriteSimpleUnaryExpr(expr.opcode, "wasm_rt_nearbyint");
break;
case Opcode::I32Extend8S:
diff --git a/src/prebuilt/wasm2c.include.c b/src/prebuilt/wasm2c.include.c
index bb23139b..cf511212 100644
--- a/src/prebuilt/wasm2c.include.c
+++ b/src/prebuilt/wasm2c.include.c
@@ -6,8 +6,6 @@ const char SECTION_NAME(includes)[] =
;
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"
@@ -25,13 +23,13 @@ const char SECTION_NAME(declarations)[] =
" || TRAP(CALL_INDIRECT) \\\n"
" , ((t)table.data[x].func)(__VA_ARGS__))\n"
"\n"
-"#define RANGE_CHECK(mem, a, t) \\\n"
-" if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)\n"
+"#define RANGE_CHECK(mem, offset, len) \\\n"
+" if (UNLIKELY(offset + (uint64_t)len > mem->size)) TRAP(OOB)\n"
"\n"
"#if WASM_RT_MEMCHECK_SIGNAL_HANDLER\n"
"#define MEMCHECK(mem, a, t)\n"
"#else\n"
-"#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, t)\n"
+"#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, sizeof(t))\n"
"#endif\n"
"\n"
"#if WABT_BIG_ENDIAN\n"
@@ -45,45 +43,48 @@ const char SECTION_NAME(declarations)[] =
" dest_chars[n - i - 1] = cursor;\n"
" }\n"
"}\n"
-"#define LOAD_DATA(m, o, i, s) do { \\\n"
-" RANGE_CHECK((&m), m.size - o - s, char[s]); \\\n"
+"#define LOAD_DATA(m, o, i, s) \\\n"
+" do { \\\n"
+" RANGE_CHECK((&m), m.size - o - s, s); \\\n"
" load_data(&(m.data[m.size - o - s]), i, s); \\\n"
" } while (0)\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"
-" __builtin_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], sizeof(t1)); \\\n"
-" return (t3)(t2)result; \\\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"
+" wasm_rt_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], \\\n"
+" 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"
-" __builtin_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, sizeof(t1)); \\\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"
+" wasm_rt_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, \\\n"
+" sizeof(t1)); \\\n"
" }\n"
"#else\n"
"static inline void load_data(void *dest, const void *src, size_t n) {\n"
" memcpy(dest, src, n);\n"
"}\n"
"#define LOAD_DATA(m, o, i, s) do { \\\n"
-" RANGE_CHECK((&m), o, char[s]); \\\n"
+" RANGE_CHECK((&m), o, s); \\\n"
" load_data(&(m.data[o]), i, s); \\\n"
" } while (0)\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"
-" __builtin_memcpy(&result, &mem->data[addr], sizeof(t1)); \\\n"
-" return (t3)(t2)result; \\\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"
+" wasm_rt_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"
-" __builtin_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \\\n"
+" wasm_rt_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \\\n"
" }\n"
"#endif\n"
"\n"
@@ -111,6 +112,79 @@ const char SECTION_NAME(declarations)[] =
"DEFINE_STORE(i64_store16, u16, u64)\n"
"DEFINE_STORE(i64_store32, u32, u64)\n"
"\n"
+"#if defined(_MSC_VER)\n"
+"\n"
+"#include <intrin.h>\n"
+"\n"
+"// Adapted from\n"
+"// https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h\n"
+"\n"
+"static inline int I64_CLZ(unsigned long long v) {\n"
+" unsigned long r = 0;\n"
+"#if defined(_M_AMD64) || defined(_M_ARM)\n"
+" if (_BitScanReverse64(&r, v)) {\n"
+" return 63 - r;\n"
+" }\n"
+"#else\n"
+" if (_BitScanReverse(&r, (unsigned long) (v >> 32))) {\n"
+" return 31 - r;\n"
+" } else if (_BitScanReverse(&r, (unsigned long) v)) {\n"
+" return 63 - r;\n"
+" }\n"
+"#endif\n"
+" return 64;\n"
+"}\n"
+"\n"
+"static inline int I32_CLZ(unsigned long v) {\n"
+" unsigned long r = 0;\n"
+" if (_BitScanReverse(&r, v)) {\n"
+" return 31 - r;\n"
+" }\n"
+" return 32;\n"
+"}\n"
+"\n"
+"static inline int I64_CTZ(unsigned long long v) {\n"
+" if (!v) {\n"
+" return 64;\n"
+" }\n"
+" unsigned long r = 0;\n"
+"#if defined(_M_AMD64) || defined(_M_ARM)\n"
+" _BitScanForward64(&r, v);\n"
+" return (int) r;\n"
+"#else\n"
+" if (_BitScanForward(&r, (unsigned int) (v))) {\n"
+" return (int) (r);\n"
+" }\n"
+"\n"
+" _BitScanForward(&r, (unsigned int) (v >> 32));\n"
+" return (int) (r + 32);\n"
+"#endif\n"
+"}\n"
+"\n"
+"static inline int I32_CTZ(unsigned long v) {\n"
+" if (!v) {\n"
+" return 32;\n"
+" }\n"
+" unsigned long r = 0;\n"
+" _BitScanForward(&r, v);\n"
+" return (int) r;\n"
+"}\n"
+"\n"
+"#define POPCOUNT_DEFINE_PORTABLE(f_n, T) \\\n"
+" static inline u32 f_n(T x) { \\\n"
+" x = x - ((x >> 1) & (T)~(T)0/3); \\\n"
+" x = (x & (T)~(T)0/15*3) + ((x >> 2) & (T)~(T)0/15*3); \\\n"
+" x = (x + (x >> 4)) & (T)~(T)0/255*15; \\\n"
+" return (T)(x * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; \\\n"
+" }\n"
+"\n"
+"POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32)\n"
+"POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64)\n"
+"\n"
+"#undef POPCOUNT_DEFINE_PORTABLE\n"
+"\n"
+"#else\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"
@@ -118,6 +192,8 @@ const char SECTION_NAME(declarations)[] =
"#define I32_POPCNT(x) (__builtin_popcount(x))\n"
"#define I64_POPCNT(x) (__builtin_popcountll(x))\n"
"\n"
+"#endif\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"
diff --git a/src/wasm2c.c.tmpl b/src/wasm2c.c.tmpl
index f6bcc941..d7ba6831 100644
--- a/src/wasm2c.c.tmpl
+++ b/src/wasm2c.c.tmpl
@@ -3,8 +3,6 @@
#include <math.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)
@@ -22,13 +20,13 @@
|| TRAP(CALL_INDIRECT) \
, ((t)table.data[x].func)(__VA_ARGS__))
-#define RANGE_CHECK(mem, a, t) \
- if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)
+#define RANGE_CHECK(mem, offset, len) \
+ if (UNLIKELY(offset + (uint64_t)len > mem->size)) TRAP(OOB)
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
#define MEMCHECK(mem, a, t)
#else
-#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, t)
+#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, sizeof(t))
#endif
#if WABT_BIG_ENDIAN
@@ -42,45 +40,48 @@ static inline void load_data(void *dest, const void *src, size_t n) {
dest_chars[n - i - 1] = cursor;
}
}
-#define LOAD_DATA(m, o, i, s) do { \
- RANGE_CHECK((&m), m.size - o - s, char[s]); \
+#define LOAD_DATA(m, o, i, s) \
+ do { \
+ RANGE_CHECK((&m), m.size - o - s, s); \
load_data(&(m.data[m.size - o - s]), i, s); \
} while (0)
-#define DEFINE_LOAD(name, t1, t2, t3) \
- static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
- MEMCHECK(mem, addr, t1); \
- t1 result; \
- __builtin_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], sizeof(t1)); \
- return (t3)(t2)result; \
+#define DEFINE_LOAD(name, t1, t2, t3) \
+ static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
+ MEMCHECK(mem, addr, t1); \
+ t1 result; \
+ wasm_rt_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], \
+ 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; \
- __builtin_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, sizeof(t1)); \
+#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; \
+ wasm_rt_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, \
+ sizeof(t1)); \
}
#else
static inline void load_data(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
#define LOAD_DATA(m, o, i, s) do { \
- RANGE_CHECK((&m), o, char[s]); \
+ RANGE_CHECK((&m), o, s); \
load_data(&(m.data[o]), i, s); \
} while (0)
-#define DEFINE_LOAD(name, t1, t2, t3) \
- static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
- MEMCHECK(mem, addr, t1); \
- t1 result; \
- __builtin_memcpy(&result, &mem->data[addr], sizeof(t1)); \
- return (t3)(t2)result; \
+#define DEFINE_LOAD(name, t1, t2, t3) \
+ static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
+ MEMCHECK(mem, addr, t1); \
+ t1 result; \
+ wasm_rt_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; \
- __builtin_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \
+ wasm_rt_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \
}
#endif
@@ -108,6 +109,79 @@ DEFINE_STORE(i64_store8, u8, u64)
DEFINE_STORE(i64_store16, u16, u64)
DEFINE_STORE(i64_store32, u32, u64)
+#if defined(_MSC_VER)
+
+#include <intrin.h>
+
+// Adapted from
+// https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h
+
+static inline int I64_CLZ(unsigned long long v) {
+ unsigned long r = 0;
+#if defined(_M_AMD64) || defined(_M_ARM)
+ if (_BitScanReverse64(&r, v)) {
+ return 63 - r;
+ }
+#else
+ if (_BitScanReverse(&r, (unsigned long) (v >> 32))) {
+ return 31 - r;
+ } else if (_BitScanReverse(&r, (unsigned long) v)) {
+ return 63 - r;
+ }
+#endif
+ return 64;
+}
+
+static inline int I32_CLZ(unsigned long v) {
+ unsigned long r = 0;
+ if (_BitScanReverse(&r, v)) {
+ return 31 - r;
+ }
+ return 32;
+}
+
+static inline int I64_CTZ(unsigned long long v) {
+ if (!v) {
+ return 64;
+ }
+ unsigned long r = 0;
+#if defined(_M_AMD64) || defined(_M_ARM)
+ _BitScanForward64(&r, v);
+ return (int) r;
+#else
+ if (_BitScanForward(&r, (unsigned int) (v))) {
+ return (int) (r);
+ }
+
+ _BitScanForward(&r, (unsigned int) (v >> 32));
+ return (int) (r + 32);
+#endif
+}
+
+static inline int I32_CTZ(unsigned long v) {
+ if (!v) {
+ return 32;
+ }
+ unsigned long r = 0;
+ _BitScanForward(&r, v);
+ return (int) r;
+}
+
+#define POPCOUNT_DEFINE_PORTABLE(f_n, T) \
+ static inline u32 f_n(T x) { \
+ x = x - ((x >> 1) & (T)~(T)0/3); \
+ x = (x & (T)~(T)0/15*3) + ((x >> 2) & (T)~(T)0/15*3); \
+ x = (x + (x >> 4)) & (T)~(T)0/255*15; \
+ return (T)(x * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; \
+ }
+
+POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32)
+POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64)
+
+#undef POPCOUNT_DEFINE_PORTABLE
+
+#else
+
#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)
@@ -115,6 +189,8 @@ DEFINE_STORE(i64_store32, u32, u64)
#define I32_POPCNT(x) (__builtin_popcount(x))
#define I64_POPCNT(x) (__builtin_popcountll(x))
+#endif
+
#define DIV_S(ut, min, x, y) \
((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \
: (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \
diff --git a/test/run-spec-wasm2c.py b/test/run-spec-wasm2c.py
index e8b3ea63..a6ad16fc 100755
--- a/test/run-spec-wasm2c.py
+++ b/test/run-spec-wasm2c.py
@@ -19,6 +19,7 @@ import argparse
import io
import json
import os
+import platform
import re
import struct
import sys
@@ -30,6 +31,8 @@ from utils import Error
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
WASM2C_DIR = os.path.join(find_exe.REPO_ROOT_DIR, 'wasm2c')
+IS_WINDOWS = sys.platform == 'win32'
+IS_MACOS = platform.mac_ver()[0] != ''
def ReinterpretF32(f32_bits):
@@ -78,7 +81,7 @@ def F64ToC(f64_bits):
elif f64_bits == F64_SIGN_BIT:
return '-0.0'
else:
- return '%.17g' % ReinterpretF64(f64_bits)
+ return '%#.17gL' % ReinterpretF64(f64_bits)
def MangleType(t):
@@ -335,21 +338,45 @@ class CWriter(object):
def Compile(cc, c_filename, out_dir, *args):
- o_filename = utils.ChangeDir(utils.ChangeExt(c_filename, '.o'), out_dir)
- cc.RunWithArgs('-c', c_filename, '-o', o_filename,
- '-Wall', '-Werror', '-Wno-unused',
- '-Wno-tautological-constant-out-of-range-compare',
- '-std=c99', '-D_DEFAULT_SOURCE',
- *args)
+ if IS_WINDOWS:
+ ext = '.obj'
+ else:
+ ext = '.o'
+ o_filename = utils.ChangeDir(utils.ChangeExt(c_filename, ext), out_dir)
+ args = list(args)
+ if IS_WINDOWS:
+ args += ['/nologo', '/MDd', '/c', c_filename, '/Fo' + o_filename]
+ else:
+ args += ['-c', c_filename, '-o', o_filename,
+ '-Wall', '-Werror', '-Wno-unused',
+ '-Wno-tautological-constant-out-of-range-compare',
+ '-std=c99', '-D_DEFAULT_SOURCE']
+ # Use RunWithArgsForStdout and discard stdout because cl.exe
+ # unconditionally prints the name of input files on stdout
+ # and we don't want that to be part of our stdout.
+ cc.RunWithArgsForStdout(*args)
return o_filename
-def Link(cc, o_filenames, main_exe, *args):
- args = ['-o', main_exe] + o_filenames + list(args)
- cc.RunWithArgs(*args)
+def Link(cc, o_filenames, main_exe, *extra_args):
+ args = o_filenames
+ if IS_WINDOWS:
+ # Windows default to 1Mb of stack but `spec/skip-stack-guard-page.wast`
+ # uses more than this. Set to 8Mb for parity with linux.
+ args += ['/nologo', '/MDd', '/link', '/stack:8388608', '/out:' + main_exe]
+ else:
+ args += ['-o', main_exe]
+ args += list(extra_args)
+ # Use RunWithArgsForStdout and discard stdout because cl.exe
+ # unconditionally prints the name of input files on stdout
+ # and we don't want that to be part of our stdout.
+ cc.RunWithArgsForStdout(*args)
def main(args):
+ default_compiler = 'cc'
+ if IS_WINDOWS:
+ default_compiler = 'cl.exe'
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--out-dir', metavar='PATH',
help='output directory for files.')
@@ -361,7 +388,8 @@ def main(args):
parser.add_argument('--wasmrt-dir', metavar='PATH',
help='directory with wasm-rt files', default=WASM2C_DIR)
parser.add_argument('--cc', metavar='PATH',
- help='the path to the C compiler', default='cc')
+ help='the path to the C compiler',
+ default=default_compiler)
parser.add_argument('--cflags', metavar='FLAGS',
help='additional flags for C compiler.',
action='append', default=[])
@@ -412,7 +440,7 @@ def main(args):
options.cflags += shlex.split(os.environ.get('WASM2C_CFLAGS', ''))
cc = utils.Executable(options.cc, *options.cflags, forward_stderr=True,
- forward_stdout=True)
+ forward_stdout=False)
cc.verbose = options.print_cmd
with open(json_file_path, encoding='utf-8') as json_file:
@@ -449,8 +477,14 @@ def main(args):
# Compile and link -main test run entry point
o_filenames.append(Compile(cc, main_filename, out_dir, includes))
- main_exe = utils.ChangeExt(json_file_path, '')
- Link(cc, o_filenames, main_exe, '-lm')
+ if IS_WINDOWS:
+ exe_ext = '.exe'
+ libs = []
+ else:
+ exe_ext = ''
+ libs = ['-lm']
+ main_exe = utils.ChangeExt(json_file_path, exe_ext)
+ Link(cc, o_filenames, main_exe, *libs)
# Run the resulting binary
if options.run:
diff --git a/test/run-tests.py b/test/run-tests.py
index 370f15f9..f0873aaf 100755
--- a/test/run-tests.py
+++ b/test/run-tests.py
@@ -160,10 +160,6 @@ TOOLS = {
]
}
-# TODO(binji): Add Windows support for compiling using run-spec-wasm2c.py
-if IS_WINDOWS:
- TOOLS['run-spec-wasm2c'].append(('SKIP', ''))
-
ROUNDTRIP_TOOLS = ('wat2wasm',)
diff --git a/test/spec-wasm2c-prefix.c b/test/spec-wasm2c-prefix.c
index df0f1d44..f1d2d1e9 100644
--- a/test/spec-wasm2c-prefix.c
+++ b/test/spec-wasm2c-prefix.c
@@ -12,8 +12,8 @@
#include "wasm-rt.h"
#include "wasm-rt-impl.h"
-int g_tests_run;
-int g_tests_passed;
+static int g_tests_run;
+static int g_tests_passed;
static void run_spec_tests(void);
diff --git a/test/utils.py b/test/utils.py
index 791d0d10..20bac49c 100644
--- a/test/utils.py
+++ b/test/utils.py
@@ -19,6 +19,7 @@ import contextlib
import os
import json
import shutil
+import shlex
import signal
import subprocess
import sys
@@ -52,12 +53,12 @@ class Executable(object):
def _RunWithArgsInternal(self, *args, **kwargs):
cmd = [self.exe] + self.before_args + list(args) + self.after_args
- cmd_str = ' '.join(cmd)
+ cmd_str = shlex.join(cmd)
if self.verbose:
print(cmd_str)
if self.error_cmdline:
- err_cmd_str = cmd_str.replace('.exe', '')
+ err_cmd_str = cmd_str
else:
err_cmd_str = self.basename
@@ -76,7 +77,7 @@ class Executable(object):
error = Error('Signal raised running "%s": %s\n%s' % (err_cmd_str,
signame, stderr))
elif process.returncode > 0:
- error = Error('Error running "%s" (%d):\n%s' % (err_cmd_str, process.returncode, stderr))
+ error = Error('Error running "%s" (%d):\n%s\n%s' % (err_cmd_str, process.returncode, stdout, stderr))
except OSError as e:
error = Error('Error running "%s": %s' % (err_cmd_str, str(e)))
return stdout, stderr, error
diff --git a/wasm2c/examples/fac/Makefile b/wasm2c/examples/fac/Makefile
index caf32e24..a5179a71 100644
--- a/wasm2c/examples/fac/Makefile
+++ b/wasm2c/examples/fac/Makefile
@@ -6,7 +6,7 @@ all: fac
clean:
rm -rf fac fac.wasm fac.c *.o
-fac: main.o fac.o ../../wasm-rt-impl.o
+fac: main.o fac.o ../../wasm-rt-impl.o -lm
fac.wasm: fac.wat ../../../bin/wat2wasm
../../../bin/wat2wasm $< -o $@
diff --git a/wasm2c/examples/fac/fac.c b/wasm2c/examples/fac/fac.c
index eeb28d9f..9ac9522c 100644
--- a/wasm2c/examples/fac/fac.c
+++ b/wasm2c/examples/fac/fac.c
@@ -3,8 +3,6 @@
#include <string.h>
#include "fac.h"
-#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)
@@ -22,13 +20,13 @@
|| TRAP(CALL_INDIRECT) \
, ((t)table.data[x].func)(__VA_ARGS__))
-#define RANGE_CHECK(mem, a, t) \
- if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)
+#define RANGE_CHECK(mem, offset, len) \
+ if (UNLIKELY(offset + (uint64_t)len > mem->size)) TRAP(OOB)
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
#define MEMCHECK(mem, a, t)
#else
-#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, t)
+#define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, sizeof(t))
#endif
#if WABT_BIG_ENDIAN
@@ -42,45 +40,48 @@ static inline void load_data(void *dest, const void *src, size_t n) {
dest_chars[n - i - 1] = cursor;
}
}
-#define LOAD_DATA(m, o, i, s) do { \
- RANGE_CHECK((&m), m.size - o - s, char[s]); \
+#define LOAD_DATA(m, o, i, s) \
+ do { \
+ RANGE_CHECK((&m), m.size - o - s, s); \
load_data(&(m.data[m.size - o - s]), i, s); \
} while (0)
-#define DEFINE_LOAD(name, t1, t2, t3) \
- static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
- MEMCHECK(mem, addr, t1); \
- t1 result; \
- __builtin_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], sizeof(t1)); \
- return (t3)(t2)result; \
+#define DEFINE_LOAD(name, t1, t2, t3) \
+ static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
+ MEMCHECK(mem, addr, t1); \
+ t1 result; \
+ wasm_rt_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], \
+ 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; \
- __builtin_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, sizeof(t1)); \
+#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; \
+ wasm_rt_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, \
+ sizeof(t1)); \
}
#else
static inline void load_data(void *dest, const void *src, size_t n) {
memcpy(dest, src, n);
}
#define LOAD_DATA(m, o, i, s) do { \
- RANGE_CHECK((&m), o, char[s]); \
+ RANGE_CHECK((&m), o, s); \
load_data(&(m.data[o]), i, s); \
} while (0)
-#define DEFINE_LOAD(name, t1, t2, t3) \
- static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
- MEMCHECK(mem, addr, t1); \
- t1 result; \
- __builtin_memcpy(&result, &mem->data[addr], sizeof(t1)); \
- return (t3)(t2)result; \
+#define DEFINE_LOAD(name, t1, t2, t3) \
+ static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \
+ MEMCHECK(mem, addr, t1); \
+ t1 result; \
+ wasm_rt_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; \
- __builtin_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \
+ wasm_rt_memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \
}
#endif
@@ -108,6 +109,78 @@ DEFINE_STORE(i64_store8, u8, u64)
DEFINE_STORE(i64_store16, u16, u64)
DEFINE_STORE(i64_store32, u32, u64)
+#if defined(_MSC_VER)
+
+#include <intrin.h>
+
+// Adapted from https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h
+
+static inline int I64_CLZ(unsigned long long v) {
+ unsigned long r = 0;
+#if defined(_M_AMD64) || defined(_M_ARM)
+ if (_BitScanReverse64(&r, v)) {
+ return 63 - r;
+ }
+#else
+ if (_BitScanReverse(&r, (unsigned long) (v >> 32))) {
+ return 31 - r;
+ } else if (_BitScanReverse(&r, (unsigned long) v)) {
+ return 63 - r;
+ }
+#endif
+ return 64;
+}
+
+static inline int I32_CLZ(unsigned long v) {
+ unsigned long r = 0;
+ if (_BitScanReverse(&r, v)) {
+ return 31 - r;
+ }
+ return 32;
+}
+
+static inline int I64_CTZ(unsigned long long v) {
+ if (!v) {
+ return 64;
+ }
+ unsigned long r = 0;
+#if defined(_M_AMD64) || defined(_M_ARM)
+ _BitScanForward64(&r, v);
+ return (int) r;
+#else
+ if (_BitScanForward(&r, (unsigned int) (v))) {
+ return (int) (r);
+ }
+
+ _BitScanForward(&r, (unsigned int) (v >> 32));
+ return (int) (r + 32);
+#endif
+}
+
+static inline int I32_CTZ(unsigned long v) {
+ if (!v) {
+ return 32;
+ }
+ unsigned long r = 0;
+ _BitScanForward(&r, v);
+ return (int) r;
+}
+
+#define POPCOUNT_DEFINE_PORTABLE(f_n, T) \
+ static inline u32 f_n(T x) { \
+ x = x - ((x >> 1) & (T)~(T)0/3); \
+ x = (x & (T)~(T)0/15*3) + ((x >> 2) & (T)~(T)0/15*3); \
+ x = (x + (x >> 4)) & (T)~(T)0/255*15; \
+ return (T)(x * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8; \
+ }
+
+POPCOUNT_DEFINE_PORTABLE(I32_POPCNT, u32)
+POPCOUNT_DEFINE_PORTABLE(I64_POPCNT, u64)
+
+#undef POPCOUNT_DEFINE_PORTABLE
+
+#else
+
#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)
@@ -115,6 +188,8 @@ DEFINE_STORE(i64_store32, u32, u64)
#define I32_POPCNT(x) (__builtin_popcount(x))
#define I64_POPCNT(x) (__builtin_popcountll(x))
+#endif
+
#define DIV_S(ut, min, x, y) \
((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \
: (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \
diff --git a/wasm2c/examples/rot13/Makefile b/wasm2c/examples/rot13/Makefile
index b58db6be..5e5f5205 100644
--- a/wasm2c/examples/rot13/Makefile
+++ b/wasm2c/examples/rot13/Makefile
@@ -6,7 +6,7 @@ all: rot13
clean:
rm -rf rot13 rot13.wasm rot13.c *.o
-rot13: main.o rot13.o ../../wasm-rt-impl.o ../../wasm-rt-os-unix.o -lm
+rot13: main.o rot13.o ../../wasm-rt-impl.o -lm
rot13.wasm: rot13.wat ../../../bin/wat2wasm
../../../bin/wat2wasm $< -o $@
diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c
index d11cd7e7..e685f38b 100644
--- a/wasm2c/wasm-rt-impl.c
+++ b/wasm2c/wasm-rt-impl.c
@@ -17,6 +17,7 @@
#include "wasm-rt-impl.h"
#include <assert.h>
+#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
@@ -26,10 +27,15 @@
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
#include <signal.h>
-#include <sys/mman.h>
#include <unistd.h>
#endif
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#endif
+
#define PAGE_SIZE 65536
typedef struct FuncType {
@@ -108,6 +114,53 @@ static void signal_handler(int sig, siginfo_t* si, void* unused) {
}
#endif
+#ifdef _WIN32
+static void* os_mmap(size_t size) {
+ return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
+}
+
+static int os_mprotect(void* addr, size_t size) {
+ DWORD old;
+ BOOL succeeded = VirtualProtect((LPVOID)addr, size, PAGE_READWRITE, &old);
+ return succeeded ? 0 : -1;
+}
+
+static void os_print_last_error(const char* msg) {
+ DWORD errorMessageID = GetLastError();
+ if (errorMessageID != 0) {
+ LPSTR messageBuffer = 0;
+ // The api creates the buffer that holds the message
+ size_t size = FormatMessageA(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&messageBuffer, 0, NULL);
+ (void)size;
+ printf("%s. %s\n", msg, messageBuffer);
+ LocalFree(messageBuffer);
+ } else {
+ printf("%s. No error code.\n", msg);
+ }
+}
+#else
+static void* os_mmap(size_t size) {
+ int map_prot = PROT_NONE;
+ int map_flags = MAP_ANONYMOUS | MAP_PRIVATE;
+ uint8_t* addr = mmap(NULL, size, map_prot, map_flags, -1, 0);
+ if (addr == MAP_FAILED)
+ return NULL;
+ return addr;
+}
+
+static int os_mprotect(void* addr, size_t size) {
+ return mprotect(addr, size, PROT_READ | PROT_WRITE);
+}
+
+static void os_print_last_error(const char* msg) {
+ perror(msg);
+}
+#endif
+
void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
uint32_t initial_pages,
uint32_t max_pages) {
@@ -129,13 +182,17 @@ void wasm_rt_allocate_memory(wasm_rt_memory_t* memory,
}
/* Reserve 8GiB. */
- void* addr =
- mmap(NULL, 0x200000000ul, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ void* addr = os_mmap(0x200000000ul);
+
if (addr == (void*)-1) {
- perror("mmap failed");
+ os_print_last_error("os_mmap failed.");
+ abort();
+ }
+ int ret = os_mprotect(addr, byte_length);
+ if (ret != 0) {
+ os_print_last_error("os_mprotect failed.");
abort();
}
- mprotect(addr, byte_length, PROT_READ | PROT_WRITE);
memory->data = addr;
#else
memory->data = calloc(byte_length, 1);
@@ -159,7 +216,10 @@ uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
uint32_t delta_size = delta * PAGE_SIZE;
#if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX
uint8_t* new_data = memory->data;
- mprotect(new_data + old_size, delta_size, PROT_READ | PROT_WRITE);
+ int ret = os_mprotect(new_data + old_size, delta_size);
+ if (ret != 0) {
+ return (uint32_t)-1;
+ }
#else
uint8_t* new_data = realloc(memory->data, new_size);
if (new_data == NULL) {
@@ -179,6 +239,74 @@ uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) {
return old_pages;
}
+#ifdef _WIN32
+static float quiet_nanf(float x) {
+ uint32_t tmp;
+ memcpy(&tmp, &x, 4);
+ tmp |= 0x7fc00000lu;
+ memcpy(&x, &tmp, 4);
+ return x;
+}
+
+static double quiet_nan(double x) {
+ uint64_t tmp;
+ memcpy(&tmp, &x, 8);
+ tmp |= 0x7ff8000000000000llu;
+ memcpy(&x, &tmp, 8);
+ return x;
+}
+
+double wasm_rt_trunc(double x) {
+ if (isnan(x)) {
+ return quiet_nan(x);
+ }
+ return trunc(x);
+}
+
+float wasm_rt_truncf(float x) {
+ if (isnan(x)) {
+ return quiet_nanf(x);
+ }
+ return truncf(x);
+}
+
+float wasm_rt_nearbyintf(float x) {
+ if (isnan(x)) {
+ return quiet_nanf(x);
+ }
+ return nearbyintf(x);
+}
+
+double wasm_rt_nearbyint(double x) {
+ if (isnan(x)) {
+ return quiet_nan(x);
+ }
+ return nearbyint(x);
+}
+
+float wasm_rt_fabsf(float x) {
+ if (isnan(x)) {
+ uint32_t tmp;
+ memcpy(&tmp, &x, 4);
+ tmp = tmp & ~(1 << 31);
+ memcpy(&x, &tmp, 4);
+ return x;
+ }
+ return fabsf(x);
+}
+
+double wasm_rt_fabs(double x) {
+ if (isnan(x)) {
+ uint64_t tmp;
+ memcpy(&tmp, &x, 8);
+ tmp = tmp & ~(1ll << 63);
+ memcpy(&x, &tmp, 8);
+ return x;
+ }
+ return fabs(x);
+}
+#endif
+
void wasm_rt_allocate_table(wasm_rt_table_t* table,
uint32_t elements,
uint32_t max_elements) {
diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h
index 639c2406..d3c25194 100644
--- a/wasm2c/wasm-rt.h
+++ b/wasm2c/wasm-rt.h
@@ -17,12 +17,32 @@
#ifndef WASM_RT_H_
#define WASM_RT_H_
+#include <stdbool.h>
#include <stdint.h>
+#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
+#ifndef __has_builtin
+#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#if __has_builtin(__builtin_expect)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define UNLIKELY(x) (x)
+#define LIKELY(x) (x)
+#endif
+
+#if __has_builtin(__builtin_memcpy)
+#define wasm_rt_memcpy __builtin_memcpy
+#else
+#define wasm_rt_memcpy memcpy
+#endif
+
/** Maximum stack depth before trapping. This can be configured by defining
* this symbol before including wasm-rt when building the generated c files,
* for example:
@@ -68,6 +88,12 @@ extern "C" {
#endif
+#if defined(_MSC_VER)
+#define WASM_RT_NO_RETURN __declspec(noreturn)
+#else
+#define WASM_RT_NO_RETURN __attribute__((noreturn))
+#endif
+
/** Reason a trap occurred. Provide this to `wasm_rt_trap`. */
typedef enum {
WASM_RT_TRAP_NONE, /** No error. */
@@ -128,7 +154,7 @@ typedef struct {
* The result of `wasm_rt_try` will be the provided trap reason.
*
* This is typically called by the generated code, and not the embedder. */
-extern void wasm_rt_trap(wasm_rt_trap_t) __attribute__((noreturn));
+WASM_RT_NO_RETURN void wasm_rt_trap(wasm_rt_trap_t);
/**
* Return a human readable error string based on a trap type.
@@ -199,6 +225,22 @@ extern void wasm_rt_allocate_table(wasm_rt_table_t*,
/** Current call stack depth. */
extern uint32_t wasm_rt_call_stack_depth;
+#ifdef _WIN32
+float wasm_rt_truncf(float x);
+double wasm_rt_trunc(double x);
+float wasm_rt_nearbyintf(float x);
+double wasm_rt_nearbyint(double x);
+float wasm_rt_fabsf(float x);
+double wasm_rt_fabs(double x);
+#else
+#define wasm_rt_truncf(x) truncf(x)
+#define wasm_rt_trunc(x) trunc(x)
+#define wasm_rt_nearbyintf(x) nearbyintf(x)
+#define wasm_rt_nearbyint(x) nearbyint(x)
+#define wasm_rt_fabsf(x) fabsf(x)
+#define wasm_rt_fabs(x) fabs(x)
+#endif
+
#ifdef __cplusplus
}
#endif