summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-03-30 14:08:50 -0700
committerGitHub <noreply@github.com>2021-03-30 14:08:50 -0700
commit38d73857a6a1ed6a404f393e69f838977dc27e83 (patch)
treeaf9551fdf68a94ce6ba1f9822488e613702cc3fe
parentdaa7e66be52285a0cbee04a7cf69886c63610097 (diff)
downloadbinaryen-38d73857a6a1ed6a404f393e69f838977dc27e83.tar.gz
binaryen-38d73857a6a1ed6a404f393e69f838977dc27e83.tar.bz2
binaryen-38d73857a6a1ed6a404f393e69f838977dc27e83.zip
Fix LegalizeJSInterface with RefFuncs (#3749)
This code used to remove functions it no longer thinks are needed. That is, if it adds a legalized version of an import, it would remove the illegal one which is no longer needed. To avoid removing an illegal import that is still used it checked for ref.func appearances. But this was bad in two ways: We need to legalize the ref.funcs too. We can't call an illegal import in any way, not using a direct call, indirect call, or call by reference of a ref.func. It's silly to remove unneeded functions here. We have a pass for that. This removes the removal of functions, and adds proper updating of ref.calls, which means to call the stub function that looks like the original import, but that calls the legalized one and connects things up properly, exactly the same way as other calls. Also remove code that checked if we were in the stub/thunk and to not replace the call there. That code is not needed: no one will ever call the illegal import, so we do not need to be careful about preserving such calls.
-rw-r--r--src/passes/LegalizeJSInterface.cpp61
-rw-r--r--test/lld/duplicate_imports.wat.out3
-rw-r--r--test/passes/legalize-js-interface-minimally.txt3
-rw-r--r--test/passes/legalize-js-interface_all-features.txt8
-rw-r--r--test/passes/legalize-js-interface_all-features.wast3
5 files changed, 26 insertions, 52 deletions
diff --git a/src/passes/LegalizeJSInterface.cpp b/src/passes/LegalizeJSInterface.cpp
index a53481d65..e840e375b 100644
--- a/src/passes/LegalizeJSInterface.cpp
+++ b/src/passes/LegalizeJSInterface.cpp
@@ -107,51 +107,16 @@ struct LegalizeJSInterface : public Pass {
}
if (!illegalImportsToLegal.empty()) {
- // Gather functions used in 'ref.func'. They should not be removed.
- std::unordered_map<Name, std::atomic<bool>> usedInRefFunc;
-
- // Fill in unordered_map, as we operate on it in parallel.
- for (auto& func : module->functions) {
- usedInRefFunc[func->name];
- }
-
- struct RefFuncScanner : public WalkerPass<PostWalker<RefFuncScanner>> {
- Module& wasm;
- std::unordered_map<Name, std::atomic<bool>>& usedInRefFunc;
-
- bool isFunctionParallel() override { return true; }
-
- Pass* create() override {
- return new RefFuncScanner(wasm, usedInRefFunc);
- }
-
- RefFuncScanner(
- Module& wasm,
- std::unordered_map<Name, std::atomic<bool>>& usedInRefFunc)
- : wasm(wasm), usedInRefFunc(usedInRefFunc) {}
-
- void visitRefFunc(RefFunc* curr) { usedInRefFunc[curr->func] = true; }
- };
-
- RefFuncScanner(*module, usedInRefFunc).run(runner, module);
- for (auto& pair : illegalImportsToLegal) {
- if (!usedInRefFunc[pair.first]) {
- module->removeFunction(pair.first);
- }
- }
-
// fix up imports: call_import of an illegal must be turned to a call of a
- // legal
- struct FixImports : public WalkerPass<PostWalker<FixImports>> {
+ // legal. the same must be done with ref.funcs.
+ struct Fixer : public WalkerPass<PostWalker<Fixer>> {
bool isFunctionParallel() override { return true; }
- Pass* create() override {
- return new FixImports(illegalImportsToLegal);
- }
+ Pass* create() override { return new Fixer(illegalImportsToLegal); }
std::map<Name, Name>* illegalImportsToLegal;
- FixImports(std::map<Name, Name>* illegalImportsToLegal)
+ Fixer(std::map<Name, Name>* illegalImportsToLegal)
: illegalImportsToLegal(illegalImportsToLegal) {}
void visitCall(Call* curr) {
@@ -160,19 +125,25 @@ struct LegalizeJSInterface : public Pass {
return;
}
- if (iter->second == getFunction()->name) {
- // inside the stub function itself, is the one safe place to do the
- // call
- return;
- }
replaceCurrent(
Builder(*getModule())
.makeCall(
iter->second, curr->operands, curr->type, curr->isReturn));
}
+
+ void visitRefFunc(RefFunc* curr) {
+ auto iter = illegalImportsToLegal->find(curr->func);
+ if (iter == illegalImportsToLegal->end()) {
+ return;
+ }
+
+ curr->func = iter->second;
+ }
};
- FixImports(&illegalImportsToLegal).run(runner, module);
+ Fixer fixer(&illegalImportsToLegal);
+ fixer.run(runner, module);
+ fixer.walkModuleCode(module);
}
}
diff --git a/test/lld/duplicate_imports.wat.out b/test/lld/duplicate_imports.wat.out
index f6e1b1223..5a5fa94e3 100644
--- a/test/lld/duplicate_imports.wat.out
+++ b/test/lld/duplicate_imports.wat.out
@@ -1,14 +1,15 @@
(module
+ (type $i64_=>_i32 (func (param i64) (result i32)))
(type $i32_f32_f64_=>_f32 (func (param i32 f32 f64) (result f32)))
(type $i32_f64_f64_=>_f32 (func (param i32 f64 f64) (result f32)))
(type $2 (func))
(type $1 (func (result i32)))
(type $0 (func (param i32) (result i32)))
- (type $i64_=>_i32 (func (param i64) (result i32)))
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
(type $f32_f64_=>_f32 (func (param f32 f64) (result f32)))
(type $f64_f64_=>_f32 (func (param f64 f64) (result f32)))
(import "env" "puts" (func $puts1 (param i32) (result i32)))
+ (import "env" "puts" (func $puts2 (param i64) (result i32)))
(import "env" "invoke_ffd" (func $invoke_ffd (param i32 f32 f64) (result f32)))
(import "env" "invoke_ffd" (func $invoke_ffd2 (param i32 f64 f64) (result f32)))
(import "env" "puts" (func $legalimport$puts2 (param i32 i32) (result i32)))
diff --git a/test/passes/legalize-js-interface-minimally.txt b/test/passes/legalize-js-interface-minimally.txt
index f39a2ce84..18fb60c1f 100644
--- a/test/passes/legalize-js-interface-minimally.txt
+++ b/test/passes/legalize-js-interface-minimally.txt
@@ -1,10 +1,11 @@
(module
(type $none_=>_i64 (func (result i64)))
- (type $i32_=>_none (func (param i32)))
(type $i64_=>_none (func (param i64)))
+ (type $i32_=>_none (func (param i32)))
(type $i32_i32_=>_none (func (param i32 i32)))
(type $none_=>_i32 (func (result i32)))
(import "env" "imported" (func $imported (result i64)))
+ (import "env" "invoke_vj" (func $invoke_vj (param i64)))
(import "env" "setTempRet0" (func $setTempRet0 (param i32)))
(import "env" "invoke_vj" (func $legalimport$invoke_vj (param i32 i32)))
(export "func" (func $func))
diff --git a/test/passes/legalize-js-interface_all-features.txt b/test/passes/legalize-js-interface_all-features.txt
index d05d1bc30..05cc43e9b 100644
--- a/test/passes/legalize-js-interface_all-features.txt
+++ b/test/passes/legalize-js-interface_all-features.txt
@@ -2,16 +2,18 @@
(type $none_=>_i32 (func (result i32)))
(type $none_=>_i64 (func (result i64)))
(type $i32_i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32 i32)))
+ (type $i32_i64_i64_=>_none (func (param i32 i64 i64)))
(type $none_=>_none (func))
(type $i32_=>_none (func (param i32)))
- (type $i32_i64_i64_=>_none (func (param i32 i64 i64)))
+ (import "env" "imported" (func $imported (result i64)))
+ (import "env" "other" (func $other (param i32 i64 i64)))
(import "env" "ref-func-arg" (func $ref-func-arg (result i64)))
(import "env" "setTempRet0" (func $setTempRet0 (param i32)))
(import "env" "getTempRet0" (func $getTempRet0 (result i32)))
(import "env" "imported" (func $legalimport$imported (result i32)))
(import "env" "other" (func $legalimport$other (param i32 i32 i32 i32 i32)))
(import "env" "ref-func-arg" (func $legalimport$ref-func-arg (result i32)))
- (elem declare func $ref-func-arg)
+ (elem declare func $legalfunc$ref-func-arg)
(export "func" (func $legalstub$func))
(export "ref-func-test" (func $ref-func-test))
(export "imported" (func $legalstub$imported))
@@ -33,7 +35,7 @@
(call $legalfunc$ref-func-arg)
)
(drop
- (ref.func $ref-func-arg)
+ (ref.func $legalfunc$ref-func-arg)
)
)
(func $legalstub$func (result i32)
diff --git a/test/passes/legalize-js-interface_all-features.wast b/test/passes/legalize-js-interface_all-features.wast
index 4697a8f18..7f4352f27 100644
--- a/test/passes/legalize-js-interface_all-features.wast
+++ b/test/passes/legalize-js-interface_all-features.wast
@@ -17,8 +17,7 @@
(unreachable)
)
- ;; If an import is used in ref.func, even if it is legalized to another
- ;; import, the original import should not be removed.
+ ;; ref.func must also be updated.
(func $ref-func-test
(drop
(call $ref-func-arg)