Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 37 additions & 6 deletions src/passes/RemoveImports.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,54 @@
// imports, we can at least get the reference interpreter to
// look at all the rest of the code).
//
// By default, all imports are removed. Imports can be specified as a
// comma-separated list with format module.base (with or without wildcards) or
// as a response file.

#include "ir/element-utils.h"
#include "ir/module-utils.h"
#include "pass.h"
#include "support/file.h"
#include "support/string.h"
#include "wasm.h"

namespace wasm {

struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
std::set<Name> toRemove;

void run(Module* module) override {
toRemove.clear();

// If no arguments are provided, all function imports are removed.
std::string param = getArgumentOrDefault(name, "");
param = String::trim(read_possible_response_file(param));
bool removeAllImports = param.empty();

String::Split patterns(param, String::Split::NewLineOr(","));
patterns = handleBracketingOperators(patterns);

ModuleUtils::iterImportedFunctions(*module, [&](Function* func) {
if (removeAllImports) {
toRemove.insert(func->name);
return;
}
auto full = func->module.toString() + '.' + func->base.toString();

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same syntax as the Asyncify pass:

static std::string getFullImportName(Name module, Name base) {
return module.toString() + '.' + base.toString();
}
. There might be weird behavior since both module and function names can be any valid UTF-8 strings. At the very least, WebAssembly ESM integration imports should be fine (the only periods that such exist are at the beginning for relative files and the file extension).

for (auto& pattern : patterns) {
if (String::wildcardMatch(pattern, full)) {
toRemove.insert(func->name);
break;
}
}
});
WalkerPass<PostWalker<RemoveImports>>::run(module);
}

void visitCall(Call* curr) {
auto* func = getModule()->getFunction(curr->target);
if (!func->imported()) {
if (!toRemove.count(curr->target)) {
return;
}
auto* func = getModule()->getFunction(curr->target);
Type type = func->getResults();
if (type == Type::none) {
replaceCurrent(getModule()->allocator.alloc<Nop>());
Expand All @@ -45,14 +79,11 @@ struct RemoveImports : public WalkerPass<PostWalker<RemoveImports>> {
}

void visitModule(Module* curr) {
std::vector<Name> names;
ModuleUtils::iterImportedFunctions(
*curr, [&](Function* func) { names.push_back(func->name); });
// Do not remove names referenced in a table
std::set<Name> indirectNames;
ElementUtils::iterAllElementFunctionNames(
curr, [&](Name name) { indirectNames.insert(name); });
for (auto& name : names) {
for (auto& name : toRemove) {
if (indirectNames.find(name) == indirectNames.end()) {
curr->removeFunction(name);
}
Expand Down
2 changes: 1 addition & 1 deletion src/passes/pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ void PassRegistry::registerPasses() {
"removes exports using a wildcard",
createRemoveExportsPass);
registerPass("remove-imports",
"removes imports and replaces them with nops",
"removes imports using a wildcard and replaces them with nops",
createRemoveImportsPass);
registerPass("remove-memory-init",
"removes memory initialization",
Expand Down
4 changes: 2 additions & 2 deletions test/lit/help/wasm-metadce.test
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-exports removes exports using a wildcard
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-imports removes imports and replaces
;; CHECK-NEXT: them with nops
;; CHECK-NEXT: --remove-imports removes imports using a wildcard
;; CHECK-NEXT: and replaces them with nops
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-memory removes memory init (legacy
;; CHECK-NEXT: name)
Expand Down
4 changes: 2 additions & 2 deletions test/lit/help/wasm-opt.test
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,8 @@
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-exports removes exports using a wildcard
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-imports removes imports and replaces
;; CHECK-NEXT: them with nops
;; CHECK-NEXT: --remove-imports removes imports using a wildcard
;; CHECK-NEXT: and replaces them with nops
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-memory removes memory init (legacy
;; CHECK-NEXT: name)
Expand Down
4 changes: 2 additions & 2 deletions test/lit/help/wasm2js.test
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-exports removes exports using a wildcard
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-imports removes imports and replaces
;; CHECK-NEXT: them with nops
;; CHECK-NEXT: --remove-imports removes imports using a wildcard
;; CHECK-NEXT: and replaces them with nops
;; CHECK-EMPTY:
;; CHECK-NEXT: --remove-memory removes memory init (legacy
;; CHECK-NEXT: name)
Expand Down
3 changes: 3 additions & 0 deletions test/lit/passes/remove-imports-file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
env.foo
other.*
*.log.*
32 changes: 32 additions & 0 deletions test/lit/passes/remove-imports-file.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: foreach %s %t wasm-opt --remove-imports=@%S/remove-imports-file.txt -all -S -o - | filecheck %s

;; Test a response file as the input to this pass. env.foo, other.baz,
;; env.log.warn will be removed.
(module
(import "env" "foo" (func $foo))
;; CHECK: (type $0 (func))

;; CHECK: (import "env" "keep" (func $keep (type $0)))
(import "env" "keep" (func $keep))
(import "other" "baz" (func $baz (result i32)))
(import "env" "log.warn" (func $log.warn))

;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (call $keep)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $test
(call $foo)
(call $keep)
(drop
(call $baz)
)
(call $log.warn)
)
)
31 changes: 31 additions & 0 deletions test/lit/passes/remove-imports-list.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.

;; RUN: foreach %s %t wasm-opt "--remove-imports=env.foo,other.*,*.log.*" -all -S -o - | filecheck %s

;; The imports will be removed except env.keep.
(module
(import "env" "foo" (func $foo))
;; CHECK: (type $0 (func))

;; CHECK: (import "env" "keep" (func $keep (type $0)))
(import "env" "keep" (func $keep))
(import "other" "baz" (func $baz (result i32)))
(import "env" "log.warn" (func $log.warn))

;; CHECK: (func $test (type $0)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: (call $keep)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $test
(call $foo)
(call $keep)
(drop
(call $baz)
)
(call $log.warn)
)
)