summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/MinifyImportsAndExports.cpp170
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
4 files changed, 173 insertions, 0 deletions
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index 984b85e63..c6507c7e9 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -28,6 +28,7 @@ SET(passes_SOURCES
MergeBlocks.cpp
MergeLocals.cpp
Metrics.cpp
+ MinifyImportsAndExports.cpp
NameList.cpp
OptimizeInstructions.cpp
PickLoadSigns.cpp
diff --git a/src/passes/MinifyImportsAndExports.cpp b/src/passes/MinifyImportsAndExports.cpp
new file mode 100644
index 000000000..9cbc3b19a
--- /dev/null
+++ b/src/passes/MinifyImportsAndExports.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 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.
+ */
+
+//
+// Minifies import and export names, renaming them to short versions,
+// and prints out a mapping to the new short versions. That mapping
+// can then be used to minify the JS calling the wasm, together enabling
+// minification of the identifiers on the JS/wasm boundary.
+//
+// For example, this may minify
+// (import "env" "longname" (func $internal))
+// to
+// (import "env" "a" (func $internal))
+// "a" is the minified name (note that we only minify the base,
+// not the module).
+//
+
+#include <map>
+#include <string>
+#include <unordered_set>
+
+#include <wasm.h>
+#include <pass.h>
+#include <shared-constants.h>
+#include <asmjs/shared-constants.h>
+#include <ir/import-utils.h>
+#include <ir/module-utils.h>
+
+namespace wasm {
+
+struct MinifyImportsAndExports : public Pass {
+
+ // Generates minified names that are valid in JS.
+ // Names are computed lazily.
+ class MinifiedNames {
+ public:
+ MinifiedNames() {
+ // Reserved words in JS up to size 4 - size 5 and above would mean we use an astronomical
+ // number of symbols, which is not realistic anyhow.
+ reserved.insert("do");
+ reserved.insert("if");
+ reserved.insert("in");
+ reserved.insert("for");
+ reserved.insert("new");
+ reserved.insert("try");
+ reserved.insert("var");
+ reserved.insert("env");
+ reserved.insert("let");
+ reserved.insert("case");
+ reserved.insert("else");
+ reserved.insert("enum");
+ reserved.insert("void");
+ reserved.insert("this");
+ reserved.insert("void");
+ reserved.insert("with");
+
+ validInitialChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
+ validLaterChars = validInitialChars + "0123456789";
+
+ minifiedState.push_back(0);
+ }
+
+ // Get the n-th minified name.
+ std::string getName(size_t n) {
+ ensure(n + 1);
+ return names[n];
+ }
+
+ private:
+ // Reserved words we must not emit.
+ std::unordered_set<std::string> reserved;
+
+ // Possible initial letters.
+ std::string validInitialChars;
+
+ // Possible later letters.
+ std::string validLaterChars;
+
+ // The minified names we computed so far.
+ std::vector<std::string> names;
+
+ // Helper state for progressively computing more minified names -
+ // a stack of the current index.
+ std::vector<size_t> minifiedState;
+
+ // Make sure we have at least n minified names.
+ void ensure(size_t n) {
+ while (names.size() < n) {
+ // Generate the current name.
+ std::string name;
+ auto index = minifiedState[0];
+ assert(index < validInitialChars.size());
+ name += validInitialChars[index];
+ for (size_t i = 1; i < minifiedState.size(); i++) {
+ auto index = minifiedState[i];
+ assert(index < validLaterChars.size());
+ name += validLaterChars[index];
+ }
+ if (reserved.count(name) == 0) {
+ names.push_back(name);
+ }
+ // Increment the state.
+ size_t i = 0;
+ while (1) {
+ minifiedState[i]++;
+ if (minifiedState[i] < (i == 0 ? validInitialChars : validLaterChars).size()) {
+ break;
+ }
+ // Overflow.
+ minifiedState[i] = 0;
+ i++;
+ if (i == minifiedState.size()) {
+ minifiedState.push_back(-1); // will become 0 after increment in next loop head
+ }
+ }
+ }
+ }
+ };
+
+ void run(PassRunner* runner, Module* module) override {
+ // Minify the imported names.
+ MinifiedNames names;
+ size_t soFar = 0;
+ std::map<Name, Name> oldToNew;
+ auto process = [&](Name& name) {
+ // do not minifiy special imports, they must always exist
+ if (name == MEMORY_BASE || name == TABLE_BASE) {
+ return;
+ }
+ auto newName = names.getName(soFar++);
+ oldToNew[newName] = name;
+ name = newName;
+ };
+ auto processImport = [&](Importable* curr) {
+ if (curr->module == ENV) {
+ process(curr->base);
+ }
+ };
+ ModuleUtils::iterImportedGlobals(*module, processImport);
+ ModuleUtils::iterImportedFunctions(*module, processImport);
+ // Minify the exported names.
+ for (auto& curr : module->exports) {
+ process(curr->name);
+ }
+ module->updateMaps();
+ // Emit the mapping.
+ for (auto& pair : oldToNew) {
+ std::cout << pair.second.str << " => " << pair.first.str << '\n';
+ }
+ }
+};
+
+Pass *createMinifyImportsAndExportsPass() {
+ return new MinifyImportsAndExports();
+}
+
+} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 66ffb9b30..577ccd36a 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -95,6 +95,7 @@ void PassRegistry::registerPasses() {
registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
registerPass("merge-locals", "merges locals when beneficial", createMergeLocalsPass);
registerPass("metrics", "reports metrics", createMetricsPass);
+ registerPass("minify-imports-and-exports", "minifies import and export names, and emits a mapping to the minified ones", createMinifyImportsAndExportsPass);
registerPass("nm", "name list", createNameListPass);
registerPass("optimize-instructions", "optimizes instruction combinations", createOptimizeInstructionsPass);
registerPass("optimize-stack-ir", "optimize Stack IR", createOptimizeStackIRPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index b4cc56898..1fd07a4f6 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -51,6 +51,7 @@ Pass* createMemoryPackingPass();
Pass* createMergeBlocksPass();
Pass* createMergeLocalsPass();
Pass* createMinifiedPrinterPass();
+Pass* createMinifyImportsAndExportsPass();
Pass* createMetricsPass();
Pass* createNameListPass();
Pass* createOptimizeInstructionsPass();