diff options
author | Alon Zakai <alonzakai@gmail.com> | 2016-03-07 13:10:44 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2016-03-07 13:10:44 -0800 |
commit | b65a994c24e83694f27cb835845b3b281207fc2f (patch) | |
tree | 86ba8aa07f966d22742150551791732248cb4f84 /src | |
parent | a96bf5cbb71ee5923f4f534db49cedeccf6d51d0 (diff) | |
parent | 91008b47488fe87943b7c2b66c3f362907d37bee (diff) | |
download | binaryen-b65a994c24e83694f27cb835845b3b281207fc2f.tar.gz binaryen-b65a994c24e83694f27cb835845b3b281207fc2f.tar.bz2 binaryen-b65a994c24e83694f27cb835845b3b281207fc2f.zip |
Merge pull request #229 from WebAssembly/integrate-wasm-fixes
Integrate wasm fixes
Diffstat (limited to 'src')
-rw-r--r-- | src/asm2wasm-main.cpp | 11 | ||||
-rw-r--r-- | src/asm2wasm.h | 81 | ||||
-rw-r--r-- | src/js/wasm.js-post.js | 15 |
3 files changed, 80 insertions, 27 deletions
diff --git a/src/asm2wasm-main.cpp b/src/asm2wasm-main.cpp index aa914c168..5ab8bb0cf 100644 --- a/src/asm2wasm-main.cpp +++ b/src/asm2wasm-main.cpp @@ -41,6 +41,10 @@ int main(int argc, const char *argv[]) { [](Options *o, const std::string &argument) { o->extra["mapped globals"] = argument; }) + .add("--total-memory", "-m", "Total memory size", Options::Arguments::One, + [](Options *o, const std::string &argument) { + o->extra["total memory"] = argument; + }) .add_positional("INFILE", Options::Arguments::One, [](Options *o, const std::string &argument) { o->extra["infile"] = argument; @@ -51,6 +55,10 @@ int main(int argc, const char *argv[]) { const char *mappedGlobals = mg_it == options.extra.end() ? nullptr : mg_it->second.c_str(); + const auto &tm_it = options.extra.find("total memory"); + size_t totalMemory = + tm_it == options.extra.end() ? 16 * 1024 * 1024 : atoi(tm_it->second.c_str()); + Asm2WasmPreProcessor pre; auto input( read_file<std::vector<char>>(options.extra["infile"], options.debug)); @@ -67,8 +75,7 @@ int main(int argc, const char *argv[]) { if (options.debug) std::cerr << "wasming..." << std::endl; AllocatingModule wasm; - wasm.memory.initial = wasm.memory.max = - 16 * 1024 * 1024; // we would normally receive this from the compiler + wasm.memory.initial = wasm.memory.max = totalMemory; Asm2WasmBuilder asm2wasm(wasm, pre.memoryGrowth, options.debug); asm2wasm.processAsm(asmjs); diff --git a/src/asm2wasm.h b/src/asm2wasm.h index 353f80413..c13c847e7 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -66,6 +66,17 @@ struct AstStackHelper { std::vector<Ref> AstStackHelper::astStack; +struct BreakSeeker : public WasmWalker<BreakSeeker> { + IString target; // look for this one + size_t found; + + BreakSeeker(IString target) : target(target), found(false) {} + + void visitBreak(Break *curr) { + if (curr->name == target) found++; + } +}; + // // Asm2WasmPreProcessor - does some initial parsing/processing // of asm.js code. @@ -204,8 +215,9 @@ private: // uses, in the first pass std::map<IString, FunctionType> importedFunctionTypes; + std::map<IString, std::vector<CallImport*>> importedFunctionCalls; - void noteImportedFunctionCall(Ref ast, WasmType resultType, AsmData *asmData) { + void noteImportedFunctionCall(Ref ast, WasmType resultType, AsmData *asmData, CallImport* call) { assert(ast[0] == CALL && ast[1][0] == NAME); IString importName = ast[1][1]->getIString(); FunctionType type; @@ -242,6 +254,7 @@ private: } else { importedFunctionTypes[importName] = type; } + importedFunctionCalls[importName].push_back(call); } FunctionType* getFunctionType(Ref parent, ExpressionList& operands) { @@ -670,6 +683,20 @@ void Asm2WasmBuilder::processAsm(Ref ast) { wasm.removeImport(curr); } + // fill out call_import - add extra params as needed. asm tolerates ffi overloading, wasm does not + for (auto& pair : importedFunctionCalls) { + IString name = pair.first; + auto& list = pair.second; + auto type = importedFunctionTypes[name]; + for (auto* call : list) { + for (size_t i = call->operands.size(); i < type.params.size(); i++) { + auto val = allocator.alloc<Const>(); + val->type = val->value.type = type.params[i]; + call->operands.push_back(val); + } + } + } + // finalize indirect calls for (auto& pair : callIndirects) { @@ -1002,7 +1029,15 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must emulate that CallImport *ret = allocator.alloc<CallImport>(); ret->target = F64_TO_INT; - ret->operands.push_back(process(ast[2][2])); + auto input = process(ast[2][2]); + if (input->type == f32) { + auto conv = allocator.alloc<Unary>(); + conv->op = PromoteFloat32; + conv->value = input; + conv->type = WasmType::f64; + input = conv; + } + ret->operands.push_back(input); ret->type = i32; static bool addedImport = false; if (!addedImport) { @@ -1148,8 +1183,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { if (wasm.importsMap.find(name) != wasm.importsMap.end()) { Ref parent = astStackHelper.getParent(); WasmType type = !!parent ? detectWasmType(parent, &asmData) : none; - ret = allocator.alloc<CallImport>(); - noteImportedFunctionCall(ast, type, &asmData); + auto specific = allocator.alloc<CallImport>(); + noteImportedFunctionCall(ast, type, &asmData, specific); + ret = specific; } else { ret = allocator.alloc<Call>(); } @@ -1256,8 +1292,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { return ret; } else if (what == DO) { if (ast[1][0] == NUM && ast[1][1]->getNumber() == 0) { - // one-time loop - auto block = allocator.alloc<Block>(); + // one-time loop, unless there is a continue IString stop; if (!parentLabel.isNull()) { stop = getBreakLabelName(parentLabel); @@ -1265,13 +1300,27 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { } else { stop = getNextId("do-once"); } - block->name = stop; + IString more = getNextId("unlikely-continue"); breakStack.push_back(stop); - continueStack.push_back(IMPOSSIBLE_CONTINUE); - block->list.push_back(process(ast[2])); + continueStack.push_back(more); + auto child = process(ast[2]); continueStack.pop_back(); breakStack.pop_back(); - return block; + // if we never continued, we don't need a loop + BreakSeeker breakSeeker(more); + breakSeeker.walk(child); + if (breakSeeker.found == 0) { + auto block = allocator.alloc<Block>(); + block->list.push_back(child); + block->name = stop; + return block; + } else { + auto loop = allocator.alloc<Loop>(); + loop->body = child; + loop->out = stop; + loop->in = more; + return loop; + } } // general do-while loop auto ret = allocator.alloc<Loop>(); @@ -1489,18 +1538,6 @@ void Asm2WasmBuilder::optimize() { return; } // we might be broken to, but maybe there isn't a break (and we may have removed it, leading to this) - - struct BreakSeeker : public WasmWalker<BreakSeeker> { - IString target; // look for this one - size_t found; - - BreakSeeker(IString target) : target(target), found(false) {} - - void visitBreak(Break *curr) { - if (curr->name == target) found++; - } - }; - // look for any breaks to this block BreakSeeker breakSeeker(curr->name); Expression *child = curr->list[0]; diff --git a/src/js/wasm.js-post.js b/src/js/wasm.js-post.js index b2ec40b00..4071ace46 100644 --- a/src/js/wasm.js-post.js +++ b/src/js/wasm.js-post.js @@ -71,7 +71,9 @@ function integrateWasmJS(Module) { // TODO: avoid this copy, by avoiding such static init writes // TODO: in shorter term, just copy up to the last static init write var oldBuffer = Module['buffer']; - assert(newBuffer.byteLength >= oldBuffer.byteLength, 'we might fail if we allocated more than TOTAL_MEMORY'); + if (newBuffer.byteLength < oldBuffer.byteLength) { + Module['printErr']('the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here'); + } var oldView = new Int8Array(oldBuffer); var newView = new Int8Array(newBuffer); if ({{{ WASM_BACKEND }}}) { @@ -122,13 +124,20 @@ function integrateWasmJS(Module) { // doesn't need to care that it is wasm and not asm. Module['asm'] = function(global, env, providedBuffer) { // Load the wasm module - var binary = Module['readBinary'](Module['wasmCodeFile']); + var binary; + if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + binary = Module['wasmBinary']; + assert(binary, "on the web, we need the wasm binary to be preloaded and set on Module['wasmBinary']. emcc.py will do that for you when generating HTML (but not JS)"); + binary = new Uint8Array(binary); + } else { + binary = Module['readBinary'](Module['wasmCodeFile']); + } // Create an instance of the module using native support in the JS engine. info['global'] = { - 'Math': global.Math, 'NaN': NaN, 'Infinity': Infinity }; + info['global.Math'] = global.Math; info['env'] = env; var instance; instance = Wasm.instantiateModule(binary, info); |