summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel Wirtz <dcode@dcode.io>2018-02-21 23:22:11 +0100
committerAlon Zakai <alonzakai@gmail.com>2018-02-21 14:22:11 -0800
commit3f5ee87d262080265b65a3789392b399c91f30ad (patch)
tree131b31b939cb6f0608e470fcb6d933cb9bb5016c /src
parent5578bb58402fde2bb2c932bfa08ab71045854a41 (diff)
downloadbinaryen-3f5ee87d262080265b65a3789392b399c91f30ad.tar.gz
binaryen-3f5ee87d262080265b65a3789392b399c91f30ad.tar.bz2
binaryen-3f5ee87d262080265b65a3789392b399c91f30ad.zip
Improve name mangling of asm.js identifiers (#1433)
Also refactors mangling to its own file so it can be reused by generators and consumers, i.e., where it is important to know that an import must be named 'switch_' where it otherwise would be 'switch'. * Update tests and JS dist files
Diffstat (limited to 'src')
-rw-r--r--src/asmjs/CMakeLists.txt1
-rw-r--r--src/asmjs/asmangle.cpp252
-rw-r--r--src/asmjs/asmangle.h30
-rw-r--r--src/wasm2asm.h34
4 files changed, 297 insertions, 20 deletions
diff --git a/src/asmjs/CMakeLists.txt b/src/asmjs/CMakeLists.txt
index 2387d3ca0..0252ed911 100644
--- a/src/asmjs/CMakeLists.txt
+++ b/src/asmjs/CMakeLists.txt
@@ -1,5 +1,6 @@
SET(asmjs_SOURCES
asm_v_wasm.cpp
+ asmangle.cpp
shared-constants.cpp
)
ADD_LIBRARY(asmjs STATIC ${asmjs_SOURCES}) \ No newline at end of file
diff --git a/src/asmjs/asmangle.cpp b/src/asmjs/asmangle.cpp
new file mode 100644
index 000000000..0453139b3
--- /dev/null
+++ b/src/asmjs/asmangle.cpp
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+#include "asmjs/asmangle.h"
+#include <assert.h>
+
+
+namespace wasm {
+
+std::string asmangle(std::string name) {
+ bool mightBeKeyword = true;
+ size_t i = 1;
+
+ assert(!name.empty());
+
+ // Names must start with a character, $ or _
+ switch (auto ch = name[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ name = "$" + name;
+ i = 2;
+ goto notKeyword;
+ }
+ notKeyword:
+ case '$':
+ case '_': {
+ mightBeKeyword = false;
+ break;
+ }
+ default: {
+ if (
+ !(ch >= 'a' && ch <= 'z') &&
+ !(ch >= 'A' && ch <= 'Z')
+ ) {
+ name = "$" + name.substr(1);
+ mightBeKeyword = false;
+ }
+ }
+ }
+
+ // Names must contain only characters, digits, $ or _
+ size_t len = name.length();
+ for (; i < len; ++i) {
+ switch (char ch = name[i]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '$':
+ case '_': {
+ mightBeKeyword = false;
+ break;
+ }
+ default: {
+ if (
+ !(ch >= 'a' && ch <= 'z') &&
+ !(ch >= 'A' && ch <= 'Z')
+ ) {
+ name = name.substr(0, i) + "_" + name.substr(i + 1);
+ mightBeKeyword = false;
+ }
+ }
+ }
+ }
+
+ // Names must not collide with keywords
+ if (mightBeKeyword && len >= 2 && len <= 10) {
+ switch (name[0]) {
+ case 'a': {
+ if (name == "arguments") {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'b': {
+ if (name == "break") {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'c': {
+ if (
+ name == "case" ||
+ name == "continue" ||
+ name == "catch" ||
+ name == "const" ||
+ name == "class"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'd': {
+ if (
+ name == "do" ||
+ name == "default" ||
+ name == "debugger"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'e': {
+ if (
+ name == "else" ||
+ name == "enum" ||
+ name == "eval" || // to be sure
+ name == "export" ||
+ name == "extends"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'f': {
+ if (
+ name == "for" ||
+ name == "false" ||
+ name == "finally" ||
+ name == "function"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'i': {
+ if (
+ name == "if" ||
+ name == "in" ||
+ name == "import" ||
+ name == "interface" ||
+ name == "implements" ||
+ name == "instanceof"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'l': {
+ if (name == "let") {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'n': {
+ if (
+ name == "new" ||
+ name == "null"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'p': {
+ if (
+ name == "public" ||
+ name == "package" ||
+ name == "private" ||
+ name == "protected"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'r': {
+ if (name == "return") {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 's': {
+ if (
+ name == "super" ||
+ name == "static" ||
+ name == "switch"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 't': {
+ if (
+ name == "try" ||
+ name == "this" ||
+ name == "true" ||
+ name == "throw" ||
+ name == "typeof"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'v': {
+ if (
+ name == "var" ||
+ name == "void"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'w': {
+ if (
+ name == "with" ||
+ name == "while"
+ ) {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ case 'y': {
+ if (name == "yield") {
+ goto mangleKeyword;
+ }
+ break;
+ }
+ mangleKeyword: {
+ name = name + "_";
+ }
+ }
+ }
+ return name;
+}
+
+} // namespace wasm
diff --git a/src/asmjs/asmangle.h b/src/asmjs/asmangle.h
new file mode 100644
index 000000000..161101c07
--- /dev/null
+++ b/src/asmjs/asmangle.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#ifndef wasm_asmjs_asmangle_h
+#define wasm_asmjs_asmangle_h
+
+#include <string>
+
+
+namespace wasm {
+
+ // Mangles a WebAssembly name to a valid JavaScript identifier.
+ std::string asmangle(std::string name);
+
+} // namespace wasm
+
+#endif // wasm_asmjs_asmangle_h
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
index eded082ad..59f2d6ab8 100644
--- a/src/wasm2asm.h
+++ b/src/wasm2asm.h
@@ -26,6 +26,7 @@
#include <numeric>
#include "asmjs/shared-constants.h"
+#include "asmjs/asmangle.h"
#include "wasm.h"
#include "wasm-builder.h"
#include "emscripten-optimizer/optimizer.h"
@@ -156,27 +157,16 @@ public:
frees[type].push_back(temp);
}
- static IString fromName(Name name) {
- // TODO: more clever name fixing, including checking we do not collide
- const char* str = name.str;
- // check the various issues, and recurse so we check the others
- if (strchr(str, '-')) {
- char* mod = strdup(str);
- str = mod;
- while (*mod) {
- if (*mod == '-') *mod = '_';
- mod++;
- }
- IString result = fromName(IString(str, false));
- free((void*)str);
- return result;
- }
- if (isdigit(str[0]) || strcmp(str, "if") == 0) {
- std::string prefixed = "$$";
- prefixed += name.str;
- return fromName(IString(prefixed.c_str(), false));
+ IString fromName(Name name) {
+ // TODO: checking names do not collide after mangling
+ auto it = mangledNames.find(name.c_str());
+ if (it != mangledNames.end()) {
+ return it->second;
}
- return name;
+ auto mangled = asmangle(std::string(name.c_str()));
+ IString ret(mangled.c_str(), false);
+ mangledNames[name.c_str()] = ret;
+ return ret;
}
void setStatement(Expression* curr) {
@@ -202,6 +192,10 @@ private:
// Expressions that will be a statement.
std::set<Expression*> willBeStatement;
+ // Mangled names cache by interned names.
+ // Utilizes the usually reused underlying cstring's pointer as the key.
+ std::unordered_map<const char*, IString> mangledNames;
+
// All our function tables have the same size TODO: optimize?
size_t tableSize;