diff options
author | Thomas Lively <7121787+tlively@users.noreply.github.com> | 2021-06-01 12:15:24 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-01 09:15:24 -0700 |
commit | 028f47368fe844130f52ad7811c8028ebd18a38e (patch) | |
tree | 7c6b2a68a55f922d70f534abd594d900079139b3 | |
parent | 88606f75b97ef3014edb74484125534c2040095b (diff) | |
download | binaryen-028f47368fe844130f52ad7811c8028ebd18a38e.tar.gz binaryen-028f47368fe844130f52ad7811c8028ebd18a38e.tar.bz2 binaryen-028f47368fe844130f52ad7811c8028ebd18a38e.zip |
[wasm-split] Minimize names of newly created exports (#3905)
wasm-split would previously use internal function names to create the external
names of the functions that are newly exported from the primary module to be
imported into the secondary module. When the input module contains full function
names (as is commonly the case when emitting symbol maps), this caused the
function names to be preserved as the export names, even when names are
otherwise being stripped. To save on code size and properly anonymize functions,
generate minimal export names when debuginfo is disabled instead.
-rw-r--r-- | src/ir/module-splitting.cpp | 12 | ||||
-rw-r--r-- | src/ir/module-splitting.h | 4 | ||||
-rw-r--r-- | src/tools/wasm-split.cpp | 1 | ||||
-rw-r--r-- | test/example/module-splitting.cpp | 44 | ||||
-rw-r--r-- | test/example/module-splitting.txt | 72 | ||||
-rw-r--r-- | test/lit/wasm-split/basic.wast | 88 | ||||
-rw-r--r-- | test/lit/wasm-split/minimized-exports.wast | 38 |
7 files changed, 213 insertions, 46 deletions
diff --git a/src/ir/module-splitting.cpp b/src/ir/module-splitting.cpp index 5f9ba0aad..d6dca8994 100644 --- a/src/ir/module-splitting.cpp +++ b/src/ir/module-splitting.cpp @@ -266,6 +266,8 @@ struct ModuleSplitter { TableSlotManager tableManager; + Names::MinifiedNameGenerator minified; + // Map from internal function names to (one of) their corresponding export // names. std::map<Name, Name> exportedPrimaryFuncs; @@ -344,8 +346,14 @@ void ModuleSplitter::exportImportFunction(Name funcName) { if (exportIt != exportedPrimaryFuncs.end()) { exportName = exportIt->second; } else { - exportName = Names::getValidExportName( - primary, config.newExportPrefix + funcName.c_str()); + if (config.minimizeNewExportNames) { + do { + exportName = config.newExportPrefix + minified.getName(); + } while (primary.getExportOrNull(exportName) != nullptr); + } else { + exportName = Names::getValidExportName( + primary, config.newExportPrefix + funcName.c_str()); + } primary.addExport( Builder::makeExport(exportName, funcName, ExternalKind::Function)); exportedPrimaryFuncs[funcName] = exportName; diff --git a/src/ir/module-splitting.h b/src/ir/module-splitting.h index 9a2597067..479fba148 100644 --- a/src/ir/module-splitting.h +++ b/src/ir/module-splitting.h @@ -62,6 +62,10 @@ struct Config { // used to differentiate between "real" exports of the module and exports that // should only be consumed by the secondary module. std::string newExportPrefix = ""; + // Whether the export names of newly created exports should be minimized. If + // false, the original function names will be used (after `newExportPrefix`) + // as the new export names. + bool minimizeNewExportNames = false; }; // Returns the new secondary module and modifies the `primary` module in place. diff --git a/src/tools/wasm-split.cpp b/src/tools/wasm-split.cpp index 3ac8b2c45..7f3fe65c4 100644 --- a/src/tools/wasm-split.cpp +++ b/src/tools/wasm-split.cpp @@ -676,6 +676,7 @@ void splitModule(Module& wasm, const WasmSplitOptions& options) { if (options.exportPrefix.size()) { config.newExportPrefix = options.exportPrefix; } + config.minimizeNewExportNames = !options.passOptions.debugInfo; std::unique_ptr<Module> secondary = ModuleSplitting::splitFunctions(wasm, config); diff --git a/test/example/module-splitting.cpp b/test/example/module-splitting.cpp index 5391fe584..2aa67d6d5 100644 --- a/test/example/module-splitting.cpp +++ b/test/example/module-splitting.cpp @@ -64,6 +64,8 @@ void do_test(const std::set<Name>& keptFuncs, std::string&& module) { assert(valid && "secondary invalid!"); } +void test_minimized_exports(); + int main() { // Trivial module do_test({}, "(module)"); @@ -437,4 +439,46 @@ int main() { (export "foo2" (func $foo)) (func $foo) ))"); + + test_minimized_exports(); +} + +void test_minimized_exports() { + Module primary; + primary.features = FeatureSet::All; + + std::set<Name> keep; + Expression* callBody = nullptr; + + Builder builder(primary); + + for (size_t i = 0; i < 10; ++i) { + Name name = std::to_string(i); + primary.addFunction(Builder::makeFunction(name, {}, {}, builder.makeNop())); + keep.insert(name); + callBody = + builder.blockify(callBody, builder.makeCall(name, {}, Type::none)); + + if (i == 3) { + primary.addExport( + Builder::makeExport("already_exported", name, ExternalKind::Function)); + } + if (i == 7) { + primary.addExport( + Builder::makeExport("%b", name, ExternalKind::Function)); + } + } + + primary.addFunction(Builder::makeFunction("call", {}, {}, callBody)); + + ModuleSplitting::Config config; + config.primaryFuncs = std::move(keep); + config.newExportPrefix = "%"; + config.minimizeNewExportNames = true; + + auto secondary = splitFunctions(primary, config); + std::cout << "Minimized names primary:\n"; + std::cout << primary << "\n"; + std::cout << "Minimized names secondary:\n"; + std::cout << *secondary << "\n"; } diff --git a/test/example/module-splitting.txt b/test/example/module-splitting.txt index 5c3728cde..2b92e9dd6 100644 --- a/test/example/module-splitting.txt +++ b/test/example/module-splitting.txt @@ -1107,3 +1107,75 @@ Secondary: ) +Minimized names primary: +(module + (type $none_=>_none (func)) + (export "already_exported" (func $3)) + (export "%b" (func $7)) + (export "%a" (func $0)) + (export "%c" (func $1)) + (export "%d" (func $2)) + (export "%e" (func $4)) + (export "%f" (func $5)) + (export "%g" (func $6)) + (export "%h" (func $8)) + (export "%i" (func $9)) + (func $0 + (nop) + ) + (func $1 + (nop) + ) + (func $2 + (nop) + ) + (func $3 + (nop) + ) + (func $4 + (nop) + ) + (func $5 + (nop) + ) + (func $6 + (nop) + ) + (func $7 + (nop) + ) + (func $8 + (nop) + ) + (func $9 + (nop) + ) +) + +Minimized names secondary: +(module + (type $none_=>_none (func)) + (import "primary" "%a" (func $0)) + (import "primary" "%c" (func $1)) + (import "primary" "%d" (func $2)) + (import "primary" "already_exported" (func $3)) + (import "primary" "%e" (func $4)) + (import "primary" "%f" (func $5)) + (import "primary" "%g" (func $6)) + (import "primary" "%b" (func $7)) + (import "primary" "%h" (func $8)) + (import "primary" "%i" (func $9)) + (func $call + (call $0) + (call $1) + (call $2) + (call $3) + (call $4) + (call $5) + (call $6) + (call $7) + (call $8) + (call $9) + ) +) + diff --git a/test/lit/wasm-split/basic.wast b/test/lit/wasm-split/basic.wast index 98fe433f3..7bbc14b49 100644 --- a/test/lit/wasm-split/basic.wast +++ b/test/lit/wasm-split/basic.wast @@ -1,19 +1,19 @@ -;; RUN: wasm-split %s --export-prefix='%' -o1 %t.none.1.wasm -o2 %t.none.2.wasm -v 2>&1 \ +;; RUN: wasm-split %s --export-prefix='%' -g -o1 %t.none.1.wasm -o2 %t.none.2.wasm -v 2>&1 \ ;; RUN: | filecheck %s --check-prefix KEEP-NONE ;; RUN: wasm-dis %t.none.1.wasm | filecheck %s --check-prefix KEEP-NONE-PRIMARY ;; RUN: wasm-dis %t.none.2.wasm | filecheck %s --check-prefix KEEP-NONE-SECONDARY -;; RUN: wasm-split %s --export-prefix='%' -o1 %t.foo.1.wasm -o2 %t.foo.2.wasm --keep-funcs=foo -v 2>&1 \ +;; RUN: wasm-split %s --export-prefix='%' -g -o1 %t.foo.1.wasm -o2 %t.foo.2.wasm --keep-funcs=foo -v 2>&1 \ ;; RUN: | filecheck %s --check-prefix KEEP-FOO ;; RUN: wasm-dis %t.foo.1.wasm | filecheck %s --check-prefix KEEP-FOO-PRIMARY ;; RUN: wasm-dis %t.foo.2.wasm | filecheck %s --check-prefix KEEP-FOO-SECONDARY -;; RUN: wasm-split %s --export-prefix='%' -o1 %t.bar.1.wasm -o2 %t.bar.2.wasm --keep-funcs=bar -v 2>&1 \ +;; RUN: wasm-split %s --export-prefix='%' -g -o1 %t.bar.1.wasm -o2 %t.bar.2.wasm --keep-funcs=bar -v 2>&1 \ ;; RUN: | filecheck %s --check-prefix KEEP-BAR ;; RUN: wasm-dis %t.bar.1.wasm | filecheck %s --check-prefix KEEP-BAR-PRIMARY ;; RUN: wasm-dis %t.bar.2.wasm | filecheck %s --check-prefix KEEP-BAR-SECONDARY -;; RUN: wasm-split %s --export-prefix='%' -o1 %t.both.1.wasm -o2 %t.both.2.wasm --keep-funcs=foo,bar -v 2>&1 \ +;; RUN: wasm-split %s --export-prefix='%' -g -o1 %t.both.1.wasm -o2 %t.both.2.wasm --keep-funcs=foo,bar -v 2>&1 \ ;; RUN: | filecheck %s --check-prefix KEEP-BOTH ;; RUN: wasm-dis %t.both.1.wasm | filecheck %s --check-prefix KEEP-BOTH-PRIMARY ;; RUN: wasm-dis %t.both.2.wasm | filecheck %s --check-prefix KEEP-BOTH-SECONDARY @@ -33,23 +33,23 @@ ;; KEEP-NONE-PRIMARY: (module ;; KEEP-NONE-PRIMARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-NONE-PRIMARY-NEXT: (import "placeholder" "0" (func $fimport$0 (param i32) (result i32))) -;; KEEP-NONE-PRIMARY-NEXT: (table $0 1 1 funcref) -;; KEEP-NONE-PRIMARY-NEXT: (elem (i32.const 0) $fimport$0) -;; KEEP-NONE-PRIMARY-NEXT: (export "%table" (table $0)) +;; KEEP-NONE-PRIMARY-NEXT: (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32))) +;; KEEP-NONE-PRIMARY-NEXT: (table $table 1 1 funcref) +;; KEEP-NONE-PRIMARY-NEXT: (elem (i32.const 0) $placeholder_0) +;; KEEP-NONE-PRIMARY-NEXT: (export "%table" (table $table)) ;; KEEP-NONE-PRIMARY-NEXT: ) ;; KEEP-NONE-SECONDARY: (module ;; KEEP-NONE-SECONDARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-NONE-SECONDARY-NEXT: (import "primary" "%table" (table $timport$0 1 1 funcref)) -;; KEEP-NONE-SECONDARY-NEXT: (elem (i32.const 0) $1) -;; KEEP-NONE-SECONDARY-NEXT: (func $0 (param $0 i32) (result i32) -;; KEEP-NONE-SECONDARY-NEXT: (call $1 +;; KEEP-NONE-SECONDARY-NEXT: (import "primary" "%table" (table $table 1 1 funcref)) +;; KEEP-NONE-SECONDARY-NEXT: (elem (i32.const 0) $foo) +;; KEEP-NONE-SECONDARY-NEXT: (func $bar (param $0 i32) (result i32) +;; KEEP-NONE-SECONDARY-NEXT: (call $foo ;; KEEP-NONE-SECONDARY-NEXT: (i32.const 1) ;; KEEP-NONE-SECONDARY-NEXT: ) ;; KEEP-NONE-SECONDARY-NEXT: ) -;; KEEP-NONE-SECONDARY-NEXT: (func $1 (param $0 i32) (result i32) -;; KEEP-NONE-SECONDARY-NEXT: (call $0 +;; KEEP-NONE-SECONDARY-NEXT: (func $foo (param $0 i32) (result i32) +;; KEEP-NONE-SECONDARY-NEXT: (call $bar ;; KEEP-NONE-SECONDARY-NEXT: (i32.const 0) ;; KEEP-NONE-SECONDARY-NEXT: ) ;; KEEP-NONE-SECONDARY-NEXT: ) @@ -60,12 +60,12 @@ ;; KEEP-FOO-PRIMARY: (module ;; KEEP-FOO-PRIMARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-FOO-PRIMARY-NEXT: (import "placeholder" "1" (func $fimport$0 (param i32) (result i32))) -;; KEEP-FOO-PRIMARY-NEXT: (table $0 2 2 funcref) -;; KEEP-FOO-PRIMARY-NEXT: (elem (i32.const 0) $0 $fimport$0) -;; KEEP-FOO-PRIMARY-NEXT: (export "%foo" (func $0)) -;; KEEP-FOO-PRIMARY-NEXT: (export "%table" (table $0)) -;; KEEP-FOO-PRIMARY-NEXT: (func $0 (param $0 i32) (result i32) +;; KEEP-FOO-PRIMARY-NEXT: (import "placeholder" "1" (func $placeholder_1 (param i32) (result i32))) +;; KEEP-FOO-PRIMARY-NEXT: (table $table 2 2 funcref) +;; KEEP-FOO-PRIMARY-NEXT: (elem (i32.const 0) $foo $placeholder_1) +;; KEEP-FOO-PRIMARY-NEXT: (export "%foo" (func $foo)) +;; KEEP-FOO-PRIMARY-NEXT: (export "%table" (table $table)) +;; KEEP-FOO-PRIMARY-NEXT: (func $foo (param $0 i32) (result i32) ;; KEEP-FOO-PRIMARY-NEXT: (call_indirect (type $i32_=>_i32) ;; KEEP-FOO-PRIMARY-NEXT: (i32.const 0) ;; KEEP-FOO-PRIMARY-NEXT: (i32.const 1) @@ -75,11 +75,11 @@ ;; KEEP-FOO-SECONDARY: (module ;; KEEP-FOO-SECONDARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-FOO-SECONDARY-NEXT: (import "primary" "%table" (table $timport$0 2 2 funcref)) -;; KEEP-FOO-SECONDARY-NEXT: (import "primary" "%foo" (func $fimport$0 (param i32) (result i32))) -;; KEEP-FOO-SECONDARY-NEXT: (elem (i32.const 1) $0) -;; KEEP-FOO-SECONDARY-NEXT: (func $0 (param $0 i32) (result i32) -;; KEEP-FOO-SECONDARY-NEXT: (call $fimport$0 +;; KEEP-FOO-SECONDARY-NEXT: (import "primary" "%table" (table $table 2 2 funcref)) +;; KEEP-FOO-SECONDARY-NEXT: (import "primary" "%foo" (func $foo (param i32) (result i32))) +;; KEEP-FOO-SECONDARY-NEXT: (elem (i32.const 1) $bar) +;; KEEP-FOO-SECONDARY-NEXT: (func $bar (param $0 i32) (result i32) +;; KEEP-FOO-SECONDARY-NEXT: (call $foo ;; KEEP-FOO-SECONDARY-NEXT: (i32.const 1) ;; KEEP-FOO-SECONDARY-NEXT: ) ;; KEEP-FOO-SECONDARY-NEXT: ) @@ -90,12 +90,12 @@ ;; KEEP-BAR-PRIMARY: (module ;; KEEP-BAR-PRIMARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-BAR-PRIMARY-NEXT: (import "placeholder" "0" (func $fimport$0 (param i32) (result i32))) -;; KEEP-BAR-PRIMARY-NEXT: (table $0 1 1 funcref) -;; KEEP-BAR-PRIMARY-NEXT: (elem (i32.const 0) $fimport$0) -;; KEEP-BAR-PRIMARY-NEXT: (export "%bar" (func $0)) -;; KEEP-BAR-PRIMARY-NEXT: (export "%table" (table $0)) -;; KEEP-BAR-PRIMARY-NEXT: (func $0 (param $0 i32) (result i32) +;; KEEP-BAR-PRIMARY-NEXT: (import "placeholder" "0" (func $placeholder_0 (param i32) (result i32))) +;; KEEP-BAR-PRIMARY-NEXT: (table $table 1 1 funcref) +;; KEEP-BAR-PRIMARY-NEXT: (elem (i32.const 0) $placeholder_0) +;; KEEP-BAR-PRIMARY-NEXT: (export "%bar" (func $bar)) +;; KEEP-BAR-PRIMARY-NEXT: (export "%table" (table $table)) +;; KEEP-BAR-PRIMARY-NEXT: (func $bar (param $0 i32) (result i32) ;; KEEP-BAR-PRIMARY-NEXT: (call_indirect (type $i32_=>_i32) ;; KEEP-BAR-PRIMARY-NEXT: (i32.const 1) ;; KEEP-BAR-PRIMARY-NEXT: (i32.const 0) @@ -105,11 +105,11 @@ ;; KEEP-BAR-SECONDARY: (module ;; KEEP-BAR-SECONDARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-BAR-SECONDARY-NEXT: (import "primary" "%table" (table $timport$0 1 1 funcref)) -;; KEEP-BAR-SECONDARY-NEXT: (import "primary" "%bar" (func $fimport$0 (param i32) (result i32))) -;; KEEP-BAR-SECONDARY-NEXT: (elem (i32.const 0) $0) -;; KEEP-BAR-SECONDARY-NEXT: (func $0 (param $0 i32) (result i32) -;; KEEP-BAR-SECONDARY-NEXT: (call $fimport$0 +;; KEEP-BAR-SECONDARY-NEXT: (import "primary" "%table" (table $table 1 1 funcref)) +;; KEEP-BAR-SECONDARY-NEXT: (import "primary" "%bar" (func $bar (param i32) (result i32))) +;; KEEP-BAR-SECONDARY-NEXT: (elem (i32.const 0) $foo) +;; KEEP-BAR-SECONDARY-NEXT: (func $foo (param $0 i32) (result i32) +;; KEEP-BAR-SECONDARY-NEXT: (call $bar ;; KEEP-BAR-SECONDARY-NEXT: (i32.const 0) ;; KEEP-BAR-SECONDARY-NEXT: ) ;; KEEP-BAR-SECONDARY-NEXT: ) @@ -121,21 +121,21 @@ ;; KEEP-BOTH-PRIMARY: (module ;; KEEP-BOTH-PRIMARY-NEXT: (type $i32_=>_i32 (func (param i32) (result i32))) -;; KEEP-BOTH-PRIMARY-NEXT: (table $0 1 1 funcref) -;; KEEP-BOTH-PRIMARY-NEXT: (elem (i32.const 0) $0) -;; KEEP-BOTH-PRIMARY-NEXT: (export "%table" (table $0)) -;; KEEP-BOTH-PRIMARY-NEXT: (func $0 (param $0 i32) (result i32) -;; KEEP-BOTH-PRIMARY-NEXT: (call $1 +;; KEEP-BOTH-PRIMARY-NEXT: (table $table 1 1 funcref) +;; KEEP-BOTH-PRIMARY-NEXT: (elem (i32.const 0) $foo) +;; KEEP-BOTH-PRIMARY-NEXT: (export "%table" (table $table)) +;; KEEP-BOTH-PRIMARY-NEXT: (func $foo (param $0 i32) (result i32) +;; KEEP-BOTH-PRIMARY-NEXT: (call $bar ;; KEEP-BOTH-PRIMARY-NEXT: (i32.const 0) ;; KEEP-BOTH-PRIMARY-NEXT: ) ;; KEEP-BOTH-PRIMARY-NEXT: ) -;; KEEP-BOTH-PRIMARY-NEXT: (func $1 (param $0 i32) (result i32) -;; KEEP-BOTH-PRIMARY-NEXT: (call $0 +;; KEEP-BOTH-PRIMARY-NEXT: (func $bar (param $0 i32) (result i32) +;; KEEP-BOTH-PRIMARY-NEXT: (call $foo ;; KEEP-BOTH-PRIMARY-NEXT: (i32.const 1) ;; KEEP-BOTH-PRIMARY-NEXT: ) ;; KEEP-BOTH-PRIMARY-NEXT: ) ;; KEEP-BOTH-PRIMARY-NEXT: ) ;; KEEP-BOTH-SECONDARY: (module -;; KEEP-BOTH-SECONDARY-NEXT: (import "primary" "%table" (table $timport$0 1 1 funcref)) +;; KEEP-BOTH-SECONDARY-NEXT: (import "primary" "%table" (table $table 1 1 funcref)) ;; KEEP-BOTH-SECONDARY-NEXT: ) diff --git a/test/lit/wasm-split/minimized-exports.wast b/test/lit/wasm-split/minimized-exports.wast new file mode 100644 index 000000000..a7c225550 --- /dev/null +++ b/test/lit/wasm-split/minimized-exports.wast @@ -0,0 +1,38 @@ +;; RUN: wasm-split %s --keep-funcs=foo,bar --export-prefix='%' -o1 %t.1.wasm -o2 %t.2.wasm +;; RUN: wasm-dis %t.1.wasm | filecheck %s --check-prefix PRIMARY +;; RUN: wasm-dis %t.2.wasm | filecheck %s --check-prefix SECONDARY + +;; PRIMARY: (module +;; PRIMARY-NEXT: (type $none_=>_none (func)) +;; PRIMARY-NEXT: (export "%a" (func $1)) +;; PRIMARY-NEXT: (export "%b" (func $0)) +;; PRIMARY-NEXT: (func $0 +;; PRIMARY-NEXT: (nop) +;; PRIMARY-NEXT: ) +;; PRIMARY-NEXT: (func $1 +;; PRIMARY-NEXT: (nop) +;; PRIMARY-NEXT: ) +;; PRIMARY-NEXT: ) + +;; SECONDARY: (module +;; SECONDARY-NEXT: (type $none_=>_none (func)) +;; SECONDARY-NEXT: (import "primary" "%a" (func $fimport$0)) +;; SECONDARY-NEXT: (import "primary" "%b" (func $fimport$1)) +;; SECONDARY-NEXT: (func $0 +;; SECONDARY-NEXT: (call $fimport$1) +;; SECONDARY-NEXT: (call $fimport$0) +;; SECONDARY-NEXT: ) +;; SECONDARY-NEXT: ) + +(module + (func $foo + (nop) + ) + (func $bar + (nop) + ) + (func $baz + (call $foo) + (call $bar) + ) +) |