Hi Jason, Jim,
Sorry for the late answer. I was away for a bit and I took some time to
do some drawings to give proper answers.
Le 23/05/2012 23:13, Jason Orendorff a écrit :
> On 5/22/12 4:59 PM, David Bruant wrote:
>> Le 21/05/2012 20:54, Jim Blandy a écrit :
>>> The way to get the effect of a 'pause' is to start up a nested event
>>> loop. Since the event loop is an aspect of the browser, and not of the
>>> JavaScript engine per se, it's not covered in Debugger.
>>>
>>> The code for this is in ThreadActor.prototype._nest, in
>>> toolkit/devtools/debugger/server/dbg-script-actors.js. That uses
>>> 'preNest' and 'postNest' hooks defined in
>>> toolkit/devtools/debugger/server/dbg-browser-actors.js.
>> Ok. So, I've played with enterNestedEventLoop and exitNestedEventLoop.
>> From reading the code of dbg-script-actors.js [1], it was not obvious
>> that the code "freezes". Knowing it does, the preNest and postNest hooks
>> make a lot of sense.
>> Freezing like that is a bit hard, because there is no way to "boostrap"
>> the nested event loop.
>
> What do you mean by "bootstrap" here? Keep in mind, basically all
> enterNestedEventLoop does is:
> while (!exitNestedEventLoopWasCalled())
> NS_ProcessNextEvent();
I have made some images to explain what I meant for "bootstrap".
Something about a thousand words. See
http://davidbruant.github.com/JSRuntime-SVGs/ if you see less than 4
images, clone g...@github.com:DavidBruant/JSRuntime-SVGs.git and open
index.html locally (I don't know what's the difference, but the github
version does some 404 on my SVGs for no reason).
I assume my mental representation to be accurate, but please correct me
if any of what I've drawn is inaccurate.
The first image is a regular JavaScript run-time with a stack on the
left, a queue at the bottom and a heap (graphical position of elements
in the heap is completely irrelevant here).
For the queue, messages can come from different sources, like DOM
events, postMessage messages, timeouts, intervals, etc. One message is
treated at a time. On processing, a message "creates" the initial frame
then, run-to-completion, etc.
For the first image, I have drawn the top frame in a different color to
mean that it's a debugger frame (on the same stack, but not the same
"type of code").
On the second image, enterNestedEventLoop is called. A new stack and a
new queue are created. Until exitNestedEventLoop, new messages will go
in the nested frame and be treated in the nested stack.
One important thing to point out for the nested event loop is that both
the stack and
the queue are empty initially. Code will run in this stack/queue only if
messages are
sent to the queue from different sources (like another window sending a
message, etc.)
What I mean by "bootstraping the nesting event loop" is described in the
third image. On creation, instead of creating empty stack and queue, the
nested event loop would be created with an initial frame on the stack.
This frame could be created thanks to a function passed as an argument
to enterNestedEventLoop.
>> My understanding is that the way it is
>> bootstraped in the Firefox debugger is that all the "intelligence" of
>> the debugger does not run within the process of the debuggee but rather
>> in its own window (which is why the debugger does have its own window).
>
> I don't know if this is right—it might be simpler than you think—but
> I'm not the right person to say either way. You might want to take
> this to dev.platform or ping me on IRC and we'll go find the right person.
I will.
Le 24/05/2012 00:56, Jim Blandy a écrit :
> On 05/22/2012 02:59 PM, David Bruant wrote:
>> Freezing like that is a bit hard, because there is no way to "boostrap"
>> the nested event loop. My understanding is that the way it is
>> bootstraped in the Firefox debugger is that all the "intelligence" of
>> the debugger does not run within the process of the debuggee but rather
>> in its own window (which is why the debugger does have its own window).
>> The nested event loop that run in the same context than the debuggee is
>> controlled by messages sent by the "intelligent" debugger.
> What do you think of the way jorendb does it? (I assume you've seen
> jorendb; if not:
https://github.com/jorendorff/jorendb) It's similar:
> the repl isn't a single loop entered once per debugging session;
> instead, the repl is entered each time the debuggee pauses, and the
> repl exits when it wants to continue/step/finish.
I wasn't aware of jorendb, thanks for sharing that.
Apparently, the trick here is the synchronous block caused by readline.
I feel a bit weird about it, but that's probably cultural. I've been
taught to conform to a JS model where you should never block.
In a way, it's fortunate that readline is defined as a synchronously
blocking primitive. If SpiderMonkey's readline was following Node.js
design [1], it would not be possible to do the same thing.
Also, I'm not sure this can be reproduced for any use case. readline
works well for a command-line tool. Even if it was, I don't think
synchronous blocking primitive should be the way to go in general.
> I don't see it as the debuggee "freezing"; I see it more as the
> debugger and debuggee sharing a single stack, which means that all the
> debugger's frames need to be gone whenever the debuggee is to continue.
I used "freezing" in the context of using enterNestedEventLoop, which,
as I drew in the second image freezes the state of the stack and queue
of the original event loop.
After the 3 initial pictures, I started to think of what I originally
meant by "pausing the debuggee" and that's the 4th image. When calling
"pause", the bottom of the stack would be "lifted up" to the top of the
debuggee frames and a new queue is created. Until calling "resume", the
messages would only accumulate in the new queue and the stack would
never go back the debuggee code.
I don't know if it's easy to do. While explaining, I realized that the
"boostraped nested event loop" is equivalent or very close to that model.
After more thoughts, I've realized that I can hack the bootstraping
myself by opening another window which role will be to wake me up after
having called enterNestedEventLoop.
David
[1]
http://nodejs.org/api/readline.html#readline_rl_question_query_callback