summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm2js.h77
-rw-r--r--test/wasm2js/labels.2asm.js22
-rw-r--r--test/wasm2js/switch.2asm.js46
3 files changed, 78 insertions, 67 deletions
diff --git a/src/wasm2js.h b/src/wasm2js.h
index 33f70a4fc..8d233eb95 100644
--- a/src/wasm2js.h
+++ b/src/wasm2js.h
@@ -85,7 +85,13 @@ IString stringToIString(std::string str) { return IString(str.c_str(), false); }
// Used when taking a wasm name and generating a JS identifier. Each scope here
// is used to ensure that all names have a unique name but the same wasm name
// within a scope always resolves to the same symbol.
+//
+// Export: Export names
+// Top: The main scope which contains functions and globals
+// Local: Local variables in a function.
+// Label: Label identifiers in a function
enum class NameScope {
+ Export,
Top,
Local,
Label,
@@ -181,11 +187,15 @@ public:
// First up check our cached of mangled names to avoid doing extra work
// below
- auto& mangledScope = mangledNames[(int)scope];
- auto it = mangledScope.find(name.c_str());
- if (it != mangledScope.end()) {
+ auto& map = wasmNameToMangledName[(int)scope];
+ auto it = map.find(name.c_str());
+ if (it != map.end()) {
return it->second;
}
+ // The mangled names in our scope.
+ auto& scopeMangledNames = mangledNames[(int)scope];
+ // In some cases (see below) we need to also check the Top scope.
+ auto& topMangledNames = mangledNames[int(NameScope::Top)];
// This is the first time we've seen the `name` and `scope` pair. Generate a
// globally unique name based on `name` and then register that in our cache
@@ -203,28 +213,30 @@ public:
}
auto mangled = asmangle(out.str());
ret = stringToIString(mangled);
- if (!allMangledNames.count(ret)) {
- break;
+ if (scopeMangledNames.count(ret)) {
+ // When export names collide things may be confusing, as this is
+ // observable externally by the person using the JS. Report a warning.
+ if (scope == NameScope::Export) {
+ std::cerr << "wasm2js: warning: export names colliding: " << mangled
+ << '\n';
+ }
+ continue;
}
-
- // In the global scope that's how you refer to actual function exports, so
- // it's a bug currently if they're not globally unique. This should
- // probably be fixed via a different namespace for exports or something
- // like that.
- // XXX This is not actually a valid check atm, since functions are not in
- // the global-most scope, but rather in the "asmFunc" scope which is
- // inside it. Also, for emscripten style glue, we emit the exports as
- // a return, so there is no name placed into the scope. For these
- // reasons, just warn here, don't error.
- if (scope == NameScope::Top) {
- std::cerr << "wasm2js: warning: global scope may be colliding with "
- "other scope: "
- << mangled << '\n';
+ // The Local scope is special: a Local name must not collide with a Top
+ // name, as they are in a single namespace in JS and can conflict:
+ //
+ // function foo(bar) {
+ // var bar = 0;
+ // }
+ // function bar() { ..
+ if (scope == NameScope::Local && topMangledNames.count(ret)) {
+ continue;
}
+ // We found a good name, use it.
+ scopeMangledNames.insert(ret);
+ map[name.c_str()] = ret;
+ return ret;
}
- allMangledNames.insert(ret);
- mangledScope[name.c_str()] = ret;
- return ret;
}
private:
@@ -238,8 +250,10 @@ private:
// Mangled names cache by interned names.
// Utilizes the usually reused underlying cstring's pointer as the key.
- std::unordered_map<const char*, IString> mangledNames[(int)NameScope::Max];
- std::unordered_set<IString> allMangledNames;
+ std::unordered_map<const char*, IString>
+ wasmNameToMangledName[(int)NameScope::Max];
+ // Set of all mangled names in each scope.
+ std::unordered_set<IString> mangledNames[(int)NameScope::Max];
// If a function is callable from outside, we'll need to cast the inputs
// and our return value. Otherwise, internally, casts are only needed
@@ -383,16 +397,13 @@ Ref Wasm2JSBuilder::processWasm(Module* wasm, Name funcName) {
ModuleUtils::iterImportedGlobals(
*wasm, [&](Global* import) { addGlobalImport(asmFunc[3], import); });
- // make sure exports get their expected names
- for (auto& e : wasm->exports) {
- if (e->kind == ExternalKind::Function) {
- fromName(e->name, NameScope::Top);
- }
- }
+ // Note the names of functions. We need to do this here as when generating
+ // mangled local names we need them not to conflict with these (see fromName)
+ // so we can't wait until we parse each function to note its name.
for (auto& f : wasm->functions) {
fromName(f->name, NameScope::Top);
}
- fromName(WASM_FETCH_HIGH_BITS, NameScope::Top);
+
// globals
bool generateFetchHighBits = false;
ModuleUtils::iterDefinedGlobals(*wasm, [&](Global* global) {
@@ -589,7 +600,7 @@ void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
if (export_->kind == ExternalKind::Function) {
ValueBuilder::appendToObjectWithQuotes(
exports,
- fromName(export_->name, NameScope::Top),
+ fromName(export_->name, NameScope::Export),
ValueBuilder::makeName(fromName(export_->value, NameScope::Top)));
}
if (export_->kind == ExternalKind::Memory) {
@@ -615,7 +626,7 @@ void Wasm2JSBuilder::addExports(Ref ast, Module* wasm) {
IString("prototype")));
ValueBuilder::appendToCall(memory, descs);
ValueBuilder::appendToObjectWithQuotes(
- exports, fromName(export_->name, NameScope::Top), memory);
+ exports, fromName(export_->name, NameScope::Export), memory);
}
}
if (wasm->memory.exists) {
diff --git a/test/wasm2js/labels.2asm.js b/test/wasm2js/labels.2asm.js
index 34a88c63a..ffc776123 100644
--- a/test/wasm2js/labels.2asm.js
+++ b/test/wasm2js/labels.2asm.js
@@ -123,7 +123,7 @@ function asmFunc(global, env, buffer) {
function $7() {
var i = 0;
i = 0;
- block_1 : {
+ block : {
l : {
break l;
}
@@ -151,9 +151,9 @@ function asmFunc(global, env, buffer) {
function $8() {
var i = 0;
i = 0;
- block_1 : {
- if_1 : {
- break if_1;
+ block : {
+ if_ : {
+ break if_;
}
i = i + 1 | 0;
if5 : {
@@ -181,7 +181,7 @@ function asmFunc(global, env, buffer) {
var $2_1 = 0, $3_1 = 0;
ret : {
exit : {
- $0_2 : {
+ $0 : {
switch ($0_1 | 0) {
case 1:
case 2:
@@ -192,7 +192,7 @@ function asmFunc(global, env, buffer) {
break ret;
default:
case 0:
- break $0_2;
+ break $0;
};
}
$2_1 = 5;
@@ -204,12 +204,12 @@ function asmFunc(global, env, buffer) {
function $10($0_1) {
$0_1 = $0_1 | 0;
- $1_1 : {
+ $1 : {
switch ($0_1 | 0) {
case 0:
return 0 | 0;
default:
- break $1_1;
+ break $1;
};
}
return 2 | 0;
@@ -316,15 +316,15 @@ function asmFunc(global, env, buffer) {
}
function $17() {
- var $1_2 = 0, $2_1 = 0;
+ var $1_1 = 0, $2_1 = 0;
l1 : {
- $1_2 = 2;
+ $1_1 = 2;
l113 : {
$2_1 = 3;
break l113;
}
}
- return $1_2 + $2_1 | 0 | 0;
+ return $1_1 + $2_1 | 0 | 0;
}
var FUNCTION_TABLE = [];
diff --git a/test/wasm2js/switch.2asm.js b/test/wasm2js/switch.2asm.js
index 3c2572315..8b6f0223a 100644
--- a/test/wasm2js/switch.2asm.js
+++ b/test/wasm2js/switch.2asm.js
@@ -58,7 +58,7 @@ function asmFunc(global, env, buffer) {
function $1(i, i$hi) {
i = i | 0;
i$hi = i$hi | 0;
- var i64toi32_i32$5 = 0, i64toi32_i32$2 = 0, $7_1 = 0, $7$hi = 0, j = 0, j$hi = 0;
+ var i64toi32_i32$5 = 0, i64toi32_i32$2 = 0, $7 = 0, $7$hi = 0, j = 0, j$hi = 0;
j = 100;
j$hi = 0;
switch_ : {
@@ -73,7 +73,7 @@ function asmFunc(global, env, buffer) {
i64toi32_i32$2 = 0;
i64toi32_i32$5 = (i64toi32_i32$2 >>> 0 < i >>> 0) + i$hi | 0;
i64toi32_i32$5 = 0 - i64toi32_i32$5 | 0;
- $7_1 = i64toi32_i32$2 - i | 0;
+ $7 = i64toi32_i32$2 - i | 0;
$7$hi = i64toi32_i32$5;
break switch_;
case 6:
@@ -84,7 +84,7 @@ function asmFunc(global, env, buffer) {
case 4:
default:
i64toi32_i32$5 = j$hi;
- $7_1 = j;
+ $7 = j;
$7$hi = i64toi32_i32$5;
break switch_;
case 7:
@@ -92,43 +92,43 @@ function asmFunc(global, env, buffer) {
};
}
i64toi32_i32$5 = -1;
- $7_1 = -5;
+ $7 = -5;
$7$hi = i64toi32_i32$5;
}
i64toi32_i32$5 = $7$hi;
- i64toi32_i32$2 = $7_1;
+ i64toi32_i32$2 = $7;
i64toi32_i32$HIGH_BITS = i64toi32_i32$5;
return i64toi32_i32$2 | 0;
}
function $2(i) {
i = i | 0;
- var $5 = 0, $6 = 0, $7_1 = 0, $8 = 0, $9 = 0;
- $2_1 : {
- $1_1 : {
- $0_1 : {
+ var $5 = 0, $6 = 0, $7 = 0, $8 = 0, $9 = 0;
+ $2 : {
+ $1 : {
+ $0 : {
default_ : {
$5 = Math_imul(2, i);
$6 = $5;
- $7_1 = $5;
+ $7 = $5;
$8 = $5;
$9 = $5;
switch (3 & i | 0 | 0) {
case 0:
- break $0_1;
+ break $0;
case 1:
- break $1_1;
+ break $1;
case 2:
- break $2_1;
+ break $2;
default:
break default_;
};
}
$6 = 1e3 + $9 | 0;
}
- $7_1 = 100 + $6 | 0;
+ $7 = 100 + $6 | 0;
}
- $8 = 10 + $7_1 | 0;
+ $8 = 10 + $7 | 0;
}
return $8 | 0;
}
@@ -137,15 +137,15 @@ function asmFunc(global, env, buffer) {
return 1 | 0;
}
- function legalstub$1($0_2, $1_2) {
- $0_2 = $0_2 | 0;
- $1_2 = $1_2 | 0;
- var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_2 = 0, $2$hi = 0;
+ function legalstub$1($0_1, $1_1) {
+ $0_1 = $0_1 | 0;
+ $1_1 = $1_1 | 0;
+ var i64toi32_i32$2 = 0, i64toi32_i32$4 = 0, i64toi32_i32$0 = 0, i64toi32_i32$1 = 0, i64toi32_i32$3 = 0, $12 = 0, $13 = 0, $4 = 0, $4$hi = 0, $7$hi = 0, $2_1 = 0, $2$hi = 0;
i64toi32_i32$0 = 0;
- $4 = $0_2;
+ $4 = $0_1;
$4$hi = i64toi32_i32$0;
i64toi32_i32$0 = 0;
- i64toi32_i32$2 = $1_2;
+ i64toi32_i32$2 = $1_1;
i64toi32_i32$1 = 0;
i64toi32_i32$3 = 32;
i64toi32_i32$4 = i64toi32_i32$3 & 31 | 0;
@@ -164,7 +164,7 @@ function asmFunc(global, env, buffer) {
i64toi32_i32$2 = i64toi32_i32$1 | i64toi32_i32$2 | 0;
i64toi32_i32$2 = $1(i64toi32_i32$0 | i64toi32_i32$3 | 0 | 0, i64toi32_i32$2 | 0) | 0;
i64toi32_i32$0 = i64toi32_i32$HIGH_BITS;
- $2_2 = i64toi32_i32$2;
+ $2_1 = i64toi32_i32$2;
$2$hi = i64toi32_i32$0;
i64toi32_i32$1 = i64toi32_i32$2;
i64toi32_i32$2 = 0;
@@ -179,7 +179,7 @@ function asmFunc(global, env, buffer) {
}
setTempRet0($13 | 0);
i64toi32_i32$2 = $2$hi;
- return $2_2 | 0;
+ return $2_1 | 0;
}
var FUNCTION_TABLE = [];