debug.js (2266B)
1 // Tests stepping through the wasm code with JS PI suspendable stack. 2 3 const g = newGlobal({ newCompartment: true }); 4 const dbg = new Debugger(g); 5 6 // Estimate internal SP range. 7 var base = stackPointerInfo(); 8 var estimatedLimit = base - 300000; 9 var checkFailed = false; 10 var checksPerformed = {}; 11 12 // Checks current SP being in the estimated range -- 13 // the debugger callbacks must be executed on the main stack. 14 function checkStack(s) { 15 var sp = stackPointerInfo(); 16 checksPerformed[s] = true; 17 if (sp < estimatedLimit || sp > base) { 18 print(`Check failed: ${sp} not in [${estimatedLimit}, ${base}], at ${s}`); 19 checkFailed = true; 20 } 21 } 22 checkStack(); 23 assertEq(checkFailed, false); 24 25 dbg.onEnterFrame = function(frame) { 26 if (frame.type != "wasmcall") { 27 return; 28 } 29 checkStack("enter"); 30 frame.onStep = () => { 31 checkStack("step"); 32 frame.offset; // check if frame is valid 33 }; 34 frame.onPop = () => { 35 checkStack("pop"); 36 } 37 }; 38 dbg.onExceptionUnwind = function (f, e) { 39 checkStack("exception"); 40 }; 41 42 // Run typical JS PI program: create suspendable stack, suspend execution, 43 // throw on suspendable stack. 44 g.eval(` 45 function wasmEvalText(t, imp) { 46 var wasm = wasmTextToBinary(t) 47 var mod = new WebAssembly.Module(wasm); 48 var ins = new WebAssembly.Instance(mod, imp); 49 return ins; 50 } 51 52 try{throw"";}catch(_){} // init onExceptionUnwind 53 54 var compute_delta = (i) => { 55 return Promise.resolve(i/100 || 1); 56 }; 57 58 var suspending_compute_delta = new WebAssembly.Suspending(compute_delta); 59 var ins = wasmEvalText(\`(module 60 (import "js" "compute_delta" 61 (func $compute_delta (param i32) (result f64))) 62 (tag $t) 63 (func (export "update_state_export") (param i32) (result f64) 64 local.get 0 65 call $compute_delta 66 i32.const 4 67 i32.const 2 68 i32.add 69 drop 70 throw $t 71 ) 72 )\`, { 73 js: { 74 compute_delta: suspending_compute_delta, 75 }, 76 }); 77 78 var update_state = WebAssembly.promising(ins.exports.update_state_export); 79 80 var res = update_state(4); 81 res.then((r) => { 82 print("RES:" + r); 83 }).catch(e => { 84 print("ERR: " + e); 85 }); 86 87 drainJobQueue(); 88 `); 89 90 assertEq(checkFailed, false); 91 for (let i of ['enter', 'step', 'pop', 'exception']) { 92 assertEq(i in checksPerformed, true, `${i} check performed`); 93 }