Open Bug 560314 (js::dbg2) Opened 14 years ago Updated 2 years ago

Implement js::dbg2: new JavaScript debugging API, replacing jsd

Categories

(Core :: JavaScript Engine, defect)

x86
Linux
defect

Tracking

()

ASSIGNED

People

(Reporter: jimb, Assigned: jimb)

References

(Depends on 5 open bugs, )

Details

https://wiki.mozilla.org/Platform/JSDebugv2

We'd like to improve the Mozilla platform's debugging facilities, for a number of reasons:

    * Beyond debuggers, we want to encourage the creation of other sorts of monitoring and manipulation tools for web code; "watching programs run" is a broad charge. Think DTrace and SystemTap.
    * Our JavaScript implementation is changing rapidly; we need to do better than falling back to the bytecode interpreter whenever the debugger is enabled.
    * We need to be able to monitor and debug worker threads.
    * We need to be able to monitor and debug JavaScript running on embedded devices.
    * Now that SpiderMonkey is C++, an interface designed in that language can be more expressive and less error-prone than a C interface.
Blocks: 529086
By title this is dup of bug 449452; by description is has no overlap. I'd like to know how I can most effectively and appropriately make my case for collaboration on improvements in jsd.
Hi, John --- I've CC'd myself on the other bug. I think we should just collaborate in the existing bugs, but I want to leave this bug here as a placeholder for issues that aren't in scope for existing bugs.  Perhaps this should block bug 449452?

I have some ideas on how to sort out the script- and function-tracking stuff that was being discussed in bug 379410.  Once I have something sketched up, I'll post there.
Status: NEW → ASSIGNED
Regarding script tracking:

Bug 449464 has part of the work I did based on the ideas in Bug 379410. I quit posting to 449464 since it did not seem like there was common ground. I now think there is a simpler solution, simply emitting events before and after JS compile and building up a data structure in JS. That way we avoid C++ memory allocation. But I don't care about the implementation, just the final result.
One use case we'd like to support is running the debugger on a workstation, with the debuggee being JS running in a browser on a mobile device, connected by net, USB, or what-have-you.  It seems to me that exchanging script creation and destruction events across the connection would be a big performance hit --- you can do a lot of computation in the time it takes to do a round trip over USB.

It seems to me that the debugger should specify breakpoint locations in a higher-level form --- script URL and line number; eval-call-location and line-within-eval-script; and so on --- and then make the JS implementation responsible for stopping at the right times.

I think this might also get us a step closer to supporting breakpoints even in JITted code (although that's down the road a bit) by not communicating in terms of bytecodes.
(In reply to comment #4)
> One use case we'd like to support is running the debugger on a workstation,
> with the debuggee being JS running in a browser on a mobile device, connected
> by net, USB, or what-have-you.  It seems to me that exchanging script creation
> and destruction events across the connection would be a big performance hit ---
> you can do a lot of computation in the time it takes to do a round trip over
> USB.

Yes, but the wire protocol and the jsd API need not be the same. In my view we should do as much as possible in JS, esp. any network. But I agree. I don't see a big advantage to real-time control between script-creation events. The browser has no meaning for these inter-compilation times. So any remote debugger should be satisfied with all the scripts in a compilation unit at once. Firebug's internal API between debugger.js and firebug-service.js is closer to the level that makes sense to me over the wire. (And in fact that is what Crossfire targets).

> 
> It seems to me that the debugger should specify breakpoint locations in a
> higher-level form --- script URL and line number; eval-call-location and
> line-within-eval-script; and so on --- and then make the JS implementation
> responsible for stopping at the right times.

Yes, that is what Crossfire and the API used by Firebug's debugger.js use. But again the jsd layer need can be more detailed and more concrete. (eval call location is not enough by the way, many eval() based systems are loaders).

> 
> I think this might also get us a step closer to supporting breakpoints even in
> JITted code (although that's down the road a bit) by not communicating in terms
> of bytecodes.

Not really on my list, but I guess breakpoints themselves may not be too hard. The basic problem of jsd in JIT land is the interpreters "PC" make no sense. So I can see why you want to think in some other terms. 

Line numbers have another problem by the way: multiple statement on a line, all the way from for() stmts, thru coding style, to compressed code.

For the bulk of users a counter that follows js source is important; PC is pretty close to that but we can't expose it to users because we don't know the bytecodes. A counter that *did* relate to logical substatement ops in JS would be great! 

For JIT level ops, no abstraction related to JS code makes sense right? I mean in the fullness of time the JIT can be seemingly unrelated to the source. So somehow the counter has to be given by the JIT along with whatever we show to users. And we'll need two levels of control, source-oriented and JIT oriented, coupled together so we can set a breakpoint in a function land and discover it is JIT code then reset on a JIT basis.
(In reply to comment #5)
> (In reply to comment #4)
> > One use case we'd like to support is running the debugger on a workstation,
> > with the debuggee being JS running in a browser on a mobile device, connected
> > by net, USB, or what-have-you.  It seems to me that exchanging script creation
> > and destruction events across the connection would be a big performance hit ---
> > you can do a lot of computation in the time it takes to do a round trip over
> > USB.
> 
> Yes, but the wire protocol and the jsd API need not be the same. In my view we
> should do as much as possible in JS, esp. any network. But I agree. I don't see
> a big advantage to real-time control between script-creation events. The
> browser has no meaning for these inter-compilation times. So any remote
> debugger should be satisfied with all the scripts in a compilation unit at
> once. Firebug's internal API between debugger.js and firebug-service.js is
> closer to the level that makes sense to me over the wire. (And in fact that is
> what Crossfire targets).

So the overall architecture for remote debugging is, unavoidably:

    debugger UI (JS)
    --- debuggee API ---
    wire protocol client
    --- wire protocol ---
    wire protocol server
    jsd, jsdbgapi, etc.
    spidermonkey

For local debugging, we have:

    debugger UI (JS)
    --- debuggee API ---
    local debugging client
    jsd, jsdbgapi, etc.
    spidermonkey

You're saying that the wire protocol client and local debugging client should be JS, and perhaps the wire protocol server, too. Is this simply because it's a higher-level language?

> Line numbers have another problem by the way: multiple statement on a
> line, all the way from for() stmts, thru coding style, to compressed
> code.

SpiderMonkey's bytecode compiler doesn't even keep track of column numbers. You can infer more detail from the bytecodes used, but that is a horrible design!

> For the bulk of users a counter that follows js source is important; PC is
> pretty close to that but we can't expose it to users because we don't know the
> bytecodes. A counter that *did* relate to logical substatement ops in JS would
> be great! 

Well, the finer distinctions you make between points in the execution, the more code transformation done by the byte code compiler, the method JIT, or the tracing JIT will be visible under the debugger. The benefit of the finer distinctions can be lost in the noise introduced by quality-of-implementation issues.

(As a side point: this isn't an interpreter vs. compiler thing, or optimized vs. unoptimized. The question to ask is: how well can the debugging data we retain relate the code that is actually running to the code we wrote? Even unoptimized, interpreted bytecode can behave strangely under a debugger if it doesn't relate in a simple way to the source.)

> For JIT level ops, no abstraction related to JS code makes sense right? I mean
> in the fullness of time the JIT can be seemingly unrelated to the source. So
> somehow the counter has to be given by the JIT along with whatever we show to
> users. And we'll need two levels of control, source-oriented and JIT oriented,
> coupled together so we can set a breakpoint in a function land and discover it
> is JIT code then reset on a JIT basis.
> For JIT level ops, no abstraction related to JS code makes sense right? I
> mean in the fullness of time the JIT can be seemingly unrelated to the
> source. So somehow the counter has to be given by the JIT along with
> whatever we show to users. And we'll need two levels of control,
> source-oriented and JIT oriented, coupled together so we can set a
> breakpoint in a function land and discover it is JIT code then reset on a
> JIT basis.

Yes, given that we've got two fast-moving JITs, I would expect a good
interface to avoid revealing their characteristics. The interface should
use a counter that relates directly to the JS source code; it should be the
responsibility of JSD and lower layers to relate that to whatever the JIT
is doing today.
(In reply to comment #6)
> (In reply to comment #5)
> > (In reply to comment #4)
> > > One use case we'd like to support is running the debugger on a workstation,
> > > with the debuggee being JS running in a browser on a mobile device, connected
> > > by net, USB, or what-have-you.  It seems to me that exchanging script creation
> > > and destruction events across the connection would be a big performance hit ---
> > > you can do a lot of computation in the time it takes to do a round trip over
> > > USB.
> > 
> > Yes, but the wire protocol and the jsd API need not be the same. In my view we
> > should do as much as possible in JS, esp. any network. But I agree. I don't see
> > a big advantage to real-time control between script-creation events. The
> > browser has no meaning for these inter-compilation times. So any remote
> > debugger should be satisfied with all the scripts in a compilation unit at
> > once. Firebug's internal API between debugger.js and firebug-service.js is
> > closer to the level that makes sense to me over the wire. (And in fact that is
> > what Crossfire targets).
> 
> So the overall architecture for remote debugging is, unavoidably:
> 
>     debugger UI (JS)
>     --- debuggee API ---
>     wire protocol client
>     --- wire protocol ---
>     wire protocol server
>     jsd, jsdbgapi, etc.
>     spidermonkey
> 
> For local debugging, we have:
> 
>     debugger UI (JS)
>     --- debuggee API ---
>     local debugging client
>     jsd, jsdbgapi, etc.
>     spidermonkey
> 
> You're saying that the wire protocol client and local debugging client should
> be JS, and perhaps the wire protocol server, too. Is this simply because it's a
> higher-level language?

Yes simply because JS is a language with GC, optimized for network data, that we have a lot of experience, tools, and support for. In general we should everything we possibly can in JS.

(and eventually "local" debugging will be multiprocess and probably we use the remote model as well).

> 
> > Line numbers have another problem by the way: multiple statement on a
> > line, all the way from for() stmts, thru coding style, to compressed
> > code.
> 
> SpiderMonkey's bytecode compiler doesn't even keep track of column numbers. You
> can infer more detail from the bytecodes used, but that is a horrible design!

Hey, we'd love to have horrible! If we had a PC/bytecode map we can do a lot we can't do now, even if its a lot less nice than perfect (which we don't have a chance of getting).

> 
> > For the bulk of users a counter that follows js source is important; PC is
> > pretty close to that but we can't expose it to users because we don't know the
> > bytecodes. A counter that *did* relate to logical substatement ops in JS would
> > be great! 
> 
> Well, the finer distinctions you make between points in the execution, the more
> code transformation done by the byte code compiler, the method JIT, or the
> tracing JIT will be visible under the debugger. The benefit of the finer
> distinctions can be lost in the noise introduced by quality-of-implementation
> issues.
> 
> (As a side point: this isn't an interpreter vs. compiler thing, or optimized
> vs. unoptimized. The question to ask is: how well can the debugging data we
> retain relate the code that is actually running to the code we wrote? Even
> unoptimized, interpreted bytecode can behave strangely under a debugger if it
> doesn't relate in a simple way to the source.)

Yes we already have user bug reports about this: for loops the PC jumps to the end. But anyway in my view debugging JIT code would be very cool but may only benefit of a few people. Most people who understand the JIT don't use it on real problems; most people who work on real JS code don't want to know about the JIT code. 

> 
> > For JIT level ops, no abstraction related to JS code makes sense right? I mean
> > in the fullness of time the JIT can be seemingly unrelated to the source. So
> > somehow the counter has to be given by the JIT along with whatever we show to
> > users. And we'll need two levels of control, source-oriented and JIT oriented,
> > coupled together so we can set a breakpoint in a function land and discover it
> > is JIT code then reset on a JIT basis.
Bug renamed, assigned alias.  Overall architecture sketch up at https://wiki.mozilla.org/Platform/JSDebugv2.

I'd like to have the WebIDL wrapping be a thinner layer around the C++ interface than jsdIDebuggerService would seem to be around jsd's C code, thus the emphasis on js::dbg2.

I'll file a separate bug for the remote protocol, and a bunch of blockers for the specific work items we've identified.
Alias: js::dbg2
Summary: JSD API needs redesign → Implement js::dbg2: new C++ JavaScript debugging API, replacing jsd
Also to do: file bugs (or find extant bugs) for the items on JJB's wish list that I agreed were in scope, and mark them as blocking:

http://groups.google.com/group/mozilla.dev.tech.js-engine/browse_thread/thread/b46b66492d87cc00#
(In reply to comment #10)
> Also to do: file bugs (or find extant bugs) for the items on JJB's wish list
> that I agreed were in scope, and mark them as blocking:

Thanks, I appreciate your listening and interest. I know creating a bunch of bugs is the mozilla way, but personally I would be much more interested in participating in discussions on priorities. Having one bug we are working towards is much more valuable than 50 resting in bugzilla without any idea if any of them are being seriously considered.
(In reply to comment #11)
> 
> Thanks, I appreciate your listening and interest. I know creating a bunch of
> bugs is the mozilla way, but personally I would be much more interested in
> participating in discussions on priorities. 

I don't think we need to change the way we've planning this work. There's been quite a lot of discussion, and it's time to start implementing.
Depends on: 567198
Depends on: 567199
Depends on: 567202
Depends on: 567204
(In reply to comment #12)
> quite a lot of discussion, and it's time to start implementing.

If the before/after compilation events are still in the plan and if jsd can run in parallel with js:dbg, then by starting with these events we could get an immediate boost in function to developers.
Depends on: 567219
Depends on: 568138
Depends on: 568139
Depends on: 568140
Depends on: 568141
Depends on: 568142
Depends on: 636907
Depends on: 636909
I'm now thinking it makes the most sense to just skip the C++ API step and go directly to providing a good JS-level debugging API; that's where the clients are anyway. See bug 636907 for my current thinking, and a link to a docs sketch.
Depends on: 638038
Depends on: 638040
Depends on: 638054
Depends on: 618650
Depends on: 433529
Summary: Implement js::dbg2: new C++ JavaScript debugging API, replacing jsd → Implement js::dbg2: new JavaScript debugging API, replacing jsd
Depends on: 656760
Component: JavaScript Debugging/Profiling APIs → JavaScript Engine
[note stolen from bug 672829]

Note that this API is documented here:
https://wiki.mozilla.org/Debugger

However, that documentation is half spec --- it includes stuff we haven't implemented yet, and what's done is not clearly delimited from what's yet to be done. But naturally, feel free to copy anything that's useful.
Depends on: 676281
Depends on: 674171
Depends on: 733461
Docs for the API are available on-line at: https://wiki.mozilla.org/Debugger
Keywords: dev-doc-needed
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.