| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Test setting and removing breakpoints in Wasm. |
| // Similar tests exist as inspector tests already, but inspector tests are not |
| // run concurrently in multiple isolates (see `run-tests.py --isolates`). |
| |
| load('test/mjsunit/wasm/wasm-module-builder.js'); |
| |
| const builder = new WasmModuleBuilder(); |
| const body_a = [ |
| kExprLocalGet, 0, // local.get i0 |
| kExprI32Const, 1, // i32.const 1 |
| kExprI32Add // i32.add i0 1 |
| ]; |
| const fun_a = builder.addFunction('a', kSig_i_i).addBody(body_a).exportFunc(); |
| const body_b = [ |
| kExprLocalGet, 0, // local.get i0 |
| kExprCallFunction, fun_a.index, // call a |
| kExprLocalGet, 1, // local.get i1 |
| kExprI32Sub, // i32.sub a(i0) i1 |
| kExprCallFunction, fun_a.index, // call a |
| ]; |
| const fun_b = builder.addFunction('b', kSig_i_ii).addBody(body_b).exportFunc(); |
| |
| const instance = builder.instantiate(); |
| |
| Debug = debug.Debug; |
| |
| const a_localget_offset = body_a.indexOf(kExprLocalGet); |
| const a_const_offset = body_a.indexOf(kExprI32Const); |
| const a_add_offset = body_a.indexOf(kExprI32Add); |
| const b_sub_offset = body_b.indexOf(kExprI32Sub); |
| |
| const expected_breaks = [ |
| `a:1:${fun_a.body_offset + a_add_offset}`, // break in a at i32.add |
| `b:1:${fun_b.body_offset + b_sub_offset}`, // break in b at i32.sub |
| `a:1:${fun_a.body_offset + a_localget_offset}`, // break in a at local.get i0 |
| `a:1:${fun_a.body_offset + a_const_offset}` // break in a at i32.const 1 |
| ]; |
| let error; |
| function onBreak(event, exec_state, data) { |
| try { |
| if (event != Debug.DebugEvent.Break) return; |
| if (error) return; |
| const pos = |
| [data.functionName(), data.sourceLine(), data.sourceColumn()].join(':'); |
| const loc = [pos, data.sourceLineText()].join(':'); |
| print(`Break at ${loc}`); |
| assertTrue(expected_breaks.length > 0, 'expecting more breaks'); |
| const expected_pos = expected_breaks.shift(); |
| assertEquals(expected_pos, pos); |
| // When we stop in b, we add another breakpoint in a at offset 0 and remove |
| // the existing breakpoint. |
| if (data.functionName() == 'b') { |
| Debug.setBreakPoint(instance.exports.a, 0, a_localget_offset); |
| Debug.clearBreakPoint(breakpoint_a); |
| } |
| // When we stop at a at local.get, we set another breakpoint *in the same |
| // function*, one instruction later (at i32.const). |
| if (data.functionName() == 'a' && |
| data.sourceColumn() == fun_a.body_offset) { |
| Debug.setBreakPoint(instance.exports.a, 0, a_const_offset); |
| } |
| } catch (e) { |
| if (!error) error = e; |
| } |
| } |
| |
| Debug.setListener(onBreak); |
| const breakpoint_a = Debug.setBreakPoint(instance.exports.a, 0, a_add_offset); |
| const breakpoint_b = Debug.setBreakPoint(instance.exports.b, 0, b_sub_offset); |
| print('Running b(11).'); |
| const result = instance.exports.b(11); |
| print('Returned from wasm.'); |
| if (error) throw error; |
| assertEquals(0, expected_breaks.length, 'all breaks were hit'); |