| @@ -0,0 +1,153 @@ | ||
| /* Generated from 'wasm2c.c.tmpl' by wasm2c_tmpl.py, do not edit! */ | ||
| const char SECTION_NAME(includes)[] = | ||
| "#include <assert.h>\n" | ||
| "#include <math.h>\n" | ||
| "#include <stdlib.h>\n" | ||
| "#include <string.h>\n" | ||
| ; | ||
| const char SECTION_NAME(declarations)[] = | ||
| "#define UNLIKELY(x) __builtin_expect(!!(x), 0)\n" | ||
| "#define LIKELY(x) __builtin_expect(!!(x), 1)\n" | ||
| "\n" | ||
| "#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)\n" | ||
| "\n" | ||
| "#define FUNC_PROLOGUE \\\n" | ||
| " if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \\\n" | ||
| " TRAP(EXHAUSTION)\n" | ||
| "\n" | ||
| "#define FUNC_EPILOGUE --wasm_rt_call_stack_depth\n" | ||
| "\n" | ||
| "#define UNREACHABLE TRAP(UNREACHABLE)\n" | ||
| "\n" | ||
| "#define CALL_INDIRECT(table, t, ft, x, ...) \\\n" | ||
| " (LIKELY((x) < table.size && table.data[x].func && \\\n" | ||
| " table.data[x].func_type == func_types[ft]) \\\n" | ||
| " ? ((t)table.data[x].func)(__VA_ARGS__) \\\n" | ||
| " : TRAP(CALL_INDIRECT))\n" | ||
| "\n" | ||
| "#define MEMCHECK(mem, a, t) \\\n" | ||
| " if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)\n" | ||
| "\n" | ||
| "#define DEFINE_LOAD(name, t1, t2, t3) \\\n" | ||
| " static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \\\n" | ||
| " MEMCHECK(mem, addr, t1); \\\n" | ||
| " t1 result; \\\n" | ||
| " memcpy(&result, &mem->data[addr], sizeof(t1)); \\\n" | ||
| " return (t3)(t2)result; \\\n" | ||
| " }\n" | ||
| "\n" | ||
| "#define DEFINE_STORE(name, t1, t2) \\\n" | ||
| " static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \\\n" | ||
| " MEMCHECK(mem, addr, t1); \\\n" | ||
| " t1 wrapped = (t1)value; \\\n" | ||
| " memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \\\n" | ||
| " }\n" | ||
| "\n" | ||
| "DEFINE_LOAD(i32_load, u32, u32, u32);\n" | ||
| "DEFINE_LOAD(i64_load, u64, u64, u64);\n" | ||
| "DEFINE_LOAD(f32_load, f32, f32, f32);\n" | ||
| "DEFINE_LOAD(f64_load, f64, f64, f64);\n" | ||
| "DEFINE_LOAD(i32_load8_s, s8, s32, u32);\n" | ||
| "DEFINE_LOAD(i64_load8_s, s8, s64, u64);\n" | ||
| "DEFINE_LOAD(i32_load8_u, u8, u32, u32);\n" | ||
| "DEFINE_LOAD(i64_load8_u, u8, u64, u64);\n" | ||
| "DEFINE_LOAD(i32_load16_s, s16, s32, u32);\n" | ||
| "DEFINE_LOAD(i64_load16_s, s16, s64, u64);\n" | ||
| "DEFINE_LOAD(i32_load16_u, u16, u32, u32);\n" | ||
| "DEFINE_LOAD(i64_load16_u, u16, u64, u64);\n" | ||
| "DEFINE_LOAD(i64_load32_s, s32, s64, u64);\n" | ||
| "DEFINE_LOAD(i64_load32_u, u32, u64, u64);\n" | ||
| "DEFINE_STORE(i32_store, u32, u32);\n" | ||
| "DEFINE_STORE(i64_store, u64, u64);\n" | ||
| "DEFINE_STORE(f32_store, f32, f32);\n" | ||
| "DEFINE_STORE(f64_store, f64, f64);\n" | ||
| "DEFINE_STORE(i32_store8, u8, u32);\n" | ||
| "DEFINE_STORE(i32_store16, u16, u32);\n" | ||
| "DEFINE_STORE(i64_store8, u8, u64);\n" | ||
| "DEFINE_STORE(i64_store16, u16, u64);\n" | ||
| "DEFINE_STORE(i64_store32, u32, u64);\n" | ||
| "\n" | ||
| "#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32)\n" | ||
| "#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64)\n" | ||
| "#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32)\n" | ||
| "#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64)\n" | ||
| "#define I32_POPCNT(x) (__builtin_popcount(x))\n" | ||
| "#define I64_POPCNT(x) (__builtin_popcountll(x))\n" | ||
| "\n" | ||
| "#define DIV_S(ut, min, x, y) \\\n" | ||
| " ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n" | ||
| " : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \\\n" | ||
| " : (ut)((x) / (y)))\n" | ||
| "\n" | ||
| "#define REM_S(ut, min, x, y) \\\n" | ||
| " ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \\\n" | ||
| " : (UNLIKELY((x) == min && (y) == -1)) ? 0 \\\n" | ||
| " : (ut)((x) % (y)))\n" | ||
| "\n" | ||
| "#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y)\n" | ||
| "#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y)\n" | ||
| "#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y)\n" | ||
| "#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y)\n" | ||
| "\n" | ||
| "#define DIVREM_U(op, x, y) \\\n" | ||
| " ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y)))\n" | ||
| "\n" | ||
| "#define DIV_U(x, y) DIVREM_U(/, x, y)\n" | ||
| "#define REM_U(x, y) DIVREM_U(%, x, y)\n" | ||
| "\n" | ||
| "#define ROTL(x, y, mask) \\\n" | ||
| " (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask))))\n" | ||
| "#define ROTR(x, y, mask) \\\n" | ||
| " (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask))))\n" | ||
| "\n" | ||
| "#define I32_ROTL(x, y) ROTL(x, y, 31)\n" | ||
| "#define I64_ROTL(x, y) ROTL(x, y, 63)\n" | ||
| "#define I32_ROTR(x, y) ROTR(x, y, 31)\n" | ||
| "#define I64_ROTR(x, y) ROTR(x, y, 63)\n" | ||
| "\n" | ||
| "#define FMIN(x, y) \\\n" | ||
| " ((UNLIKELY((x) != (x))) ? NAN \\\n" | ||
| " : (UNLIKELY((y) != (y))) ? NAN \\\n" | ||
| " : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \\\n" | ||
| " : (x < y) ? x : y)\n" | ||
| "\n" | ||
| "#define FMAX(x, y) \\\n" | ||
| " ((UNLIKELY((x) != (x))) ? NAN \\\n" | ||
| " : (UNLIKELY((y) != (y))) ? NAN \\\n" | ||
| " : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \\\n" | ||
| " : (x > y) ? x : y)\n" | ||
| "\n" | ||
| "#define TRUNC_S(ut, st, ft, min, max, maxop, x) \\\n" | ||
| " ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n" | ||
| " : (UNLIKELY((x) < (ft)(min) || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \\\n" | ||
| " : (ut)(st)(x))\n" | ||
| "\n" | ||
| "#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, INT32_MIN, INT32_MAX, >=, x)\n" | ||
| "#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, INT64_MIN, INT64_MAX, >=, x)\n" | ||
| "#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, INT32_MIN, INT32_MAX, >, x)\n" | ||
| "#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, INT64_MIN, INT64_MAX, >=, x)\n" | ||
| "\n" | ||
| "#define TRUNC_U(ut, ft, max, maxop, x) \\\n" | ||
| " ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \\\n" | ||
| " : (UNLIKELY((x) <= (ft)-1 || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \\\n" | ||
| " : (ut)(x))\n" | ||
| "\n" | ||
| "#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, UINT32_MAX, >=, x)\n" | ||
| "#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, UINT64_MAX, >=, x)\n" | ||
| "#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, UINT32_MAX, >, x)\n" | ||
| "#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, UINT64_MAX, >=, x)\n" | ||
| "\n" | ||
| "#define DEFINE_REINTERPRET(name, t1, t2) \\\n" | ||
| " static inline t2 name(t1 x) { \\\n" | ||
| " t2 result; \\\n" | ||
| " memcpy(&result, &x, sizeof(result)); \\\n" | ||
| " return result; \\\n" | ||
| " }\n" | ||
| "\n" | ||
| "DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32)\n" | ||
| "DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32)\n" | ||
| "DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64)\n" | ||
| "DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64)\n" | ||
| "\n" | ||
| ; |
| @@ -0,0 +1,40 @@ | ||
| /* Generated from 'wasm2c.h.tmpl' by wasm2c_tmpl.py, do not edit! */ | ||
| const char SECTION_NAME(top)[] = | ||
| "#ifdef __cplusplus\n" | ||
| "extern \"C\" {\n" | ||
| "#endif\n" | ||
| "\n" | ||
| "#include <stdint.h>\n" | ||
| "\n" | ||
| "#include \"wasm-rt.h\"\n" | ||
| "\n" | ||
| "#ifndef WASM_RT_MODULE_PREFIX\n" | ||
| "#define WASM_RT_MODULE_PREFIX\n" | ||
| "#endif\n" | ||
| "\n" | ||
| "#define WASM_RT_PASTE_(x, y) x ## y\n" | ||
| "#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)\n" | ||
| "#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)\n" | ||
| "\n" | ||
| "#define WASM_RT_DEFINE_EXTERNAL(decl, target) decl = ⌖\n" | ||
| "\n" | ||
| "/* TODO(binji): only use stdint.h types in header */\n" | ||
| "typedef uint8_t u8;\n" | ||
| "typedef int8_t s8;\n" | ||
| "typedef uint16_t u16;\n" | ||
| "typedef int16_t s16;\n" | ||
| "typedef uint32_t u32;\n" | ||
| "typedef int32_t s32;\n" | ||
| "typedef uint64_t u64;\n" | ||
| "typedef int64_t s64;\n" | ||
| "typedef float f32;\n" | ||
| "typedef double f64;\n" | ||
| "\n" | ||
| "extern void WASM_RT_ADD_PREFIX(init)(void);\n" | ||
| ; | ||
|
|
||
| const char SECTION_NAME(bottom)[] = | ||
| "#ifdef __cplusplus\n" | ||
| "}\n" | ||
| "#endif\n" | ||
| ; |
| @@ -32,6 +32,6 @@ struct Range { | ||
| typedef Range<Offset> OffsetRange; | ||
| typedef Range<int> ColumnRange; | ||
|
|
||
| } // namespace wabt | ||
|
|
||
| #endif // WABT_RANGE_H_ | ||
| @@ -0,0 +1,111 @@ | ||
| /* | ||
| * Copyright 2018 WebAssembly Community Group participants | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include <cstdio> | ||
| #include <thread> | ||
| #include <vector> | ||
|
|
||
| #include "gtest/gtest.h" | ||
|
|
||
| #include "src/literal.h" | ||
|
|
||
| using namespace wabt; | ||
|
|
||
| namespace { | ||
|
|
||
| void AssertHexFloatEquals(uint32_t expected_bits, const char* s) { | ||
| uint32_t actual_bits; | ||
| ASSERT_EQ(Result::Ok, | ||
| ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits)); | ||
| ASSERT_EQ(expected_bits, actual_bits); | ||
| } | ||
|
|
||
| void AssertHexFloatFails(const char* s) { | ||
| uint32_t actual_bits; | ||
| ASSERT_EQ(Result::Error, | ||
| ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits)); | ||
| } | ||
|
|
||
| void AssertHexDoubleEquals(uint64_t expected_bits, const char* s) { | ||
| uint64_t actual_bits; | ||
| ASSERT_EQ(Result::Ok, | ||
| ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits)); | ||
| ASSERT_EQ(expected_bits, actual_bits); | ||
| } | ||
|
|
||
| void AssertHexDoubleFails(const char* s) { | ||
| uint64_t actual_bits; | ||
| ASSERT_EQ(Result::Error, | ||
| ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits)); | ||
| } | ||
|
|
||
| } // end anonymous namespace | ||
|
|
||
| TEST(ParseFloat, NonCanonical) { | ||
| AssertHexFloatEquals(0x3f800000, "0x00000000000000000000001.0p0"); | ||
| AssertHexFloatEquals(0x3f800000, "0x1.00000000000000000000000p0"); | ||
| AssertHexFloatEquals(0x3f800000, "0x0.0000000000000000000001p88"); | ||
| } | ||
|
|
||
| TEST(ParseFloat, Rounding) { | ||
| // |------- 23 bits -----| V-- extra bit | ||
| // | ||
| // 11111111111111111111101 0 ==> no rounding | ||
| AssertHexFloatEquals(0x7f7ffffd, "0x1.fffffap127"); | ||
| // 11111111111111111111101 1 ==> round up | ||
| AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffbp127"); | ||
| // 11111111111111111111110 0 ==> no rounding | ||
| AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffcp127"); | ||
| // 11111111111111111111110 1 ==> round down | ||
| AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffdp127"); | ||
| // 11111111111111111111111 0 ==> no rounding | ||
| AssertHexFloatEquals(0x7f7fffff, "0x1.fffffep127"); | ||
| } | ||
|
|
||
| TEST(ParseFloat, OutOfRange) { | ||
| AssertHexFloatFails("0x1p128"); | ||
| AssertHexFloatFails("-0x1p128"); | ||
| AssertHexFloatFails("0x1.ffffffp127"); | ||
| AssertHexFloatFails("-0x1.ffffffp127"); | ||
| } | ||
|
|
||
| TEST(ParseDouble, NonCanonical) { | ||
| AssertHexDoubleEquals(0x3ff0000000000000, "0x00000000000000000000001.0p0"); | ||
| AssertHexDoubleEquals(0x3ff0000000000000, "0x1.00000000000000000000000p0"); | ||
| AssertHexDoubleEquals(0x3ff0000000000000, "0x0.0000000000000000000001p88"); | ||
| } | ||
|
|
||
| TEST(ParseDouble, Rounding) { | ||
| // |-------------------- 52 bits ---------------------| V-- extra bit | ||
| // | ||
| // 1111111111111111111111111111111111111111111111111101 0 ==> no rounding | ||
| AssertHexDoubleEquals(0x7feffffffffffffd, "0x1.ffffffffffffd0p1023"); | ||
| // 1111111111111111111111111111111111111111111111111101 1 ==> round up | ||
| AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffd8p1023"); | ||
| // 1111111111111111111111111111111111111111111111111110 0 ==> no rounding | ||
| AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe0p1023"); | ||
| // 1111111111111111111111111111111111111111111111111110 1 ==> round down | ||
| AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe8p1023"); | ||
| // 1111111111111111111111111111111111111111111111111111 0 ==> no rounding | ||
| AssertHexDoubleEquals(0x7fefffffffffffff, "0x1.fffffffffffff0p1023"); | ||
| } | ||
|
|
||
| TEST(ParseDouble, OutOfRange) { | ||
| AssertHexDoubleFails("0x1p1024"); | ||
| AssertHexDoubleFails("-0x1p1024"); | ||
| AssertHexDoubleFails("0x1.fffffffffffff8p1023"); | ||
| AssertHexDoubleFails("-0x1.fffffffffffff8p1023"); | ||
| } |
| @@ -0,0 +1,149 @@ | ||
| /* | ||
| * Copyright 2017 WebAssembly Community Group participants | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include <cassert> | ||
| #include <cinttypes> | ||
| #include <cstdio> | ||
| #include <cstdlib> | ||
|
|
||
| #include "src/apply-names.h" | ||
| #include "src/binary-reader.h" | ||
| #include "src/binary-reader-ir.h" | ||
| #include "src/error-handler.h" | ||
| #include "src/feature.h" | ||
| #include "src/generate-names.h" | ||
| #include "src/ir.h" | ||
| #include "src/option-parser.h" | ||
| #include "src/stream.h" | ||
| #include "src/validator.h" | ||
| #include "src/wast-lexer.h" | ||
|
|
||
| #include "src/c-writer.h" | ||
|
|
||
| using namespace wabt; | ||
|
|
||
| static int s_verbose; | ||
| static std::string s_infile; | ||
| static std::string s_outfile; | ||
| static Features s_features; | ||
| static WriteCOptions s_write_c_options; | ||
| static bool s_read_debug_names = true; | ||
| static std::unique_ptr<FileStream> s_log_stream; | ||
|
|
||
| static const char s_description[] = | ||
| R"( Read a file in the WebAssembly binary format, and convert it to | ||
| a C source file and header. | ||
| examples: | ||
| # parse binary file test.wasm and write test.c and test.h | ||
| $ wasm2c test.wasm -o test.c | ||
| # parse test.wasm, write test.c and test.h, but ignore the debug names, if any | ||
| $ wasm2c test.wasm --no-debug-names -o test.c | ||
| )"; | ||
|
|
||
| static void ParseOptions(int argc, char** argv) { | ||
| OptionParser parser("wasm2c", s_description); | ||
|
|
||
| parser.AddOption('v', "verbose", "Use multiple times for more info", []() { | ||
| s_verbose++; | ||
| s_log_stream = FileStream::CreateStdout(); | ||
| }); | ||
| parser.AddHelpOption(); | ||
| parser.AddOption( | ||
| 'o', "output", "FILENAME", | ||
| "Output file for the generated C source file, by default use stdout", | ||
| [](const char* argument) { | ||
| s_outfile = argument; | ||
| ConvertBackslashToSlash(&s_outfile); | ||
| }); | ||
| s_features.AddOptions(&parser); | ||
| parser.AddOption("no-debug-names", "Ignore debug names in the binary file", | ||
| []() { s_read_debug_names = false; }); | ||
| parser.AddArgument("filename", OptionParser::ArgumentCount::One, | ||
| [](const char* argument) { | ||
| s_infile = argument; | ||
| ConvertBackslashToSlash(&s_infile); | ||
| }); | ||
| parser.Parse(argc, argv); | ||
| } | ||
|
|
||
| // TODO(binji): copied from binary-writer-spec.cc, probably should share. | ||
| static string_view strip_extension(string_view s) { | ||
| string_view ext = s.substr(s.find_last_of('.')); | ||
| string_view result = s; | ||
|
|
||
| if (ext == ".c") | ||
| result.remove_suffix(ext.length()); | ||
| return result; | ||
| } | ||
|
|
||
| int ProgramMain(int argc, char** argv) { | ||
| Result result; | ||
|
|
||
| InitStdio(); | ||
| ParseOptions(argc, argv); | ||
|
|
||
| std::vector<uint8_t> file_data; | ||
| result = ReadFile(s_infile.c_str(), &file_data); | ||
| if (Succeeded(result)) { | ||
| ErrorHandlerFile error_handler(Location::Type::Binary); | ||
| Module module; | ||
| const bool kStopOnFirstError = true; | ||
| ReadBinaryOptions options(s_features, s_log_stream.get(), | ||
| s_read_debug_names, kStopOnFirstError); | ||
| result = ReadBinaryIr(s_infile.c_str(), file_data.data(), file_data.size(), | ||
| &options, &error_handler, &module); | ||
| if (Succeeded(result)) { | ||
| if (Succeeded(result)) { | ||
| ValidateOptions options(s_features); | ||
| WastLexer* lexer = nullptr; | ||
| result = ValidateModule(lexer, &module, &error_handler, &options); | ||
| result |= GenerateNames(&module); | ||
| } | ||
|
|
||
| if (Succeeded(result)) { | ||
| /* TODO(binji): This shouldn't fail; if a name can't be applied | ||
| * (because the index is invalid, say) it should just be skipped. */ | ||
| Result dummy_result = ApplyNames(&module); | ||
| WABT_USE(dummy_result); | ||
| } | ||
|
|
||
| if (Succeeded(result)) { | ||
| if (!s_outfile.empty()) { | ||
| std::string header_name = | ||
| strip_extension(s_outfile).to_string() + ".h"; | ||
| FileStream c_stream(s_outfile.c_str()); | ||
| FileStream h_stream(header_name); | ||
| result = WriteC(&c_stream, &h_stream, header_name.c_str(), &module, | ||
| &s_write_c_options); | ||
| } else { | ||
| FileStream stream(stdout); | ||
| result = | ||
| WriteC(&stream, &stream, "wasm.h", &module, &s_write_c_options); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return result != Result::Ok; | ||
| } | ||
|
|
||
| int main(int argc, char** argv) { | ||
| WABT_TRY | ||
| return ProgramMain(argc, argv); | ||
| WABT_CATCH_BAD_ALLOC_AND_EXIT | ||
| } | ||
|
|
| @@ -25,4 +25,4 @@ bool IsValidUtf8(const char* s, size_t length); | ||
|
|
||
| } // namespace wabt | ||
|
|
||
| #endif // WABT_UTF8_H_ | ||
| @@ -0,0 +1,149 @@ | ||
| %%includes | ||
| #include <assert.h> | ||
| #include <math.h> | ||
| #include <stdlib.h> | ||
| #include <string.h> | ||
| %%declarations | ||
| #define UNLIKELY(x) __builtin_expect(!!(x), 0) | ||
| #define LIKELY(x) __builtin_expect(!!(x), 1) | ||
|
|
||
| #define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) | ||
|
|
||
| #define FUNC_PROLOGUE \ | ||
| if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \ | ||
| TRAP(EXHAUSTION) | ||
|
|
||
| #define FUNC_EPILOGUE --wasm_rt_call_stack_depth | ||
|
|
||
| #define UNREACHABLE TRAP(UNREACHABLE) | ||
|
|
||
| #define CALL_INDIRECT(table, t, ft, x, ...) \ | ||
| (LIKELY((x) < table.size && table.data[x].func && \ | ||
| table.data[x].func_type == func_types[ft]) \ | ||
| ? ((t)table.data[x].func)(__VA_ARGS__) \ | ||
| : TRAP(CALL_INDIRECT)) | ||
|
|
||
| #define MEMCHECK(mem, a, t) \ | ||
| if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB) | ||
|
|
||
| #define DEFINE_LOAD(name, t1, t2, t3) \ | ||
| static inline t3 name(wasm_rt_memory_t* mem, u64 addr) { \ | ||
| MEMCHECK(mem, addr, t1); \ | ||
| t1 result; \ | ||
| memcpy(&result, &mem->data[addr], sizeof(t1)); \ | ||
| return (t3)(t2)result; \ | ||
| } | ||
|
|
||
| #define DEFINE_STORE(name, t1, t2) \ | ||
| static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \ | ||
| MEMCHECK(mem, addr, t1); \ | ||
| t1 wrapped = (t1)value; \ | ||
| memcpy(&mem->data[addr], &wrapped, sizeof(t1)); \ | ||
| } | ||
|
|
||
| DEFINE_LOAD(i32_load, u32, u32, u32); | ||
| DEFINE_LOAD(i64_load, u64, u64, u64); | ||
| DEFINE_LOAD(f32_load, f32, f32, f32); | ||
| DEFINE_LOAD(f64_load, f64, f64, f64); | ||
| DEFINE_LOAD(i32_load8_s, s8, s32, u32); | ||
| DEFINE_LOAD(i64_load8_s, s8, s64, u64); | ||
| DEFINE_LOAD(i32_load8_u, u8, u32, u32); | ||
| DEFINE_LOAD(i64_load8_u, u8, u64, u64); | ||
| DEFINE_LOAD(i32_load16_s, s16, s32, u32); | ||
| DEFINE_LOAD(i64_load16_s, s16, s64, u64); | ||
| DEFINE_LOAD(i32_load16_u, u16, u32, u32); | ||
| DEFINE_LOAD(i64_load16_u, u16, u64, u64); | ||
| DEFINE_LOAD(i64_load32_s, s32, s64, u64); | ||
| DEFINE_LOAD(i64_load32_u, u32, u64, u64); | ||
| DEFINE_STORE(i32_store, u32, u32); | ||
| DEFINE_STORE(i64_store, u64, u64); | ||
| DEFINE_STORE(f32_store, f32, f32); | ||
| DEFINE_STORE(f64_store, f64, f64); | ||
| DEFINE_STORE(i32_store8, u8, u32); | ||
| DEFINE_STORE(i32_store16, u16, u32); | ||
| DEFINE_STORE(i64_store8, u8, u64); | ||
| DEFINE_STORE(i64_store16, u16, u64); | ||
| DEFINE_STORE(i64_store32, u32, u64); | ||
|
|
||
| #define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32) | ||
| #define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64) | ||
| #define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32) | ||
| #define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64) | ||
| #define I32_POPCNT(x) (__builtin_popcount(x)) | ||
| #define I64_POPCNT(x) (__builtin_popcountll(x)) | ||
|
|
||
| #define DIV_S(ut, min, x, y) \ | ||
| ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ | ||
| : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \ | ||
| : (ut)((x) / (y))) | ||
|
|
||
| #define REM_S(ut, min, x, y) \ | ||
| ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) \ | ||
| : (UNLIKELY((x) == min && (y) == -1)) ? 0 \ | ||
| : (ut)((x) % (y))) | ||
|
|
||
| #define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y) | ||
| #define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y) | ||
| #define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y) | ||
| #define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y) | ||
|
|
||
| #define DIVREM_U(op, x, y) \ | ||
| ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y))) | ||
|
|
||
| #define DIV_U(x, y) DIVREM_U(/, x, y) | ||
| #define REM_U(x, y) DIVREM_U(%, x, y) | ||
|
|
||
| #define ROTL(x, y, mask) \ | ||
| (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask)))) | ||
| #define ROTR(x, y, mask) \ | ||
| (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask)))) | ||
|
|
||
| #define I32_ROTL(x, y) ROTL(x, y, 31) | ||
| #define I64_ROTL(x, y) ROTL(x, y, 63) | ||
| #define I32_ROTR(x, y) ROTR(x, y, 31) | ||
| #define I64_ROTR(x, y) ROTR(x, y, 63) | ||
|
|
||
| #define FMIN(x, y) \ | ||
| ((UNLIKELY((x) != (x))) ? NAN \ | ||
| : (UNLIKELY((y) != (y))) ? NAN \ | ||
| : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \ | ||
| : (x < y) ? x : y) | ||
|
|
||
| #define FMAX(x, y) \ | ||
| ((UNLIKELY((x) != (x))) ? NAN \ | ||
| : (UNLIKELY((y) != (y))) ? NAN \ | ||
| : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \ | ||
| : (x > y) ? x : y) | ||
|
|
||
| #define TRUNC_S(ut, st, ft, min, max, maxop, x) \ | ||
| ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ | ||
| : (UNLIKELY((x) < (ft)(min) || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ | ||
| : (ut)(st)(x)) | ||
|
|
||
| #define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, INT32_MIN, INT32_MAX, >=, x) | ||
| #define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, INT64_MIN, INT64_MAX, >=, x) | ||
| #define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, INT32_MIN, INT32_MAX, >, x) | ||
| #define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, INT64_MIN, INT64_MAX, >=, x) | ||
|
|
||
| #define TRUNC_U(ut, ft, max, maxop, x) \ | ||
| ((UNLIKELY((x) != (x))) ? TRAP(INVALID_CONVERSION) \ | ||
| : (UNLIKELY((x) <= (ft)-1 || (x) maxop (ft)(max))) ? TRAP(INT_OVERFLOW) \ | ||
| : (ut)(x)) | ||
|
|
||
| #define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, UINT32_MAX, >=, x) | ||
| #define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, UINT64_MAX, >=, x) | ||
| #define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, UINT32_MAX, >, x) | ||
| #define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, UINT64_MAX, >=, x) | ||
|
|
||
| #define DEFINE_REINTERPRET(name, t1, t2) \ | ||
| static inline t2 name(t1 x) { \ | ||
| t2 result; \ | ||
| memcpy(&result, &x, sizeof(result)); \ | ||
| return result; \ | ||
| } | ||
|
|
||
| DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32) | ||
| DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32) | ||
| DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64) | ||
| DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64) | ||
|
|
| @@ -0,0 +1,36 @@ | ||
| %%top | ||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "wasm-rt.h" | ||
|
|
||
| #ifndef WASM_RT_MODULE_PREFIX | ||
| #define WASM_RT_MODULE_PREFIX | ||
| #endif | ||
|
|
||
| #define WASM_RT_PASTE_(x, y) x ## y | ||
| #define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y) | ||
| #define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x) | ||
|
|
||
| #define WASM_RT_DEFINE_EXTERNAL(decl, target) decl = ⌖ | ||
|
|
||
| /* TODO(binji): only use stdint.h types in header */ | ||
| typedef uint8_t u8; | ||
| typedef int8_t s8; | ||
| typedef uint16_t u16; | ||
| typedef int16_t s16; | ||
| typedef uint32_t u32; | ||
| typedef int32_t s32; | ||
| typedef uint64_t u64; | ||
| typedef int64_t s64; | ||
| typedef float f32; | ||
| typedef double f64; | ||
|
|
||
| extern void WASM_RT_ADD_PREFIX(init)(void); | ||
| %%bottom | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif |
| @@ -0,0 +1,80 @@ | ||
| #!/usr/bin/env python | ||
| # | ||
| # Copyright 2018 WebAssembly Community Group participants | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| # | ||
|
|
||
| from __future__ import print_function | ||
| import argparse | ||
| try: | ||
| from cStringIO import StringIO | ||
| except ImportError: | ||
| from io import StringIO | ||
| import os | ||
| import sys | ||
|
|
||
| def EscapeCString(s): | ||
| out = '' | ||
| for b in bytearray(s.encode('utf-8')): | ||
| if b in (34, 92): | ||
| # " or \ | ||
| out += '\\' + chr(b) | ||
| elif b == 10: | ||
| # newline | ||
| out += '\\n' | ||
| elif 32 <= b <= 127: | ||
| # printable char | ||
| out += chr(b) | ||
| else: | ||
| # non-printable; write as \xab | ||
| out += '\\x%02x' % b | ||
|
|
||
| return out | ||
|
|
||
|
|
||
| def main(args): | ||
| arg_parser = argparse.ArgumentParser() | ||
| arg_parser.add_argument('-o', '--output', metavar='PATH', | ||
| help='output file.') | ||
| arg_parser.add_argument('file', help='input file.') | ||
| options = arg_parser.parse_args(args) | ||
|
|
||
| section_name = None | ||
| output = StringIO() | ||
|
|
||
| output.write('/* Generated from \'%s\' by wasm2c_tmpl.py, do not edit! */\n' % | ||
| os.path.basename(options.file)) | ||
|
|
||
| with open(options.file) as f: | ||
| for line in f.readlines(): | ||
| if line.startswith('%%'): | ||
| if section_name is not None: | ||
| output.write(';\n\n'); | ||
| section_name = line[2:-1] | ||
| output.write('const char SECTION_NAME(%s)[] =\n' % section_name) | ||
| else: | ||
| output.write('"%s"\n' % EscapeCString(line)) | ||
|
|
||
| output.write(';\n'); | ||
| if options.output: | ||
| with open(options.output, 'w') as outf: | ||
| outf.write(output.getvalue()) | ||
| else: | ||
| sys.stdout.write(output.getvalue()) | ||
|
|
||
| return 0 | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| sys.exit(main(sys.argv[1:])) |