diff options
-rw-r--r-- | src/wasm2js.h | 77 | ||||
-rw-r--r-- | test/wasm2js/labels.2asm.js | 22 | ||||
-rw-r--r-- | test/wasm2js/switch.2asm.js | 46 |
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 = []; |