diff options
author | Alon Zakai <azakai@google.com> | 2024-02-05 15:50:19 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-05 15:50:19 -0800 |
commit | d490318d64a0de809c19333c4b1c5ddfdfa65d18 (patch) | |
tree | 5dbb284927733326188b1900df414f5fa8db9f14 /src | |
parent | a549c5991584038fc3f56df8512b52c1a81fa946 (diff) | |
download | binaryen-d490318d64a0de809c19333c4b1c5ddfdfa65d18.tar.gz binaryen-d490318d64a0de809c19333c4b1c5ddfdfa65d18.tar.bz2 binaryen-d490318d64a0de809c19333c4b1c5ddfdfa65d18.zip |
StringLowering pass (#6271)
This extends StringGathering by replacing the gathered string globals to imported
globals. It adds a custom section with the strings that the imports are expected to
provide. It also replaces the string type with extern.
This is a complete lowering of strings, except for string operations that are a TODO.
After running this, no strings remain in the wasm, and the outside JS is expected
to provide the proper imports, which it can do by processing the JSON of the
strings in the custom section "string.consts", which looks like
["foo", "bar", ..]
That is, an array of strings, which are imported as
(import "string.const" "0" (global $string.const_foo (ref extern))) ;; foo
(import "string.const" "1" (global $string.const_bar (ref extern))) ;; bar
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/StringLowering.cpp | 64 | ||||
-rw-r--r-- | src/passes/pass.cpp | 3 | ||||
-rw-r--r-- | src/passes/passes.h | 1 |
3 files changed, 64 insertions, 4 deletions
diff --git a/src/passes/StringLowering.cpp b/src/passes/StringLowering.cpp index f880a50b2..31e41b9e8 100644 --- a/src/passes/StringLowering.cpp +++ b/src/passes/StringLowering.cpp @@ -21,17 +21,18 @@ // globals, avoiding them appearing in code that can run more than once (which // can have overhead in VMs). // -// Building on that, an extended version of StringGathering will also replace -// those new globals with imported globals of type externref, for use with the -// string imports proposal. String operations will likewise need to be lowered. -// TODO +// StringLowering does the same, and also replaces those new globals with +// imported globals of type externref, for use with the string imports proposal. +// String operations will likewise need to be lowered. TODO // #include <algorithm> #include "ir/module-utils.h" #include "ir/names.h" +#include "ir/type-updating.h" #include "pass.h" +#include "support/json.h" #include "wasm-builder.h" #include "wasm.h" @@ -175,6 +176,61 @@ struct StringGathering : public Pass { } }; +struct StringLowering : public StringGathering { + void run(Module* module) override { + if (!module->features.has(FeatureSet::Strings)) { + return; + } + + // First, run the gathering operation so all string.consts are in one place. + StringGathering::run(module); + + // Lower the string.const globals into imports. + makeImports(module); + + // Remove all HeapType::string etc. in favor of externref. + updateTypes(module); + + // Disable the feature here after we lowered everything away. + module->features.disable(FeatureSet::Strings); + } + + void makeImports(Module* module) { + Index importIndex = 0; + json::Value stringArray; + stringArray.setArray(); + std::vector<Name> importedStrings; + for (auto& global : module->globals) { + if (global->init) { + if (auto* c = global->init->dynCast<StringConst>()) { + global->module = "string.const"; + global->base = std::to_string(importIndex); + importIndex++; + global->init = nullptr; + + auto str = json::Value::make(std::string(c->string.str).c_str()); + stringArray.push_back(str); + } + } + } + + // Add a custom section with the JSON. + std::stringstream stream; + stringArray.stringify(stream); + auto str = stream.str(); + auto vec = std::vector<char>(str.begin(), str.end()); + module->customSections.emplace_back( + CustomSection{"string.consts", std::move(vec)}); + } + + void updateTypes(Module* module) { + TypeMapper::TypeUpdates updates; + updates[HeapType::string] = HeapType::ext; + TypeMapper(*module, updates).map(); + } +}; + Pass* createStringGatheringPass() { return new StringGathering(); } +Pass* createStringLoweringPass() { return new StringLowering(); } } // namespace wasm diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 057642ea2..c00a5e706 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -478,6 +478,9 @@ void PassRegistry::registerPasses() { registerPass("string-gathering", "gathers wasm strings to globals", createStringGatheringPass); + registerPass("string-lowering", + "lowers wasm strings and operations to imports", + createStringLoweringPass); registerPass( "strip", "deprecated; same as strip-debug", createStripDebugPass); registerPass("stack-check", diff --git a/src/passes/passes.h b/src/passes/passes.h index 295772109..3f8b3fe6b 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -154,6 +154,7 @@ Pass* createSimplifyLocalsNoStructurePass(); Pass* createSimplifyLocalsNoTeeNoStructurePass(); Pass* createStackCheckPass(); Pass* createStringGatheringPass(); +Pass* createStringLoweringPass(); Pass* createStripDebugPass(); Pass* createStripDWARFPass(); Pass* createStripProducersPass(); |