mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 901712 - black boxing doesn't work with source maps; r=dcamp
This commit is contained in:
parent
0b1437fc64
commit
673896a47f
@ -131,9 +131,7 @@ BreakpointStore.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the breakpoint store has a requested breakpoint
|
* Checks if the breakpoint store has a requested breakpoint.
|
||||||
* Returns the stored breakpoint if it exists
|
|
||||||
* null otherwise
|
|
||||||
*
|
*
|
||||||
* @param Object aLocation
|
* @param Object aLocation
|
||||||
* The location of the breakpoint you are retrieving. It is an object
|
* The location of the breakpoint you are retrieving. It is an object
|
||||||
@ -141,6 +139,7 @@ BreakpointStore.prototype = {
|
|||||||
* - url
|
* - url
|
||||||
* - line
|
* - line
|
||||||
* - column (optional)
|
* - column (optional)
|
||||||
|
* @returns The stored breakpoint if it exists, null otherwise.
|
||||||
*/
|
*/
|
||||||
hasBreakpoint: function BS_hasBreakpoint(aLocation) {
|
hasBreakpoint: function BS_hasBreakpoint(aLocation) {
|
||||||
let { url, line, column } = aLocation;
|
let { url, line, column } = aLocation;
|
||||||
@ -179,7 +178,7 @@ BreakpointStore.prototype = {
|
|||||||
for (let url of this._iterUrls(aSearchParams.url)) {
|
for (let url of this._iterUrls(aSearchParams.url)) {
|
||||||
for (let line of this._iterLines(url, aSearchParams.line)) {
|
for (let line of this._iterLines(url, aSearchParams.line)) {
|
||||||
// Always yield whole line breakpoints first. See comment in
|
// Always yield whole line breakpoints first. See comment in
|
||||||
// |BreakpointStore.prototype.getBreakpoint|.
|
// |BreakpointStore.prototype.hasBreakpoint|.
|
||||||
if (aSearchParams.column == null
|
if (aSearchParams.column == null
|
||||||
&& this._wholeLineBreakpoints[url]
|
&& this._wholeLineBreakpoints[url]
|
||||||
&& this._wholeLineBreakpoints[url][line]) {
|
&& this._wholeLineBreakpoints[url][line]) {
|
||||||
@ -255,6 +254,136 @@ BreakpointStore.prototype = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages pushing event loops and automatically pops and exits them in the
|
||||||
|
* correct order as they are resolved.
|
||||||
|
*
|
||||||
|
* @param nsIJSInspector inspector
|
||||||
|
* The underlying JS inspector we use to enter and exit nested event
|
||||||
|
* loops.
|
||||||
|
* @param Object hooks
|
||||||
|
* An object with the following properties:
|
||||||
|
* - url: The URL string of the debuggee we are spinning an event loop
|
||||||
|
* for.
|
||||||
|
* - preNest: function called before entering a nested event loop
|
||||||
|
* - postNest: function called after exiting a nested event loop
|
||||||
|
* @param ThreadActor thread
|
||||||
|
* The thread actor instance that owns this EventLoopStack.
|
||||||
|
*/
|
||||||
|
function EventLoopStack({ inspector, thread, hooks }) {
|
||||||
|
this._inspector = inspector;
|
||||||
|
this._hooks = hooks;
|
||||||
|
this._thread = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoopStack.prototype = {
|
||||||
|
/**
|
||||||
|
* The number of nested event loops on the stack.
|
||||||
|
*/
|
||||||
|
get size() {
|
||||||
|
return this._inspector.eventLoopNestLevel;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the debuggee who pushed the event loop on top of the stack.
|
||||||
|
*/
|
||||||
|
get lastPausedUrl() {
|
||||||
|
return this.size > 0
|
||||||
|
? this._inspector.lastNestRequestor.url
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push a new nested event loop onto the stack.
|
||||||
|
*
|
||||||
|
* @returns EventLoop
|
||||||
|
*/
|
||||||
|
push: function () {
|
||||||
|
return new EventLoop({
|
||||||
|
inspector: this._inspector,
|
||||||
|
thread: this._thread,
|
||||||
|
hooks: this._hooks
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that represents a nested event loop. It is used as the nest
|
||||||
|
* requestor with nsIJSInspector instances.
|
||||||
|
*
|
||||||
|
* @param nsIJSInspector inspector
|
||||||
|
* The JS Inspector that runs nested event loops.
|
||||||
|
* @param ThreadActor thread
|
||||||
|
* The thread actor that is creating this nested event loop.
|
||||||
|
* @param Object hooks
|
||||||
|
* The same hooks object passed into EventLoopStack during its
|
||||||
|
* initialization.
|
||||||
|
*/
|
||||||
|
function EventLoop({ inspector, thread, hooks }) {
|
||||||
|
this._inspector = inspector;
|
||||||
|
this._thread = thread;
|
||||||
|
this._hooks = hooks;
|
||||||
|
|
||||||
|
this.enter = this.enter.bind(this);
|
||||||
|
this.resolve = this.resolve.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoop.prototype = {
|
||||||
|
entered: false,
|
||||||
|
resolved: false,
|
||||||
|
get url() { return this._hooks.url; },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enter this nested event loop.
|
||||||
|
*/
|
||||||
|
enter: function () {
|
||||||
|
let nestData = this._hooks.preNest
|
||||||
|
? this._hooks.preNest()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
this.entered = true;
|
||||||
|
this._inspector.enterNestedEventLoop(this);
|
||||||
|
|
||||||
|
// Keep exiting nested event loops while the last requestor is resolved.
|
||||||
|
if (this._inspector.eventLoopNestLevel > 0) {
|
||||||
|
const { resolved } = this._inspector.lastNestRequestor;
|
||||||
|
if (resolved) {
|
||||||
|
this._inspector.exitNestedEventLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg_assert(this._thread.state === "running",
|
||||||
|
"Should be in the running state");
|
||||||
|
|
||||||
|
if (this._hooks.postNest) {
|
||||||
|
this._hooks.postNest(nestData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve this nested event loop.
|
||||||
|
*
|
||||||
|
* @returns boolean
|
||||||
|
* True if we exited this nested event loop because it was on top of
|
||||||
|
* the stack, false if there is another nested event loop above this
|
||||||
|
* one that hasn't resolved yet.
|
||||||
|
*/
|
||||||
|
resolve: function () {
|
||||||
|
if (!this.entered) {
|
||||||
|
throw new Error("Can't resolve an event loop before it has been entered!");
|
||||||
|
}
|
||||||
|
if (this.resolved) {
|
||||||
|
throw new Error("Already resolved this nested event loop!");
|
||||||
|
}
|
||||||
|
this.resolved = true;
|
||||||
|
if (this === this._inspector.lastNestRequestor) {
|
||||||
|
this._inspector.exitNestedEventLoop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSD2 actors.
|
* JSD2 actors.
|
||||||
*/
|
*/
|
||||||
@ -280,6 +409,11 @@ function ThreadActor(aHooks, aGlobal)
|
|||||||
this._environmentActors = [];
|
this._environmentActors = [];
|
||||||
this._hooks = aHooks;
|
this._hooks = aHooks;
|
||||||
this.global = aGlobal;
|
this.global = aGlobal;
|
||||||
|
this._nestedEventLoops = new EventLoopStack({
|
||||||
|
inspector: DebuggerServer.xpcInspector,
|
||||||
|
hooks: aHooks,
|
||||||
|
thread: this
|
||||||
|
});
|
||||||
// A map of actorID -> actor for breakpoints created and managed by the server.
|
// A map of actorID -> actor for breakpoints created and managed by the server.
|
||||||
this._hiddenBreakpoints = new Map();
|
this._hiddenBreakpoints = new Map();
|
||||||
|
|
||||||
@ -326,6 +460,27 @@ ThreadActor.prototype = {
|
|||||||
return this._sources;
|
return this._sources;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of all of the nested event loops we use to pause the debuggee
|
||||||
|
* when we hit a breakpoint/debugger statement/etc in one place so we can
|
||||||
|
* resolve them when we get resume packets. We have more than one (and keep
|
||||||
|
* them in a stack) because we can pause within client evals.
|
||||||
|
*/
|
||||||
|
_threadPauseEventLoops: null,
|
||||||
|
_pushThreadPause: function TA__pushThreadPause() {
|
||||||
|
if (!this._threadPauseEventLoops) {
|
||||||
|
this._threadPauseEventLoops = [];
|
||||||
|
}
|
||||||
|
const eventLoop = this._nestedEventLoops.push();
|
||||||
|
this._threadPauseEventLoops.push(eventLoop);
|
||||||
|
eventLoop.enter();
|
||||||
|
},
|
||||||
|
_popThreadPause: function TA__popThreadPause() {
|
||||||
|
const eventLoop = this._threadPauseEventLoops.pop();
|
||||||
|
dbg_assert(eventLoop, "Should have an event loop.");
|
||||||
|
eventLoop.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
clearDebuggees: function TA_clearDebuggees() {
|
clearDebuggees: function TA_clearDebuggees() {
|
||||||
if (this.dbg) {
|
if (this.dbg) {
|
||||||
this.dbg.removeAllDebuggees();
|
this.dbg.removeAllDebuggees();
|
||||||
@ -485,7 +640,7 @@ ThreadActor.prototype = {
|
|||||||
this.conn.send(packet);
|
this.conn.send(packet);
|
||||||
|
|
||||||
// Start a nested event loop.
|
// Start a nested event loop.
|
||||||
this._nest();
|
this._pushThreadPause();
|
||||||
|
|
||||||
// We already sent a response to this request, don't send one
|
// We already sent a response to this request, don't send one
|
||||||
// now.
|
// now.
|
||||||
@ -529,7 +684,7 @@ ThreadActor.prototype = {
|
|||||||
* promise.
|
* promise.
|
||||||
*/
|
*/
|
||||||
_pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason,
|
_pauseAndRespond: function TA__pauseAndRespond(aFrame, aReason,
|
||||||
onPacket=function (k) k) {
|
onPacket=function (k) { return k; }) {
|
||||||
try {
|
try {
|
||||||
let packet = this._paused(aFrame);
|
let packet = this._paused(aFrame);
|
||||||
if (!packet) {
|
if (!packet) {
|
||||||
@ -548,14 +703,17 @@ ThreadActor.prototype = {
|
|||||||
message: error.message + "\n" + error.stack
|
message: error.message + "\n" + error.stack
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.then(packet => this.conn.send(packet));
|
.then(packet => {
|
||||||
|
this.conn.send(packet)
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._nest();
|
this._pushThreadPause();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
reportError(e, "Got an exception during TA__pauseAndRespond: ");
|
reportError(e, "Got an exception during TA__pauseAndRespond: ");
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -573,13 +731,13 @@ ThreadActor.prototype = {
|
|||||||
// In case of multiple nested event loops (due to multiple debuggers open in
|
// In case of multiple nested event loops (due to multiple debuggers open in
|
||||||
// different tabs or multiple debugger clients connected to the same tab)
|
// different tabs or multiple debugger clients connected to the same tab)
|
||||||
// only allow resumption in a LIFO order.
|
// only allow resumption in a LIFO order.
|
||||||
if (DebuggerServer.xpcInspector.eventLoopNestLevel > 1) {
|
if (this._nestedEventLoops.size
|
||||||
let lastNestRequestor = DebuggerServer.xpcInspector.lastNestRequestor;
|
&& this._nestedEventLoops.lastPausedUrl !== this._hooks.url) {
|
||||||
if (lastNestRequestor.connection != this.conn) {
|
return {
|
||||||
return { error: "wrongOrder",
|
error: "wrongOrder",
|
||||||
message: "trying to resume in the wrong order.",
|
message: "trying to resume in the wrong order.",
|
||||||
lastPausedUrl: lastNestRequestor.url };
|
lastPausedUrl: this._nestedEventLoops.lastPausedUrl
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aRequest && aRequest.forceCompletion) {
|
if (aRequest && aRequest.forceCompletion) {
|
||||||
@ -592,7 +750,7 @@ ThreadActor.prototype = {
|
|||||||
|
|
||||||
this.dbg.getNewestFrame().pop(aRequest.completionValue);
|
this.dbg.getNewestFrame().pop(aRequest.completionValue);
|
||||||
let packet = this._resumed();
|
let packet = this._resumed();
|
||||||
DebuggerServer.xpcInspector.exitNestedEventLoop();
|
this._popThreadPause();
|
||||||
return { type: "resumeLimit", frameFinished: aRequest.forceCompletion };
|
return { type: "resumeLimit", frameFinished: aRequest.forceCompletion };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,17 +772,27 @@ ThreadActor.prototype = {
|
|||||||
// Define the JS hook functions for stepping.
|
// Define the JS hook functions for stepping.
|
||||||
|
|
||||||
let onEnterFrame = aFrame => {
|
let onEnterFrame = aFrame => {
|
||||||
if (this.sources.isBlackBoxed(aFrame.script.url)) {
|
let { url } = this.synchronize(this.sources.getOriginalLocation(
|
||||||
return undefined;
|
aFrame.script.url,
|
||||||
}
|
aFrame.script.getOffsetLine(aFrame.offset),
|
||||||
return pauseAndRespond(aFrame);
|
getOffsetColumn(aFrame.offset, aFrame.script)));
|
||||||
|
|
||||||
|
return this.sources.isBlackBoxed(url)
|
||||||
|
? undefined
|
||||||
|
: pauseAndRespond(aFrame);
|
||||||
};
|
};
|
||||||
|
|
||||||
let thread = this;
|
let thread = this;
|
||||||
|
|
||||||
let onPop = function TA_onPop(aCompletion) {
|
let onPop = function TA_onPop(aCompletion) {
|
||||||
// onPop is called with 'this' set to the current frame.
|
// onPop is called with 'this' set to the current frame.
|
||||||
if (thread.sources.isBlackBoxed(this.script.url)) {
|
|
||||||
|
let { url } = thread.synchronize(thread.sources.getOriginalLocation(
|
||||||
|
this.script.url,
|
||||||
|
this.script.getOffsetLine(this.offset),
|
||||||
|
getOffsetColumn(this.offset, this.script)));
|
||||||
|
|
||||||
|
if (thread.sources.isBlackBoxed(url)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,7 +818,12 @@ ThreadActor.prototype = {
|
|||||||
let onStep = function TA_onStep() {
|
let onStep = function TA_onStep() {
|
||||||
// onStep is called with 'this' set to the current frame.
|
// onStep is called with 'this' set to the current frame.
|
||||||
|
|
||||||
if (thread.sources.isBlackBoxed(this.script.url)) {
|
let { url } = thread.synchronize(thread.sources.getOriginalLocation(
|
||||||
|
this.script.url,
|
||||||
|
this.script.getOffsetLine(this.offset),
|
||||||
|
getOffsetColumn(this.offset, this.script)));
|
||||||
|
|
||||||
|
if (thread.sources.isBlackBoxed(url)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,10 +885,44 @@ ThreadActor.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let packet = this._resumed();
|
let packet = this._resumed();
|
||||||
DebuggerServer.xpcInspector.exitNestedEventLoop();
|
this._popThreadPause();
|
||||||
return packet;
|
return packet;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spin up a nested event loop so we can synchronously resolve a promise.
|
||||||
|
*
|
||||||
|
* @param aPromise
|
||||||
|
* The promise we want to resolve.
|
||||||
|
* @returns The promise's resolution.
|
||||||
|
*/
|
||||||
|
synchronize: function(aPromise) {
|
||||||
|
let needNest = true;
|
||||||
|
let eventLoop;
|
||||||
|
let returnVal;
|
||||||
|
|
||||||
|
aPromise
|
||||||
|
.then((aResolvedVal) => {
|
||||||
|
needNest = false;
|
||||||
|
returnVal = aResolvedVal;
|
||||||
|
})
|
||||||
|
.then(null, (aError) => {
|
||||||
|
reportError(aError, "Error inside synchronize:");
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
if (eventLoop) {
|
||||||
|
eventLoop.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (needNest) {
|
||||||
|
eventLoop = this._nestedEventLoops.push();
|
||||||
|
eventLoop.enter();
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnVal;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the debugging hook to pause on exceptions if configured to do so.
|
* Set the debugging hook to pause on exceptions if configured to do so.
|
||||||
*/
|
*/
|
||||||
@ -1278,7 +1485,7 @@ ThreadActor.prototype = {
|
|||||||
this.conn.send(packet);
|
this.conn.send(packet);
|
||||||
|
|
||||||
// Start a nested event loop.
|
// Start a nested event loop.
|
||||||
this._nest();
|
this._pushThreadPause();
|
||||||
|
|
||||||
// We already sent a response to this request, don't send one
|
// We already sent a response to this request, don't send one
|
||||||
// now.
|
// now.
|
||||||
@ -1428,26 +1635,6 @@ ThreadActor.prototype = {
|
|||||||
return packet;
|
return packet;
|
||||||
},
|
},
|
||||||
|
|
||||||
_nest: function TA_nest() {
|
|
||||||
if (this._hooks.preNest) {
|
|
||||||
var nestData = this._hooks.preNest();
|
|
||||||
}
|
|
||||||
|
|
||||||
let requestor = Object.create(null);
|
|
||||||
requestor.url = this._hooks.url;
|
|
||||||
requestor.connection = this.conn;
|
|
||||||
DebuggerServer.xpcInspector.enterNestedEventLoop(requestor);
|
|
||||||
|
|
||||||
dbg_assert(this.state === "running", "Should be in the running state");
|
|
||||||
|
|
||||||
if (this._hooks.postNest) {
|
|
||||||
this._hooks.postNest(nestData)
|
|
||||||
}
|
|
||||||
|
|
||||||
// "continue" resumption value.
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
|
|
||||||
_resumed: function TA_resumed() {
|
_resumed: function TA_resumed() {
|
||||||
this._state = "running";
|
this._state = "running";
|
||||||
|
|
||||||
@ -1753,10 +1940,14 @@ ThreadActor.prototype = {
|
|||||||
onDebuggerStatement: function TA_onDebuggerStatement(aFrame) {
|
onDebuggerStatement: function TA_onDebuggerStatement(aFrame) {
|
||||||
// Don't pause if we are currently stepping (in or over) or the frame is
|
// Don't pause if we are currently stepping (in or over) or the frame is
|
||||||
// black-boxed.
|
// black-boxed.
|
||||||
if (this.sources.isBlackBoxed(aFrame.script.url) || aFrame.onStep) {
|
let { url } = this.synchronize(this.sources.getOriginalLocation(
|
||||||
return undefined;
|
aFrame.script.url,
|
||||||
}
|
aFrame.script.getOffsetLine(aFrame.offset),
|
||||||
return this._pauseAndRespond(aFrame, { type: "debuggerStatement" });
|
getOffsetColumn(aFrame.offset, aFrame.script)));
|
||||||
|
|
||||||
|
return this.sources.isBlackBoxed(url) || aFrame.onStep
|
||||||
|
? undefined
|
||||||
|
: this._pauseAndRespond(aFrame, { type: "debuggerStatement" });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1769,9 +1960,15 @@ ThreadActor.prototype = {
|
|||||||
* The exception that was thrown.
|
* The exception that was thrown.
|
||||||
*/
|
*/
|
||||||
onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) {
|
onExceptionUnwind: function TA_onExceptionUnwind(aFrame, aValue) {
|
||||||
if (this.sources.isBlackBoxed(aFrame.script.url)) {
|
let { url } = this.synchronize(this.sources.getOriginalLocation(
|
||||||
|
aFrame.script.url,
|
||||||
|
aFrame.script.getOffsetLine(aFrame.offset),
|
||||||
|
getOffsetColumn(aFrame.offset, aFrame.script)));
|
||||||
|
|
||||||
|
if (this.sources.isBlackBoxed(url)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let packet = this._paused(aFrame);
|
let packet = this._paused(aFrame);
|
||||||
if (!packet) {
|
if (!packet) {
|
||||||
@ -1781,11 +1978,13 @@ ThreadActor.prototype = {
|
|||||||
packet.why = { type: "exception",
|
packet.why = { type: "exception",
|
||||||
exception: this.createValueGrip(aValue) };
|
exception: this.createValueGrip(aValue) };
|
||||||
this.conn.send(packet);
|
this.conn.send(packet);
|
||||||
return this._nest();
|
|
||||||
|
this._pushThreadPause();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
reportError(e, "Got an exception during TA_onExceptionUnwind: ");
|
reportError(e, "Got an exception during TA_onExceptionUnwind: ");
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2781,8 +2980,13 @@ BreakpointActor.prototype = {
|
|||||||
hit: function BA_hit(aFrame) {
|
hit: function BA_hit(aFrame) {
|
||||||
// Don't pause if we are currently stepping (in or over) or the frame is
|
// Don't pause if we are currently stepping (in or over) or the frame is
|
||||||
// black-boxed.
|
// black-boxed.
|
||||||
if (this.threadActor.sources.isBlackBoxed(this.location.url) ||
|
let { url } = this.threadActor.synchronize(
|
||||||
aFrame.onStep) {
|
this.threadActor.sources.getOriginalLocation(
|
||||||
|
this.location.url,
|
||||||
|
this.location.line,
|
||||||
|
this.location.column));
|
||||||
|
|
||||||
|
if (this.threadActor.sources.isBlackBoxed(url) || aFrame.onStep) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
|
|||||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||||
|
Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
|
||||||
|
|
||||||
function testExceptionHook(ex) {
|
function testExceptionHook(ex) {
|
||||||
try {
|
try {
|
||||||
@ -346,3 +347,9 @@ function StubTransport() { }
|
|||||||
StubTransport.prototype.ready = function () {};
|
StubTransport.prototype.ready = function () {};
|
||||||
StubTransport.prototype.send = function () {};
|
StubTransport.prototype.send = function () {};
|
||||||
StubTransport.prototype.close = function () {};
|
StubTransport.prototype.close = function () {};
|
||||||
|
|
||||||
|
function executeSoon(aFunc) {
|
||||||
|
Services.tm.mainThread.dispatch({
|
||||||
|
run: DevToolsUtils.makeInfallible(aFunc)
|
||||||
|
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
104
toolkit/devtools/server/tests/unit/test_blackboxing-06.js
Normal file
104
toolkit/devtools/server/tests/unit/test_blackboxing-06.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that we can black box source mapped sources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var gDebuggee;
|
||||||
|
var gClient;
|
||||||
|
var gThreadClient;
|
||||||
|
|
||||||
|
Components.utils.import('resource:///modules/devtools/SourceMap.jsm');
|
||||||
|
|
||||||
|
const promise = devtools.require("sdk/core/promise");
|
||||||
|
|
||||||
|
function run_test()
|
||||||
|
{
|
||||||
|
initTestDebuggerServer();
|
||||||
|
gDebuggee = addTestGlobal("test-black-box");
|
||||||
|
gClient = new DebuggerClient(DebuggerServer.connectPipe());
|
||||||
|
gClient.connect(function() {
|
||||||
|
attachTestTabAndResume(gClient, "test-black-box", function(aResponse, aTabClient, aThreadClient) {
|
||||||
|
gThreadClient = aThreadClient;
|
||||||
|
|
||||||
|
promise.resolve(setup_code())
|
||||||
|
.then(black_box_code)
|
||||||
|
.then(run_code)
|
||||||
|
.then(test_correct_location)
|
||||||
|
.then(null, function (error) {
|
||||||
|
do_check_true(false, "Should not get an error, got " + error);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
finishClient(gClient);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
do_test_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_code() {
|
||||||
|
let { code, map } = (new SourceNode(null, null, null, [
|
||||||
|
new SourceNode(1, 0, "a.js", "" + function a() {
|
||||||
|
return b();
|
||||||
|
}),
|
||||||
|
"\n",
|
||||||
|
new SourceNode(1, 0, "b.js", "" + function b() {
|
||||||
|
debugger; // Don't want to stop here.
|
||||||
|
return c();
|
||||||
|
}),
|
||||||
|
"\n",
|
||||||
|
new SourceNode(1, 0, "c.js", "" + function c() {
|
||||||
|
debugger; // Want to stop here.
|
||||||
|
}),
|
||||||
|
"\n"
|
||||||
|
])).toStringWithSourceMap({
|
||||||
|
file: "abc.js",
|
||||||
|
sourceRoot: "http://example.com/"
|
||||||
|
});
|
||||||
|
|
||||||
|
code += "//# sourceMappingURL=data:text/json," + map.toString();
|
||||||
|
|
||||||
|
Components.utils.evalInSandbox(code,
|
||||||
|
gDebuggee,
|
||||||
|
"1.8",
|
||||||
|
"http://example.com/abc.js");
|
||||||
|
}
|
||||||
|
|
||||||
|
function black_box_code() {
|
||||||
|
const d = promise.defer();
|
||||||
|
|
||||||
|
gThreadClient.getSources(function ({ sources, error }) {
|
||||||
|
do_check_true(!error, "Shouldn't get an error getting sources");
|
||||||
|
const source = sources.filter((s) => {
|
||||||
|
return s.url.indexOf("b.js") !== -1;
|
||||||
|
})[0];
|
||||||
|
do_check_true(!!source, "We should have our source in the sources list");
|
||||||
|
|
||||||
|
gThreadClient.source(source).blackBox(function ({ error }) {
|
||||||
|
do_check_true(!error, "Should not get an error black boxing");
|
||||||
|
d.resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_code() {
|
||||||
|
const d = promise.defer();
|
||||||
|
|
||||||
|
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||||
|
d.resolve(aPacket);
|
||||||
|
gThreadClient.resume();
|
||||||
|
});
|
||||||
|
gDebuggee.a();
|
||||||
|
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_correct_location(aPacket) {
|
||||||
|
do_check_eq(aPacket.why.type, "debuggerStatement",
|
||||||
|
"Should hit a debugger statement.");
|
||||||
|
do_check_eq(aPacket.frame.where.url, "http://example.com/c.js",
|
||||||
|
"Should have skipped over the debugger statement in the black boxed source");
|
||||||
|
}
|
38
toolkit/devtools/server/tests/unit/test_nesting-01.js
Normal file
38
toolkit/devtools/server/tests/unit/test_nesting-01.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- Mode: javascript; js-indent-level: 2; -*- */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test that we can nest event loops when needed in
|
||||||
|
// ThreadActor.prototype.synchronize.
|
||||||
|
|
||||||
|
const { defer } = devtools.require("sdk/core/promise");
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
initTestDebuggerServer();
|
||||||
|
do_test_pending();
|
||||||
|
test_nesting();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_nesting() {
|
||||||
|
const thread = new DebuggerServer.ThreadActor(DebuggerServer);
|
||||||
|
const { resolve, reject, promise } = defer();
|
||||||
|
|
||||||
|
let currentStep = 0;
|
||||||
|
|
||||||
|
executeSoon(function () {
|
||||||
|
// Should be on the first step
|
||||||
|
do_check_eq(++currentStep, 1);
|
||||||
|
// We should have one nested event loop from synchronize
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 1);
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
do_check_eq(thread.synchronize(promise), true);
|
||||||
|
|
||||||
|
// Should be on the second step
|
||||||
|
do_check_eq(++currentStep, 2);
|
||||||
|
// There shouldn't be any nested event loops anymore
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 0);
|
||||||
|
|
||||||
|
do_test_finished();
|
||||||
|
}
|
68
toolkit/devtools/server/tests/unit/test_nesting-02.js
Normal file
68
toolkit/devtools/server/tests/unit/test_nesting-02.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/* -*- Mode: javascript; js-indent-level: 2; -*- */
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test that we can nest event loops and then automatically exit nested event
|
||||||
|
// loops when requested.
|
||||||
|
|
||||||
|
const { defer } = devtools.require("sdk/core/promise");
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
initTestDebuggerServer();
|
||||||
|
do_test_pending();
|
||||||
|
test_nesting();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_nesting() {
|
||||||
|
const thread = new DebuggerServer.ThreadActor(DebuggerServer);
|
||||||
|
const { resolve, reject, promise } = defer();
|
||||||
|
|
||||||
|
// The following things should happen (in order):
|
||||||
|
// 1. In the new event loop (created by synchronize)
|
||||||
|
// 2. Resolve the promise (shouldn't exit any event loops)
|
||||||
|
// 3. Exit the event loop (should also then exit synchronize's event loop)
|
||||||
|
// 4. Be after the synchronize call
|
||||||
|
let currentStep = 0;
|
||||||
|
|
||||||
|
executeSoon(function () {
|
||||||
|
let eventLoop;
|
||||||
|
|
||||||
|
executeSoon(function () {
|
||||||
|
// Should be at step 2
|
||||||
|
do_check_eq(++currentStep, 2);
|
||||||
|
// Before resolving, should have the synchronize event loop and the one just created.
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 2);
|
||||||
|
|
||||||
|
executeSoon(function () {
|
||||||
|
// Should be at step 3
|
||||||
|
do_check_eq(++currentStep, 3);
|
||||||
|
// Before exiting the manually created event loop, should have the
|
||||||
|
// synchronize event loop and the manual event loop.
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 2);
|
||||||
|
// Should have the event loop
|
||||||
|
do_check_true(!!eventLoop);
|
||||||
|
eventLoop.resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
// Shouldn't exit any event loops because a new one started since the call to synchronize
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should be at step 1
|
||||||
|
do_check_eq(++currentStep, 1);
|
||||||
|
// Should have only the synchronize event loop
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 1);
|
||||||
|
eventLoop = thread._nestedEventLoops.push();
|
||||||
|
eventLoop.enter();
|
||||||
|
});
|
||||||
|
|
||||||
|
do_check_eq(thread.synchronize(promise), true);
|
||||||
|
|
||||||
|
// Should be on the fourth step
|
||||||
|
do_check_eq(++currentStep, 4);
|
||||||
|
// There shouldn't be any nested event loops anymore
|
||||||
|
do_check_eq(thread._nestedEventLoops.size, 0);
|
||||||
|
|
||||||
|
do_test_finished();
|
||||||
|
}
|
@ -33,8 +33,6 @@ function test_simple_source_map()
|
|||||||
"http://example.com/www/js/b.js",
|
"http://example.com/www/js/b.js",
|
||||||
"http://example.com/www/js/c.js"]);
|
"http://example.com/www/js/c.js"]);
|
||||||
|
|
||||||
let numNewSources = 0;
|
|
||||||
|
|
||||||
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
gClient.addOneTimeListener("paused", function (aEvent, aPacket) {
|
||||||
gThreadClient.getSources(function (aResponse) {
|
gThreadClient.getSources(function (aResponse) {
|
||||||
do_check_true(!aResponse.error, "Should not get an error");
|
do_check_true(!aResponse.error, "Should not get an error");
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
head = head_dbg.js
|
head = head_dbg.js
|
||||||
tail =
|
tail =
|
||||||
|
|
||||||
|
[test_nesting-01.js]
|
||||||
|
[test_nesting-02.js]
|
||||||
[test_forwardingprefix.js]
|
[test_forwardingprefix.js]
|
||||||
[test_getyoungestframe.js]
|
[test_getyoungestframe.js]
|
||||||
[test_nsjsinspector.js]
|
[test_nsjsinspector.js]
|
||||||
@ -18,6 +20,7 @@ reason = bug 821285
|
|||||||
[test_blackboxing-03.js]
|
[test_blackboxing-03.js]
|
||||||
[test_blackboxing-04.js]
|
[test_blackboxing-04.js]
|
||||||
[test_blackboxing-05.js]
|
[test_blackboxing-05.js]
|
||||||
|
[test_blackboxing-06.js]
|
||||||
[test_frameactor-01.js]
|
[test_frameactor-01.js]
|
||||||
[test_frameactor-02.js]
|
[test_frameactor-02.js]
|
||||||
[test_frameactor-03.js]
|
[test_frameactor-03.js]
|
||||||
|
Loading…
Reference in New Issue
Block a user