From f79b3e8e92eda27a925871d365c800fa92215025 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 09:06:01 -0700 Subject: [PATCH 1/6] work --- .clang-format | 3 --- src/wasm2js.h | 29 +++++++++++------------------ test/wasm2js/left-to-right.2asm.js | 12 ++++++------ test/wasm2js/refs.2asm.js | 18 +++++++++++++++++- test/wasm2js/refs.2asm.js.opt | 12 +++++++++++- test/wasm2js/refs.wast | 20 ++++++++++++++++++++ 6 files changed, 65 insertions(+), 29 deletions(-) diff --git a/.clang-format b/.clang-format index 316f76d89fc..cedadcbd0e6 100644 --- a/.clang-format +++ b/.clang-format @@ -12,6 +12,3 @@ BinPackParameters: false Language: JavaScript DisableFormat: true --- -Language: Json -BasedOnStyle: LLVM ---- diff --git a/src/wasm2js.h b/src/wasm2js.h index 34260547d25..3bc8710f2cb 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -206,12 +206,13 @@ class Wasm2JSBuilder { // Get a temp var. IString getTemp(Type type, Function* func) { IString ret; - TODO_SINGLE_COMPOUND(type); - if (frees[type.getBasic()].size() > 0) { - ret = frees[type.getBasic()].back(); - frees[type.getBasic()].pop_back(); + // TODO: handle tuples + assert(!type.isTuple() && "Unexpected tuple type"); \ + if (frees[type].size() > 0) { + ret = frees[type].back(); + frees[type].pop_back(); } else { - size_t index = temps[type.getBasic()]++; + auto index = temps[type]++; ret = IString((std::string("wasm2js_") + type.toString() + "$" + std::to_string(index)) .c_str(), @@ -225,8 +226,9 @@ class Wasm2JSBuilder { // Free a temp var. void freeTemp(Type type, IString temp) { - TODO_SINGLE_COMPOUND(type); - frees[type.getBasic()].push_back(temp); + // TODO: handle tuples + assert(!type.isTuple() && "Unexpected tuple type"); \ + frees[type].push_back(temp); } // Generates a mangled name from `name` within the specified scope. @@ -301,9 +303,9 @@ class Wasm2JSBuilder { PassOptions options; // How many temp vars we need - std::vector temps; // type => num temps + std::unordered_map temps; // type => num temps // Which are currently free to use - std::vector> frees; // type => list of free names + std::unordered_map> frees; // type => list of free names // Mangled names cache by interned names. // Utilizes the usually reused underlying cstring's pointer as the key. @@ -878,11 +880,6 @@ Ref Wasm2JSBuilder::processFunction(Module* m, // sure that everything has a name and it's unique. Names::ensureNames(func); Ref ret = ValueBuilder::makeFunction(fromName(func->name, NameScope::Top)); - frees.clear(); - frees.resize(std::max(Type::i32, std::max(Type::f32, Type::f64)) + 1); - temps.clear(); - temps.resize(std::max(Type::i32, std::max(Type::f32, Type::f64)) + 1); - temps[Type::i32] = temps[Type::f32] = temps[Type::f64] = 0; // arguments bool needCoercions = options.optimizeLevel == 0 || standaloneFunction || functionsCallableFromOutside.count(func->name); @@ -915,10 +912,6 @@ Ref Wasm2JSBuilder::processFunction(Module* m, if (theVar[1]->size() == 0) { ret[3]->splice(theVarIndex, 1); } - // checks: all temp vars should be free at the end - assert(frees[Type::i32].size() == temps[Type::i32]); - assert(frees[Type::f32].size() == temps[Type::f32]); - assert(frees[Type::f64].size() == temps[Type::f64]); return ret; } diff --git a/test/wasm2js/left-to-right.2asm.js b/test/wasm2js/left-to-right.2asm.js index 6553cbc11d5..ca8d6bda739 100644 --- a/test/wasm2js/left-to-right.2asm.js +++ b/test/wasm2js/left-to-right.2asm.js @@ -942,23 +942,23 @@ function asmFunc(imports) { } function $53() { - var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$1; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$2; return get() | 0 | 0; } function $54() { - var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$1; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$2; return get() | 0 | 0; } function $55() { - var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$2; return get() | 0 | 0; } diff --git a/test/wasm2js/refs.2asm.js b/test/wasm2js/refs.2asm.js index f1d60af6cc6..d048a5df78a 100644 --- a/test/wasm2js/refs.2asm.js +++ b/test/wasm2js/refs.2asm.js @@ -1,3 +1,4 @@ +import * as fuzzing_support from 'fuzzing-support'; function wasm2js_trap() { throw new Error('abort'); } @@ -12,6 +13,8 @@ function asmFunc(imports) { var Math_ceil = Math.ceil; var Math_trunc = Math.trunc; var Math_sqrt = Math.sqrt; + var fuzzing_support = imports["fuzzing-support"]; + var log = fuzzing_support["log-f64"]; var global = null; var global_ref = use_global_ref; function null_() { @@ -50,6 +53,16 @@ function asmFunc(imports) { return temp; } + function funcref_temps($0) { + var $1 = null, $2 = null, wasm2js_funcref$0 = null, wasm2js_funcref$1 = null, wasm2js_i32$0 = 0; + $1 = $0; + loop : while (1) { + $2 = funcref_temps; + break loop; + }; + log(+(+((wasm2js_funcref$0 = $1, wasm2js_funcref$1 = $2 || wasm2js_trap(), wasm2js_i32$0 = 0, wasm2js_i32$0 ? wasm2js_funcref$0 : wasm2js_funcref$1) == null | 0))); + } + return { "null_": null_, "is_null": is_null, @@ -57,11 +70,13 @@ function asmFunc(imports) { "ref_eq": ref_eq, "ref_as": ref_as, "use_global": use_global, - "use_global_ref": use_global_ref + "use_global_ref": use_global_ref, + "funcref_temps": funcref_temps }; } var retasmFunc = asmFunc({ + "fuzzing-support": fuzzing_support, }); export var null_ = retasmFunc.null_; export var is_null = retasmFunc.is_null; @@ -70,3 +85,4 @@ export var ref_eq = retasmFunc.ref_eq; export var ref_as = retasmFunc.ref_as; export var use_global = retasmFunc.use_global; export var use_global_ref = retasmFunc.use_global_ref; +export var funcref_temps = retasmFunc.funcref_temps; diff --git a/test/wasm2js/refs.2asm.js.opt b/test/wasm2js/refs.2asm.js.opt index fa1947215a8..3f67caeca62 100644 --- a/test/wasm2js/refs.2asm.js.opt +++ b/test/wasm2js/refs.2asm.js.opt @@ -1,3 +1,4 @@ +import * as fuzzing_support from 'fuzzing-support'; function wasm2js_trap() { throw new Error('abort'); } @@ -12,6 +13,8 @@ function asmFunc(imports) { var Math_ceil = Math.ceil; var Math_trunc = Math.trunc; var Math_sqrt = Math.sqrt; + var fuzzing_support = imports["fuzzing-support"]; + var log = fuzzing_support["log-f64"]; var global = null; var global_ref = use_global_ref; function null_() { @@ -48,6 +51,10 @@ function asmFunc(imports) { return $1; } + function funcref_temps($0) { + log(0.0); + } + return { "null_": null_, "is_null": is_null, @@ -55,11 +62,13 @@ function asmFunc(imports) { "ref_eq": ref_eq, "ref_as": ref_as, "use_global": use_global, - "use_global_ref": use_global_ref + "use_global_ref": use_global_ref, + "funcref_temps": funcref_temps }; } var retasmFunc = asmFunc({ + "fuzzing-support": fuzzing_support, }); export var null_ = retasmFunc.null_; export var is_null = retasmFunc.is_null; @@ -68,3 +77,4 @@ export var ref_eq = retasmFunc.ref_eq; export var ref_as = retasmFunc.ref_as; export var use_global = retasmFunc.use_global; export var use_global_ref = retasmFunc.use_global_ref; +export var funcref_temps = retasmFunc.funcref_temps; diff --git a/test/wasm2js/refs.wast b/test/wasm2js/refs.wast index 244cf2e974e..ae31e991173 100644 --- a/test/wasm2js/refs.wast +++ b/test/wasm2js/refs.wast @@ -1,4 +1,6 @@ (module + (import "fuzzing-support" "log-f64" (func $log (param f64))) + (global $global (mut anyref) (ref.null any)) (global $global-ref (mut funcref) (ref.func $use-global-ref)) @@ -62,4 +64,22 @@ ) (local.get $temp) ) + + (func $funcref_temps (export "funcref_temps") (param $0 funcref) + ;; A deeply-nested expression that ends up requiring multiple function type + ;; temp variables. + (call $log + (f64.convert_i32_s + (ref.is_null + (select (result funcref) + (local.get $0) + (loop $loop (result funcref) + (ref.func $funcref_temps) + ) + (i32.const 0) + ) + ) + ) + ) + ) ) From 9e49fd5bae02a5ed5bce645956a374f37b45115d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 09:06:13 -0700 Subject: [PATCH 2/6] format fix --- .clang-format | 3 +++ src/wasm2js.h | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.clang-format b/.clang-format index cedadcbd0e6..316f76d89fc 100644 --- a/.clang-format +++ b/.clang-format @@ -12,3 +12,6 @@ BinPackParameters: false Language: JavaScript DisableFormat: true --- +Language: Json +BasedOnStyle: LLVM +--- diff --git a/src/wasm2js.h b/src/wasm2js.h index 3bc8710f2cb..342772f797f 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -207,7 +207,7 @@ class Wasm2JSBuilder { IString getTemp(Type type, Function* func) { IString ret; // TODO: handle tuples - assert(!type.isTuple() && "Unexpected tuple type"); \ + assert(!type.isTuple() && "Unexpected tuple type"); if (frees[type].size() > 0) { ret = frees[type].back(); frees[type].pop_back(); @@ -227,7 +227,7 @@ class Wasm2JSBuilder { // Free a temp var. void freeTemp(Type type, IString temp) { // TODO: handle tuples - assert(!type.isTuple() && "Unexpected tuple type"); \ + assert(!type.isTuple() && "Unexpected tuple type"); frees[type].push_back(temp); } @@ -305,7 +305,8 @@ class Wasm2JSBuilder { // How many temp vars we need std::unordered_map temps; // type => num temps // Which are currently free to use - std::unordered_map> frees; // type => list of free names + std::unordered_map> + frees; // type => list of free names // Mangled names cache by interned names. // Utilizes the usually reused underlying cstring's pointer as the key. From fb27006ad8d9a8b63062395e99fd718522c4e10f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 14:47:27 -0700 Subject: [PATCH 3/6] improve.comments --- src/wasm2js.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/wasm2js.h b/src/wasm2js.h index 342772f797f..e6407b46a89 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -302,11 +302,10 @@ class Wasm2JSBuilder { Flags flags; PassOptions options; - // How many temp vars we need - std::unordered_map temps; // type => num temps - // Which are currently free to use - std::unordered_map> - frees; // type => list of free names + // How many temp vars we need for each type (type => num). + std::unordered_map temps; + // Which temp vars are currently free to use for each type (type => freelist). + std::unordered_map>; // Mangled names cache by interned names. // Utilizes the usually reused underlying cstring's pointer as the key. From 25e433c95435f53ce165e9fcc76fa1da80a282cc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 14:49:01 -0700 Subject: [PATCH 4/6] oops --- src/wasm2js.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm2js.h b/src/wasm2js.h index e6407b46a89..4dc05f7f938 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -305,7 +305,7 @@ class Wasm2JSBuilder { // How many temp vars we need for each type (type => num). std::unordered_map temps; // Which temp vars are currently free to use for each type (type => freelist). - std::unordered_map>; + std::unordered_map> frees; // Mangled names cache by interned names. // Utilizes the usually reused underlying cstring's pointer as the key. From c3b2189e3091c1c0a162f2db1fbf942a3270c4df Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 14:58:37 -0700 Subject: [PATCH 5/6] fix --- src/wasm2js.h | 5 +++++ test/wasm2js/left-to-right.2asm.js | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/wasm2js.h b/src/wasm2js.h index 4dc05f7f938..321734688e7 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -876,6 +876,11 @@ Ref Wasm2JSBuilder::processFunction(Module* m, runner.runOnFunction(func); } + // We process multiple functions from a single Wasm2JSBuilder instance, so + // clean up the function-specific local state before each function. + frees.clear(); + temps.clear(); + // We will be symbolically referring to all variables in the function, so make // sure that everything has a name and it's unique. Names::ensureNames(func); diff --git a/test/wasm2js/left-to-right.2asm.js b/test/wasm2js/left-to-right.2asm.js index ca8d6bda739..6553cbc11d5 100644 --- a/test/wasm2js/left-to-right.2asm.js +++ b/test/wasm2js/left-to-right.2asm.js @@ -942,23 +942,23 @@ function asmFunc(imports) { } function $53() { - var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$2; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP8[wasm2js_i32$0 >> 0] = wasm2js_i32$1; return get() | 0 | 0; } function $54() { - var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$2; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP16[wasm2js_i32$0 >> 1] = wasm2js_i32$1; return get() | 0 | 0; } function $55() { - var wasm2js_i32$0 = 0, wasm2js_i32$2 = 0; + var wasm2js_i32$0 = 0, wasm2js_i32$1 = 0; reset(); - (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$2 = i64_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$2; + (wasm2js_i32$0 = i32_left() | 0, wasm2js_i32$1 = i64_right() | 0), HEAP32[wasm2js_i32$0 >> 2] = wasm2js_i32$1; return get() | 0 | 0; } From 02f8e710eb040ef1e1aa510f28bc71ff3d77dcb8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 14 Jun 2024 15:38:31 -0700 Subject: [PATCH 6/6] Avoid an import in the test --- test/wasm2js/refs.2asm.js | 15 ++++++--------- test/wasm2js/refs.2asm.js.opt | 9 +++------ test/wasm2js/refs.wast | 7 +++---- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/test/wasm2js/refs.2asm.js b/test/wasm2js/refs.2asm.js index d048a5df78a..f4c08408f70 100644 --- a/test/wasm2js/refs.2asm.js +++ b/test/wasm2js/refs.2asm.js @@ -1,4 +1,3 @@ -import * as fuzzing_support from 'fuzzing-support'; function wasm2js_trap() { throw new Error('abort'); } @@ -13,8 +12,6 @@ function asmFunc(imports) { var Math_ceil = Math.ceil; var Math_trunc = Math.trunc; var Math_sqrt = Math.sqrt; - var fuzzing_support = imports["fuzzing-support"]; - var log = fuzzing_support["log-f64"]; var global = null; var global_ref = use_global_ref; function null_() { @@ -53,14 +50,15 @@ function asmFunc(imports) { return temp; } - function funcref_temps($0) { - var $1 = null, $2 = null, wasm2js_funcref$0 = null, wasm2js_funcref$1 = null, wasm2js_i32$0 = 0; - $1 = $0; + function funcref_temps($0, $1) { + $1 = +$1; + var $2 = null, $3 = null, wasm2js_funcref$0 = null, wasm2js_funcref$1 = null, wasm2js_i32$0 = 0; + $2 = $0; loop : while (1) { - $2 = funcref_temps; + $3 = funcref_temps; break loop; }; - log(+(+((wasm2js_funcref$0 = $1, wasm2js_funcref$1 = $2 || wasm2js_trap(), wasm2js_i32$0 = 0, wasm2js_i32$0 ? wasm2js_funcref$0 : wasm2js_funcref$1) == null | 0))); + funcref_temps(funcref_temps, +(+((wasm2js_funcref$0 = $2, wasm2js_funcref$1 = $3 || wasm2js_trap(), wasm2js_i32$0 = 0, wasm2js_i32$0 ? wasm2js_funcref$0 : wasm2js_funcref$1) == null | 0))); } return { @@ -76,7 +74,6 @@ function asmFunc(imports) { } var retasmFunc = asmFunc({ - "fuzzing-support": fuzzing_support, }); export var null_ = retasmFunc.null_; export var is_null = retasmFunc.is_null; diff --git a/test/wasm2js/refs.2asm.js.opt b/test/wasm2js/refs.2asm.js.opt index 3f67caeca62..0071a15b53e 100644 --- a/test/wasm2js/refs.2asm.js.opt +++ b/test/wasm2js/refs.2asm.js.opt @@ -1,4 +1,3 @@ -import * as fuzzing_support from 'fuzzing-support'; function wasm2js_trap() { throw new Error('abort'); } @@ -13,8 +12,6 @@ function asmFunc(imports) { var Math_ceil = Math.ceil; var Math_trunc = Math.trunc; var Math_sqrt = Math.sqrt; - var fuzzing_support = imports["fuzzing-support"]; - var log = fuzzing_support["log-f64"]; var global = null; var global_ref = use_global_ref; function null_() { @@ -51,8 +48,9 @@ function asmFunc(imports) { return $1; } - function funcref_temps($0) { - log(0.0); + function funcref_temps($0, $1) { + $1 = +$1; + funcref_temps(funcref_temps, 0.0); } return { @@ -68,7 +66,6 @@ function asmFunc(imports) { } var retasmFunc = asmFunc({ - "fuzzing-support": fuzzing_support, }); export var null_ = retasmFunc.null_; export var is_null = retasmFunc.is_null; diff --git a/test/wasm2js/refs.wast b/test/wasm2js/refs.wast index ae31e991173..087567e8ce7 100644 --- a/test/wasm2js/refs.wast +++ b/test/wasm2js/refs.wast @@ -1,6 +1,4 @@ (module - (import "fuzzing-support" "log-f64" (func $log (param f64))) - (global $global (mut anyref) (ref.null any)) (global $global-ref (mut funcref) (ref.func $use-global-ref)) @@ -65,10 +63,11 @@ (local.get $temp) ) - (func $funcref_temps (export "funcref_temps") (param $0 funcref) + (func $funcref_temps (export "funcref_temps") (param $0 funcref) (param $1 f64) ;; A deeply-nested expression that ends up requiring multiple function type ;; temp variables. - (call $log + (call $funcref_temps + (ref.func $funcref_temps) (f64.convert_i32_s (ref.is_null (select (result funcref)