diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/ir/names.cpp | 77 | ||||
-rw-r--r-- | src/ir/names.h | 9 | ||||
-rw-r--r-- | src/passes/MinifyImportsAndExports.cpp | 92 |
4 files changed, 89 insertions, 90 deletions
diff --git a/src/ir/CMakeLists.txt b/src/ir/CMakeLists.txt index cfc233fd8..f98f7b7aa 100644 --- a/src/ir/CMakeLists.txt +++ b/src/ir/CMakeLists.txt @@ -2,6 +2,7 @@ FILE(GLOB ir_HEADERS *.h) set(ir_SOURCES ExpressionAnalyzer.cpp ExpressionManipulator.cpp + names.cpp LocalGraph.cpp ReFinalize.cpp stack-utils.cpp diff --git a/src/ir/names.cpp b/src/ir/names.cpp new file mode 100644 index 000000000..cbc703438 --- /dev/null +++ b/src/ir/names.cpp @@ -0,0 +1,77 @@ +/* + * Copyright 2021 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. + */ + +#include "ir/names.h" +#include <sstream> + +namespace wasm { + +namespace Names { + +// Reserved words in JS that we will not emit up to size 4 - size 5 and above +// would mean we use an astronomical number of symbols, which is not realistic +// anyhow. +static std::unordered_set<std::string> reserved = {"do", + "if", + "in", + "for", + "new", + "try", + "var", + "env", + "let", + "case", + "else", + "enum", + "void", + "this", + "with"}; + +// Possible initial letters. +static std::string validInitialChars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"; + +// Possible later letters. +static std::string validLaterChars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$0123456789"; + +std::string MinifiedNameGenerator::getName() { + std::string name; + do { + size_t n = state++; + std::stringstream ss; + ss << validInitialChars[n % validInitialChars.size()]; + n /= validInitialChars.size(); + // `m` is the number of `state` counts each of the `n` represents. + size_t m = validInitialChars.size(); + while (n) { + if (n % (validLaterChars.size() + 1) == 0) { + // Skip states that contain zeros in later positions. + state += m; + ++n; + } + ss << validLaterChars[(n % (validLaterChars.size() + 1)) - 1]; + n /= (validLaterChars.size() + 1); + m *= (validLaterChars.size() + 1); + } + name = ss.str(); + } while (reserved.count(name)); + return name; +} + +} // namespace Names + +} // namespace wasm diff --git a/src/ir/names.h b/src/ir/names.h index cefeb5b42..46cb239ef 100644 --- a/src/ir/names.h +++ b/src/ir/names.h @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #ifndef wasm_ir_names_h #define wasm_ir_names_h @@ -88,6 +87,14 @@ inline Name getValidElementSegmentName(Module& module, Name root) { root, [&](Name test) { return !module.getElementSegmentOrNull(test); }); } +class MinifiedNameGenerator { + size_t state = 0; + +public: + // Get a fresh minified name. + std::string getName(); +}; + } // namespace Names } // namespace wasm diff --git a/src/passes/MinifyImportsAndExports.cpp b/src/passes/MinifyImportsAndExports.cpp index ca8426e8a..532616851 100644 --- a/src/passes/MinifyImportsAndExports.cpp +++ b/src/passes/MinifyImportsAndExports.cpp @@ -38,6 +38,7 @@ #include <asmjs/shared-constants.h> #include <ir/import-utils.h> #include <ir/module-utils.h> +#include <ir/names.h> #include <pass.h> #include <shared-constants.h> #include <wasm.h> @@ -54,103 +55,16 @@ public: private: // 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("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()) { - // will become 0 after increment in next loop head - minifiedState.push_back(-1); - } - } - } - } - }; void run(PassRunner* runner, Module* module) override { // Minify the imported names. - MinifiedNames names; - size_t soFar = 0; + Names::MinifiedNameGenerator names; std::map<Name, Name> oldToNew; std::map<Name, Name> newToOld; auto process = [&](Name& name) { auto iter = oldToNew.find(name); if (iter == oldToNew.end()) { - auto newName = names.getName(soFar++); + auto newName = names.getName(); oldToNew[name] = newName; newToOld[newName] = name; name = newName; |