mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 717749 - Part 2: Hook up the debugger to the slow script debug service. (r=past)
This commit is contained in:
parent
287faf4d54
commit
87dc6d7e59
@ -462,6 +462,13 @@ ThreadState.prototype = {
|
|||||||
* Update the UI after a thread state change.
|
* Update the UI after a thread state change.
|
||||||
*/
|
*/
|
||||||
_update: function(aEvent) {
|
_update: function(aEvent) {
|
||||||
|
// Ignore "interrupted" events, which are generated by the slow script
|
||||||
|
// dialog and internal events such as setting breakpoints, to avoid UI
|
||||||
|
// flicker.
|
||||||
|
if (aEvent == "interrupted") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DebuggerView.Toolbar.toggleResumeButtonState(this.activeThread.state);
|
DebuggerView.Toolbar.toggleResumeButtonState(this.activeThread.state);
|
||||||
|
|
||||||
if (gTarget && (aEvent == "paused" || aEvent == "resumed")) {
|
if (gTarget && (aEvent == "paused" || aEvent == "resumed")) {
|
||||||
@ -568,6 +575,11 @@ StackFrames.prototype = {
|
|||||||
this._currentReturnedValue = aPacket.why.frameFinished.return;
|
this._currentReturnedValue = aPacket.why.frameFinished.return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// If paused by an explicit interrupt, which are generated by the slow
|
||||||
|
// script dialog and internal events such as setting breakpoints, ignore
|
||||||
|
// the event to avoid UI flicker.
|
||||||
|
case "interrupted":
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
|
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
|
||||||
|
@ -580,6 +580,79 @@ let gDevToolsBrowser = {
|
|||||||
mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
|
mainKeyset.parentNode.insertBefore(devtoolsKeyset, mainKeyset);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook the JS debugger tool to the "Debug Script" button of the slow script
|
||||||
|
* dialog.
|
||||||
|
*/
|
||||||
|
setSlowScriptDebugHandler: function DT_setSlowScriptDebugHandler() {
|
||||||
|
let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
|
||||||
|
.getService(Ci.nsISlowScriptDebug);
|
||||||
|
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||||
|
|
||||||
|
debugService.activationHandler = function(aWindow) {
|
||||||
|
let chromeWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
|
.QueryInterface(Ci.nsIDocShellTreeItem)
|
||||||
|
.rootTreeItem
|
||||||
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindow)
|
||||||
|
.QueryInterface(Ci.nsIDOMChromeWindow);
|
||||||
|
let target = devtools.TargetFactory.forTab(chromeWindow.gBrowser.selectedTab);
|
||||||
|
|
||||||
|
let setupFinished = false;
|
||||||
|
gDevTools.showToolbox(target, "jsdebugger").then(toolbox => {
|
||||||
|
let threadClient = toolbox.getCurrentPanel().panelWin.gThreadClient;
|
||||||
|
|
||||||
|
// Break in place, which means resuming the debuggee thread and pausing
|
||||||
|
// right before the next step happens.
|
||||||
|
switch (threadClient.state) {
|
||||||
|
case "paused":
|
||||||
|
// When the debugger is already paused.
|
||||||
|
threadClient.breakOnNext();
|
||||||
|
setupFinished = true;
|
||||||
|
break;
|
||||||
|
case "attached":
|
||||||
|
// When the debugger is already open.
|
||||||
|
threadClient.interrupt(() => {
|
||||||
|
threadClient.breakOnNext();
|
||||||
|
setupFinished = true;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "resuming":
|
||||||
|
// The debugger is newly opened.
|
||||||
|
threadClient.addOneTimeListener("resumed", () => {
|
||||||
|
threadClient.interrupt(() => {
|
||||||
|
threadClient.breakOnNext();
|
||||||
|
setupFinished = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Error("invalid thread client state in slow script debug handler: " +
|
||||||
|
threadClient.state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Don't return from the interrupt handler until the debugger is brought
|
||||||
|
// up; no reason to continue executing the slow script.
|
||||||
|
let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Ci.nsIDOMWindowUtils);
|
||||||
|
utils.enterModalState();
|
||||||
|
while (!setupFinished) {
|
||||||
|
tm.currentThread.processNextEvent(true);
|
||||||
|
}
|
||||||
|
utils.leaveModalState();
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unset the slow script debug handler.
|
||||||
|
*/
|
||||||
|
unsetSlowScriptDebugHandler: function DT_unsetSlowScriptDebugHandler() {
|
||||||
|
let debugService = Cc["@mozilla.org/dom/slow-script-debug;1"]
|
||||||
|
.getService(Ci.nsISlowScriptDebug);
|
||||||
|
debugService.activationHandler = undefined;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect the presence of a Firebug.
|
* Detect the presence of a Firebug.
|
||||||
@ -669,6 +742,10 @@ let gDevToolsBrowser = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toolDefinition.id === "jsdebugger") {
|
||||||
|
gDevToolsBrowser.setSlowScriptDebugHandler();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -844,6 +921,10 @@ let gDevToolsBrowser = {
|
|||||||
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
|
for (let win of gDevToolsBrowser._trackedBrowserWindows) {
|
||||||
gDevToolsBrowser._removeToolFromMenu(toolId, win.document);
|
gDevToolsBrowser._removeToolFromMenu(toolId, win.document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toolId === "jsdebugger") {
|
||||||
|
gDevToolsBrowser.unsetSlowScriptDebugHandler();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1493,6 +1493,16 @@ ThreadClient.prototype = {
|
|||||||
this._doResume(null, aOnResponse);
|
this._doResume(null, aOnResponse);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resume then pause without stepping.
|
||||||
|
*
|
||||||
|
* @param function aOnResponse
|
||||||
|
* Called with the response packet.
|
||||||
|
*/
|
||||||
|
breakOnNext: function (aOnResponse) {
|
||||||
|
this._doResume({ type: "break" }, aOnResponse);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Step over a function call.
|
* Step over a function call.
|
||||||
*
|
*
|
||||||
|
@ -951,7 +951,15 @@ ThreadActor.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_makeOnStep: function ({ thread, pauseAndRespond, startFrame,
|
_makeOnStep: function ({ thread, pauseAndRespond, startFrame,
|
||||||
startLocation }) {
|
startLocation, steppingType }) {
|
||||||
|
// Breaking in place: we should always pause.
|
||||||
|
if (steppingType === "break") {
|
||||||
|
return function () {
|
||||||
|
return pauseAndRespond(this);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise take what a "step" means into consideration.
|
||||||
return function () {
|
return function () {
|
||||||
// onStep is called with 'this' set to the current frame.
|
// onStep is called with 'this' set to the current frame.
|
||||||
|
|
||||||
@ -996,7 +1004,7 @@ ThreadActor.prototype = {
|
|||||||
/**
|
/**
|
||||||
* Define the JS hook functions for stepping.
|
* Define the JS hook functions for stepping.
|
||||||
*/
|
*/
|
||||||
_makeSteppingHooks: function (aStartLocation) {
|
_makeSteppingHooks: function (aStartLocation, steppingType) {
|
||||||
// Bind these methods and state because some of the hooks are called
|
// Bind these methods and state because some of the hooks are called
|
||||||
// with 'this' set to the current frame. Rather than repeating the
|
// with 'this' set to the current frame. Rather than repeating the
|
||||||
// binding in each _makeOnX method, just do it once here and pass it
|
// binding in each _makeOnX method, just do it once here and pass it
|
||||||
@ -1008,7 +1016,8 @@ ThreadActor.prototype = {
|
|||||||
createValueGrip: this.createValueGrip.bind(this),
|
createValueGrip: this.createValueGrip.bind(this),
|
||||||
thread: this,
|
thread: this,
|
||||||
startFrame: this.youngestFrame,
|
startFrame: this.youngestFrame,
|
||||||
startLocation: aStartLocation
|
startLocation: aStartLocation,
|
||||||
|
steppingType: steppingType
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1029,7 +1038,7 @@ ThreadActor.prototype = {
|
|||||||
*/
|
*/
|
||||||
_handleResumeLimit: function (aRequest) {
|
_handleResumeLimit: function (aRequest) {
|
||||||
let steppingType = aRequest.resumeLimit.type;
|
let steppingType = aRequest.resumeLimit.type;
|
||||||
if (["step", "next", "finish"].indexOf(steppingType) == -1) {
|
if (["break", "step", "next", "finish"].indexOf(steppingType) == -1) {
|
||||||
return reject({ error: "badParameterType",
|
return reject({ error: "badParameterType",
|
||||||
message: "Unknown resumeLimit type" });
|
message: "Unknown resumeLimit type" });
|
||||||
}
|
}
|
||||||
@ -1037,7 +1046,8 @@ ThreadActor.prototype = {
|
|||||||
const generatedLocation = getFrameLocation(this.youngestFrame);
|
const generatedLocation = getFrameLocation(this.youngestFrame);
|
||||||
return this.sources.getOriginalLocation(generatedLocation)
|
return this.sources.getOriginalLocation(generatedLocation)
|
||||||
.then(originalLocation => {
|
.then(originalLocation => {
|
||||||
const { onEnterFrame, onPop, onStep } = this._makeSteppingHooks(originalLocation);
|
const { onEnterFrame, onPop, onStep } = this._makeSteppingHooks(originalLocation,
|
||||||
|
steppingType);
|
||||||
|
|
||||||
// Make sure there is still a frame on the stack if we are to continue
|
// Make sure there is still a frame on the stack if we are to continue
|
||||||
// stepping.
|
// stepping.
|
||||||
@ -1047,6 +1057,7 @@ ThreadActor.prototype = {
|
|||||||
case "step":
|
case "step":
|
||||||
this.dbg.onEnterFrame = onEnterFrame;
|
this.dbg.onEnterFrame = onEnterFrame;
|
||||||
// Fall through.
|
// Fall through.
|
||||||
|
case "break":
|
||||||
case "next":
|
case "next":
|
||||||
if (stepFrame.script) {
|
if (stepFrame.script) {
|
||||||
stepFrame.onStep = onStep;
|
stepFrame.onStep = onStep;
|
||||||
|
Loading…
Reference in New Issue
Block a user