From cee41eb27d162e6930624f8789f368f375e47182 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 May 2026 13:35:07 -0700 Subject: [PATCH 1/5] go --- src/passes/CMakeLists.txt | 1 + src/passes/RemoveExports.cpp | 55 +++++++++++++++++++++++++++++ src/passes/pass.cpp | 3 ++ src/passes/passes.h | 1 + test/lit/passes/remove-exports.wast | 42 ++++++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 src/passes/RemoveExports.cpp create mode 100644 test/lit/passes/remove-exports.wast 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..c510bf59926 --- /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.str)) { + 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/passes/remove-exports.wast b/test/lit/passes/remove-exports.wast new file mode 100644 index 00000000000..bf958f83adf --- /dev/null +++ b/test/lit/passes/remove-exports.wast @@ -0,0 +1,42 @@ +;; 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 + (func $foo (export "foo") + (drop (i32.const 1)) + ) + + (func $__foo (export "__foo") + (drop (i32.const 2)) + ) + + (func $bar (export "bar") + (drop (i32.const 3)) + ) + + (func $__bar (export "__bar") + (drop (i32.const 4)) + ) + + (func $__ (export "__") + (drop (i32.const 4)) + ) +) + +;; Test non-function exports. The prefixed __mem and __table exports vanish. +(module + (memory $memory 10 20) + + (table $table 10 20 funcref) + + (export "mem" (memory $memory)) + + (export "__mem" (memory $memory)) + + (export "tab" (table $table)) + + (export "__tab" (table $table)) +) From ef9db652ccc8ea86972dbd50e3b21e2b1fda143c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 May 2026 13:36:06 -0700 Subject: [PATCH 2/5] go --- src/passes/RemoveExports.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/passes/RemoveExports.cpp b/src/passes/RemoveExports.cpp index c510bf59926..99cd0ff641d 100644 --- a/src/passes/RemoveExports.cpp +++ b/src/passes/RemoveExports.cpp @@ -37,7 +37,7 @@ struct RemoveExports : public Pass { std::vector toRemove; for (auto& exp : module->exports) { - if (String::wildcardMatch(pattern, exp->name.str)) { + if (String::wildcardMatch(pattern, exp->name.toString())) { toRemove.push_back(exp->name); } } From 1aca960dd5057bc18eaad8f00a7cfbed1fb8da9b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 May 2026 13:38:14 -0700 Subject: [PATCH 3/5] go --- test/lit/passes/remove-exports.wast | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/lit/passes/remove-exports.wast b/test/lit/passes/remove-exports.wast index bf958f83adf..0f7fa384b4e 100644 --- a/test/lit/passes/remove-exports.wast +++ b/test/lit/passes/remove-exports.wast @@ -5,22 +5,59 @@ ;; 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 "__foo" (func $__foo)) + + ;; CHECK: (export "bar" (func $bar)) + + ;; CHECK: (export "__bar" (func $__bar)) + + ;; CHECK: (export "__" (func $__)) + + ;; 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)) ) @@ -28,15 +65,21 @@ ;; 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)) + ;; CHECK: (export "__mem" (memory $memory)) (export "__mem" (memory $memory)) + ;; CHECK: (export "tab" (table $table)) (export "tab" (table $table)) + ;; CHECK: (export "__tab" (table $table)) (export "__tab" (table $table)) ) From b7c099d959c0359bd05dc699ff994dbb0e4ba3de Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 May 2026 13:38:56 -0700 Subject: [PATCH 4/5] fix.lit.escap --- test/lit/passes/remove-exports.wast | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/test/lit/passes/remove-exports.wast b/test/lit/passes/remove-exports.wast index 0f7fa384b4e..0a5af581346 100644 --- a/test/lit/passes/remove-exports.wast +++ b/test/lit/passes/remove-exports.wast @@ -1,7 +1,7 @@ ;; 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 +;; 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 @@ -9,14 +9,8 @@ ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (export "__foo" (func $__foo)) - ;; CHECK: (export "bar" (func $bar)) - ;; CHECK: (export "__bar" (func $__bar)) - - ;; CHECK: (export "__" (func $__)) - ;; CHECK: (func $foo (type $0) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 1) @@ -74,12 +68,10 @@ ;; CHECK: (export "mem" (memory $memory)) (export "mem" (memory $memory)) - ;; CHECK: (export "__mem" (memory $memory)) (export "__mem" (memory $memory)) ;; CHECK: (export "tab" (table $table)) (export "tab" (table $table)) - ;; CHECK: (export "__tab" (table $table)) (export "__tab" (table $table)) ) From e680cad094e0c784db93081217e0322d4a6ab1d3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 4 May 2026 13:58:59 -0700 Subject: [PATCH 5/5] help --- test/lit/help/wasm-metadce.test | 2 ++ test/lit/help/wasm-opt.test | 2 ++ test/lit/help/wasm2js.test | 2 ++ 3 files changed, 6 insertions(+) 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: