wasm-06.js (10818B)
1 // |jit-test| test-also=--wasm-compiler=optimizing; error: TestComplete; skip-if: !wasmDebuggingEnabled() 2 // Tests that wasm module scripts raises onEnterFrame and onLeaveFrame events. 3 4 load(libdir + "asserts.js"); 5 6 function runWasmWithDebugger(wast, lib, init, done) { 7 let g = newGlobal({newCompartment: true}); 8 let dbg = new Debugger(g); 9 10 g.eval(` 11 var wasm = wasmTextToBinary('${wast}'); 12 var lib = ${lib || 'undefined'}; 13 var m = new WebAssembly.Instance(new WebAssembly.Module(wasm), lib);`); 14 15 init(dbg, g); 16 let result = undefined, error = undefined; 17 try { 18 result = g.eval("m.exports.test()"); 19 } catch (ex) { 20 error = ex; 21 } 22 done(dbg, result, error, g); 23 } 24 25 // Checking if onEnterFrame is fired for wasm frames and verifying the content 26 // of the frame and environment properties. 27 var onEnterFrameCalled, onLeaveFrameCalled, onExceptionUnwindCalled, testComplete; 28 runWasmWithDebugger( 29 '(module (func (result i32) (i32.const 42)) (export "test" (func 0)))', undefined, 30 function (dbg) { 31 var wasmScript = dbg.findScripts().filter(s => s.format == 'wasm')[0]; 32 assertEq(!!wasmScript, true); 33 onEnterFrameCalled = 0; 34 onLeaveFrameCalled = 0; 35 testComplete = false; 36 var evalFrame; 37 dbg.onEnterFrame = function (frame) { 38 if (frame.type !== 'wasmcall') { 39 if (frame.type === 'eval') 40 evalFrame = frame; 41 return; 42 } 43 44 onEnterFrameCalled++; 45 46 assertEq(frame.script, wasmScript); 47 assertEq(frame.older, evalFrame); 48 assertEq(frame.type, 'wasmcall'); 49 50 let env = frame.environment; 51 assertEq(env instanceof Object, true); 52 assertEq(env.inspectable, true); 53 assertEq(env.parent !== null, true); 54 assertEq(env.type, 'declarative'); 55 assertEq(env.calleeScript, null); 56 assertEq(Array.isArray(env.names()), true); 57 assertEq(env.names().length, 0); 58 59 frame.onPop = function() { 60 onLeaveFrameCalled++; 61 testComplete = true; 62 }; 63 }; 64 }, 65 function (dbg, result, error) { 66 assertEq(testComplete, true); 67 assertEq(onEnterFrameCalled, 1); 68 assertEq(onLeaveFrameCalled, 1); 69 assertEq(result, 42); 70 assertEq(error, undefined); 71 } 72 ); 73 74 // Checking the dbg.getNewestFrame() and frame.older. 75 runWasmWithDebugger( 76 '(module (import "env" "ex" (func $fn1)) (func $fn2 (call $fn1)) (export "test" (func $fn2)))', 77 '{env: { ex: () => { }}}', 78 function (dbg) { 79 onEnterFrameCalled = 0; 80 onLeaveFrameCalled = 0; 81 testComplete = false; 82 var evalFrame, wasmFrame; 83 dbg.onEnterFrame = function (frame) { 84 onEnterFrameCalled++; 85 86 assertEq(dbg.getNewestFrame(), frame); 87 88 switch (frame.type) { 89 case 'eval': 90 evalFrame = frame; 91 break; 92 case 'wasmcall': 93 wasmFrame = frame; 94 break; 95 case 'call': 96 assertEq(frame.older, wasmFrame); 97 assertEq(frame.older.older, evalFrame); 98 assertEq(frame.older.older.older, null); 99 testComplete = true; 100 break; 101 } 102 103 frame.onPop = function() { 104 onLeaveFrameCalled++; 105 }; 106 }; 107 }, 108 function (dbg, result, error) { 109 assertEq(testComplete, true); 110 assertEq(onEnterFrameCalled, 3); 111 assertEq(onLeaveFrameCalled, 3); 112 assertEq(error, undefined); 113 } 114 ); 115 116 // Checking if we can enumerate frames and find 'wasmcall' one. 117 runWasmWithDebugger( 118 '(module (import "env" "ex" (func $fn1)) (func $fn2 (call $fn1)) (export "test" (func $fn2)))', 119 '{env: { ex: () => { debugger; }}}', 120 function (dbg) { 121 testComplete = false; 122 dbg.onDebuggerStatement = function (frame) { 123 assertEq(frame.type, 'call'); 124 assertEq(frame.older.type, 'wasmcall'); 125 assertEq(frame.older.older.type, 'eval'); 126 assertEq(frame.older.older.older, null); 127 testComplete = true; 128 } 129 }, 130 function (dbg, result, error) { 131 assertEq(testComplete, true); 132 assertEq(error, undefined); 133 } 134 ); 135 136 // Checking if onPop works without onEnterFrame handler. 137 runWasmWithDebugger( 138 '(module (import "env" "ex" (func $fn1)) (func $fn2 (call $fn1)) (export "test" (func $fn2)))', 139 '{env: { ex: () => { debugger; }}}', 140 function (dbg) { 141 onLeaveFrameCalled = 0; 142 dbg.onDebuggerStatement = function (frame) { 143 if (!frame.older || frame.older.type != 'wasmcall') 144 return; 145 frame.older.onPop = function () { 146 onLeaveFrameCalled++; 147 }; 148 } 149 }, 150 function (dbg, result, error) { 151 assertEq(onLeaveFrameCalled, 1); 152 assertEq(error, undefined); 153 } 154 ); 155 156 // Checking if function return values are not changed. 157 runWasmWithDebugger( 158 '(module (func (result f64) (f64.const 0.42)) (export "test" (func 0)))', undefined, 159 function (dbg) { 160 dbg.onEnterFrame = function (frame) { 161 dbg.onPop = function () {}; 162 }; 163 }, 164 function (dbg, result, error) { 165 assertEq(result, 0.42); 166 assertEq(error, undefined); 167 } 168 ); 169 runWasmWithDebugger( 170 '(module (func (result f32) (f32.const 4.25)) (export "test" (func 0)))', undefined, 171 function (dbg) { 172 dbg.onEnterFrame = function (frame) { 173 dbg.onPop = function () {}; 174 }; 175 }, 176 function (dbg, result, error) { 177 assertEq(result, 4.25); 178 assertEq(error, undefined); 179 } 180 ); 181 182 // Checking if onEnterFrame/onExceptionUnwind work during exceptions -- 183 // `unreachable` causes wasm to throw WebAssembly.RuntimeError exception. 184 runWasmWithDebugger( 185 '(module (func (unreachable)) (export "test" (func 0)))', undefined, 186 function (dbg) { 187 onEnterFrameCalled = 0; 188 onLeaveFrameCalled = 0; 189 onExceptionUnwindCalled = 0; 190 dbg.onEnterFrame = function (frame) { 191 if (frame.type !== "wasmcall") return; 192 onEnterFrameCalled++; 193 frame.onPop = function() { 194 onLeaveFrameCalled++; 195 }; 196 }; 197 dbg.onExceptionUnwind = function (frame) { 198 if (frame.type !== "wasmcall") return; 199 onExceptionUnwindCalled++; 200 }; 201 }, 202 function (dbg, result, error, g) { 203 assertEq(onEnterFrameCalled, 1); 204 assertEq(onLeaveFrameCalled, 1); 205 assertEq(onExceptionUnwindCalled, 1); 206 assertEq(error instanceof g.WebAssembly.RuntimeError, true); 207 } 208 ); 209 210 // Checking if onEnterFrame/onExceptionUnwind work during exceptions 211 // originated in the JavaScript import call. 212 runWasmWithDebugger( 213 '(module (import "env" "ex" (func $fn1)) (func $fn2 (call $fn1)) (export "test" (func $fn2)))', 214 '{env: { ex: () => { throw new Error(); }}}', 215 function (dbg) { 216 onEnterFrameCalled = 0; 217 onLeaveFrameCalled = 0; 218 onExceptionUnwindCalled = 0; 219 dbg.onEnterFrame = function (frame) { 220 if (frame.type !== "wasmcall") return; 221 onEnterFrameCalled++; 222 frame.onPop = function() { 223 onLeaveFrameCalled++; 224 }; 225 }; 226 dbg.onExceptionUnwind = function (frame) { 227 if (frame.type !== "wasmcall") return; 228 onExceptionUnwindCalled++; 229 }; 230 }, 231 function (dbg, result, error, g) { 232 assertEq(onEnterFrameCalled, 1); 233 assertEq(onLeaveFrameCalled, 1); 234 assertEq(onExceptionUnwindCalled, 1); 235 assertEq(error instanceof g.Error, true); 236 } 237 ); 238 239 // Checking throwing in the handler. 240 runWasmWithDebugger( 241 '(module (func (unreachable)) (export "test" (func 0)))', undefined, 242 function (dbg) { 243 dbg.uncaughtExceptionHook = function (value) { 244 assertEq(value instanceof Error, true); 245 return {throw: 'test'}; 246 }; 247 dbg.onEnterFrame = function (frame) { 248 if (frame.type !== "wasmcall") return; 249 throw new Error(); 250 }; 251 }, 252 function (dbg, result, error) { 253 assertEq(error, 'test'); 254 } 255 ); 256 runWasmWithDebugger( 257 '(module (func (unreachable)) (export "test" (func 0)))', undefined, 258 function (dbg) { 259 dbg.uncaughtExceptionHook = function (value) { 260 assertEq(value instanceof Error, true); 261 return {throw: 'test'}; 262 }; 263 dbg.onEnterFrame = function (frame) { 264 if (frame.type !== "wasmcall") return; 265 frame.onPop = function () { 266 throw new Error(); 267 } 268 }; 269 }, 270 function (dbg, result, error) { 271 assertEq(error, 'test'); 272 } 273 ); 274 275 // Checking resumption values for JS_THROW. 276 runWasmWithDebugger( 277 '(module (func (nop)) (export "test" (func 0)))', undefined, 278 function (dbg, g) { 279 dbg.onEnterFrame = function (frame) { 280 if (frame.type !== "wasmcall") return; 281 return {throw: 'test'}; 282 }; 283 }, 284 function (dbg, result, error, g) { 285 assertEq(error, 'test'); 286 } 287 ); 288 runWasmWithDebugger( 289 '(module (func (nop)) (export "test" (func 0)))', undefined, 290 function (dbg, g) { 291 dbg.onEnterFrame = function (frame) { 292 if (frame.type !== "wasmcall") return; 293 frame.onPop = function () { 294 return {throw: 'test'}; 295 } 296 }; 297 }, 298 function (dbg, result, error, g) { 299 assertEq(error, 'test'); 300 } 301 ); 302 303 // Checking resumption values for JS_RETURN (not implemented by wasm baseline). 304 runWasmWithDebugger( 305 '(module (func (unreachable)) (export "test" (func 0)))', undefined, 306 function (dbg) { 307 dbg.onEnterFrame = function (frame) { 308 if (frame.type !== "wasmcall") return; 309 return {return: 2}; 310 }; 311 }, 312 function (dbg, result, error) { 313 assertEq(result, undefined, 'NYI: result == 2, if JS_RETURN is implemented'); 314 assertEq(error != undefined, true, 'NYI: error == undefined, if JS_RETURN is implemented'); 315 } 316 ); 317 runWasmWithDebugger( 318 '(module (func (unreachable)) (export "test" (func 0)))', undefined, 319 function (dbg) { 320 dbg.onEnterFrame = function (frame) { 321 if (frame.type !== "wasmcall") return; 322 frame.onPop = function () { 323 return {return: 2}; 324 } 325 }; 326 }, 327 function (dbg, result, error) { 328 assertEq(result, undefined, 'NYI: result == 2, if JS_RETURN is implemented'); 329 assertEq(error != undefined, true, 'NYI: error == undefined, if JS_RETURN is implemented'); 330 } 331 ); 332 throw "TestComplete";