| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="../../http/tests/inspector/resources/protocol-test.js"></script> | |
| <script> | |
| let sharedNativeModule; | |
| let sharedNativeInstances = []; | |
| function createSharedNativeModule() | |
| { | |
| return new WebAssembly.Module(new Uint8Array([ | |
| 0, 97, 115, 109, 1, 0, 0, 0, | |
| 1, 6, 1, 96, 1, 127, 1, 127, | |
| 3, 3, 2, 0, 0, | |
| 7, 18, 2, 5, 102, 105, 114, 115, 116, 0, 0, 6, 115, 101, 99, 111, 110, 100, 0, 1, | |
| 10, 17, 2, 7, 0, 32, 0, 65, 1, 106, 11, 7, 0, 32, 0, 65, 2, 106, 11, | |
| ])); | |
| } | |
| function prepareSharedNativeFunctions() | |
| { | |
| sharedNativeModule = createSharedNativeModule(); | |
| sharedNativeInstances = [ | |
| new WebAssembly.Instance(sharedNativeModule), | |
| new WebAssembly.Instance(sharedNativeModule), | |
| ]; | |
| return document.getElementById("native-result").textContent; | |
| } | |
| function runSharedNativeFunctions() | |
| { | |
| let values = []; | |
| for (let index = 0; index < sharedNativeInstances.length; ++index) { | |
| let {first, second} = sharedNativeInstances[index].exports; | |
| values.push(first((index + 1) * 10), second((index + 1) * 10)); | |
| } | |
| document.getElementById("native-result").textContent = values.join(", "); | |
| return JSON.stringify(values); | |
| } | |
| function test() | |
| { | |
| let suite = ProtocolTest.createAsyncSuite("Debugger.SymbolicBreakpoint.SharedNativeCode"); | |
| async function evaluate(expression) | |
| { | |
| let response = await InspectorProtocol.awaitCommand({ | |
| method: "Runtime.evaluate", | |
| params: {expression, returnByValue: true}, | |
| }); | |
| ProtocolTest.assert(!response.wasThrown, "The real page operation should not throw."); | |
| return response.result.value; | |
| } | |
| function addBreakpoint(symbol) | |
| { | |
| return InspectorProtocol.awaitCommand({ | |
| method: "Debugger.addSymbolicBreakpoint", | |
| params: {symbol, isRegex: true}, | |
| }); | |
| } | |
| function removeBreakpoint(symbol) | |
| { | |
| return InspectorProtocol.awaitCommand({ | |
| method: "Debugger.removeSymbolicBreakpoint", | |
| params: {symbol, isRegex: true}, | |
| }); | |
| } | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.Prepare", | |
| async test() { | |
| await InspectorProtocol.awaitCommand({method: "Runtime.enable"}); | |
| await InspectorProtocol.awaitCommand({method: "Debugger.enable"}); | |
| await InspectorProtocol.awaitCommand({method: "Debugger.setBreakpointsActive", params: {active: false}}); | |
| ProtocolTest.expectEqual(await evaluate("prepareSharedNativeFunctions()"), "Ready", "The actual page should compile both exports and materialize a DOM native method."); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22]", "Both real instances should return their own export results."); | |
| }, | |
| }); | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.Install", | |
| async test() { | |
| await addBreakpoint(".*"); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22]", "A broad native hook should preserve both shared instances."); | |
| ProtocolTest.expectEqual(await evaluate("document.getElementById('native-result').textContent"), "11, 12, 21, 22", "The hooked DOM native method should still read the actual page output."); | |
| }, | |
| }); | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.NewExports", | |
| async test() { | |
| await evaluate("sharedNativeInstances.push(new WebAssembly.Instance(sharedNativeModule), new WebAssembly.Instance(createSharedNativeModule())); GCController.collect()"); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22,31,32,41,42]", "Exports created while hooks are active should retain correct code through collection."); | |
| }, | |
| }); | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.OverlappingOwners", | |
| async test() { | |
| await addBreakpoint(".+"); | |
| await removeBreakpoint(".*"); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22,31,32,41,42]", "Removing one symbolic owner should preserve the other owner's native hooks."); | |
| }, | |
| }); | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.Restore", | |
| async test() { | |
| await removeBreakpoint(".+"); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22,31,32,41,42]", "Removing all hooks should restore every real export."); | |
| ProtocolTest.expectEqual(await evaluate("document.getElementById('native-result').textContent"), "11, 12, 21, 22, 31, 32, 41, 42", "Restoring native code should preserve DOM method behavior."); | |
| }, | |
| }); | |
| suite.addTestCase({ | |
| name: "Debugger.SymbolicBreakpoint.SharedNativeCode.Repeat", | |
| async test() { | |
| for (let index = 0; index < 3; ++index) { | |
| await addBreakpoint(".*"); | |
| await evaluate("runSharedNativeFunctions()"); | |
| await removeBreakpoint(".*"); | |
| } | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22,31,32,41,42]", "Repeated native hook installation should leave no stale entry points."); | |
| await InspectorProtocol.awaitCommand({method: "Debugger.setBreakpointsActive", params: {active: true}}); | |
| await InspectorProtocol.awaitCommand({method: "Debugger.disable"}); | |
| await evaluate("GCController.collect()"); | |
| ProtocolTest.expectEqual(await evaluate("runSharedNativeFunctions()"), "[11,12,21,22,31,32,41,42]", "Disabling the debugger should leave every shared export executable after collection."); | |
| await evaluate("document.getElementById('native-result').remove()"); | |
| }, | |
| }); | |
| suite.runTestCasesAndFinish(); | |
| } | |
| </script> | |
| </head> | |
| <body onload="runTest()"> | |
| <p>Tests symbolic breakpoint hooks on real exports that share native JIT code.</p> | |
| <output id="native-result">Ready</output> | |
| </body> | |
| </html> |