summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-02-05 15:50:19 -0800
committerGitHub <noreply@github.com>2024-02-05 15:50:19 -0800
commitd490318d64a0de809c19333c4b1c5ddfdfa65d18 (patch)
tree5dbb284927733326188b1900df414f5fa8db9f14 /src
parenta549c5991584038fc3f56df8512b52c1a81fa946 (diff)
downloadbinaryen-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.cpp64
-rw-r--r--src/passes/pass.cpp3
-rw-r--r--src/passes/passes.h1
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();