diff options
-rw-r--r-- | README.md | 18 | ||||
-rwxr-xr-x | check.py | 19 | ||||
-rw-r--r-- | src/js/wasm.js-post.js | 30 | ||||
-rw-r--r-- | src/wasm-binary.h | 190 | ||||
m--------- | test/emscripten | 0 |
5 files changed, 123 insertions, 134 deletions
@@ -121,18 +121,9 @@ The `BINARYEN` flag tells it to emit code using `wasm.js`, and the `BINARYEN_ROO ### C/C++ Source => asm2wasm => WebAssembly -Using emcc you can generate asm.js files for direct parsing by `asm2wasm` on the commandline, for example using +When using `emcc` with the `BINARYEN` option, it will use Binaryen to build to WebAssembly. See the [emscripten wiki](https://github.com/kripken/emscripten/wiki/WebAssembly) for more details. -``` -emcc src.cpp -o a.html --separate-asm -``` - -That will emit `a.html`, `a.js`, and `a.asm.js`. That last file is the asm.js module, which you can pass into `asm2wasm`. - -For basic tests, that command should work, but in general you need a few more arguments to emcc, see what emcc.py does when given the `BINARYEN` option, including: - - * `ALIASING_FUNCTION_POINTERS=0` because WebAssembly does not allow aliased function pointers (there is a single table). - * `GLOBAL_BASE=1000` because WebAssembly lacks global variables, so `asm2wasm` maps them onto addresses in memory. This requires that you have some reserved space for those variables. With that argument, we reserve the area up to `1000`. + * Build with `EMCC_DEBUG=1` in the env to see Emscripten's debug output as it runs the various tools, and also to save the intermediate files in `/tmp/emscripten_temp`. It will save both the `.s` and `.wast` files there (in addition to other files it normally saves). ### C/C++ Source => WebAssembly LLVM backend => s2wasm => WebAssembly @@ -157,10 +148,7 @@ EMCC_WASM_BACKEND=1 ./emcc input.cpp -s BINARYEN=1 (without the env var, the `BINARYEN` option will make it use the asm.js backend, then `asm2wasm`). - * You can see vanilla LLVM tested with Emscripten in `check.py` in this repo (look for `VANILLA_EMCC` in that file), using an Emscripten submodule. - * Due to current limitations of the WebAssembly backend, you might want to build with `-s ONLY_MY_CODE=1 -O1`, which will avoid linking in libc (which contains varargs, which are not yet supported), and optimizes so that the stack is not used (which is also not yet supported). - * The output when building in this mode is similar to what you get in general when building with Binaryen in Emscripten: a main `.js` file, and the compiled code in a `.wast` file alongside it. - * Build with `EMCC_DEBUG=1` in the env to see Emscripten's debug output as it runs the various tools, and also to save the intermediate files in `/tmp/emscripten_temp`. It will save both the `.s` and `.wast` files there (in addition to other files it normally saves). +For more details, see the [emscripten wiki](https://github.com/kripken/emscripten/wiki/WebAssembly). ## Testing @@ -586,19 +586,20 @@ if has_emcc: print '\n[ checking wasm.js methods... ]\n' - for method_init in [None, 'asm2wasm', 'wasm-s-parser', 'just-asm', 'wasm-binary']: + for method_init in [None, 'interpret-asm2wasm', 'interpret-s-expr', 'asmjs', 'interpret-binary']: for success in [1, 0]: method = method_init command = ['emcc', '-o', 'a.wasm.js', '-s', 'BINARYEN=1', os.path.join('test', 'hello_world.c') ] if method: command += ['-s', 'BINARYEN_METHOD="' + method + '"'] else: - method = 'wasm-s-parser' # this is the default + method = 'interpret-s-expr' # this is the default print method, ' : ', ' '.join(command), ' => ', success subprocess.check_call(command) see_polyfill = 'var WasmJS = ' in open('a.wasm.js').read() - if method and 'asm2wasm' not in method and 'wasm-s-parser' not in method and 'wasm-binary' not in method: + + if method and 'interpret' not in method: assert not see_polyfill, 'verify polyfill was not added - we specified a method, and it does not need it' else: assert see_polyfill, 'we need the polyfill' @@ -608,20 +609,20 @@ if has_emcc: asm = asm.replace('"almost asm"', '"use asm"; var not_in_asm = [].length + (true || { x: 5 }.x);') asm = asm.replace("'almost asm'", '"use asm"; var not_in_asm = [].length + (true || { x: 5 }.x);') open('a.wasm.asm.js', 'w').write(asm) - if method == 'asm2wasm': + if method == 'interpret-asm2wasm': os.unlink('a.wasm.wast') # we should not need the .wast if not success: break_cashew() # we need cashew - elif method == 'wasm-s-parser': + elif method == 'interpret-s-expr': os.unlink('a.wasm.asm.js') # we should not need the .asm.js if not success: os.unlink('a.wasm.wast.mappedGlobals') - elif method == 'just-asm': + elif method == 'asmjs': os.unlink('a.wasm.wast') # we should not need the .wast break_cashew() # we don't use cashew, so ok to break it if not success: os.unlink('a.wasm.js') - elif method == 'wasm-binary': + elif method == 'interpret-binary': os.unlink('a.wasm.wast') # we should not need the .wast os.unlink('a.wasm.asm.js') # we should not need the .asm.js if not success: @@ -656,7 +657,7 @@ if has_emcc: extra = json.loads(open(emcc).read()) if os.path.exists('a.normal.js'): os.unlink('a.normal.js') for opts in [[], ['-O1'], ['-O2'], ['-O3'], ['-Oz']]: - for method in ['asm2wasm', 'wasm-s-parser', 'just-asm', 'wasm-binary']: + for method in ['interpret-asm2wasm', 'interpret-s-expr', 'asmjs', 'interpret-binary']: command = ['emcc', '-o', 'a.wasm.js', '-s', 'BINARYEN=1', os.path.join('test', c)] + opts + extra command += ['-s', 'BINARYEN_METHOD="' + method + '"'] print '....' + ' '.join(command) @@ -683,7 +684,7 @@ if has_emcc: execute() - if method in ['asm2wasm', 'wasm-s-parser']: + if method in ['interpret-asm2wasm', 'interpret-s-expr']: # binary and back shutil.copyfile('a.wasm.wast', 'a.wasm.original.wast') recreated = binary_format_check('a.wasm.wast', verify_final_result=False) diff --git a/src/js/wasm.js-post.js b/src/js/wasm.js-post.js index 12e9e5315..0549dbd51 100644 --- a/src/js/wasm.js-post.js +++ b/src/js/wasm.js-post.js @@ -17,10 +17,10 @@ function integrateWasmJS(Module) { // wasm.js has several methods for creating the compiled code module here: // * 'native-wasm' : use native WebAssembly support in the browser - // * 'wasm-s-parser': load s-expression code from a .wast and interpret - // * 'wasm-binary': load binary wasm and interpret - // * 'asm2wasm': load asm.js code, translate to wasm, and interpret - // * 'just-asm': no wasm, just load the asm.js code and use that (good for testing) + // * 'interpret-s-expr': load s-expression code from a .wast and interpret + // * 'interpret-binary': load binary wasm and interpret + // * 'interpret-asm2wasm': load asm.js code, translate to wasm, and interpret + // * 'asmjs': no wasm, just load the asm.js code and use that (good for testing) // The method can be set at compile time (BINARYEN_METHOD), or runtime by setting Module['wasmJSMethod']. // The method can be a comma-separated list, in which case, we will try the // options one by one. Some of them can fail gracefully, and then we can try @@ -28,7 +28,7 @@ function integrateWasmJS(Module) { // inputs - var method = Module['wasmJSMethod'] || {{{ wasmJSMethod }}} || 'native-wasm,wasm-s-parser'; // by default, try native and then .wast + var method = Module['wasmJSMethod'] || {{{ wasmJSMethod }}} || 'native-wasm,interpret-s-expr'; // by default, try native and then .wast var wasmTextFile = Module['wasmTextFile'] || {{{ wasmTextFile }}}; var wasmBinaryFile = Module['wasmBinaryFile'] || {{{ wasmBinaryFile }}}; @@ -229,23 +229,23 @@ function integrateWasmJS(Module) { wasmJS['providedTotalMemory'] = Module['buffer'].byteLength; - // Prepare to generate wasm, using either asm2wasm or wasm-s-parser + // Prepare to generate wasm, using either asm2wasm or s-exprs var code; - if (method === 'wasm-binary') { + if (method === 'interpret-binary') { code = getBinary(); } else { - code = Module['read'](method == 'asm2wasm' ? asmjsCodeFile : wasmTextFile); + code = Module['read'](method == 'interpret-asm2wasm' ? asmjsCodeFile : wasmTextFile); } var temp; - if (method == 'asm2wasm') { + if (method == 'interpret-asm2wasm') { temp = wasmJS['_malloc'](code.length + 1); wasmJS['writeAsciiToMemory'](code, temp); wasmJS['_load_asm2wasm'](temp); - } else if (method === 'wasm-s-parser') { + } else if (method === 'interpret-s-expr') { temp = wasmJS['_malloc'](code.length + 1); wasmJS['writeAsciiToMemory'](code, temp); wasmJS['_load_s_expr2wasm'](temp); - } else if (method === 'wasm-binary') { + } else if (method === 'interpret-binary') { temp = wasmJS['_malloc'](code.length); wasmJS['HEAPU8'].set(code, temp); wasmJS['_load_binary2wasm'](temp, code.length); @@ -261,9 +261,9 @@ function integrateWasmJS(Module) { Module['newBuffer'] = null; } - if (method == 'wasm-s-parser') { + if (method == 'interpret-s-expr') { applyMappedGlobals(wasmTextFile); - } else if (method == 'wasm-binary') { + } else if (method == 'interpret-binary') { applyMappedGlobals(wasmBinaryFile); } @@ -281,9 +281,9 @@ function integrateWasmJS(Module) { //Module['printErr']('using wasm/js method: ' + curr); if (curr === 'native-wasm') { if (doNativeWasm()) return; - } else if (curr === 'just-asm') { + } else if (curr === 'asmjs') { if (doJustAsm()) return; - } else if (curr === 'asm2wasm' || curr === 'wasm-s-parser' || curr === 'wasm-binary') { + } else if (curr === 'interpret-asm2wasm' || curr === 'interpret-s-expr' || curr === 'interpret-binary') { if (doWasmPolyfill(curr)) return; } else { throw 'bad method: ' + curr; diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 3ce76e247..cea086ba3 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -77,8 +77,8 @@ struct LEB { } }; -typedef LEB<uint32_t> LEB128; -typedef LEB<uint64_t> LEB256; +typedef LEB<uint32_t> U32LEB; +typedef LEB<uint64_t> U64LEB; // // We mostly stream into a buffer as we create the binary format, however, @@ -122,13 +122,13 @@ public: push_back(x & 0xff); return *this; } - BufferWithRandomAccess& operator<<(LEB128 x) { - if (debug) std::cerr << "writeLEB128: " << x.value << " (at " << size() << ")" << std::endl; + BufferWithRandomAccess& operator<<(U32LEB x) { + if (debug) std::cerr << "writeU32LEB: " << x.value << " (at " << size() << ")" << std::endl; x.write(this); return *this; } - BufferWithRandomAccess& operator<<(LEB256 x) { - if (debug) std::cerr << "writeLEB256: " << x.value << " (at " << size() << ")" << std::endl; + BufferWithRandomAccess& operator<<(U64LEB x) { + if (debug) std::cerr << "writeU64LEB: " << x.value << " (at " << size() << ")" << std::endl; x.write(this); return *this; } @@ -167,8 +167,8 @@ public: (*this)[i+2] = x & 0xff; x >>= 8; (*this)[i+3] = x & 0xff; } - void writeAt(size_t i, LEB128 x) { - if (debug) std::cerr << "backpatchLEB128: " << x.value << " (at " << i << ")" << std::endl; + void writeAt(size_t i, U32LEB x) { + if (debug) std::cerr << "backpatchU32LEB: " << x.value << " (at " << i << ")" << std::endl; x.writeAt(this, i, 5); // fill all 5 bytes, we have to do this when backpatching } @@ -442,7 +442,7 @@ public: o << int32_t(10); // version number } - int32_t writeLEB128Placeholder() { + int32_t writeU32LEBPlaceholder() { int32_t ret = o.size(); o << int32_t(0); o << int8_t(0); @@ -451,21 +451,21 @@ public: int32_t startSection(const char* name) { // emit 5 bytes of 0, which we'll fill with LEB later - auto ret = writeLEB128Placeholder(); + auto ret = writeU32LEBPlaceholder(); writeInlineString(name); return ret; } void finishSection(int32_t start) { int32_t size = o.size() - start - 5; // section size does not include the 5 bytes of the size field itself - o.writeAt(start, LEB128(size)); + o.writeAt(start, U32LEB(size)); } void writeStart() { if (!wasm->start.is()) return; if (debug) std::cerr << "== writeStart" << std::endl; auto start = startSection(BinaryConsts::Section::Start); - o << LEB128(getFunctionIndex(wasm->start.str)); + o << U32LEB(getFunctionIndex(wasm->start.str)); finishSection(start); } @@ -473,8 +473,8 @@ public: if (wasm->memory.max == 0) return; if (debug) std::cerr << "== writeMemory" << std::endl; auto start = startSection(BinaryConsts::Section::Memory); - o << LEB128(wasm->memory.initial) - << LEB128(wasm->memory.max) + o << U32LEB(wasm->memory.initial) + << U32LEB(wasm->memory.max) << int8_t(1); // export memory finishSection(start); } @@ -483,10 +483,10 @@ public: if (wasm->functionTypes.size() == 0) return; if (debug) std::cerr << "== writeSignatures" << std::endl; auto start = startSection(BinaryConsts::Section::Signatures); - o << LEB128(wasm->functionTypes.size()); + o << U32LEB(wasm->functionTypes.size()); for (auto* type : wasm->functionTypes) { if (debug) std::cerr << "write one" << std::endl; - o << LEB128(type->params.size()); + o << U32LEB(type->params.size()); o << binaryWasmType(type->result); for (auto param : type->params) { o << binaryWasmType(param); @@ -507,10 +507,10 @@ public: if (wasm->imports.size() == 0) return; if (debug) std::cerr << "== writeImports" << std::endl; auto start = startSection(BinaryConsts::Section::ImportTable); - o << LEB128(wasm->imports.size()); + o << U32LEB(wasm->imports.size()); for (auto* import : wasm->imports) { if (debug) std::cerr << "write one" << std::endl; - o << LEB128(getFunctionTypeIndex(import->type->name)); + o << U32LEB(getFunctionTypeIndex(import->type->name)); writeInlineString(import->module.str); writeInlineString(import->base.str); } @@ -561,10 +561,10 @@ public: if (wasm->functions.size() == 0) return; if (debug) std::cerr << "== writeFunctionSignatures" << std::endl; auto start = startSection(BinaryConsts::Section::FunctionSignatures); - o << LEB128(wasm->functions.size()); + o << U32LEB(wasm->functions.size()); for (auto* curr : wasm->functions) { if (debug) std::cerr << "write one" << std::endl; - o << LEB128(getFunctionTypeIndex(curr->type)); + o << U32LEB(getFunctionTypeIndex(curr->type)); } finishSection(start); } @@ -574,26 +574,26 @@ public: if (debug) std::cerr << "== writeFunctions" << std::endl; auto start = startSection(BinaryConsts::Section::Functions); size_t total = wasm->functions.size(); - o << LEB128(total); + o << U32LEB(total); for (size_t i = 0; i < total; i++) { if (debug) std::cerr << "write one at" << o.size() << std::endl; - size_t sizePos = writeLEB128Placeholder(); + size_t sizePos = writeU32LEBPlaceholder(); size_t start = o.size(); Function* function = wasm->functions[i]; mappedLocals.clear(); numLocalsByType.clear(); if (debug) std::cerr << "writing" << function->name << std::endl; mapLocals(function); - o << LEB128( + o << U32LEB( (numLocalsByType[i32] ? 1 : 0) + (numLocalsByType[i64] ? 1 : 0) + (numLocalsByType[f32] ? 1 : 0) + (numLocalsByType[f64] ? 1 : 0) ); - if (numLocalsByType[i32]) o << LEB128(numLocalsByType[i32]) << binaryWasmType(i32); - if (numLocalsByType[i64]) o << LEB128(numLocalsByType[i64]) << binaryWasmType(i64); - if (numLocalsByType[f32]) o << LEB128(numLocalsByType[f32]) << binaryWasmType(f32); - if (numLocalsByType[f64]) o << LEB128(numLocalsByType[f64]) << binaryWasmType(f64); + if (numLocalsByType[i32]) o << U32LEB(numLocalsByType[i32]) << binaryWasmType(i32); + if (numLocalsByType[i64]) o << U32LEB(numLocalsByType[i64]) << binaryWasmType(i64); + if (numLocalsByType[f32]) o << U32LEB(numLocalsByType[f32]) << binaryWasmType(f32); + if (numLocalsByType[f64]) o << U32LEB(numLocalsByType[f64]) << binaryWasmType(f64); depth = 0; recurse(function->body); o << int8_t(BinaryConsts::EndMarker); @@ -601,7 +601,7 @@ public: size_t size = o.size() - start; assert(size <= std::numeric_limits<uint32_t>::max()); if (debug) std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl; - o.writeAt(sizePos, LEB128(size)); + o.writeAt(sizePos, U32LEB(size)); } finishSection(start); } @@ -610,10 +610,10 @@ public: if (wasm->exports.size() == 0) return; if (debug) std::cerr << "== writeexports" << std::endl; auto start = startSection(BinaryConsts::Section::ExportTable); - o << LEB128(wasm->exports.size()); + o << U32LEB(wasm->exports.size()); for (auto* curr : wasm->exports) { if (debug) std::cerr << "write one" << std::endl; - o << LEB128(getFunctionIndex(curr->value)); + o << U32LEB(getFunctionIndex(curr->value)); writeInlineString(curr->name.str); } finishSection(start); @@ -626,10 +626,10 @@ public: if (segment.size > 0) num++; } auto start = startSection(BinaryConsts::Section::DataSegments); - o << LEB128(num); + o << U32LEB(num); for (auto& segment : wasm->memory.segments) { if (segment.size == 0) continue; - o << LEB128(segment.offset); + o << U32LEB(segment.offset); writeInlineBuffer(segment.data, segment.size); } finishSection(start); @@ -654,9 +654,9 @@ public: if (wasm->table.names.size() == 0) return; if (debug) std::cerr << "== writeFunctionTable" << std::endl; auto start = startSection(BinaryConsts::Section::FunctionTable); - o << LEB128(wasm->table.names.size()); + o << U32LEB(wasm->table.names.size()); for (auto name : wasm->table.names) { - o << LEB128(getFunctionIndex(name)); + o << U32LEB(getFunctionIndex(name)); } finishSection(start); } @@ -665,10 +665,10 @@ public: if (wasm->functions.size() == 0) return; if (debug) std::cerr << "== writeNames" << std::endl; auto start = startSection(BinaryConsts::Section::Names); - o << LEB128(wasm->functions.size()); + o << U32LEB(wasm->functions.size()); for (auto* curr : wasm->functions) { writeInlineString(curr->name.str); - o << LEB128(0); // TODO: locals + o << U32LEB(0); // TODO: locals } finishSection(start); } @@ -682,14 +682,14 @@ public: void writeInlineString(const char* name) { int32_t size = strlen(name); - o << LEB128(size); + o << U32LEB(size); for (int32_t i = 0; i < size; i++) { o << int8_t(name[i]); } } void writeInlineBuffer(const char* data, size_t size) { - o << LEB128(size); + o << U32LEB(size); for (size_t i = 0; i < size; i++) { o << int8_t(data[i]); } @@ -789,15 +789,15 @@ public: } if (curr->condition) recurse(curr->condition); o << int8_t(curr->condition ? BinaryConsts::BrIf : BinaryConsts::Br) - << LEB128(getBreakIndex(curr->name)); + << U32LEB(getBreakIndex(curr->name)); } void visitSwitch(Switch *curr) { if (debug) std::cerr << "zz node: Switch" << std::endl; - o << int8_t(BinaryConsts::TableSwitch) << LEB128(curr->targets.size()); + o << int8_t(BinaryConsts::TableSwitch) << U32LEB(curr->targets.size()); for (auto target : curr->targets) { - o << LEB128(getBreakIndex(target)); + o << U32LEB(getBreakIndex(target)); } - o << LEB128(getBreakIndex(curr->default_)); + o << U32LEB(getBreakIndex(curr->default_)); recurse(curr->condition); o << int8_t(BinaryConsts::EndMarker); if (curr->value) { @@ -812,14 +812,14 @@ public: for (auto* operand : curr->operands) { recurse(operand); } - o << int8_t(BinaryConsts::CallFunction) << LEB128(getFunctionIndex(curr->target)); + o << int8_t(BinaryConsts::CallFunction) << U32LEB(getFunctionIndex(curr->target)); } void visitCallImport(CallImport *curr) { if (debug) std::cerr << "zz node: CallImport" << std::endl; for (auto* operand : curr->operands) { recurse(operand); } - o << int8_t(BinaryConsts::CallImport) << LEB128(getImportIndex(curr->target)); + o << int8_t(BinaryConsts::CallImport) << U32LEB(getImportIndex(curr->target)); } void visitCallIndirect(CallIndirect *curr) { if (debug) std::cerr << "zz node: CallIndirect" << std::endl; @@ -827,21 +827,21 @@ public: for (auto* operand : curr->operands) { recurse(operand); } - o << int8_t(BinaryConsts::CallIndirect) << LEB128(getFunctionTypeIndex(curr->fullType->name)); + o << int8_t(BinaryConsts::CallIndirect) << U32LEB(getFunctionTypeIndex(curr->fullType->name)); } void visitGetLocal(GetLocal *curr) { if (debug) std::cerr << "zz node: GetLocal " << (o.size() + 1) << std::endl; - o << int8_t(BinaryConsts::GetLocal) << LEB128(mappedLocals[curr->name]); + o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->name]); } void visitSetLocal(SetLocal *curr) { if (debug) std::cerr << "zz node: SetLocal" << std::endl; recurse(curr->value); - o << int8_t(BinaryConsts::SetLocal) << LEB128(mappedLocals[curr->name]); + o << int8_t(BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->name]); } void emitMemoryAccess(size_t alignment, size_t bytes, uint32_t offset) { - o << LEB128(Log2(alignment ? alignment : bytes)); - o << LEB128(offset); + o << U32LEB(Log2(alignment ? alignment : bytes)); + o << U32LEB(offset); } void visitLoad(Load *curr) { @@ -907,11 +907,11 @@ public: if (debug) std::cerr << "zz node: Const" << curr << " : " << curr->type << std::endl; switch (curr->type) { case i32: { - o << int8_t(BinaryConsts::I32Const) << LEB128(curr->value.geti32()); + o << int8_t(BinaryConsts::I32Const) << U32LEB(curr->value.geti32()); break; } case i64: { - o << int8_t(BinaryConsts::I64Const) << LEB256(curr->value.geti64()); + o << int8_t(BinaryConsts::I64Const) << U64LEB(curr->value.geti64()); break; } case f32: { @@ -1088,9 +1088,9 @@ public: // read sections until the end while (more()) { - auto sectionSize = getLEB128(); + auto sectionSize = getU32LEB(); assert(sectionSize < pos + input.size()); - auto nameSize = getLEB128(); + auto nameSize = getU32LEB(); auto match = [&](const char* name) { for (size_t i = 0; i < nameSize; i++) { if (pos + i >= input.size()) return false; @@ -1162,22 +1162,22 @@ public: return ret; } - uint32_t getLEB128() { + uint32_t getU32LEB() { if (debug) std::cerr << "<==" << std::endl; - LEB128 ret; + U32LEB ret; ret.read([&]() { return getInt8(); }); - if (debug) std::cerr << "getLEB128: " << ret.value << " ==>" << std::endl; + if (debug) std::cerr << "getU32LEB: " << ret.value << " ==>" << std::endl; return ret.value; } - uint64_t getLEB256() { + uint64_t getU64LEB() { if (debug) std::cerr << "<==" << std::endl; - LEB256 ret; + U64LEB ret; ret.read([&]() { return getInt8(); }); - if (debug) std::cerr << "getLEB256: " << ret.value << " ==>" << std::endl; + if (debug) std::cerr << "getU64LEB: " << ret.value << " ==>" << std::endl; return ret.value; } WasmType getWasmType() { @@ -1202,7 +1202,7 @@ public: Name getInlineString() { if (debug) std::cerr << "<==" << std::endl; - auto len = getLEB128(); + auto len = getU32LEB(); std::string str; for (size_t i = 0; i < len; i++) { str = str + char(getInt8()); @@ -1250,24 +1250,24 @@ public: void readStart() { if (debug) std::cerr << "== readStart" << std::endl; - startIndex = getLEB128(); + startIndex = getU32LEB(); } void readMemory() { if (debug) std::cerr << "== readMemory" << std::endl; - wasm.memory.initial = getLEB128(); - wasm.memory.max = getLEB128(); + wasm.memory.initial = getU32LEB(); + wasm.memory.max = getU32LEB(); verifyInt8(1); // export memory } void readSignatures() { if (debug) std::cerr << "== readSignatures" << std::endl; - size_t numTypes = getLEB128(); + size_t numTypes = getU32LEB(); if (debug) std::cerr << "num: " << numTypes << std::endl; for (size_t i = 0; i < numTypes; i++) { if (debug) std::cerr << "read one" << std::endl; auto curr = allocator.alloc<FunctionType>(); - size_t numParams = getLEB128(); + size_t numParams = getU32LEB(); if (debug) std::cerr << "num params: " << numParams << std::endl; curr->result = getWasmType(); for (size_t j = 0; j < numParams; j++) { @@ -1279,13 +1279,13 @@ public: void readImports() { if (debug) std::cerr << "== readImports" << std::endl; - size_t num = getLEB128(); + size_t num = getU32LEB(); if (debug) std::cerr << "num: " << num << std::endl; for (size_t i = 0; i < num; i++) { if (debug) std::cerr << "read one" << std::endl; auto curr = allocator.alloc<Import>(); curr->name = Name(std::string("import$") + std::to_string(i)); - auto index = getLEB128(); + auto index = getU32LEB(); assert(index < wasm.functionTypes.size()); curr->type = wasm.functionTypes[index]; assert(curr->type->name.is()); @@ -1299,11 +1299,11 @@ public: void readFunctionSignatures() { if (debug) std::cerr << "== readFunctionSignatures" << std::endl; - size_t num = getLEB128(); + size_t num = getU32LEB(); if (debug) std::cerr << "num: " << num << std::endl; for (size_t i = 0; i < num; i++) { if (debug) std::cerr << "read one" << std::endl; - auto index = getLEB128(); + auto index = getU32LEB(); assert(index < wasm.functionTypes.size()); functionTypes.push_back(wasm.functionTypes[index]); } @@ -1322,10 +1322,10 @@ public: void readFunctions() { if (debug) std::cerr << "== readFunctions" << std::endl; - size_t total = getLEB128(); + size_t total = getU32LEB(); for (size_t i = 0; i < total; i++) { if (debug) std::cerr << "read one at " << pos << std::endl; - size_t size = getLEB128(); + size_t size = getU32LEB(); assert(size > 0); // we could also check it matches the seen size auto type = functionTypes[i]; if (debug) std::cerr << "reading" << i << std::endl; @@ -1340,9 +1340,9 @@ public: for (size_t j = 0; j < type->params.size(); j++) { func->params.emplace_back(addVar(), type->params[j]); } - size_t numLocalTypes = getLEB128(); + size_t numLocalTypes = getU32LEB(); for (size_t t = 0; t < numLocalTypes; t++) { - auto num = getLEB128(); + auto num = getU32LEB(); auto type = getWasmType(); while (num > 0) { func->locals.emplace_back(addVar(), type); @@ -1383,12 +1383,12 @@ public: void readExports() { if (debug) std::cerr << "== readExports" << std::endl; - size_t num = getLEB128(); + size_t num = getU32LEB(); if (debug) std::cerr << "num: " << num << std::endl; for (size_t i = 0; i < num; i++) { if (debug) std::cerr << "read one" << std::endl; auto curr = allocator.alloc<Export>(); - auto index = getLEB128(); + auto index = getU32LEB(); assert(index < functionTypes.size()); curr->name = getInlineString(); exportIndexes[curr] = index; @@ -1450,11 +1450,11 @@ public: void readDataSegments() { if (debug) std::cerr << "== readDataSegments" << std::endl; - auto num = getLEB128(); + auto num = getU32LEB(); for (size_t i = 0; i < num; i++) { Memory::Segment curr; - curr.offset = getLEB128(); - auto size = getLEB128(); + curr.offset = getU32LEB(); + auto size = getU32LEB(); auto buffer = (char*)malloc(size); for (size_t j = 0; j < size; j++) { buffer[j] = char(getInt8()); @@ -1469,19 +1469,19 @@ public: void readFunctionTable() { if (debug) std::cerr << "== readFunctionTable" << std::endl; - auto num = getLEB128(); + auto num = getU32LEB(); for (size_t i = 0; i < num; i++) { - auto index = getLEB128(); + auto index = getU32LEB(); functionTable.push_back(index); } } void readNames() { if (debug) std::cerr << "== readNames" << std::endl; - auto num = getLEB128(); + auto num = getU32LEB(); for (size_t i = 0; i < num; i++) { functions[i]->name = getInlineString(); - auto numLocals = getLEB128(); + auto numLocals = getU32LEB(); assert(numLocals == 0); // TODO } } @@ -1612,17 +1612,17 @@ public: void visitBreak(Break *curr, uint8_t code) { if (debug) std::cerr << "zz node: Break" << std::endl; - curr->name = getBreakName(getLEB128()); + curr->name = getBreakName(getU32LEB()); if (code == BinaryConsts::BrIf) curr->condition = popExpression(); curr->value = popExpression(); } void visitSwitch(Switch *curr) { if (debug) std::cerr << "zz node: Switch" << std::endl; - auto numTargets = getLEB128(); + auto numTargets = getU32LEB(); for (size_t i = 0; i < numTargets; i++) { - curr->targets.push_back(getBreakName(getLEB128())); + curr->targets.push_back(getBreakName(getU32LEB())); } - curr->default_ = getBreakName(getLEB128()); + curr->default_ = getBreakName(getU32LEB()); processExpressions(); curr->condition = popExpression(); processExpressions(); @@ -1631,7 +1631,7 @@ public: } void visitCall(Call *curr) { if (debug) std::cerr << "zz node: Call" << std::endl; - auto index = getLEB128(); + auto index = getU32LEB(); auto type = functionTypes[index]; auto num = type->params.size(); curr->operands.resize(num); @@ -1643,7 +1643,7 @@ public: } void visitCallImport(CallImport *curr) { if (debug) std::cerr << "zz node: CallImport" << std::endl; - curr->target = wasm.imports[getLEB128()]->name; + curr->target = wasm.imports[getU32LEB()]->name; assert(wasm.importsMap.find(curr->target) != wasm.importsMap.end()); auto type = wasm.importsMap[curr->target]->type; assert(type); @@ -1657,7 +1657,7 @@ public: } void visitCallIndirect(CallIndirect *curr) { if (debug) std::cerr << "zz node: CallIndirect" << std::endl; - curr->fullType = wasm.functionTypes[getLEB128()]; + curr->fullType = wasm.functionTypes[getU32LEB()]; auto num = curr->fullType->params.size(); curr->operands.resize(num); for (size_t i = 0; i < num; i++) { @@ -1668,21 +1668,21 @@ public: } void visitGetLocal(GetLocal *curr) { if (debug) std::cerr << "zz node: GetLocal " << pos << std::endl; - curr->name = mappedLocals[getLEB128()]; + curr->name = mappedLocals[getU32LEB()]; assert(curr->name.is()); curr->type = localTypes[curr->name]; } void visitSetLocal(SetLocal *curr) { if (debug) std::cerr << "zz node: SetLocal" << std::endl; - curr->name = mappedLocals[getLEB128()]; + curr->name = mappedLocals[getU32LEB()]; assert(curr->name.is()); curr->value = popExpression(); curr->type = curr->value->type; } void readMemoryAccess(uint32_t& alignment, size_t bytes, uint32_t& offset) { - alignment = Pow2(getLEB128()); - offset = getLEB128(); + alignment = Pow2(getU32LEB()); + offset = getU32LEB(); } bool maybeVisitImpl(Load *curr, uint8_t code) { @@ -1729,8 +1729,8 @@ public: } bool maybeVisitImpl(Const *curr, uint8_t code) { switch (code) { - case BinaryConsts::I32Const: curr->value = Literal(getLEB128()); break; - case BinaryConsts::I64Const: curr->value = Literal(getLEB256()); break; + case BinaryConsts::I32Const: curr->value = Literal(getU32LEB()); break; + case BinaryConsts::I64Const: curr->value = Literal(getU64LEB()); break; case BinaryConsts::F32Const: curr->value = Literal(getFloat32()); break; case BinaryConsts::F64Const: curr->value = Literal(getFloat64()); break; default: return false; diff --git a/test/emscripten b/test/emscripten -Subproject b4e694961408bc530155161998f0165e5d4c8ba +Subproject 2c7867418c0159eef403b0cf673e8b9aaaf29ee |