summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h41
-rw-r--r--src/passes/pass.cpp11
2 files changed, 43 insertions, 9 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();
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index c9fc7c40e..37c59f570 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -21,6 +21,7 @@
#include <passes/passes.h>
#include <pass.h>
#include <wasm-validator.h>
+#include <wasm-io.h>
namespace wasm {
@@ -193,13 +194,11 @@ void PassRunner::addDefaultGlobalOptimizationPostPasses() {
static void dumpWast(Name name, Module* wasm) {
// write out the wast
- Colors::disable();
static int counter = 0;
- std::stringstream text;
- WasmPrinter::printModule(wasm, text);
- FILE* f = fopen((std::string("byn-") + std::to_string(counter++) + "-" + name.str + ".wast").c_str(), "w");
- fputs(text.str().c_str(), f);
- fclose(f);
+ auto fullName = std::string("byn-") + std::to_string(counter++) + "-" + name.str + ".wasm";
+ ModuleWriter writer;
+ writer.setBinary(false); // TODO: add an option for binary
+ writer.write(*wasm, fullName);
}
void PassRunner::run() {