diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index c2952e174b8..a61bfb6195c 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -105,6 +105,7 @@ set(passes_SOURCES TraceCalls.cpp RandomizeBranchHints.cpp RedundantSetElimination.cpp + RemoveExports.cpp RemoveImports.cpp RemoveMemoryInit.cpp RemoveNonJSOps.cpp diff --git a/src/passes/RemoveExports.cpp b/src/passes/RemoveExports.cpp new file mode 100644 index 00000000000..99cd0ff641d --- /dev/null +++ b/src/passes/RemoveExports.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2026 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Remove exports using a wildcard. For example: +// +// --remove-exports=__* +// +// That will remove all exports with names like "__foo" and "__bar". +// + +#include "pass.h" +#include "support/string.h" +#include "wasm.h" + +namespace wasm { + +namespace { + +struct RemoveExports : public Pass { + void run(Module* module) override { + std::string pattern = + getArgument(name, "Usage usage: wasm-opt --" + name + "=WILDCARD"); + + std::vector toRemove; + for (auto& exp : module->exports) { + if (String::wildcardMatch(pattern, exp->name.toString())) { + toRemove.push_back(exp->name); + } + } + + for (auto& name : toRemove) { + module->removeExport(name); + } + } +}; + +} // anonymous namespace + +Pass* createRemoveExportsPass() { return new RemoveExports(); } + +} // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index e5de76176ba..dc6d91feb4e 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -412,6 +412,9 @@ void PassRegistry::registerPasses() { registerPass("remove-relaxed-simd", "replaces relaxed SIMD instructions with unreachable", createRemoveRelaxedSIMDPass); + registerPass("remove-exports", + "removes exports using a wildcard", + createRemoveExportsPass); registerPass("remove-imports", "removes imports and replaces them with nops", createRemoveImportsPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index be06369a9f8..2fdacd84ab0 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -135,6 +135,7 @@ Pass* createPropagateGlobalsGloballyPass(); Pass* createRandomizeBranchHintsPass(); Pass* createRemoveNonJSOpsPass(); Pass* createRemoveRelaxedSIMDPass(); +Pass* createRemoveExportsPass(); Pass* createRemoveImportsPass(); Pass* createRemoveMemoryInitPass(); Pass* createRemoveUnusedBrsPass(); diff --git a/test/lit/help/wasm-metadce.test b/test/lit/help/wasm-metadce.test index 1b0cc7d4569..4d5f8e33b89 100644 --- a/test/lit/help/wasm-metadce.test +++ b/test/lit/help/wasm-metadce.test @@ -383,6 +383,8 @@ ;; CHECK-NEXT: --propagate-globals-globally propagate global values to other ;; CHECK-NEXT: globals (useful for tests) ;; CHECK-NEXT: +;; CHECK-NEXT: --remove-exports removes exports using a wildcard +;; CHECK-NEXT: ;; CHECK-NEXT: --remove-imports removes imports and replaces ;; CHECK-NEXT: them with nops ;; CHECK-NEXT: diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index d616e1cf085..08e8e5657c3 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -415,6 +415,8 @@ ;; CHECK-NEXT: --propagate-globals-globally propagate global values to other ;; CHECK-NEXT: globals (useful for tests) ;; CHECK-NEXT: +;; CHECK-NEXT: --remove-exports removes exports using a wildcard +;; CHECK-NEXT: ;; CHECK-NEXT: --remove-imports removes imports and replaces ;; CHECK-NEXT: them with nops ;; CHECK-NEXT: diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index a91d5b5c050..88d6504b384 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -347,6 +347,8 @@ ;; CHECK-NEXT: --propagate-globals-globally propagate global values to other ;; CHECK-NEXT: globals (useful for tests) ;; CHECK-NEXT: +;; CHECK-NEXT: --remove-exports removes exports using a wildcard +;; CHECK-NEXT: ;; CHECK-NEXT: --remove-imports removes imports and replaces ;; CHECK-NEXT: them with nops ;; CHECK-NEXT: diff --git a/test/lit/passes/remove-exports.wast b/test/lit/passes/remove-exports.wast new file mode 100644 index 00000000000..0a5af581346 --- /dev/null +++ b/test/lit/passes/remove-exports.wast @@ -0,0 +1,77 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. +;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up. + +;; RUN: foreach %s %t wasm-opt "--remove-exports=__*" -all -S -o - | filecheck %s + +;; foo and bar will be kept as exports, but __foo, __bar, and __ will not. +(module + ;; CHECK: (type $0 (func)) + + ;; CHECK: (export "foo" (func $foo)) + + ;; CHECK: (export "bar" (func $bar)) + + ;; CHECK: (func $foo (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $foo (export "foo") + (drop (i32.const 1)) + ) + + ;; CHECK: (func $__foo (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $__foo (export "__foo") + (drop (i32.const 2)) + ) + + ;; CHECK: (func $bar (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $bar (export "bar") + (drop (i32.const 3)) + ) + + ;; CHECK: (func $__bar (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $__bar (export "__bar") + (drop (i32.const 4)) + ) + + ;; CHECK: (func $__ (type $0) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 4) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $__ (export "__") + (drop (i32.const 4)) + ) +) + +;; Test non-function exports. The prefixed __mem and __table exports vanish. +(module + ;; CHECK: (memory $memory 10 20) + (memory $memory 10 20) + + ;; CHECK: (table $table 10 20 funcref) + (table $table 10 20 funcref) + + ;; CHECK: (export "mem" (memory $memory)) + (export "mem" (memory $memory)) + + (export "__mem" (memory $memory)) + + ;; CHECK: (export "tab" (table $table)) + (export "tab" (table $table)) + + (export "__tab" (table $table)) +)