diff options
author | Alon Zakai <azakai@google.com> | 2021-03-30 14:08:50 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-30 14:08:50 -0700 |
commit | 38d73857a6a1ed6a404f393e69f838977dc27e83 (patch) | |
tree | af9551fdf68a94ce6ba1f9822488e613702cc3fe | |
parent | daa7e66be52285a0cbee04a7cf69886c63610097 (diff) | |
download | binaryen-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.cpp | 61 | ||||
-rw-r--r-- | test/lld/duplicate_imports.wat.out | 3 | ||||
-rw-r--r-- | test/passes/legalize-js-interface-minimally.txt | 3 | ||||
-rw-r--r-- | test/passes/legalize-js-interface_all-features.txt | 8 | ||||
-rw-r--r-- | test/passes/legalize-js-interface_all-features.wast | 3 |
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) |