function-call-bind.js (2593B)
1 // See "Wasm Function.prototype.call.bind optimization" in WasmInstance.cpp 2 // for more information. 3 4 function wrapFunc(params, func) { 5 let funcCallBind = Function.prototype.call.bind(func); 6 7 return wasmEvalText(`(module 8 (func (import "" "f") (param ${params.join(" ")})) 9 (func (export "f") (param ${params.join(" ")}) 10 ${params.map((x, i) => `local.get ${i}`).join("\n")} 11 call 0 12 ) 13 )`, {"": {"f": funcCallBind}}).exports.f; 14 } 15 16 // Test passing all kinds of externref values to func through the 'this' 17 // parameter. 18 { 19 let func = function (expected) { 20 "use strict"; 21 assertEq(this, expected); 22 }; 23 let test = wrapFunc(["externref", "externref"], func); 24 for (let val of WasmExternrefValues) { 25 test(val, val); 26 } 27 } 28 29 // Same as above but with two non-this params. 30 { 31 let func = function (a, b) { 32 "use strict"; 33 assertEq(this, a); 34 assertEq(a, b); 35 }; 36 let test = wrapFunc(["externref", "externref", "externref"], func); 37 for (let val of WasmExternrefValues) { 38 test(val, val, val); 39 } 40 } 41 42 // Test passing primitives as the 'this' value. 43 { 44 let func = function (expected) { 45 "use strict"; 46 assertEq(this, expected); 47 }; 48 let vals = [0, 1, 2, 3, 4, 5]; 49 for (let valType of ["i32", "i64", "f32", "f64"]) { 50 let test = wrapFunc([valType, valType], func); 51 for (let val of vals) { 52 if (valType === "i64") { 53 val = BigInt(val); 54 } 55 test(val, val); 56 } 57 } 58 } 59 60 // Function.prototype.call on a non-strict function will coerce null/undefined 61 // to the global object. 62 { 63 let func = function (expected) { 64 assertEq(this, expected); 65 }; 66 let test = wrapFunc(["externref", "externref"], func); 67 test(null, globalThis); 68 test(undefined, globalThis); 69 } 70 71 // Test binding extra JS arguments still works (this should skip the 72 // optimization) 73 { 74 function func(x) { 75 "use strict"; 76 assertEq(this, 1); 77 assertEq(x, 2); 78 } 79 80 // Bind '2' to be the first normal arg to 'call', which will then become 81 // the 'this' parameter always. 82 let funcCallBind = Function.prototype.call.bind(func, 1); 83 84 let {test} = wasmEvalText(`(module 85 (func (import "" "f") (param i32)) 86 (export "test" (func 0)) 87 )`, {"": {"f": funcCallBind}}).exports; 88 89 test(2); 90 } 91 92 // Test a missing this parameter. 93 { 94 let test = wrapFunc([], function () { 95 "use strict"; 96 assertEq(this, undefined); 97 }); 98 test(); 99 }