diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-02-27 14:04:45 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-27 14:04:45 -0800 |
commit | 89daa028fec6b627f1cbad3285b3176361f36e3d (patch) | |
tree | 7b3d4a596c6ce38a60f7617302439e23de40dc0e /src/asm2wasm.h | |
parent | de999c4673688e1b6f29a9a3023e1295fca33446 (diff) | |
download | binaryen-89daa028fec6b627f1cbad3285b3176361f36e3d.tar.gz binaryen-89daa028fec6b627f1cbad3285b3176361f36e3d.tar.bz2 binaryen-89daa028fec6b627f1cbad3285b3176361f36e3d.zip |
Flexible param numbers in asm2wasm (#1439)
* refactor BINARYEN_PASS_DEBUG code for writing byn-* files, make it easy to emit binaries instead of text
* fix up bad argument numbers in asm2wasm. This can be caused by undefined behavior on the LLVM side, which happens to work natively. it's nicer to fix it up like it would be in a native build, and give a warning, instead of failing to compile
* update build-js.sh
* updated builds
Diffstat (limited to 'src/asm2wasm.h')
-rw-r--r-- | src/asm2wasm.h | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index e2731eb08..8ce094a6f 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -1229,15 +1229,48 @@ void Asm2WasmBuilder::processAsm(Ref ast) { name = "finalize-calls"; } + void notifyAboutWrongOperands(std::string why, Function* calledFunc) { + std::cerr << why << " in call from " << getFunction()->name << " to " << calledFunc->name << " (this is likely due to undefined behavior in C, like defining a function one way and calling it in another, which is important to fix)\n"; + } + void visitCall(Call* curr) { - if (!getModule()->getFunctionOrNull(curr->target)) { + auto* calledFunc = getModule()->getFunctionOrNull(curr->target); + if (!calledFunc) { std::cerr << "invalid call target: " << curr->target << '\n'; WASM_UNREACHABLE(); } - auto result = getModule()->getFunction(curr->target)->result; + // The result type of the function being called is now known, and can be applied. + auto result = calledFunc->result; if (curr->type != result) { curr->type = result; } + // Handle mismatched numbers of arguments. In clang, if a function is declared one way + // but called in another, it inserts bitcasts to make things work. Those end up + // working since it is "ok" to drop or add parameters in native platforms, even + // though it's undefined behavior. We warn about it here, but tolerate it, if there is + // a simple solution. + if (curr->operands.size() < calledFunc->params.size()) { + notifyAboutWrongOperands("warning: asm2wasm adding operands", calledFunc); + while (curr->operands.size() < calledFunc->params.size()) { + // Add params as necessary, with zeros. + curr->operands.push_back( + LiteralUtils::makeZero(calledFunc->params[curr->operands.size()], *getModule()) + ); + } + } + if (curr->operands.size() > calledFunc->params.size()) { + notifyAboutWrongOperands("warning: asm2wasm dropping operands", calledFunc); + curr->operands.resize(calledFunc->params.size()); + } + // If the types are wrong, validation will fail later anyhow, but add a warning here, + // it may help people. + for (Index i = 0; i < curr->operands.size(); i++) { + auto sent = curr->operands[i]->type; + auto expected = calledFunc->params[i]; + if (sent != unreachable && sent != expected) { + notifyAboutWrongOperands("error: asm2wasm seeing an invalid argument type at index " + std::to_string(i) + " (this will not validate)", calledFunc); + } + } } void visitCallImport(CallImport* curr) { @@ -1618,7 +1651,9 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { return ret; } // global var - assert(mappedGlobals.find(name) != mappedGlobals.end()); + if (mappedGlobals.find(name) == mappedGlobals.end()) { + Fatal() << "error: access of a non-existent global var " << name.str; + } auto* ret = builder.makeSetGlobal(name, process(assign->value())); // set_global does not return; if our value is trivially not used, don't emit a load (if nontrivially not used, opts get it later) auto parent = astStackHelper.getParent(); |