Any way to reset global object for context after context is created?

440 views
Skip to first unread message

Jane Chen

unread,
May 10, 2018, 4:24:56 PM5/10/18
to v8-users
Embedding v8 v5.3.

Is there any way to reset global object for a context so that the context can be re-used?

How is Context::DetachGlobal() is meant to be used?

Thanks,
Jane


Ben Noordhuis

unread,
May 11, 2018, 8:50:07 AM5/11/18
to v8-users
You can't reset a context but you can detach the global object and
create a new context with it. It will revert to its pristine state in
the new context. In a nutshell:

auto global = old_context->Global();
old_context->Exit(); // Need to exit the context before detaching.
old_context->DetachGlobal();
auto new_context = v8::Context::New(global->GetIsolate(),
v8::Local<v8::ObjectTemplate>(), global);

Jane Chen

unread,
May 12, 2018, 12:42:54 AM5/12/18
to v8-users
Thanks Ben.

I want to re-use my context for performance reasons, but some JavaScript programs have constant global variables that cannot be re-defined, such as those declared with let or const.  To work around this, I thought I could just evaluate each program in a closure by artificially enclosing the script with {}.  Do you see any issue with doing it?  Is there any better way to do so?

Ben Noordhuis

unread,
May 12, 2018, 7:38:15 AM5/12/18
to v8-users
On Sat, May 12, 2018 at 6:42 AM, Jane Chen <jxch...@gmail.com> wrote:
> Thanks Ben.
>
> I want to re-use my context for performance reasons, but some JavaScript
> programs have constant global variables that cannot be re-defined, such as
> those declared with let or const. To work around this, I thought I could
> just evaluate each program in a closure by artificially enclosing the script
> with {}. Do you see any issue with doing it?

I don't see anything wrong with that but if you reuse the context, you
have to scrub globals introduced with `var`, undo any monkey-patching
of builtins, figure out how to cancel pending promises, etc. Using a
new context is probably a lot simpler and robuster.

> Is there any better way to do so?

You could compile your code as an es6 module or with
v8::ScriptCompiler::CompileFunctionInContext() but you'd probably have
to upgrade first. Modules don't exist in V8 5.3 and
CompileFunctionInContext() has a bug where the line and column in
stack traces are wrong.

Modules and functions have different run-time semantics than a
top-level script, of course, so they might not be a good fit if
backwards compatibility is a concern.

Jane Chen

unread,
Jan 3, 2019, 12:55:26 AM1/3/19
to v8-users
Hi Ben,

I checked out Module API on v8 6.7 and it was working great, except one problem:  I lost a way to bind external variables to the global object used for module evaluation.  I have tried setting them on the global object of the context, the module namespace object (return value of Module::GetModuleNamespace()), and the global object template for context creation, but nothing worked.  I know that there's syntax for a module to import external variables.  But for backward compatibility, I'd like to be able to set some global variables for module evaluation.  Is there anyway to do that?

Thanks a lot!

Jane Chen

unread,
Jan 4, 2019, 12:55:55 AM1/4/19
to v8-users
Actually, setting properties on the context's global object still works.  I found the difference between a script and a module is in re-declaring the variables.  For example:

Assuming h and w are two properties defined to be "hello" and "world" on the global object, the following line:

var h;; var w; h + ' ' + w;
=> hello world (when evaluated as a script)
=> undefined undefined (when evaluated as a module)

while the following:

h + ' ' + w;
=> hello world (as a script)
=> hello world (as a module)

It would be nice to allow the embedder to set properties on the module namespace object, so that each module has its own isolated variable bindings.  Is that possible?
Reply all
Reply to author
Forward
0 new messages