From 54794dcf02d62ec3555ff51f2e6d4b7e0c57ba4a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Mar 2022 17:08:27 -0800 Subject: [PATCH 1/3] Add windows implementation of wasm2c runtime Split out from #1833 --- CMakeLists.txt | 19 ++- src/c-writer.cc | 12 +- src/prebuilt/wasm2c.include.c | 127 +++++++++++++---- src/wasm2c.c.tmpl | 127 +++++++++++++---- test/run-spec-wasm2c.py | 66 ++++++--- test/run-tests.py | 4 - test/spec-wasm2c-prefix.c | 4 +- test/utils.py | 7 +- wasm2c/.gitignore | 3 +- wasm2c/README.md | 7 +- wasm2c/examples/fac/Makefile | 2 +- wasm2c/wasm-rt-impl.c | 105 +++++++++++++- wasm2c/wasm-rt-os-unix.c | 190 +++++++++++++++++++++++++ wasm2c/wasm-rt-os-win.c | 256 ++++++++++++++++++++++++++++++++++ wasm2c/wasm-rt-os.h | 47 +++++++ wasm2c/wasm-rt.h | 35 ++++- 16 files changed, 909 insertions(+), 102 deletions(-) create mode 100644 wasm2c/wasm-rt-os-unix.c create mode 100644 wasm2c/wasm-rt-os-win.c create mode 100644 wasm2c/wasm-rt-os.h diff --git a/CMakeLists.txt b/CMakeLists.txt index cbf34e201..097d2250f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ # cmake_minimum_required(VERSION 3.0.0) +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum OS X deployment version") project(WABT LANGUAGES C CXX VERSION 1.0.27) include(GNUInstallDirs) @@ -361,11 +362,19 @@ set(WABT_LIBRARY_SRC add_library(wabt STATIC ${WABT_LIBRARY_SRC}) -IF (NOT WIN32) - add_library(wasm-rt-impl STATIC wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-impl.h) - install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR}) - install(FILES wasm2c/wasm-rt.h wasm2c/wasm-rt-impl.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -endif () +add_library(wasm-rt-impl SHARED STATIC + wasm2c/wasm-rt-impl.c + wasm2c/wasm-rt-os-unix.c + wasm2c/wasm-rt-os-win.c) +set_property(TARGET wasm-rt-impl PROPERTY POSITION_INDEPENDENT_CODE ON) +install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR}) +install(FILES wasm2c/wasm-rt.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +add_custom_target(wasm-rt-impl-copy-to-bin ALL + COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy $ ${WABT_SOURCE_DIR}/bin + DEPENDS wasm-rt-impl +) if (BUILD_FUZZ_TOOLS) set(FUZZ_FLAGS "-fsanitize=fuzzer,address") diff --git a/src/c-writer.cc b/src/c-writer.cc index de34cb619..e2bef4a35 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 bb23139bb..400cbf7e5 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,78 @@ 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 \n" +"\n" +"// Adapted from 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 +191,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 f6bcc941a..f7991194d 100644 --- a/src/wasm2c.c.tmpl +++ b/src/wasm2c.c.tmpl @@ -3,8 +3,6 @@ #include #include %%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,78 @@ DEFINE_STORE(i64_store8, u8, u64) DEFINE_STORE(i64_store16, u16, u64) DEFINE_STORE(i64_store32, u32, u64) +#if defined(_MSC_VER) + +#include + +// 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/test/run-spec-wasm2c.py b/test/run-spec-wasm2c.py index e8b3ea63a..2d126133d 100755 --- a/test/run-spec-wasm2c.py +++ b/test/run-spec-wasm2c.py @@ -19,6 +19,7 @@ import io import json import os +import platform import re import struct import sys @@ -30,6 +31,8 @@ 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 @@ def _Action(self, command): 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: @@ -443,14 +471,16 @@ def main(args): o_filenames.append(Compile(cc, c_filename, out_dir, includes, defines)) if options.compile: - # Compile wasm-rt-impl. - wasm_rt_impl_c = os.path.join(options.wasmrt_dir, 'wasm-rt-impl.c') - o_filenames.append(Compile(cc, wasm_rt_impl_c, out_dir, includes)) - # 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 = ['/libpath:' + options.bindir, 'wasm-rt-impl.lib'] + else: + exe_ext = '' + libs = ['-L' + options.bindir, '-lwasm-rt-impl', '-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 370f15f9b..f0873aaf1 100755 --- a/test/run-tests.py +++ b/test/run-tests.py @@ -160,10 +160,6 @@ ] } -# 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 df0f1d443..f1d2d1e97 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 791d0d104..20bac49c2 100644 --- a/test/utils.py +++ b/test/utils.py @@ -19,6 +19,7 @@ import os import json import shutil +import shlex import signal import subprocess import sys @@ -52,12 +53,12 @@ def _ForwardHandle(self, forward): 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 @@ def _RunWithArgsInternal(self, *args, **kwargs): 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/.gitignore b/wasm2c/.gitignore index 5d665f068..1b74b1559 100644 --- a/wasm2c/.gitignore +++ b/wasm2c/.gitignore @@ -1,5 +1,4 @@ -wasm-rt-impl.o -examples/**/*.o +*.o examples/fac/fac examples/rot13/rot13 examples/rot13/rot13.c diff --git a/wasm2c/README.md b/wasm2c/README.md index 43af5e40c..a586b4218 100644 --- a/wasm2c/README.md +++ b/wasm2c/README.md @@ -90,11 +90,12 @@ int main(int argc, char** argv) { ``` To compile the executable, we need to use `main.c` and the generated `fac.c`. -We'll also include `wasm-rt-impl.c` which has implementations of the various -`wasm_rt_*` functions used by `fac.c` and `fac.h`. +We'll also include `wasm-rt-impl.c`, `wasm-rt-os-unix.c` and `wasm-rt-os-win.c` +which include some OS specific initialization which has implementations of the +various `wasm_rt_*` functions used by `fac.c` and `fac.h`. ```sh -$ cc -o fac main.c fac.c wasm-rt-impl.c +$ cc -o fac main.c fac.c wasm-rt-impl.c wasm-rt-os-unix.c wasm-rt-os-win.c ``` Now let's test it out! diff --git a/wasm2c/examples/fac/Makefile b/wasm2c/examples/fac/Makefile index caf32e245..334035f2f 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 ../../wasm-rt-os-unix.o -lm fac.wasm: fac.wat ../../../bin/wat2wasm ../../../bin/wat2wasm $< -o $@ diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c index d11cd7e73..c8b5d5ce8 100644 --- a/wasm2c/wasm-rt-impl.c +++ b/wasm2c/wasm-rt-impl.c @@ -15,8 +15,10 @@ */ #include "wasm-rt-impl.h" +#include "wasm-rt-os.h" #include +#include #include #include #include @@ -108,7 +110,10 @@ static void signal_handler(int sig, siginfo_t* si, void* unused) { } #endif -void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, +// Heap aligned to 4GB +#define WASM_HEAP_ALIGNMENT 0x100000000ull + +bool wasm_rt_allocate_memory(wasm_rt_memory_t* memory, uint32_t initial_pages, uint32_t max_pages) { uint32_t byte_length = initial_pages * PAGE_SIZE; @@ -130,12 +135,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); + os_mmap_aligned(NULL, 0x200000000ul, MMAP_PROT_NONE, MMAP_MAP_NONE, + WASM_HEAP_ALIGNMENT, /*alignment_offset=*/0); + if (addr == (void*)-1) { - perror("mmap failed"); + os_print_last_error("os_mmap failed."); abort(); } - mprotect(addr, byte_length, PROT_READ | PROT_WRITE); + int ret = os_mmap_commit(addr, byte_length, MMAP_PROT_READ | MMAP_PROT_WRITE); + if (ret != 0) { + return false; + } memory->data = addr; #else memory->data = calloc(byte_length, 1); @@ -143,6 +153,7 @@ void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, memory->size = byte_length; memory->pages = initial_pages; memory->max_pages = max_pages; + return true; } uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) { @@ -159,7 +170,11 @@ 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_mmap_commit(new_data + old_size, delta_size, + MMAP_PROT_READ | MMAP_PROT_WRITE); + if (ret != 0) { + return (uint32_t)-1; + } #else uint8_t* new_data = realloc(memory->data, new_size); if (new_data == NULL) { @@ -179,6 +194,86 @@ 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; +} +#endif + +double wasm_rt_trunc(double x) { +#ifdef _WIN32 + if (isnan(x)) + return quiet_nan(x); +#endif + return trunc(x); +} + +float wasm_rt_truncf(float x) { +#ifdef _WIN32 + if (isnan(x)) + return quiet_nanf(x); +#endif + return truncf(x); +} + +float wasm_rt_nearbyintf(float x) { +#ifdef _WIN32 + if (isnan(x)) + return quiet_nanf(x); +#endif + return nearbyintf(x); +} + +double wasm_rt_nearbyint(double x) { +#ifdef _WIN32 + if (isnan(x)) + return quiet_nan(x); +#endif + return nearbyint(x); +} + +float wasm_rt_fabsf(float x) { +#ifdef _WIN32 + if (isnan(x)) { + uint32_t tmp; + memcpy(&tmp, &x, 4); + if (tmp & (1 << 31)) { + tmp = tmp & ~(1 << 31); + memcpy(&x, &tmp, 4); + } + return x; + } +#endif + return fabsf(x); +} + +double wasm_rt_fabs(double x) { +#ifdef _WIN32 + if (isnan(x)) { + uint64_t tmp; + memcpy(&tmp, &x, 8); + if (tmp & (1ll << 63)) { + tmp = tmp & ~(1ll << 63); + memcpy(&x, &tmp, 8); + } + return x; + } +#endif + return fabs(x); +} + void wasm_rt_allocate_table(wasm_rt_table_t* table, uint32_t elements, uint32_t max_elements) { diff --git a/wasm2c/wasm-rt-os-unix.c b/wasm2c/wasm-rt-os-unix.c new file mode 100644 index 000000000..f981c4be2 --- /dev/null +++ b/wasm2c/wasm-rt-os-unix.c @@ -0,0 +1,190 @@ +// Based on +// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD +// Check for any posix or unix OS +#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__))) + +#include "wasm-rt-os.h" +#include "wasm-rt.h" + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) && defined(__MACH__) +// Macs priors to OSX 10.12 don't have the clock functions. So we will use mac +// specific options +#include +#include +#endif +#include +#include + +#ifdef VERBOSE_LOGGING +#define VERBOSE_LOG(...) \ + { printf(__VA_ARGS__); } +#else +#define VERBOSE_LOG(...) +#endif + +size_t os_getpagesize() { + return getpagesize(); +} + +void* os_mmap(void* hint, size_t size, int prot, int flags) { + int map_prot = PROT_NONE; + int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; + uint64_t request_size, page_size; + uint8_t* addr; + + page_size = (uint64_t)os_getpagesize(); + request_size = (size + page_size - 1) & ~(page_size - 1); + + if ((size_t)request_size < size) + /* integer overflow */ + return NULL; + + if (request_size > 16 * (uint64_t)UINT32_MAX) + /* At most 16 G is allowed */ + return NULL; + + if (prot & MMAP_PROT_READ) + map_prot |= PROT_READ; + + if (prot & MMAP_PROT_WRITE) + map_prot |= PROT_WRITE; + + if (prot & MMAP_PROT_EXEC) + map_prot |= PROT_EXEC; + +#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) +#ifndef __APPLE__ + if (flags & MMAP_MAP_32BIT) + map_flags |= MAP_32BIT; +#endif +#endif + + if (flags & MMAP_MAP_FIXED) + map_flags |= MAP_FIXED; + + addr = mmap(hint, request_size, map_prot, map_flags, -1, 0); + + if (addr == MAP_FAILED) + return NULL; + + return addr; +} + +void os_munmap(void* addr, size_t size) { + uint64_t page_size = (uint64_t)os_getpagesize(); + uint64_t request_size = (size + page_size - 1) & ~(page_size - 1); + + if (addr) { + if (munmap(addr, request_size)) { + printf("os_munmap error addr:%p, size:0x%" PRIx64 ", errno:%d\n", addr, + request_size, errno); + } + } +} + +int os_mprotect(void* addr, size_t size, int prot) { + int map_prot = PROT_NONE; + uint64_t page_size = (uint64_t)os_getpagesize(); + uint64_t request_size = (size + page_size - 1) & ~(page_size - 1); + + if (!addr) + return 0; + + if (prot & MMAP_PROT_READ) + map_prot |= PROT_READ; + + if (prot & MMAP_PROT_WRITE) + map_prot |= PROT_WRITE; + + if (prot & MMAP_PROT_EXEC) + map_prot |= PROT_EXEC; + + return mprotect(addr, request_size, map_prot); +} + +void* os_mmap_aligned(void* addr, + size_t requested_length, + int prot, + int flags, + size_t alignment, + size_t alignment_offset) { + size_t padded_length = requested_length + alignment + alignment_offset; + uintptr_t unaligned = (uintptr_t)os_mmap(addr, padded_length, prot, flags); + + VERBOSE_LOG( + "os_mmap_aligned: alignment:%llu, alignment_offset:%llu, " + "requested_length:%llu, padded_length: %llu, initial mapping: %p\n", + (unsigned long long)alignment, (unsigned long long)alignment_offset, + (unsigned long long)requested_length, (unsigned long long)padded_length, + (void*)unaligned); + + if (!unaligned) { + return (void*)unaligned; + } + + // Round up the next address that has addr % alignment = 0 + const size_t alignment_corrected = alignment == 0 ? 1 : alignment; + uintptr_t aligned_nonoffset = + (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1); + + // Currently offset 0 is aligned according to alignment + // Alignment needs to be enforced at the given offset + uintptr_t aligned = 0; + if ((aligned_nonoffset - alignment_offset) >= unaligned) { + aligned = aligned_nonoffset - alignment_offset; + } else { + aligned = aligned_nonoffset - alignment_offset + alignment; + } + + // Sanity check + if (aligned < unaligned || + (aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) || + (aligned + alignment_offset) % alignment_corrected != 0) { + VERBOSE_LOG("os_mmap_aligned: sanity check fail. aligned: %p\n", + (void*)aligned); + os_munmap((void*)unaligned, padded_length); + return NULL; + } + + { + size_t unused_front = aligned - unaligned; + if (unused_front != 0) { + os_munmap((void*)unaligned, unused_front); + } + } + + { + size_t unused_back = + (unaligned + (padded_length - 1)) - (aligned + (requested_length - 1)); + if (unused_back != 0) { + os_munmap((void*)(aligned + requested_length), unused_back); + } + } + + VERBOSE_LOG("os_mmap_aligned: final mapping: %p\n", (void*)aligned); + return (void*)aligned; +} + +int os_mmap_commit(void* curr_heap_end_pointer, + size_t expanded_size, + int prot) { + return os_mprotect(curr_heap_end_pointer, expanded_size, prot); +} + +void os_print_last_error(const char* msg) { + perror(msg); +} + +#undef VERBOSE_LOG + +#else +// https://stackoverflow.com/questions/26541150/warning-iso-c-forbids-an-empty-translation-unit +typedef int make_iso_compilers_happy; +#endif diff --git a/wasm2c/wasm-rt-os-win.c b/wasm2c/wasm-rt-os-win.c new file mode 100644 index 000000000..67cf84533 --- /dev/null +++ b/wasm2c/wasm-rt-os-win.c @@ -0,0 +1,256 @@ +// Based on +// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD +// Check for windows (non cygwin) environment +#if defined(_WIN32) + +#include "wasm-rt-os.h" +#include "wasm-rt.h" + +#include +#include +#include +#include +#include + +#include + +#ifdef VERBOSE_LOGGING +#define VERBOSE_LOG(...) \ + { printf(__VA_ARGS__); } +#else +#define VERBOSE_LOG(...) +#endif + +#define DONT_USE_VIRTUAL_ALLOC2 + +size_t os_getpagesize() { + SYSTEM_INFO S; + GetNativeSystemInfo(&S); + return S.dwPageSize; +} + +static void* win_mmap(void* hint, + size_t size, + int prot, + int flags, + DWORD alloc_flag) { + DWORD flProtect = PAGE_NOACCESS; + size_t request_size, page_size; + void* addr; + + page_size = os_getpagesize(); + request_size = (size + page_size - 1) & ~(page_size - 1); + + if (request_size < size) + /* integer overflow */ + return NULL; + + if (request_size == 0) + request_size = page_size; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_EXECUTE_READ; + } else if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_READWRITE; + else if (prot & MMAP_PROT_READ) + flProtect = PAGE_READONLY; + + addr = VirtualAlloc((LPVOID)hint, request_size, alloc_flag, flProtect); + return addr; +} + +void* os_mmap(void* hint, size_t size, int prot, int flags) { + DWORD alloc_flag = MEM_RESERVE | MEM_COMMIT; + return win_mmap(hint, size, prot, flags, alloc_flag); +} + +#ifndef DONT_USE_VIRTUAL_ALLOC2 +static void* win_mmap_aligned(void* hint, + size_t size, + int prot, + int flags, + size_t pow2alignment) { + DWORD alloc_flag = MEM_RESERVE | MEM_COMMIT; + DWORD flProtect = PAGE_NOACCESS; + size_t request_size, page_size; + void* addr; + + page_size = os_getpagesize(); + request_size = (size + page_size - 1) & ~(page_size - 1); + + if (request_size < size) + /* integer overflow */ + return NULL; + + if (request_size == 0) + request_size = page_size; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_EXECUTE_READ; + } else if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_READWRITE; + else if (prot & MMAP_PROT_READ) + flProtect = PAGE_READONLY; + + MEM_ADDRESS_REQUIREMENTS addressReqs = {0}; + MEM_EXTENDED_PARAMETER param = {0}; + + addressReqs.Alignment = pow2alignment; + addressReqs.HighestEndingAddress = 0; + addressReqs.LowestStartingAddress = 0; + + param.Type = MemExtendedParameterAddressRequirements; + param.Pointer = &addressReqs; + + addr = VirtualAlloc2(0, (LPVOID)addr, request_size, alloc_flag, flProtect, + ¶m, 1); + return addr; +} +#endif + +void os_munmap(void* addr, size_t size) { + DWORD alloc_flag = MEM_RELEASE; + if (addr) { + if (VirtualFree(addr, 0, alloc_flag) == 0) { + size_t page_size = os_getpagesize(); + size_t request_size = (size + page_size - 1) & ~(page_size - 1); + int64_t curr_err = errno; + printf("os_munmap error addr:%p, size:0x%zx, errno:%" PRId64 "\n", addr, + request_size, curr_err); + } + } +} + +int os_mprotect(void* addr, size_t size, int prot) { + DWORD flProtect = PAGE_NOACCESS; + + if (!addr) + return 0; + + if (prot & MMAP_PROT_EXEC) { + if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_EXECUTE_READ; + } else if (prot & MMAP_PROT_WRITE) + flProtect = PAGE_READWRITE; + else if (prot & MMAP_PROT_READ) + flProtect = PAGE_READONLY; + + DWORD old; + BOOL succeeded = VirtualProtect((LPVOID)addr, size, flProtect, &old); + return succeeded ? 0 : -1; +} + +#ifndef DONT_USE_VIRTUAL_ALLOC2 +static int IsPowerOfTwoOrZero(size_t x) { + return (x & (x - 1)) == 0; +} +#endif + +void* os_mmap_aligned(void* addr, + size_t requested_length, + int prot, + int flags, + size_t alignment, + size_t alignment_offset) { +#ifndef DONT_USE_VIRTUAL_ALLOC2 + if (IsPowerOfTwoOrZero(alignment) && alignment_offset == 0) { + return win_mmap_aligned(addr, requested_length, prot, flags, alignment); + } else +#endif + { + size_t padded_length = requested_length + alignment + alignment_offset; + uintptr_t unaligned = + (uintptr_t)win_mmap(addr, padded_length, prot, flags, MEM_RESERVE); + + VERBOSE_LOG( + "os_mmap_aligned: alignment:%llu, alignment_offset:%llu, " + "requested_length:%llu, padded_length: %llu, initial mapping: %p\n", + (unsigned long long)alignment, (unsigned long long)alignment_offset, + (unsigned long long)requested_length, (unsigned long long)padded_length, + (void*)unaligned); + + if (!unaligned) { + return (void*)unaligned; + } + + // Round up the next address that has addr % alignment = 0 + const size_t alignment_corrected = alignment == 0 ? 1 : alignment; + uintptr_t aligned_nonoffset = + (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1); + + // Currently offset 0 is aligned according to alignment + // Alignment needs to be enforced at the given offset + uintptr_t aligned = 0; + if ((aligned_nonoffset - alignment_offset) >= unaligned) { + aligned = aligned_nonoffset - alignment_offset; + } else { + aligned = aligned_nonoffset - alignment_offset + alignment; + } + + if (aligned == unaligned && padded_length == requested_length) { + return (void*)aligned; + } + + // Sanity check + if (aligned < unaligned || + (aligned + (requested_length - 1)) > + (unaligned + (padded_length - 1)) || + (aligned + alignment_offset) % alignment_corrected != 0) { + VERBOSE_LOG("os_mmap_aligned: sanity check fail. aligned: %p\n", + (void*)aligned); + os_munmap((void*)unaligned, padded_length); + return NULL; + } + + // windows does not support partial unmapping, so unmap and remap + os_munmap((void*)unaligned, padded_length); + aligned = (uintptr_t)win_mmap((void*)aligned, requested_length, prot, flags, + MEM_RESERVE); + VERBOSE_LOG("os_mmap_aligned: final mapping: %p\n", (void*)aligned); + return (void*)aligned; + } +} + +int os_mmap_commit(void* curr_heap_end_pointer, + size_t expanded_size, + int prot) { + uintptr_t addr = (uintptr_t)win_mmap(curr_heap_end_pointer, expanded_size, + prot, MMAP_MAP_NONE, MEM_COMMIT); + int ret = addr ? 0 : -1; + return ret; +} + +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; + // Copy the error message into a std::string. + printf("%s. %s\n", msg, messageBuffer); + LocalFree(messageBuffer); + } else { + printf("%s. No error code.\n", msg); + } +} + +#undef VERBOSE_LOG +#undef DONT_USE_VIRTUAL_ALLOC2 + +#else +// https://stackoverflow.com/questions/26541150/warning-iso-c-forbids-an-empty-translation-unit +typedef int make_iso_compilers_happy; +#endif diff --git a/wasm2c/wasm-rt-os.h b/wasm2c/wasm-rt-os.h new file mode 100644 index 000000000..3b9ee5d75 --- /dev/null +++ b/wasm2c/wasm-rt-os.h @@ -0,0 +1,47 @@ +#ifndef WASM_RT_OS_H_ +#define WASM_RT_OS_H_ + +#include +#include +#include + +enum { + MMAP_PROT_NONE = 0, + MMAP_PROT_READ = 1, + MMAP_PROT_WRITE = 2, + MMAP_PROT_EXEC = 4 +}; + +/* Memory map flags */ +enum { + MMAP_MAP_NONE = 0, + /* Put the mapping into 0 to 2 G, supported only on x86_64 */ + MMAP_MAP_32BIT = 1, + /* Don't interpret addr as a hint: place the mapping at exactly + that address. */ + MMAP_MAP_FIXED = 2 +}; + +size_t os_getpagesize(); +// Try allocating Memory space. +// Returns pointer to allocated region on success, 0 on failure. +void* os_mmap(void* hint, size_t size, int prot, int flags); +void os_munmap(void* addr, size_t size); +// Set the permissions of the memory region. +// Returns 0 on success, non zero on failure. +int os_mprotect(void* addr, size_t size, int prot); +// Like mmap but returns an aligned region +void* os_mmap_aligned(void* addr, + size_t requested_length, + int prot, + int flags, + size_t alignment, + size_t alignment_offset); +// Commits and sets the permissions on an already allocated memory region +// Returns 0 on success, non zero on failure. +int os_mmap_commit(void* curr_heap_end_pointer, size_t expanded_size, int prot); + +// print the error message +void os_print_last_error(const char* msg); + +#endif diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h index 639c2406e..b4a2ef7e1 100644 --- a/wasm2c/wasm-rt.h +++ b/wasm2c/wasm-rt.h @@ -17,12 +17,32 @@ #ifndef WASM_RT_H_ #define WASM_RT_H_ +#include #include +#include #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,13 @@ extern void wasm_rt_allocate_table(wasm_rt_table_t*, /** Current call stack depth. */ extern uint32_t wasm_rt_call_stack_depth; +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); + #ifdef __cplusplus } #endif From 96eef8f28961a0c9f78bd2e890d7ad0cb318382a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 9 Mar 2022 12:01:20 -0800 Subject: [PATCH 2/3] simplify --- CMakeLists.txt | 19 +-- src/prebuilt/wasm2c.include.c | 33 ++--- src/wasm2c.c.tmpl | 33 ++--- test/run-spec-wasm2c.py | 8 +- wasm2c/.gitignore | 3 +- wasm2c/README.md | 7 +- wasm2c/examples/fac/Makefile | 2 +- wasm2c/examples/fac/fac.c | 127 ++++++++++++---- wasm2c/examples/rot13/Makefile | 2 +- wasm2c/wasm-rt-impl.c | 98 +++++++++---- wasm2c/wasm-rt-os-unix.c | 190 ------------------------ wasm2c/wasm-rt-os-win.c | 256 --------------------------------- wasm2c/wasm-rt-os.h | 47 ------ wasm2c/wasm-rt.h | 9 ++ 14 files changed, 230 insertions(+), 604 deletions(-) delete mode 100644 wasm2c/wasm-rt-os-unix.c delete mode 100644 wasm2c/wasm-rt-os-win.c delete mode 100644 wasm2c/wasm-rt-os.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 097d2250f..cbf34e201 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ # cmake_minimum_required(VERSION 3.0.0) -set(CMAKE_OSX_DEPLOYMENT_TARGET "10.11" CACHE STRING "Minimum OS X deployment version") project(WABT LANGUAGES C CXX VERSION 1.0.27) include(GNUInstallDirs) @@ -362,19 +361,11 @@ set(WABT_LIBRARY_SRC add_library(wabt STATIC ${WABT_LIBRARY_SRC}) -add_library(wasm-rt-impl SHARED STATIC - wasm2c/wasm-rt-impl.c - wasm2c/wasm-rt-os-unix.c - wasm2c/wasm-rt-os-win.c) -set_property(TARGET wasm-rt-impl PROPERTY POSITION_INDEPENDENT_CODE ON) -install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES wasm2c/wasm-rt.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -add_custom_target(wasm-rt-impl-copy-to-bin ALL - COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin - COMMAND ${CMAKE_COMMAND} -E copy $ ${WABT_SOURCE_DIR}/bin - DEPENDS wasm-rt-impl -) +IF (NOT WIN32) + add_library(wasm-rt-impl STATIC wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-impl.h) + install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES wasm2c/wasm-rt.h wasm2c/wasm-rt-impl.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif () if (BUILD_FUZZ_TOOLS) set(FUZZ_FLAGS "-fsanitize=fuzzer,address") diff --git a/src/prebuilt/wasm2c.include.c b/src/prebuilt/wasm2c.include.c index 400cbf7e5..cf5112122 100644 --- a/src/prebuilt/wasm2c.include.c +++ b/src/prebuilt/wasm2c.include.c @@ -116,20 +116,21 @@ const char SECTION_NAME(declarations)[] = "\n" "#include \n" "\n" -"// Adapted from https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.h\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" +" 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" +" 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" @@ -148,15 +149,15 @@ const char SECTION_NAME(declarations)[] = " }\n" " unsigned long r = 0;\n" "#if defined(_M_AMD64) || defined(_M_ARM)\n" -" _BitScanForward64(&r, v);\n" -" return (int) r;\n" +" _BitScanForward64(&r, v);\n" +" return (int) r;\n" "#else\n" -" if (_BitScanForward(&r, (unsigned int) (v))) {\n" -" return (int) (r);\n" -" }\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" +" _BitScanForward(&r, (unsigned int) (v >> 32));\n" +" return (int) (r + 32);\n" "#endif\n" "}\n" "\n" diff --git a/src/wasm2c.c.tmpl b/src/wasm2c.c.tmpl index f7991194d..d7ba68313 100644 --- a/src/wasm2c.c.tmpl +++ b/src/wasm2c.c.tmpl @@ -113,20 +113,21 @@ DEFINE_STORE(i64_store32, u32, u64) #include -// Adapted from https://github.com/nemequ/portable-snippets/blob/master/builtin/builtin.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; - } + 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; - } + if (_BitScanReverse(&r, (unsigned long) (v >> 32))) { + return 31 - r; + } else if (_BitScanReverse(&r, (unsigned long) v)) { + return 63 - r; + } #endif return 64; } @@ -145,15 +146,15 @@ static inline int I64_CTZ(unsigned long long v) { } unsigned long r = 0; #if defined(_M_AMD64) || defined(_M_ARM) - _BitScanForward64(&r, v); - return (int) r; + _BitScanForward64(&r, v); + return (int) r; #else - if (_BitScanForward(&r, (unsigned int) (v))) { - return (int) (r); - } + if (_BitScanForward(&r, (unsigned int) (v))) { + return (int) (r); + } - _BitScanForward(&r, (unsigned int) (v >> 32)); - return (int) (r + 32); + _BitScanForward(&r, (unsigned int) (v >> 32)); + return (int) (r + 32); #endif } diff --git a/test/run-spec-wasm2c.py b/test/run-spec-wasm2c.py index 2d126133d..a6ad16fc0 100755 --- a/test/run-spec-wasm2c.py +++ b/test/run-spec-wasm2c.py @@ -471,14 +471,18 @@ def main(args): o_filenames.append(Compile(cc, c_filename, out_dir, includes, defines)) if options.compile: + # Compile wasm-rt-impl. + wasm_rt_impl_c = os.path.join(options.wasmrt_dir, 'wasm-rt-impl.c') + o_filenames.append(Compile(cc, wasm_rt_impl_c, out_dir, includes)) + # Compile and link -main test run entry point o_filenames.append(Compile(cc, main_filename, out_dir, includes)) if IS_WINDOWS: exe_ext = '.exe' - libs = ['/libpath:' + options.bindir, 'wasm-rt-impl.lib'] + libs = [] else: exe_ext = '' - libs = ['-L' + options.bindir, '-lwasm-rt-impl', '-lm'] + libs = ['-lm'] main_exe = utils.ChangeExt(json_file_path, exe_ext) Link(cc, o_filenames, main_exe, *libs) diff --git a/wasm2c/.gitignore b/wasm2c/.gitignore index 1b74b1559..5d665f068 100644 --- a/wasm2c/.gitignore +++ b/wasm2c/.gitignore @@ -1,4 +1,5 @@ -*.o +wasm-rt-impl.o +examples/**/*.o examples/fac/fac examples/rot13/rot13 examples/rot13/rot13.c diff --git a/wasm2c/README.md b/wasm2c/README.md index a586b4218..43af5e40c 100644 --- a/wasm2c/README.md +++ b/wasm2c/README.md @@ -90,12 +90,11 @@ int main(int argc, char** argv) { ``` To compile the executable, we need to use `main.c` and the generated `fac.c`. -We'll also include `wasm-rt-impl.c`, `wasm-rt-os-unix.c` and `wasm-rt-os-win.c` -which include some OS specific initialization which has implementations of the -various `wasm_rt_*` functions used by `fac.c` and `fac.h`. +We'll also include `wasm-rt-impl.c` which has implementations of the various +`wasm_rt_*` functions used by `fac.c` and `fac.h`. ```sh -$ cc -o fac main.c fac.c wasm-rt-impl.c wasm-rt-os-unix.c wasm-rt-os-win.c +$ cc -o fac main.c fac.c wasm-rt-impl.c ``` Now let's test it out! diff --git a/wasm2c/examples/fac/Makefile b/wasm2c/examples/fac/Makefile index 334035f2f..a5179a71f 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 ../../wasm-rt-os-unix.o -lm +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 eeb28d9fb..9ac9522c0 100644 --- a/wasm2c/examples/fac/fac.c +++ b/wasm2c/examples/fac/fac.c @@ -3,8 +3,6 @@ #include #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 + +// 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 b58db6bee..5e5f5205c 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 c8b5d5ce8..86e14adf8 100644 --- a/wasm2c/wasm-rt-impl.c +++ b/wasm2c/wasm-rt-impl.c @@ -15,7 +15,6 @@ */ #include "wasm-rt-impl.h" -#include "wasm-rt-os.h" #include #include @@ -28,10 +27,15 @@ #if WASM_RT_MEMCHECK_SIGNAL_HANDLER_POSIX #include -#include #include #endif +#ifdef _WIN32 +#include +#else +#include +#endif + #define PAGE_SIZE 65536 typedef struct FuncType { @@ -110,10 +114,55 @@ static void signal_handler(int sig, siginfo_t* si, void* unused) { } #endif -// Heap aligned to 4GB -#define WASM_HEAP_ALIGNMENT 0x100000000ull +#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; + // Copy the error message into a std::string. + 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); +} -bool wasm_rt_allocate_memory(wasm_rt_memory_t* memory, +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) { uint32_t byte_length = initial_pages * PAGE_SIZE; @@ -134,17 +183,16 @@ bool wasm_rt_allocate_memory(wasm_rt_memory_t* memory, } /* Reserve 8GiB. */ - void* addr = - os_mmap_aligned(NULL, 0x200000000ul, MMAP_PROT_NONE, MMAP_MAP_NONE, - WASM_HEAP_ALIGNMENT, /*alignment_offset=*/0); + void* addr = os_mmap(0x200000000ul); if (addr == (void*)-1) { os_print_last_error("os_mmap failed."); abort(); } - int ret = os_mmap_commit(addr, byte_length, MMAP_PROT_READ | MMAP_PROT_WRITE); + int ret = os_mprotect(addr, byte_length); if (ret != 0) { - return false; + os_print_last_error("os_mprotect failed."); + abort(); } memory->data = addr; #else @@ -153,7 +201,6 @@ bool wasm_rt_allocate_memory(wasm_rt_memory_t* memory, memory->size = byte_length; memory->pages = initial_pages; memory->max_pages = max_pages; - return true; } uint32_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint32_t delta) { @@ -170,8 +217,7 @@ 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; - int ret = os_mmap_commit(new_data + old_size, delta_size, - MMAP_PROT_READ | MMAP_PROT_WRITE); + int ret = os_mprotect(new_data + old_size, delta_size); if (ret != 0) { return (uint32_t)-1; } @@ -210,42 +256,36 @@ static double quiet_nan(double x) { memcpy(&x, &tmp, 8); return x; } -#endif double wasm_rt_trunc(double x) { -#ifdef _WIN32 - if (isnan(x)) + if (isnan(x)) { return quiet_nan(x); -#endif + } return trunc(x); } float wasm_rt_truncf(float x) { -#ifdef _WIN32 - if (isnan(x)) + if (isnan(x)) { return quiet_nanf(x); -#endif + } return truncf(x); } float wasm_rt_nearbyintf(float x) { -#ifdef _WIN32 - if (isnan(x)) + if (isnan(x)) { return quiet_nanf(x); -#endif + } return nearbyintf(x); } double wasm_rt_nearbyint(double x) { -#ifdef _WIN32 - if (isnan(x)) + if (isnan(x)) { return quiet_nan(x); -#endif + } return nearbyint(x); } float wasm_rt_fabsf(float x) { -#ifdef _WIN32 if (isnan(x)) { uint32_t tmp; memcpy(&tmp, &x, 4); @@ -255,12 +295,10 @@ float wasm_rt_fabsf(float x) { } return x; } -#endif return fabsf(x); } double wasm_rt_fabs(double x) { -#ifdef _WIN32 if (isnan(x)) { uint64_t tmp; memcpy(&tmp, &x, 8); @@ -270,9 +308,9 @@ double wasm_rt_fabs(double x) { } return x; } -#endif return fabs(x); } +#endif void wasm_rt_allocate_table(wasm_rt_table_t* table, uint32_t elements, diff --git a/wasm2c/wasm-rt-os-unix.c b/wasm2c/wasm-rt-os-unix.c deleted file mode 100644 index f981c4be2..000000000 --- a/wasm2c/wasm-rt-os-unix.c +++ /dev/null @@ -1,190 +0,0 @@ -// Based on -// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD -// Check for any posix or unix OS -#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || \ - (defined(__APPLE__) && defined(__MACH__))) - -#include "wasm-rt-os.h" -#include "wasm-rt.h" - -#include -#include -#include -#include -#include - -#if defined(__APPLE__) && defined(__MACH__) -// Macs priors to OSX 10.12 don't have the clock functions. So we will use mac -// specific options -#include -#include -#endif -#include -#include - -#ifdef VERBOSE_LOGGING -#define VERBOSE_LOG(...) \ - { printf(__VA_ARGS__); } -#else -#define VERBOSE_LOG(...) -#endif - -size_t os_getpagesize() { - return getpagesize(); -} - -void* os_mmap(void* hint, size_t size, int prot, int flags) { - int map_prot = PROT_NONE; - int map_flags = MAP_ANONYMOUS | MAP_PRIVATE; - uint64_t request_size, page_size; - uint8_t* addr; - - page_size = (uint64_t)os_getpagesize(); - request_size = (size + page_size - 1) & ~(page_size - 1); - - if ((size_t)request_size < size) - /* integer overflow */ - return NULL; - - if (request_size > 16 * (uint64_t)UINT32_MAX) - /* At most 16 G is allowed */ - return NULL; - - if (prot & MMAP_PROT_READ) - map_prot |= PROT_READ; - - if (prot & MMAP_PROT_WRITE) - map_prot |= PROT_WRITE; - - if (prot & MMAP_PROT_EXEC) - map_prot |= PROT_EXEC; - -#if defined(BUILD_TARGET_X86_64) || defined(BUILD_TARGET_AMD_64) -#ifndef __APPLE__ - if (flags & MMAP_MAP_32BIT) - map_flags |= MAP_32BIT; -#endif -#endif - - if (flags & MMAP_MAP_FIXED) - map_flags |= MAP_FIXED; - - addr = mmap(hint, request_size, map_prot, map_flags, -1, 0); - - if (addr == MAP_FAILED) - return NULL; - - return addr; -} - -void os_munmap(void* addr, size_t size) { - uint64_t page_size = (uint64_t)os_getpagesize(); - uint64_t request_size = (size + page_size - 1) & ~(page_size - 1); - - if (addr) { - if (munmap(addr, request_size)) { - printf("os_munmap error addr:%p, size:0x%" PRIx64 ", errno:%d\n", addr, - request_size, errno); - } - } -} - -int os_mprotect(void* addr, size_t size, int prot) { - int map_prot = PROT_NONE; - uint64_t page_size = (uint64_t)os_getpagesize(); - uint64_t request_size = (size + page_size - 1) & ~(page_size - 1); - - if (!addr) - return 0; - - if (prot & MMAP_PROT_READ) - map_prot |= PROT_READ; - - if (prot & MMAP_PROT_WRITE) - map_prot |= PROT_WRITE; - - if (prot & MMAP_PROT_EXEC) - map_prot |= PROT_EXEC; - - return mprotect(addr, request_size, map_prot); -} - -void* os_mmap_aligned(void* addr, - size_t requested_length, - int prot, - int flags, - size_t alignment, - size_t alignment_offset) { - size_t padded_length = requested_length + alignment + alignment_offset; - uintptr_t unaligned = (uintptr_t)os_mmap(addr, padded_length, prot, flags); - - VERBOSE_LOG( - "os_mmap_aligned: alignment:%llu, alignment_offset:%llu, " - "requested_length:%llu, padded_length: %llu, initial mapping: %p\n", - (unsigned long long)alignment, (unsigned long long)alignment_offset, - (unsigned long long)requested_length, (unsigned long long)padded_length, - (void*)unaligned); - - if (!unaligned) { - return (void*)unaligned; - } - - // Round up the next address that has addr % alignment = 0 - const size_t alignment_corrected = alignment == 0 ? 1 : alignment; - uintptr_t aligned_nonoffset = - (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1); - - // Currently offset 0 is aligned according to alignment - // Alignment needs to be enforced at the given offset - uintptr_t aligned = 0; - if ((aligned_nonoffset - alignment_offset) >= unaligned) { - aligned = aligned_nonoffset - alignment_offset; - } else { - aligned = aligned_nonoffset - alignment_offset + alignment; - } - - // Sanity check - if (aligned < unaligned || - (aligned + (requested_length - 1)) > (unaligned + (padded_length - 1)) || - (aligned + alignment_offset) % alignment_corrected != 0) { - VERBOSE_LOG("os_mmap_aligned: sanity check fail. aligned: %p\n", - (void*)aligned); - os_munmap((void*)unaligned, padded_length); - return NULL; - } - - { - size_t unused_front = aligned - unaligned; - if (unused_front != 0) { - os_munmap((void*)unaligned, unused_front); - } - } - - { - size_t unused_back = - (unaligned + (padded_length - 1)) - (aligned + (requested_length - 1)); - if (unused_back != 0) { - os_munmap((void*)(aligned + requested_length), unused_back); - } - } - - VERBOSE_LOG("os_mmap_aligned: final mapping: %p\n", (void*)aligned); - return (void*)aligned; -} - -int os_mmap_commit(void* curr_heap_end_pointer, - size_t expanded_size, - int prot) { - return os_mprotect(curr_heap_end_pointer, expanded_size, prot); -} - -void os_print_last_error(const char* msg) { - perror(msg); -} - -#undef VERBOSE_LOG - -#else -// https://stackoverflow.com/questions/26541150/warning-iso-c-forbids-an-empty-translation-unit -typedef int make_iso_compilers_happy; -#endif diff --git a/wasm2c/wasm-rt-os-win.c b/wasm2c/wasm-rt-os-win.c deleted file mode 100644 index 67cf84533..000000000 --- a/wasm2c/wasm-rt-os-win.c +++ /dev/null @@ -1,256 +0,0 @@ -// Based on -// https://web.archive.org/web/20191012035921/http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system#BSD -// Check for windows (non cygwin) environment -#if defined(_WIN32) - -#include "wasm-rt-os.h" -#include "wasm-rt.h" - -#include -#include -#include -#include -#include - -#include - -#ifdef VERBOSE_LOGGING -#define VERBOSE_LOG(...) \ - { printf(__VA_ARGS__); } -#else -#define VERBOSE_LOG(...) -#endif - -#define DONT_USE_VIRTUAL_ALLOC2 - -size_t os_getpagesize() { - SYSTEM_INFO S; - GetNativeSystemInfo(&S); - return S.dwPageSize; -} - -static void* win_mmap(void* hint, - size_t size, - int prot, - int flags, - DWORD alloc_flag) { - DWORD flProtect = PAGE_NOACCESS; - size_t request_size, page_size; - void* addr; - - page_size = os_getpagesize(); - request_size = (size + page_size - 1) & ~(page_size - 1); - - if (request_size < size) - /* integer overflow */ - return NULL; - - if (request_size == 0) - request_size = page_size; - - if (prot & MMAP_PROT_EXEC) { - if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_EXECUTE_READWRITE; - else - flProtect = PAGE_EXECUTE_READ; - } else if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_READWRITE; - else if (prot & MMAP_PROT_READ) - flProtect = PAGE_READONLY; - - addr = VirtualAlloc((LPVOID)hint, request_size, alloc_flag, flProtect); - return addr; -} - -void* os_mmap(void* hint, size_t size, int prot, int flags) { - DWORD alloc_flag = MEM_RESERVE | MEM_COMMIT; - return win_mmap(hint, size, prot, flags, alloc_flag); -} - -#ifndef DONT_USE_VIRTUAL_ALLOC2 -static void* win_mmap_aligned(void* hint, - size_t size, - int prot, - int flags, - size_t pow2alignment) { - DWORD alloc_flag = MEM_RESERVE | MEM_COMMIT; - DWORD flProtect = PAGE_NOACCESS; - size_t request_size, page_size; - void* addr; - - page_size = os_getpagesize(); - request_size = (size + page_size - 1) & ~(page_size - 1); - - if (request_size < size) - /* integer overflow */ - return NULL; - - if (request_size == 0) - request_size = page_size; - - if (prot & MMAP_PROT_EXEC) { - if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_EXECUTE_READWRITE; - else - flProtect = PAGE_EXECUTE_READ; - } else if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_READWRITE; - else if (prot & MMAP_PROT_READ) - flProtect = PAGE_READONLY; - - MEM_ADDRESS_REQUIREMENTS addressReqs = {0}; - MEM_EXTENDED_PARAMETER param = {0}; - - addressReqs.Alignment = pow2alignment; - addressReqs.HighestEndingAddress = 0; - addressReqs.LowestStartingAddress = 0; - - param.Type = MemExtendedParameterAddressRequirements; - param.Pointer = &addressReqs; - - addr = VirtualAlloc2(0, (LPVOID)addr, request_size, alloc_flag, flProtect, - ¶m, 1); - return addr; -} -#endif - -void os_munmap(void* addr, size_t size) { - DWORD alloc_flag = MEM_RELEASE; - if (addr) { - if (VirtualFree(addr, 0, alloc_flag) == 0) { - size_t page_size = os_getpagesize(); - size_t request_size = (size + page_size - 1) & ~(page_size - 1); - int64_t curr_err = errno; - printf("os_munmap error addr:%p, size:0x%zx, errno:%" PRId64 "\n", addr, - request_size, curr_err); - } - } -} - -int os_mprotect(void* addr, size_t size, int prot) { - DWORD flProtect = PAGE_NOACCESS; - - if (!addr) - return 0; - - if (prot & MMAP_PROT_EXEC) { - if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_EXECUTE_READWRITE; - else - flProtect = PAGE_EXECUTE_READ; - } else if (prot & MMAP_PROT_WRITE) - flProtect = PAGE_READWRITE; - else if (prot & MMAP_PROT_READ) - flProtect = PAGE_READONLY; - - DWORD old; - BOOL succeeded = VirtualProtect((LPVOID)addr, size, flProtect, &old); - return succeeded ? 0 : -1; -} - -#ifndef DONT_USE_VIRTUAL_ALLOC2 -static int IsPowerOfTwoOrZero(size_t x) { - return (x & (x - 1)) == 0; -} -#endif - -void* os_mmap_aligned(void* addr, - size_t requested_length, - int prot, - int flags, - size_t alignment, - size_t alignment_offset) { -#ifndef DONT_USE_VIRTUAL_ALLOC2 - if (IsPowerOfTwoOrZero(alignment) && alignment_offset == 0) { - return win_mmap_aligned(addr, requested_length, prot, flags, alignment); - } else -#endif - { - size_t padded_length = requested_length + alignment + alignment_offset; - uintptr_t unaligned = - (uintptr_t)win_mmap(addr, padded_length, prot, flags, MEM_RESERVE); - - VERBOSE_LOG( - "os_mmap_aligned: alignment:%llu, alignment_offset:%llu, " - "requested_length:%llu, padded_length: %llu, initial mapping: %p\n", - (unsigned long long)alignment, (unsigned long long)alignment_offset, - (unsigned long long)requested_length, (unsigned long long)padded_length, - (void*)unaligned); - - if (!unaligned) { - return (void*)unaligned; - } - - // Round up the next address that has addr % alignment = 0 - const size_t alignment_corrected = alignment == 0 ? 1 : alignment; - uintptr_t aligned_nonoffset = - (unaligned + (alignment_corrected - 1)) & ~(alignment_corrected - 1); - - // Currently offset 0 is aligned according to alignment - // Alignment needs to be enforced at the given offset - uintptr_t aligned = 0; - if ((aligned_nonoffset - alignment_offset) >= unaligned) { - aligned = aligned_nonoffset - alignment_offset; - } else { - aligned = aligned_nonoffset - alignment_offset + alignment; - } - - if (aligned == unaligned && padded_length == requested_length) { - return (void*)aligned; - } - - // Sanity check - if (aligned < unaligned || - (aligned + (requested_length - 1)) > - (unaligned + (padded_length - 1)) || - (aligned + alignment_offset) % alignment_corrected != 0) { - VERBOSE_LOG("os_mmap_aligned: sanity check fail. aligned: %p\n", - (void*)aligned); - os_munmap((void*)unaligned, padded_length); - return NULL; - } - - // windows does not support partial unmapping, so unmap and remap - os_munmap((void*)unaligned, padded_length); - aligned = (uintptr_t)win_mmap((void*)aligned, requested_length, prot, flags, - MEM_RESERVE); - VERBOSE_LOG("os_mmap_aligned: final mapping: %p\n", (void*)aligned); - return (void*)aligned; - } -} - -int os_mmap_commit(void* curr_heap_end_pointer, - size_t expanded_size, - int prot) { - uintptr_t addr = (uintptr_t)win_mmap(curr_heap_end_pointer, expanded_size, - prot, MMAP_MAP_NONE, MEM_COMMIT); - int ret = addr ? 0 : -1; - return ret; -} - -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; - // Copy the error message into a std::string. - printf("%s. %s\n", msg, messageBuffer); - LocalFree(messageBuffer); - } else { - printf("%s. No error code.\n", msg); - } -} - -#undef VERBOSE_LOG -#undef DONT_USE_VIRTUAL_ALLOC2 - -#else -// https://stackoverflow.com/questions/26541150/warning-iso-c-forbids-an-empty-translation-unit -typedef int make_iso_compilers_happy; -#endif diff --git a/wasm2c/wasm-rt-os.h b/wasm2c/wasm-rt-os.h deleted file mode 100644 index 3b9ee5d75..000000000 --- a/wasm2c/wasm-rt-os.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef WASM_RT_OS_H_ -#define WASM_RT_OS_H_ - -#include -#include -#include - -enum { - MMAP_PROT_NONE = 0, - MMAP_PROT_READ = 1, - MMAP_PROT_WRITE = 2, - MMAP_PROT_EXEC = 4 -}; - -/* Memory map flags */ -enum { - MMAP_MAP_NONE = 0, - /* Put the mapping into 0 to 2 G, supported only on x86_64 */ - MMAP_MAP_32BIT = 1, - /* Don't interpret addr as a hint: place the mapping at exactly - that address. */ - MMAP_MAP_FIXED = 2 -}; - -size_t os_getpagesize(); -// Try allocating Memory space. -// Returns pointer to allocated region on success, 0 on failure. -void* os_mmap(void* hint, size_t size, int prot, int flags); -void os_munmap(void* addr, size_t size); -// Set the permissions of the memory region. -// Returns 0 on success, non zero on failure. -int os_mprotect(void* addr, size_t size, int prot); -// Like mmap but returns an aligned region -void* os_mmap_aligned(void* addr, - size_t requested_length, - int prot, - int flags, - size_t alignment, - size_t alignment_offset); -// Commits and sets the permissions on an already allocated memory region -// Returns 0 on success, non zero on failure. -int os_mmap_commit(void* curr_heap_end_pointer, size_t expanded_size, int prot); - -// print the error message -void os_print_last_error(const char* msg); - -#endif diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h index b4a2ef7e1..d3c251942 100644 --- a/wasm2c/wasm-rt.h +++ b/wasm2c/wasm-rt.h @@ -225,12 +225,21 @@ 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 } From d2b29773cb869962b34e538229970749c0e39ad5 Mon Sep 17 00:00:00 2001 From: Zhi An Ng Date: Thu, 10 Mar 2022 02:13:24 +0000 Subject: [PATCH 3/3] - feedback --- wasm2c/wasm-rt-impl.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c index 86e14adf8..e685f38be 100644 --- a/wasm2c/wasm-rt-impl.c +++ b/wasm2c/wasm-rt-impl.c @@ -136,7 +136,6 @@ static void os_print_last_error(const char* msg) { NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); (void)size; - // Copy the error message into a std::string. printf("%s. %s\n", msg, messageBuffer); LocalFree(messageBuffer); } else { @@ -289,10 +288,8 @@ float wasm_rt_fabsf(float x) { if (isnan(x)) { uint32_t tmp; memcpy(&tmp, &x, 4); - if (tmp & (1 << 31)) { - tmp = tmp & ~(1 << 31); - memcpy(&x, &tmp, 4); - } + tmp = tmp & ~(1 << 31); + memcpy(&x, &tmp, 4); return x; } return fabsf(x); @@ -302,10 +299,8 @@ double wasm_rt_fabs(double x) { if (isnan(x)) { uint64_t tmp; memcpy(&tmp, &x, 8); - if (tmp & (1ll << 63)) { - tmp = tmp & ~(1ll << 63); - memcpy(&x, &tmp, 8); - } + tmp = tmp & ~(1ll << 63); + memcpy(&x, &tmp, 8); return x; } return fabs(x);