import * as assert from '../assert.js'; import Builder from '../Builder.js'; const callerTopBits = 0xC0FEBEEF; const innerReturnHi = 0xDEADFACE; const innerReturnLo = 0xC0FEC0FE; const callerModule = () => { const builder = (new Builder()) .Type().End() .Import() .Function("exports", "callMe", { params: ["i64"], ret: "i64" }) .End() .Function().End() .Export() .Function("entry") .End() .Code() .Function("entry", { params: ["i32"], ret: "i32" }, ["i64"]) .I32Const(callerTopBits).I64ExtendUI32().I32Const(32).I64ExtendUI32().I64Shl() // ((i64)callerTopBits) << 32 .GetLocal(0).I64ExtendUI32() .I64Or() // value: param | (((i64)callerTopBits << 32)) .Call(0) // Calls exports.callMe(param | (((i64)callerTopBits) << 32)). .TeeLocal(1).I32WrapI64() // lo: (i32)callResult .GetLocal(1).I32Const(32).I64ExtendUI32().I64ShrU().I32WrapI64() // hi: (i32)(callResult >> 32) .I32Xor() .Return() .End() .End(); return new WebAssembly.Module(builder.WebAssembly().get()); }; const calleeModule = () => { const builder = (new Builder()) .Type().End() .Import() .Function("imp", "func", { params: ["i32", "i32"], ret: "i32" }) .End() .Function().End() .Export() .Function("callMe") .End() .Code() .Function("callMe", { params: ["i64"], ret: "i64" }) .GetLocal(0).I32WrapI64() // lo: (i32)param .GetLocal(0).I32Const(32).I64ExtendUI32().I64ShrU().I32WrapI64() // hi: (i32)(param >> 32) .Call(0) // Calls imp.func with the 64-bit value as i32 { hi, lo }. .Drop() .I32Const(innerReturnHi).I64ExtendUI32().I32Const(32).I64ExtendUI32().I64Shl().I32Const(innerReturnLo).I64ExtendUI32().I64Or() // ((i64)hi << 32) | (i64)lo .Return() .End() .End(); return new WebAssembly.Module(builder.WebAssembly().get()); }; (function WasmToWasm() { let value; const func = (hi, lo) => { value = { hi: hi, lo: lo }; return hi ^ lo; }; const callee = new WebAssembly.Instance(calleeModule(), { imp: { func: func } }); const caller = new WebAssembly.Instance(callerModule(), callee); for (let i = 0; i < 4096; ++i) { assert.eq(caller.exports.entry(i), innerReturnHi ^ innerReturnLo); assert.eq(value.lo >>> 0, callerTopBits); assert.eq(value.hi >>> 0, i); } })(); // FIXME test the following https://bugs.webkit.org/show_bug.cgi?id=166625 // - wasm->wasm using 32-bit things (including float), as well as 64-bit NaNs that don't get canonicalized // - Do a throw two-deep // - Check that the first wasm's instance is back in OK state (with table or global?) // - Test calling through a Table