V8 bindings: The difference between v8::Context::GetEntered() & v8::Context::GetCurrent()

963 views
Skip to first unread message

Marja Hölttä

unread,
Jul 18, 2013, 6:03:46 AM7/18/13
to blin...@chromium.org, har...@chromium.org, johnj...@chromium.org, sven...@chromium.org, mstar...@chromium.org, ad...@chromium.org, aba...@chromium.org
Hi everybody interested in V8 bindings,

"What's the difference between Context::GetEntered and Context::GetCurrent" seems to cause some confusion.

I opportunistically asked this question in https://codereview.chromium.org/19457002/ , and haraken answered. In order to not spam the code review, let's discuss here.

haraken:
> For example, imagine that a function in document A calls a function defined in
> document B. In this case, GetCurrent() returns document B, whereas GetEntered()
> returns document A.

> GetCurrent() returns a context on which we're. On the other hand, GetEntered()
> returns a context that we have entered last (e.g. context->Enter() or
> Context::Scope(context) enters the context).

Hmm. Will the context of document B be somewhere lower in the "entered contexts" stack, or just not entered at all in that case? I don't yet understand the relationship between documents and contexts. When do we enter a context? When do we need to enter a context? Why are we running a function defined in document B in the context of document A? When do we enter a context even though we're already in another context (so, to create a stack of entered contexts)?

Can you explain this like I'm a 5 year old? :)

Somebody (= haraken, since you're the first person who actually has answered this question) should add a comment clarifying the difference between GetCurrent and GetEntered to v8.h. This seems to confuse and frighten people.

------------

For the record, the V8 comments near these functions:

Context:GetEntered:
  /** Returns the last entered context. */
  static Local<Context> GetEntered();

Context::GetCurrent:
  // TODO(svenpanne) Actually deprecate this.
  /** Deprecated. Use Isolate::GetCurrentContext instead. */
  static Local<Context> GetCurrent();

Isolate:GetCurrentContext:
  /** Returns the context that is on the top of the stack. */
  Local<Context> GetCurrentContext();

(Huh? Is the comment of Isolate::GetCurrentContext just plain wrong, or why does it sound like it's exactly the same as Context::GetEntered?)

- marja

Kentaro Hara

unread,
Jul 18, 2013, 6:39:38 AM7/18/13
to Marja Hölttä, ag...@chromium.org, blink-dev, johnjbarton, sven...@chromium.org, mstar...@chromium.org, Adam Klein, aba...@chromium.org
Hmm. Will the context of document B be somewhere lower in the "entered contexts" stack, or just not entered at all in that case? I don't yet understand the relationship between documents and contexts. When do we enter a context? When do we need to enter a context? Why are we running a function defined in document B in the context of document A? When do we enter a context even though we're already in another context (so, to create a stack of entered contexts)?

Here is a good explanation from mads@ four years ago:

>> quick answer:  When you use V8 you have to enter a context before
>> giving V8 some code to execute.  GetEntered() returns the last context
>> that you entered using the API.  When you call JavaScript functions,
>> the JavaScript engine enters the context in which that function was
>> defined.  When calling functions across frames, this context will be
>> different from the context that you entered through the API.
>> GetCurrent will always give you the context of the currently executing
>> function (the context in which the currently executing function was
>> declared).  GetCalling will get you the context of the function that
>> called the function you are currently executing.

Does it make sense to you?

I agree with that we should elaborate the comment in v8.h.


--
Kentaro Hara, Tokyo, Japan

Marja Hölttä

unread,
Jul 18, 2013, 7:17:29 AM7/18/13
to Kentaro Hara, ag...@chromium.org, blink-dev, johnjbarton, sven...@chromium.org, mstar...@chromium.org, Adam Klein, aba...@chromium.org
mads:
>> When you call JavaScript functions,
>> the JavaScript engine enters the context in which that function was
>> defined.

Does that mean, that in haraken's example, V8 does enter the context for document B (and thus, it is the topmost in the context stack), but GetEntered still returns context for document A? Does "GetEntered" mean "get last context which was entered by the embedder", and V8 will internally enter the context where the func was defined on top of that?

Kentaro Hara

unread,
Jul 18, 2013, 7:40:04 AM7/18/13
to Marja Hölttä, ag...@chromium.org, blink-dev, johnjbarton, sven...@chromium.org, mstar...@chromium.org, Adam Klein, aba...@chromium.org
Does that mean, that in haraken's example, V8 does enter the context for document B (and thus, it is the topmost in the context stack), but GetEntered still returns context for document A?

(Note: Accurately, I should have said 'context A or B' instead of 'document A or B'. document and context are not 1:1.)

V8 does not enter context B. When a JavaScript function defined in context A calls a function defined in context B, V8 pushes context A to the context stack but doesn't enter context B. Remember that "pushing to the context stack" and "entering" are different concepts.

The rule is as follows:

- A context is entered when V8 or embedder explicitly calls Context::Enter() or creates Context::Scope. V8 doesn't enter a context when calling JavaScript functions.

- A context is pushed to the context stack when the context is entered or when V8 calls a JavaScript function defined in another context.

- GetCurrent() returns the topmost context in the context stack.

- GetEntered() returns the context that you entered last.


(Note: V8 experts will give you more accurate explanation.)

Marja Hölttä

unread,
Jul 18, 2013, 8:04:48 AM7/18/13
to Kentaro Hara, ag...@chromium.org, blink-dev, johnjbarton, sven...@chromium.org, mstar...@chromium.org, Adam Klein, aba...@chromium.org
Alright, cool, we're getting there :) The relevant piece of new information (to me) was:

> "pushing to the context stack" and "entering" are different concepts.

So the next clarifying questions:

1) What's the purpose of the context stack then? I had thought it's a stack of entered contexts, but apparently it's not.
2) What does "entering a context" mean (in addition to pushing it to the stack)?

John Barton

unread,
Jul 18, 2013, 10:49:03 AM7/18/13
to Marja Hölttä, Kentaro Hara, ag...@chromium.org, blink-dev, johnjbarton, sven...@chromium.org, mstar...@chromium.org, Adam Klein, aba...@chromium.org
I'm replying here not as an expert but as someone who also finds this confusing.

Stack geometry is fundamentally ambiguous: the meaning of the top and bottom -- even if we agree to vertical -- depend on the reader. 

Therefore we should document stacks using time, not space:
     GetCurrent() returns the most recently pushed context on the context stack.
     GetEntered() returns the first (or oldest) context pushed on the context stack.

I speculate that "entered" here means "the context used to enter V8" not "V8 entered a context".  From the JS function call perspective the context is secondary: a function is calling a function, eom. So once we have entered V8, V8 does not need to think about "entering contexts". It's just calling functions. When the function needs to look up symbols, then it needs to look in its context, but I'm not even sure the context stack is all that important to the JS function call mechanism. This stack has no meaning in the JS language. Embedders need it to figure out how to deal with JS calls into host API.

Marja, does that help?
jjb

Adam Barth

unread,
Jul 18, 2013, 2:41:01 PM7/18/13
to Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On Thu, Jul 18, 2013 at 5:04 AM, Marja Hölttä <ma...@chromium.org> wrote:
Alright, cool, we're getting there :) The relevant piece of new information (to me) was:

> "pushing to the context stack" and "entering" are different concepts.

So the next clarifying questions:

1) What's the purpose of the context stack then? I had thought it's a stack of entered contexts, but apparently it's not.

V8 contains a runtime stack of JavaScript functions.  When one function calls another, the callee is pushed into the runtime stack.  When that function returns, the runtime is popped from the runtime stack and control returns to the function that's now on the top of the stack.  Each function as an associated context (it's CreationContext).

There is a second stack which operates on a much coarser granularity.  When C++ calls into V8, it does so in a given context.  The way C++ tells V8 which context it wants to use is by calling Enter() on a v8::Context object.  When control returns to C++, the C++ code calls Exit() on the same context object.  It's possible that someone higher on the C++ runtime stack might have done the same thing (e.g., we're dispatching an event that was triggered synchronously by JavaScript).  Therefore, V8 contains another stack of v8::Context objects so that it can restore the previous v8::Context when C++ calls Exit().

2) What does "entering a context" mean (in addition to pushing it to the stack)?

The entered context is the v8::Context object is the v8::Context object upon which Enter() was called most recently.

Note: We don't usually call Enter() and Exit() on v8::Context objects directly.  Instead, we use a v8::Context::Scope object which calls Enter() in its constructor and Exit() in its destructor.

If I have time this afternoon, I'll try drawing a diagram, which will hopefully be clearer.

Adam

Marja Hölttä

unread,
Jul 19, 2013, 7:43:21 AM7/19/13
to Adam Barth, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
Thanks for answers, this is much clearer now!


2013/7/18 Adam Barth <aba...@chromium.org>

Wez

unread,
Jul 19, 2013, 10:56:32 AM7/19/13
to Marja Hölttä, Adam Barth, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
My summary of this, based on this thread:
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
  2. The "current" context is that in which the executing V8 code was defined.
    • If you're executing C++ then that's the context of the V8 function that called you.
  3. Both of these concepts have a stack because:
    • V8 code may call a function in a different context, making it "current" until the call returns.
    • V8 may call into C++ that then "re-enters" by calling into V8, etc.
Correct?


--
You received this message because you are subscribed to the Google Groups "blink-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/blink-dev/CAED6dUBsa9BSjX%2BOyjc6%3DPVPMq4qNFCAjagrsB3iS%2BLq55KcYg%40mail.gmail.com.
 
 

Marja Hölttä

unread,
Jul 19, 2013, 11:07:46 AM7/19/13
to Wez, Adam Barth, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
2013/7/19 Wez <w...@chromium.org>
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
Afaik not, but I'm not 100% what you meant by this. Isn't Context only entered if you call Enter on it (or have a Context::Scope which calls it in the ctor) and that's the only way to enter a context?

Wez

unread,
Jul 19, 2013, 12:15:34 PM7/19/13
to Marja Hölttä, Adam Barth, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
I meant this in terms of what "entered" and "current" mean conceptually, regardless of exactly how entering a scope is actually implemented - IIUC the embedder is expected to always Enter() a context before calling into V8.

You can presumably Enter() a context without then calling into V8, but I'm not sure how that would ever be useful. :)

Adam Barth

unread,
Jul 19, 2013, 2:08:33 PM7/19/13
to Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On Fri, Jul 19, 2013 at 9:15 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 11:07, Marja Hölttä <ma...@chromium.org> wrote:
2013/7/19 Wez <w...@chromium.org>
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
Afaik not, but I'm not 100% what you meant by this. Isn't Context only entered if you call Enter on it (or have a Context::Scope which calls it in the ctor) and that's the only way to enter a context?

I meant this in terms of what "entered" and "current" mean conceptually, regardless of exactly how entering a scope is actually implemented - IIUC the embedder is expected to always Enter() a context before calling into V8.

That's not the case.  The embedder is only required to have called Enter() more times than Exit() when calling into V8.

Adam

Adam Barth

unread,
Jul 19, 2013, 2:12:17 PM7/19/13
to Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On Fri, Jul 19, 2013 at 7:56 AM, Wez <w...@chromium.org> wrote:
My summary of this, based on this thread:
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
  2. The "current" context is that in which the executing V8 code was defined.
    • If you're executing C++ then that's the context of the V8 function that called you.
That's not entirely accurate.  The Current context is the creation context of the JavaScript function that is currently executing (i.e., most recently pushed onto the JavaScript runtime stack).  It's not the case that C++ was necessarily called by that function.  We could have entered C++ for other reasons (e.g., garbage collection).

Adam

Wez

unread,
Jul 19, 2013, 2:38:19 PM7/19/13
to Adam Barth, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
True; so if you're executing C++ then that's the context of the V8 function that caused the C++ to be executed.
 

Adam


Wez

unread,
Jul 19, 2013, 2:40:00 PM7/19/13
to Adam Barth, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
Oh, interesting.  I think the thing I'm missing is what the Entered context is actually useful for.

Is the Entered context the most recently Enter()d, or the first Enter()d?
 

Adam


Adam Barth

unread,
Jul 19, 2013, 2:55:11 PM7/19/13
to Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
We use the Entered context to implement the concept of the "entry script" from the HTML Standard:


We use the Current context to implement the concept of the "incumbent script":


You can look at what references each of these definition to get a sense for how each concept is useful for.

There's also v8::Context::GetCalling(), which complicates the picture even more.  It's the creation context of the JavaScript function that called the JavaScript function that was most recently pushed onto the runtime stack (i.e., the one we'll return to when we pop the runtime stack).  The Calling context might not exist if there's only one JavaScript function on the runtime stack.

Is the Entered context the most recently Enter()d, or the first Enter()d?

The most recently Entered.

Adam

Wez

unread,
Jul 19, 2013, 2:58:17 PM7/19/13
to Adam Barth, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On 19 July 2013 14:55, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 11:40 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 14:08, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 9:15 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 11:07, Marja Hölttä <ma...@chromium.org> wrote:
2013/7/19 Wez <w...@chromium.org>
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
Afaik not, but I'm not 100% what you meant by this. Isn't Context only entered if you call Enter on it (or have a Context::Scope which calls it in the ctor) and that's the only way to enter a context?

I meant this in terms of what "entered" and "current" mean conceptually, regardless of exactly how entering a scope is actually implemented - IIUC the embedder is expected to always Enter() a context before calling into V8.

That's not the case.  The embedder is only required to have called Enter() more times than Exit() when calling into V8.

Oh, interesting.  I think the thing I'm missing is what the Entered context is actually useful for.

We use the Entered context to implement the concept of the "entry script" from the HTML Standard:


We use the Current context to implement the concept of the "incumbent script":


You can look at what references each of these definition to get a sense for how each concept is useful for.

Aha.  Perhaps the GetEntered and GetCurrent API comments should refer to these definitions.

Adam Barth

unread,
Jul 19, 2013, 3:04:37 PM7/19/13
to Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On Fri, Jul 19, 2013 at 11:58 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 14:55, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 11:40 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 14:08, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 9:15 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 11:07, Marja Hölttä <ma...@chromium.org> wrote:
2013/7/19 Wez <w...@chromium.org>
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
Afaik not, but I'm not 100% what you meant by this. Isn't Context only entered if you call Enter on it (or have a Context::Scope which calls it in the ctor) and that's the only way to enter a context?

I meant this in terms of what "entered" and "current" mean conceptually, regardless of exactly how entering a scope is actually implemented - IIUC the embedder is expected to always Enter() a context before calling into V8.

That's not the case.  The embedder is only required to have called Enter() more times than Exit() when calling into V8.

Oh, interesting.  I think the thing I'm missing is what the Entered context is actually useful for.

We use the Entered context to implement the concept of the "entry script" from the HTML Standard:


We use the Current context to implement the concept of the "incumbent script":


You can look at what references each of these definition to get a sense for how each concept is useful for.

Aha.  Perhaps the GetEntered and GetCurrent API comments should refer to these definitions.

That's a great idea.  Would you be willing to write that CL?

For historical context, these APIs predate the HTML Standard nailing down these concepts.  Life used to be much... fuzzier.  At some point, I tried to align the terminology in the bindings with the terminology in the HTML Standard, but the spec's terminology has changed since them (much for the better).  We might want to update the terminology in the implementation to match the spec again.

Adam

Wez

unread,
Jul 19, 2013, 3:08:46 PM7/19/13
to Adam Barth, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
On 19 July 2013 15:04, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 11:58 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 14:55, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 11:40 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 14:08, Adam Barth <aba...@chromium.org> wrote:
On Fri, Jul 19, 2013 at 9:15 AM, Wez <w...@chromium.org> wrote:
On 19 July 2013 11:07, Marja Hölttä <ma...@chromium.org> wrote:
2013/7/19 Wez <w...@chromium.org>
  1. A V8 context is "entered" whenever control passes from C++ into V8, end exited when control returns.
Afaik not, but I'm not 100% what you meant by this. Isn't Context only entered if you call Enter on it (or have a Context::Scope which calls it in the ctor) and that's the only way to enter a context?

I meant this in terms of what "entered" and "current" mean conceptually, regardless of exactly how entering a scope is actually implemented - IIUC the embedder is expected to always Enter() a context before calling into V8.

That's not the case.  The embedder is only required to have called Enter() more times than Exit() when calling into V8.

Oh, interesting.  I think the thing I'm missing is what the Entered context is actually useful for.

We use the Entered context to implement the concept of the "entry script" from the HTML Standard:


We use the Current context to implement the concept of the "incumbent script":


You can look at what references each of these definition to get a sense for how each concept is useful for.

Aha.  Perhaps the GetEntered and GetCurrent API comments should refer to these definitions.

That's a great idea.  Would you be willing to write that CL?

Sure.

For historical context, these APIs predate the HTML Standard nailing down these concepts.  Life used to be much... fuzzier.  At some point, I tried to align the terminology in the bindings with the terminology in the HTML Standard, but the spec's terminology has changed since them (much for the better).  We might want to update the terminology in the implementation to match the spec again.

Primarily renaming "current" -> "uncumbent"?

Good to keep naming in-sync, but something for the V8 folks to weigh in on, I think. :)

Adam Barth

unread,
Jul 19, 2013, 3:14:49 PM7/19/13
to Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
I meant on the Blink side:

    DOMWindow* activeDOMWindow();
    DOMWindow* firstDOMWindow();

To match the spec's terminology, these should be incumbentDOMWindow and entryDOMWindow, respectively.

Adam

Sven Panne

unread,
Jul 26, 2013, 8:52:15 AM7/26/13
to Adam Barth, Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Michael Starzinger, Adam Klein
It would be great if somebody could document this in the v8 cheat sheet (https://docs.google.com/a/google.com/document/d/1DeEaAQlN4ZCVkaUzhHIhHOQVvF2aOvl-7uEkvi3oq-c/). I had a look at all those API entries in the past, and I couldn't figure out what they were supposed to do and why they were there, and I bet most other people working on v8 made similar experiences. :-}

Adam Barth

unread,
Jul 26, 2013, 12:41:23 PM7/26/13
to Sven Panne, Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Michael Starzinger, Adam Klein
I'm happy to add the information if you're willing to give me write access to the doc.  :)

Adam

Sven Panne

unread,
Jul 29, 2013, 2:29:11 AM7/29/13
to Adam Barth, Wez, Marja Hölttä, Kentaro Hara, Mads Sig Ager, blink-dev, johnjbarton, Michael Starzinger, Adam Klein
On Fri, Jul 26, 2013 at 6:41 PM, Adam Barth <aba...@chromium.org> wrote:
I'm happy to add the information if you're willing to give me write access to the doc.  :)

Ooops, done: I've added Adam, Jochen and Marja. Anybody else I forgot? 

cleme...@uni-rostock.de

unread,
Aug 19, 2013, 10:35:08 AM8/19/13
to blin...@chromium.org, har...@chromium.org, johnj...@chromium.org, sven...@chromium.org, mstar...@chromium.org, ad...@chromium.org, aba...@chromium.org
I think I get that - and this thread is really helpful. But then...wait.

Why would I then get a "Cannot exit non-entered context" in the following code fragment?

  Context::GetEntered()->Exit();

I get the same error in

  Context::GetCurrent()->Exit();

What I am trying to achieve is the following: I want to execute a Javascript function in a V8 Container. Then, later, I want to execute another Javascript function in a "fresh" Container without having to repeat all the initialization. "Fresh" means that there should be no influence from the former execution on the latter. Currently I start an Isolate, generate a context using a persistent object template to add some C++ functions. Then I run some Javascript to make some additional functions known to the global object - and THEN I execute my Javascript function. What is now the fastest way to a "fresh" "situation" with the same initializations (C++ and Javascript)? 

I tried exiting the current content and generating a fresh one ... and that's where I ran into the above problem.




Adam Barth

unread,
Aug 19, 2013, 1:28:46 PM8/19/13
to cleme...@uni-rostock.de, blink-dev, Kentaro Hara, johnjbarton, Sven Panne, Michael Starzinger, Adam Klein
Your situation doesn't appear related to Blink, which means that it is off-topic for this mailing list.  Perhaps the v8-users mailing list would be more appropriate?


Adam

yangw...@bytedance.com

unread,
Nov 30, 2017, 3:09:51 AM11/30/17
to blink-dev, aba...@chromium.org, w...@chromium.org, ma...@chromium.org, har...@chromium.org, ag...@chromium.org, johnj...@chromium.org, mstar...@chromium.org, ad...@chromium.org, sven...@chromium.org
hello, I can't read the document. why?

在 2013年7月26日星期五 UTC+8下午8:52:15,Sven Panne写道:
Reply all
Reply to author
Forward
0 new messages