2017-01-03 13:16:48 -08:00
|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
// following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2019-02-25 17:27:19 -05:00
|
|
|
#include "node_contextify.h"
|
|
|
|
|
2017-11-14 13:34:52 +01:00
|
|
|
#include "base_object-inl.h"
|
2024-03-31 22:27:33 +02:00
|
|
|
#include "cppgc/allocation.h"
|
2021-05-14 00:58:19 +08:00
|
|
|
#include "memory_tracker-inl.h"
|
|
|
|
#include "module_wrap.h"
|
2018-03-04 14:59:51 -06:00
|
|
|
#include "node_context_data.h"
|
2018-04-25 12:22:20 -05:00
|
|
|
#include "node_errors.h"
|
2021-05-14 00:58:19 +08:00
|
|
|
#include "node_external_reference.h"
|
|
|
|
#include "node_internals.h"
|
2024-04-29 22:21:53 +02:00
|
|
|
#include "node_process.h"
|
2024-03-12 03:18:53 +08:00
|
|
|
#include "node_sea.h"
|
2022-08-16 23:44:01 +08:00
|
|
|
#include "node_snapshot_builder.h"
|
2024-04-29 22:21:53 +02:00
|
|
|
#include "node_url.h"
|
2021-05-14 00:58:19 +08:00
|
|
|
#include "node_watchdog.h"
|
2019-05-09 12:52:38 -07:00
|
|
|
#include "util-inl.h"
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
|
|
|
namespace node {
|
2017-12-09 10:32:34 -06:00
|
|
|
namespace contextify {
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-11-30 08:13:45 -06:00
|
|
|
using errors::TryCatchScope;
|
|
|
|
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Array;
|
2018-09-18 01:28:41 -04:00
|
|
|
using v8::ArrayBufferView;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Boolean;
|
|
|
|
using v8::Context;
|
2014-03-13 20:38:14 +04:00
|
|
|
using v8::EscapableHandleScope;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Function;
|
|
|
|
using v8::FunctionCallbackInfo;
|
|
|
|
using v8::FunctionTemplate;
|
|
|
|
using v8::HandleScope;
|
2017-10-17 17:27:27 +02:00
|
|
|
using v8::IndexedPropertyHandlerConfiguration;
|
2024-06-20 10:14:57 +01:00
|
|
|
using v8::IndexFilter;
|
2020-02-08 01:49:43 +08:00
|
|
|
using v8::Int32;
|
2024-06-20 10:14:57 +01:00
|
|
|
using v8::Integer;
|
2024-05-01 18:50:02 +02:00
|
|
|
using v8::Intercepted;
|
2018-03-16 15:23:39 +01:00
|
|
|
using v8::Isolate;
|
2024-09-17 09:53:54 +02:00
|
|
|
using v8::JustVoid;
|
2024-06-20 10:14:57 +01:00
|
|
|
using v8::KeyCollectionMode;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Local;
|
2015-06-01 12:22:19 -04:00
|
|
|
using v8::Maybe;
|
|
|
|
using v8::MaybeLocal;
|
2020-04-22 10:28:20 +08:00
|
|
|
using v8::MeasureMemoryExecution;
|
2020-02-08 01:49:43 +08:00
|
|
|
using v8::MeasureMemoryMode;
|
2024-04-29 22:21:53 +02:00
|
|
|
using v8::Message;
|
2020-06-23 00:33:04 +02:00
|
|
|
using v8::MicrotaskQueue;
|
|
|
|
using v8::MicrotasksPolicy;
|
2015-06-01 12:22:19 -04:00
|
|
|
using v8::Name;
|
|
|
|
using v8::NamedPropertyHandlerConfiguration;
|
2023-01-25 21:06:55 +01:00
|
|
|
using v8::Nothing;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Object;
|
|
|
|
using v8::ObjectTemplate;
|
2018-08-17 17:26:34 -05:00
|
|
|
using v8::PrimitiveArray;
|
2020-02-08 01:49:43 +08:00
|
|
|
using v8::Promise;
|
2015-05-22 19:41:28 -04:00
|
|
|
using v8::PropertyAttribute;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::PropertyCallbackInfo;
|
2017-02-01 13:00:40 +00:00
|
|
|
using v8::PropertyDescriptor;
|
2024-06-20 10:14:57 +01:00
|
|
|
using v8::PropertyFilter;
|
2019-05-01 23:22:47 +02:00
|
|
|
using v8::PropertyHandlerFlags;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::Script;
|
2014-03-31 15:13:37 +02:00
|
|
|
using v8::ScriptCompiler;
|
|
|
|
using v8::ScriptOrigin;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
using v8::String;
|
2023-06-21 16:01:50 +02:00
|
|
|
using v8::Symbol;
|
2017-10-17 17:27:27 +02:00
|
|
|
using v8::Uint32;
|
2014-03-31 15:13:37 +02:00
|
|
|
using v8::UnboundScript;
|
2013-08-27 00:13:50 +02:00
|
|
|
using v8::Value;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-11-09 06:35:04 +01:00
|
|
|
// The vm module executes code in a sandboxed environment with a different
|
|
|
|
// global object than the rest of the code. This is achieved by applying
|
|
|
|
// every call that changes or queries a property on the global `this` in the
|
|
|
|
// sandboxed code, to the sandbox object.
|
|
|
|
//
|
|
|
|
// The implementation uses V8's interceptors for methods like `set`, `get`,
|
|
|
|
// `delete`, `defineProperty`, and for any query of the property attributes.
|
|
|
|
// Property handlers with interceptors are set on the object template for
|
|
|
|
// the sandboxed code. Handlers for both named properties and for indexed
|
|
|
|
// properties are used. Their functionality is almost identical, the indexed
|
|
|
|
// interceptors mostly just call the named interceptors.
|
|
|
|
//
|
|
|
|
// For every `get` of a global property in the sandboxed context, the
|
|
|
|
// interceptor callback checks the sandbox object for the property.
|
|
|
|
// If the property is defined on the sandbox, that result is returned to
|
|
|
|
// the original call instead of finishing the query on the global object.
|
|
|
|
//
|
|
|
|
// For every `set` of a global property, the interceptor callback defines or
|
|
|
|
// changes the property both on the sandbox and the global proxy.
|
|
|
|
|
2017-04-12 19:17:24 +02:00
|
|
|
namespace {
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-11-09 06:35:04 +01:00
|
|
|
// Convert an int to a V8 Name (String or Symbol).
|
2017-10-17 17:27:27 +02:00
|
|
|
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
|
|
|
|
return Uint32::New(context->GetIsolate(), index)->ToString(context)
|
|
|
|
.ToLocalChecked();
|
|
|
|
}
|
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
} // anonymous namespace
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
BaseObjectPtr<ContextifyContext> ContextifyContext::New(
|
2023-08-16 22:18:46 +02:00
|
|
|
Environment* env, Local<Object> sandbox_obj, ContextOptions* options) {
|
2024-08-29 11:05:03 +02:00
|
|
|
Local<ObjectTemplate> object_template;
|
2022-09-26 21:40:45 +08:00
|
|
|
HandleScope scope(env->isolate());
|
2024-08-29 11:05:03 +02:00
|
|
|
CHECK_IMPLIES(sandbox_obj.IsEmpty(), options->vanilla);
|
|
|
|
if (!sandbox_obj.IsEmpty()) {
|
|
|
|
// Do not use the template with interceptors for vanilla contexts.
|
|
|
|
object_template = env->contextify_global_template();
|
|
|
|
DCHECK(!object_template.IsEmpty());
|
|
|
|
}
|
|
|
|
|
2022-12-12 18:18:37 +01:00
|
|
|
const SnapshotData* snapshot_data = env->isolate_data()->snapshot_data();
|
2022-08-16 23:22:32 +08:00
|
|
|
|
|
|
|
MicrotaskQueue* queue =
|
2023-08-16 22:18:46 +02:00
|
|
|
options->own_microtask_queue
|
|
|
|
? options->own_microtask_queue.get()
|
2022-08-16 23:22:32 +08:00
|
|
|
: env->isolate()->GetCurrentContext()->GetMicrotaskQueue();
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2022-08-16 23:22:32 +08:00
|
|
|
Local<Context> v8_context;
|
2022-08-16 23:44:01 +08:00
|
|
|
if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue)
|
2022-09-26 21:40:45 +08:00
|
|
|
.ToLocal(&v8_context))) {
|
2022-08-16 23:22:32 +08:00
|
|
|
// Allocation failure, maximum call stack size reached, termination, etc.
|
2022-09-26 21:40:45 +08:00
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
2022-08-16 23:22:32 +08:00
|
|
|
}
|
2022-09-26 21:40:45 +08:00
|
|
|
return New(v8_context, env, sandbox_obj, options);
|
|
|
|
}
|
2019-01-27 14:22:51 +01:00
|
|
|
|
2023-08-16 22:18:46 +02:00
|
|
|
void ContextifyContext::MemoryInfo(MemoryTracker* tracker) const {}
|
2019-07-11 00:12:02 +02:00
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
ContextifyContext::ContextifyContext(Environment* env,
|
|
|
|
Local<Object> wrapper,
|
|
|
|
Local<Context> v8_context,
|
2023-08-16 22:18:46 +02:00
|
|
|
ContextOptions* options)
|
2022-09-26 21:40:45 +08:00
|
|
|
: BaseObject(env, wrapper),
|
2023-08-16 22:18:46 +02:00
|
|
|
microtask_queue_(options->own_microtask_queue
|
|
|
|
? options->own_microtask_queue.release()
|
|
|
|
: nullptr) {
|
2022-09-26 21:40:45 +08:00
|
|
|
context_.Reset(env->isolate(), v8_context);
|
|
|
|
// This should only be done after the initial initializations of the context
|
|
|
|
// global object is finished.
|
|
|
|
DCHECK_NULL(v8_context->GetAlignedPointerFromEmbedderData(
|
|
|
|
ContextEmbedderIndex::kContextifyContext));
|
|
|
|
v8_context->SetAlignedPointerInEmbedderData(
|
|
|
|
ContextEmbedderIndex::kContextifyContext, this);
|
|
|
|
// It's okay to make this reference weak - V8 would create an internal
|
|
|
|
// reference to this context via the constructor of the wrapper.
|
|
|
|
// As long as the wrapper is alive, it's constructor is alive, and so
|
|
|
|
// is the context.
|
|
|
|
context_.SetWeak();
|
|
|
|
}
|
2019-07-11 00:12:02 +02:00
|
|
|
|
|
|
|
ContextifyContext::~ContextifyContext() {
|
2021-05-25 23:52:45 -04:00
|
|
|
Isolate* isolate = env()->isolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
|
2023-04-03 00:04:57 +08:00
|
|
|
env()->UnassignFromContext(PersistentToLocal::Weak(isolate, context_));
|
2022-09-26 21:40:45 +08:00
|
|
|
context_.Reset();
|
2019-07-11 00:12:02 +02:00
|
|
|
}
|
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
void ContextifyContext::InitializeGlobalTemplates(IsolateData* isolate_data) {
|
|
|
|
DCHECK(isolate_data->contextify_wrapper_template().IsEmpty());
|
|
|
|
Local<FunctionTemplate> global_func_template =
|
|
|
|
FunctionTemplate::New(isolate_data->isolate());
|
|
|
|
Local<ObjectTemplate> global_object_template =
|
|
|
|
global_func_template->InstanceTemplate();
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2019-05-01 23:22:47 +02:00
|
|
|
NamedPropertyHandlerConfiguration config(
|
|
|
|
PropertyGetterCallback,
|
|
|
|
PropertySetterCallback,
|
2024-06-20 10:14:57 +01:00
|
|
|
PropertyQueryCallback,
|
2019-05-01 23:22:47 +02:00
|
|
|
PropertyDeleterCallback,
|
|
|
|
PropertyEnumeratorCallback,
|
|
|
|
PropertyDefinerCallback,
|
2024-06-20 10:14:57 +01:00
|
|
|
PropertyDescriptorCallback,
|
2022-08-16 23:22:32 +08:00
|
|
|
{},
|
2019-05-01 23:22:47 +02:00
|
|
|
PropertyHandlerFlags::kHasNoSideEffect);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
IndexedPropertyHandlerConfiguration indexed_config(
|
|
|
|
IndexedPropertyGetterCallback,
|
|
|
|
IndexedPropertySetterCallback,
|
2024-06-20 10:14:57 +01:00
|
|
|
IndexedPropertyQueryCallback,
|
2017-12-09 10:32:34 -06:00
|
|
|
IndexedPropertyDeleterCallback,
|
2024-06-20 10:14:57 +01:00
|
|
|
IndexedPropertyEnumeratorCallback,
|
2017-12-09 10:32:34 -06:00
|
|
|
IndexedPropertyDefinerCallback,
|
2024-06-20 10:14:57 +01:00
|
|
|
IndexedPropertyDescriptorCallback,
|
2022-08-16 23:22:32 +08:00
|
|
|
{},
|
2019-05-01 23:22:47 +02:00
|
|
|
PropertyHandlerFlags::kHasNoSideEffect);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
global_object_template->SetHandler(config);
|
|
|
|
global_object_template->SetHandler(indexed_config);
|
|
|
|
isolate_data->set_contextify_global_template(global_object_template);
|
2022-08-16 23:22:32 +08:00
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
Local<FunctionTemplate> wrapper_func_template =
|
|
|
|
BaseObject::MakeLazilyInitializedJSTemplate(isolate_data);
|
|
|
|
Local<ObjectTemplate> wrapper_object_template =
|
|
|
|
wrapper_func_template->InstanceTemplate();
|
|
|
|
isolate_data->set_contextify_wrapper_template(wrapper_object_template);
|
2022-08-16 23:22:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MaybeLocal<Context> ContextifyContext::CreateV8Context(
|
|
|
|
Isolate* isolate,
|
|
|
|
Local<ObjectTemplate> object_template,
|
2022-08-16 23:44:01 +08:00
|
|
|
const SnapshotData* snapshot_data,
|
2022-08-16 23:22:32 +08:00
|
|
|
MicrotaskQueue* queue) {
|
|
|
|
EscapableHandleScope scope(isolate);
|
|
|
|
|
2022-08-16 23:44:01 +08:00
|
|
|
Local<Context> ctx;
|
2024-08-29 11:05:03 +02:00
|
|
|
if (object_template.IsEmpty() || snapshot_data == nullptr) {
|
2023-09-06 15:03:35 +02:00
|
|
|
ctx = Context::New(
|
|
|
|
isolate,
|
|
|
|
nullptr, // extensions
|
|
|
|
object_template,
|
|
|
|
{}, // global object
|
|
|
|
v8::DeserializeInternalFieldsCallback(), // deserialization callback
|
|
|
|
queue);
|
2022-08-17 15:48:46 +08:00
|
|
|
if (ctx.IsEmpty() || InitializeBaseContextForSnapshot(ctx).IsNothing()) {
|
|
|
|
return MaybeLocal<Context>();
|
|
|
|
}
|
2023-09-06 15:03:35 +02:00
|
|
|
} else if (!Context::FromSnapshot(
|
|
|
|
isolate,
|
|
|
|
SnapshotData::kNodeVMContextIndex,
|
|
|
|
v8::DeserializeInternalFieldsCallback(), // deserialization
|
|
|
|
// callback
|
|
|
|
nullptr, // extensions
|
|
|
|
{}, // global object
|
|
|
|
queue)
|
2022-08-17 15:48:46 +08:00
|
|
|
.ToLocal(&ctx)) {
|
2022-08-16 23:44:01 +08:00
|
|
|
return MaybeLocal<Context>();
|
|
|
|
}
|
2022-09-26 21:40:45 +08:00
|
|
|
|
2022-08-16 23:22:32 +08:00
|
|
|
return scope.Escape(ctx);
|
|
|
|
}
|
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
BaseObjectPtr<ContextifyContext> ContextifyContext::New(
|
|
|
|
Local<Context> v8_context,
|
|
|
|
Environment* env,
|
|
|
|
Local<Object> sandbox_obj,
|
2023-08-16 22:18:46 +02:00
|
|
|
ContextOptions* options) {
|
2022-08-16 23:22:32 +08:00
|
|
|
HandleScope scope(env->isolate());
|
2024-08-29 11:05:03 +02:00
|
|
|
CHECK_IMPLIES(sandbox_obj.IsEmpty(), options->vanilla);
|
2022-08-16 23:22:32 +08:00
|
|
|
// This only initializes part of the context. The primordials are
|
2023-02-25 21:29:59 +01:00
|
|
|
// only initialized when needed because even deserializing them slows
|
2022-08-16 23:22:32 +08:00
|
|
|
// things down significantly and they are only needed in rare occasions
|
|
|
|
// in the vm contexts.
|
2022-09-26 21:40:45 +08:00
|
|
|
if (InitializeContextRuntime(v8_context).IsNothing()) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
2016-02-22 20:38:56 -08:00
|
|
|
}
|
|
|
|
|
2022-08-16 23:22:32 +08:00
|
|
|
Local<Context> main_context = env->context();
|
2022-09-26 21:40:45 +08:00
|
|
|
Local<Object> new_context_global = v8_context->Global();
|
|
|
|
v8_context->SetSecurityToken(main_context->GetSecurityToken());
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
// We need to tie the lifetime of the sandbox object with the lifetime of
|
|
|
|
// newly created context. We do this by making them hold references to each
|
|
|
|
// other. The context can directly hold a reference to the sandbox as an
|
2022-09-26 21:40:45 +08:00
|
|
|
// embedder data field. The sandbox uses a private symbol to hold a reference
|
|
|
|
// to the ContextifyContext wrapper which in turn internally references
|
|
|
|
// the context from its constructor.
|
2024-08-29 11:05:03 +02:00
|
|
|
if (sandbox_obj.IsEmpty()) {
|
|
|
|
v8_context->SetEmbedderData(ContextEmbedderIndex::kSandboxObject,
|
|
|
|
v8::Undefined(env->isolate()));
|
|
|
|
} else {
|
|
|
|
v8_context->SetEmbedderData(ContextEmbedderIndex::kSandboxObject,
|
|
|
|
sandbox_obj);
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2022-06-14 01:34:31 +08:00
|
|
|
// Delegate the code generation validation to
|
|
|
|
// node::ModifyCodeGenerationFromStrings.
|
2022-09-26 21:40:45 +08:00
|
|
|
v8_context->AllowCodeGenerationFromStrings(false);
|
|
|
|
v8_context->SetEmbedderData(
|
|
|
|
ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
|
2023-08-16 22:18:46 +02:00
|
|
|
options->allow_code_gen_strings);
|
2022-09-26 21:40:45 +08:00
|
|
|
v8_context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
|
2023-08-16 22:18:46 +02:00
|
|
|
options->allow_code_gen_wasm);
|
2018-02-26 14:29:41 -06:00
|
|
|
|
2023-08-16 22:18:46 +02:00
|
|
|
Utf8Value name_val(env->isolate(), options->name);
|
2017-12-09 10:32:34 -06:00
|
|
|
ContextInfo info(*name_val);
|
2023-08-16 22:18:46 +02:00
|
|
|
if (!options->origin.IsEmpty()) {
|
|
|
|
Utf8Value origin_val(env->isolate(), options->origin);
|
2017-12-09 10:32:34 -06:00
|
|
|
info.origin = *origin_val;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
BaseObjectPtr<ContextifyContext> result;
|
|
|
|
Local<Object> wrapper;
|
2022-08-16 23:22:32 +08:00
|
|
|
{
|
2022-09-26 21:40:45 +08:00
|
|
|
Context::Scope context_scope(v8_context);
|
2024-08-29 11:05:03 +02:00
|
|
|
if (!sandbox_obj.IsEmpty()) {
|
|
|
|
Local<String> ctor_name = sandbox_obj->GetConstructorName();
|
|
|
|
if (!ctor_name->Equals(v8_context, env->object_string())
|
|
|
|
.FromMaybe(false) &&
|
|
|
|
new_context_global
|
|
|
|
->DefineOwnProperty(
|
|
|
|
v8_context,
|
|
|
|
v8::Symbol::GetToStringTag(env->isolate()),
|
|
|
|
ctor_name,
|
|
|
|
static_cast<v8::PropertyAttribute>(v8::DontEnum))
|
|
|
|
.IsNothing()) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
|
|
|
}
|
2022-08-16 23:22:32 +08:00
|
|
|
}
|
2023-11-01 14:05:13 +08:00
|
|
|
|
|
|
|
// Assign host_defined_options_id to the global object so that in the
|
|
|
|
// callback of ImportModuleDynamically, we can get the
|
|
|
|
// host_defined_options_id from the v8::Context without accessing the
|
|
|
|
// wrapper object.
|
|
|
|
if (new_context_global
|
|
|
|
->SetPrivate(v8_context,
|
|
|
|
env->host_defined_option_symbol(),
|
|
|
|
options->host_defined_options_id)
|
|
|
|
.IsNothing()) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
|
|
|
}
|
|
|
|
|
2022-09-26 21:40:45 +08:00
|
|
|
env->AssignToContext(v8_context, nullptr, info);
|
|
|
|
|
|
|
|
if (!env->contextify_wrapper_template()
|
|
|
|
->NewInstance(v8_context)
|
|
|
|
.ToLocal(&wrapper)) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
|
|
|
}
|
|
|
|
|
|
|
|
result =
|
|
|
|
MakeBaseObject<ContextifyContext>(env, wrapper, v8_context, options);
|
|
|
|
// The only strong reference to the wrapper will come from the sandbox.
|
|
|
|
result->MakeWeak();
|
2022-08-16 23:22:32 +08:00
|
|
|
}
|
|
|
|
|
2024-08-29 11:05:03 +02:00
|
|
|
Local<Object> wrapper_holder =
|
|
|
|
sandbox_obj.IsEmpty() ? new_context_global : sandbox_obj;
|
|
|
|
if (!wrapper_holder.IsEmpty() &&
|
|
|
|
wrapper_holder
|
2022-09-26 21:40:45 +08:00
|
|
|
->SetPrivate(
|
|
|
|
v8_context, env->contextify_context_private_symbol(), wrapper)
|
|
|
|
.IsNothing()) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
|
|
|
}
|
2024-08-29 11:05:03 +02:00
|
|
|
|
|
|
|
// Assign host_defined_options_id to the sandbox object or the global object
|
|
|
|
// (for vanilla contexts) so that module callbacks like
|
|
|
|
// importModuleDynamically can be registered once back to the JS land.
|
|
|
|
if (!sandbox_obj.IsEmpty() &&
|
|
|
|
sandbox_obj
|
2023-11-01 14:05:13 +08:00
|
|
|
->SetPrivate(v8_context,
|
|
|
|
env->host_defined_option_symbol(),
|
|
|
|
options->host_defined_options_id)
|
|
|
|
.IsNothing()) {
|
|
|
|
return BaseObjectPtr<ContextifyContext>();
|
|
|
|
}
|
2022-09-26 21:40:45 +08:00
|
|
|
return result;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
2016-05-20 22:55:37 +02:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
void ContextifyContext::CreatePerIsolateProperties(
|
|
|
|
IsolateData* isolate_data, Local<ObjectTemplate> target) {
|
|
|
|
Isolate* isolate = isolate_data->isolate();
|
|
|
|
SetMethod(isolate, target, "makeContext", MakeContext);
|
|
|
|
SetMethod(isolate, target, "compileFunction", CompileFunction);
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2021-05-14 00:58:19 +08:00
|
|
|
void ContextifyContext::RegisterExternalReferences(
|
|
|
|
ExternalReferenceRegistry* registry) {
|
|
|
|
registry->Register(MakeContext);
|
|
|
|
registry->Register(CompileFunction);
|
2024-06-20 10:14:57 +01:00
|
|
|
registry->Register(PropertyQueryCallback);
|
2022-08-16 23:22:32 +08:00
|
|
|
registry->Register(PropertyGetterCallback);
|
|
|
|
registry->Register(PropertySetterCallback);
|
|
|
|
registry->Register(PropertyDescriptorCallback);
|
|
|
|
registry->Register(PropertyDeleterCallback);
|
|
|
|
registry->Register(PropertyEnumeratorCallback);
|
|
|
|
registry->Register(PropertyDefinerCallback);
|
2024-06-20 10:14:57 +01:00
|
|
|
registry->Register(IndexedPropertyQueryCallback);
|
2022-08-16 23:22:32 +08:00
|
|
|
registry->Register(IndexedPropertyGetterCallback);
|
|
|
|
registry->Register(IndexedPropertySetterCallback);
|
|
|
|
registry->Register(IndexedPropertyDescriptorCallback);
|
|
|
|
registry->Register(IndexedPropertyDeleterCallback);
|
|
|
|
registry->Register(IndexedPropertyDefinerCallback);
|
2024-06-20 10:14:57 +01:00
|
|
|
registry->Register(IndexedPropertyEnumeratorCallback);
|
2021-05-14 00:58:19 +08:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-03-16 15:23:39 +01:00
|
|
|
// makeContext(sandbox, name, origin, strings, wasm);
|
2017-12-09 10:32:34 -06:00
|
|
|
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
2024-08-29 11:05:03 +02:00
|
|
|
ContextOptions options;
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2023-11-01 14:05:13 +08:00
|
|
|
CHECK_EQ(args.Length(), 7);
|
2024-08-29 11:05:03 +02:00
|
|
|
Local<Object> sandbox;
|
|
|
|
if (args[0]->IsObject()) {
|
|
|
|
sandbox = args[0].As<Object>();
|
|
|
|
// Don't allow contextifying a sandbox multiple times.
|
|
|
|
CHECK(!sandbox
|
|
|
|
->HasPrivate(env->context(),
|
|
|
|
env->contextify_context_private_symbol())
|
|
|
|
.FromJust());
|
|
|
|
} else {
|
|
|
|
CHECK(args[0]->IsSymbol());
|
|
|
|
options.vanilla = true;
|
|
|
|
}
|
2018-03-16 15:23:39 +01:00
|
|
|
|
|
|
|
CHECK(args[1]->IsString());
|
|
|
|
options.name = args[1].As<String>();
|
|
|
|
|
|
|
|
CHECK(args[2]->IsString() || args[2]->IsUndefined());
|
|
|
|
if (args[2]->IsString()) {
|
|
|
|
options.origin = args[2].As<String>();
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK(args[3]->IsBoolean());
|
|
|
|
options.allow_code_gen_strings = args[3].As<Boolean>();
|
|
|
|
|
|
|
|
CHECK(args[4]->IsBoolean());
|
|
|
|
options.allow_code_gen_wasm = args[4].As<Boolean>();
|
2013-08-23 21:17:15 -04:00
|
|
|
|
2023-08-16 22:18:46 +02:00
|
|
|
if (args[5]->IsBoolean() && args[5]->BooleanValue(env->isolate())) {
|
|
|
|
options.own_microtask_queue =
|
|
|
|
MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit);
|
2020-06-23 00:33:04 +02:00
|
|
|
}
|
|
|
|
|
2023-11-01 14:05:13 +08:00
|
|
|
CHECK(args[6]->IsSymbol());
|
|
|
|
options.host_defined_options_id = args[6].As<Symbol>();
|
|
|
|
|
2018-11-30 08:13:45 -06:00
|
|
|
TryCatchScope try_catch(env);
|
2022-09-26 21:40:45 +08:00
|
|
|
BaseObjectPtr<ContextifyContext> context_ptr =
|
2023-08-16 22:18:46 +02:00
|
|
|
ContextifyContext::New(env, sandbox, &options);
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
if (try_catch.HasCaught()) {
|
2019-02-15 14:33:23 +01:00
|
|
|
if (!try_catch.HasTerminated())
|
|
|
|
try_catch.ReThrow();
|
2017-12-09 10:32:34 -06:00
|
|
|
return;
|
|
|
|
}
|
2024-08-29 11:05:03 +02:00
|
|
|
|
|
|
|
if (sandbox.IsEmpty()) {
|
|
|
|
args.GetReturnValue().Set(context_ptr->context()->Global());
|
|
|
|
} else {
|
|
|
|
args.GetReturnValue().Set(sandbox);
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
2014-02-05 13:46:00 +04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
|
|
|
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
|
2024-08-29 11:05:03 +02:00
|
|
|
Environment* env, const Local<Object>& wrapper_holder) {
|
|
|
|
Local<Value> contextify;
|
|
|
|
if (wrapper_holder
|
2022-09-26 21:40:45 +08:00
|
|
|
->GetPrivate(env->context(), env->contextify_context_private_symbol())
|
2024-08-29 11:05:03 +02:00
|
|
|
.ToLocal(&contextify) &&
|
|
|
|
contextify->IsObject()) {
|
|
|
|
return Unwrap<ContextifyContext>(contextify.As<Object>());
|
2013-08-23 21:33:16 -04:00
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
return nullptr;
|
|
|
|
}
|
2013-08-23 21:33:16 -04:00
|
|
|
|
2018-05-01 17:24:41 +02:00
|
|
|
template <typename T>
|
|
|
|
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
|
2022-09-26 21:40:45 +08:00
|
|
|
return Get(args.This());
|
|
|
|
}
|
|
|
|
|
|
|
|
ContextifyContext* ContextifyContext::Get(Local<Object> object) {
|
2022-08-16 23:22:32 +08:00
|
|
|
Local<Context> context;
|
2022-09-26 21:40:45 +08:00
|
|
|
if (!object->GetCreationContext().ToLocal(&context)) {
|
2022-08-16 23:22:32 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!ContextEmbedderTag::IsNodeContext(context)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-05-01 17:24:41 +02:00
|
|
|
return static_cast<ContextifyContext*>(
|
2022-08-16 23:22:32 +08:00
|
|
|
context->GetAlignedPointerFromEmbedderData(
|
|
|
|
ContextEmbedderIndex::kContextifyContext));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ContextifyContext::IsStillInitializing(const ContextifyContext* ctx) {
|
|
|
|
return ctx == nullptr || ctx->context_.IsEmpty();
|
2018-05-01 17:24:41 +02:00
|
|
|
}
|
|
|
|
|
2024-06-20 10:14:57 +01:00
|
|
|
// static
|
|
|
|
Intercepted ContextifyContext::PropertyQueryCallback(
|
|
|
|
Local<Name> property, const PropertyCallbackInfo<Integer>& args) {
|
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
|
|
|
|
|
|
|
// Still initializing
|
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
Local<Context> context = ctx->context();
|
|
|
|
Local<Object> sandbox = ctx->sandbox();
|
|
|
|
|
|
|
|
PropertyAttribute attr;
|
|
|
|
|
|
|
|
Maybe<bool> maybe_has = sandbox->HasRealNamedProperty(context, property);
|
|
|
|
if (maybe_has.IsNothing()) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
} else if (maybe_has.FromJust()) {
|
|
|
|
Maybe<PropertyAttribute> maybe_attr =
|
|
|
|
sandbox->GetRealNamedPropertyAttributes(context, property);
|
|
|
|
if (!maybe_attr.To(&attr)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
args.GetReturnValue().Set(attr);
|
|
|
|
return Intercepted::kYes;
|
|
|
|
} else {
|
|
|
|
maybe_has = ctx->global_proxy()->HasRealNamedProperty(context, property);
|
|
|
|
if (maybe_has.IsNothing()) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
} else if (maybe_has.FromJust()) {
|
|
|
|
Maybe<PropertyAttribute> maybe_attr =
|
|
|
|
ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
|
|
|
|
property);
|
|
|
|
if (!maybe_attr.To(&attr)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
args.GetReturnValue().Set(attr);
|
|
|
|
return Intercepted::kYes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::PropertyGetterCallback(
|
|
|
|
Local<Name> property, const PropertyCallbackInfo<Value>& args) {
|
2024-01-07 15:02:32 +01:00
|
|
|
Environment* env = Environment::GetCurrent(args);
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
Local<Context> context = ctx->context();
|
|
|
|
Local<Object> sandbox = ctx->sandbox();
|
2024-01-07 15:02:32 +01:00
|
|
|
|
|
|
|
TryCatchScope try_catch(env);
|
2017-12-09 10:32:34 -06:00
|
|
|
MaybeLocal<Value> maybe_rv =
|
|
|
|
sandbox->GetRealNamedProperty(context, property);
|
|
|
|
if (maybe_rv.IsEmpty()) {
|
|
|
|
maybe_rv =
|
|
|
|
ctx->global_proxy()->GetRealNamedProperty(context, property);
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
Local<Value> rv;
|
|
|
|
if (maybe_rv.ToLocal(&rv)) {
|
2024-01-07 15:02:32 +01:00
|
|
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
|
|
|
try_catch.ReThrow();
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
if (rv == sandbox)
|
|
|
|
rv = ctx->global_proxy();
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
args.GetReturnValue().Set(rv);
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kYes;
|
2013-08-23 21:17:15 -04:00
|
|
|
}
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kNo;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
2013-08-23 21:17:15 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::PropertySetterCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Local<Name> property,
|
|
|
|
Local<Value> value,
|
2024-05-01 18:50:02 +02:00
|
|
|
const PropertyCallbackInfo<void>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2021-02-22 18:29:48 +08:00
|
|
|
Local<Context> context = ctx->context();
|
2021-05-12 15:42:25 +08:00
|
|
|
PropertyAttribute attributes = PropertyAttribute::None;
|
2017-12-09 10:32:34 -06:00
|
|
|
bool is_declared_on_global_proxy = ctx->global_proxy()
|
2021-02-22 18:29:48 +08:00
|
|
|
->GetRealNamedPropertyAttributes(context, property)
|
2017-12-09 10:32:34 -06:00
|
|
|
.To(&attributes);
|
|
|
|
bool read_only =
|
|
|
|
static_cast<int>(attributes) &
|
|
|
|
static_cast<int>(PropertyAttribute::ReadOnly);
|
|
|
|
|
|
|
|
bool is_declared_on_sandbox = ctx->sandbox()
|
2021-02-22 18:29:48 +08:00
|
|
|
->GetRealNamedPropertyAttributes(context, property)
|
2017-12-09 10:32:34 -06:00
|
|
|
.To(&attributes);
|
|
|
|
read_only = read_only ||
|
|
|
|
(static_cast<int>(attributes) &
|
|
|
|
static_cast<int>(PropertyAttribute::ReadOnly));
|
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
if (read_only) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
// true for x = 5
|
|
|
|
// false for this.x = 5
|
|
|
|
// false for Object.defineProperty(this, 'foo', ...)
|
|
|
|
// false for vmResult.x = 5 where vmResult = vm.runInContext();
|
|
|
|
bool is_contextual_store = ctx->global_proxy() != args.This();
|
|
|
|
|
|
|
|
// Indicator to not return before setting (undeclared) function declarations
|
|
|
|
// on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
|
|
|
|
// True for 'function f() {}', 'this.f = function() {}',
|
|
|
|
// 'var f = function()'.
|
|
|
|
// In effect only for 'function f() {}' because
|
|
|
|
// var f = function(), is_declared = true
|
|
|
|
// this.f = function() {}, is_contextual_store = false.
|
|
|
|
bool is_function = value->IsFunction();
|
|
|
|
|
|
|
|
bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
|
|
|
|
if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
|
2024-05-01 18:50:02 +02:00
|
|
|
!is_function) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
if (!is_declared && property->IsSymbol()) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
if (ctx->sandbox()->Set(context, property, value).IsNothing()) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2023-03-18 10:19:19 +01:00
|
|
|
|
|
|
|
Local<Value> desc;
|
|
|
|
if (is_declared_on_sandbox &&
|
|
|
|
ctx->sandbox()
|
|
|
|
->GetOwnPropertyDescriptor(context, property)
|
2023-05-15 02:24:15 -07:00
|
|
|
.ToLocal(&desc) &&
|
|
|
|
!desc->IsUndefined()) {
|
2023-03-18 10:19:19 +01:00
|
|
|
Environment* env = Environment::GetCurrent(context);
|
|
|
|
Local<Object> desc_obj = desc.As<Object>();
|
|
|
|
|
|
|
|
// We have to specify the return value for any contextual or get/set
|
|
|
|
// property
|
|
|
|
if (desc_obj->HasOwnProperty(context, env->get_string()).FromMaybe(false) ||
|
2024-05-01 18:50:02 +02:00
|
|
|
desc_obj->HasOwnProperty(context, env->set_string()).FromMaybe(false)) {
|
|
|
|
return Intercepted::kYes;
|
|
|
|
}
|
2023-02-04 11:32:31 +01:00
|
|
|
}
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kNo;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::PropertyDescriptorCallback(
|
|
|
|
Local<Name> property, const PropertyCallbackInfo<Value>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2015-07-07 15:27:14 -07:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
Local<Context> context = ctx->context();
|
2015-06-01 12:22:19 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
Local<Object> sandbox = ctx->sandbox();
|
2015-06-01 12:22:19 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
|
2020-06-09 09:25:39 -05:00
|
|
|
Local<Value> desc;
|
|
|
|
if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
|
|
|
|
args.GetReturnValue().Set(desc);
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kYes;
|
2020-06-09 09:25:39 -05:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kNo;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::PropertyDefinerCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Local<Name> property,
|
|
|
|
const PropertyDescriptor& desc,
|
2024-05-01 18:50:02 +02:00
|
|
|
const PropertyCallbackInfo<void>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
Local<Context> context = ctx->context();
|
2018-05-11 08:27:20 +02:00
|
|
|
Isolate* isolate = context->GetIsolate();
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2021-05-12 15:42:25 +08:00
|
|
|
PropertyAttribute attributes = PropertyAttribute::None;
|
2017-12-09 10:32:34 -06:00
|
|
|
bool is_declared =
|
2021-02-22 18:29:48 +08:00
|
|
|
ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
|
2017-12-09 10:32:34 -06:00
|
|
|
property)
|
|
|
|
.To(&attributes);
|
|
|
|
bool read_only =
|
|
|
|
static_cast<int>(attributes) &
|
|
|
|
static_cast<int>(PropertyAttribute::ReadOnly);
|
2024-02-01 04:12:15 -05:00
|
|
|
bool dont_delete = static_cast<int>(attributes) &
|
|
|
|
static_cast<int>(PropertyAttribute::DontDelete);
|
2017-12-09 10:32:34 -06:00
|
|
|
|
2024-02-01 04:12:15 -05:00
|
|
|
// If the property is set on the global as neither writable nor
|
|
|
|
// configurable, don't change it on the global or sandbox.
|
|
|
|
if (is_declared && read_only && dont_delete) {
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kNo;
|
2024-02-01 04:12:15 -05:00
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
Local<Object> sandbox = ctx->sandbox();
|
|
|
|
|
|
|
|
auto define_prop_on_sandbox =
|
|
|
|
[&] (PropertyDescriptor* desc_for_sandbox) {
|
|
|
|
if (desc.has_enumerable()) {
|
|
|
|
desc_for_sandbox->set_enumerable(desc.enumerable());
|
|
|
|
}
|
|
|
|
if (desc.has_configurable()) {
|
|
|
|
desc_for_sandbox->set_configurable(desc.configurable());
|
|
|
|
}
|
|
|
|
// Set the property on the sandbox.
|
2020-06-09 09:25:39 -05:00
|
|
|
USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
|
2017-12-09 10:32:34 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
if (desc.has_get() || desc.has_set()) {
|
|
|
|
PropertyDescriptor desc_for_sandbox(
|
2018-05-11 08:27:20 +02:00
|
|
|
desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
|
|
|
|
desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
define_prop_on_sandbox(&desc_for_sandbox);
|
2024-05-01 18:50:02 +02:00
|
|
|
// TODO(https://github.com/nodejs/node/issues/52634): this should return
|
|
|
|
// kYes to behave according to the expected semantics.
|
|
|
|
return Intercepted::kNo;
|
2017-12-09 10:32:34 -06:00
|
|
|
} else {
|
|
|
|
Local<Value> value =
|
2018-05-11 08:27:20 +02:00
|
|
|
desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
|
2017-12-09 10:32:34 -06:00
|
|
|
|
|
|
|
if (desc.has_writable()) {
|
|
|
|
PropertyDescriptor desc_for_sandbox(value, desc.writable());
|
2017-10-17 17:27:27 +02:00
|
|
|
define_prop_on_sandbox(&desc_for_sandbox);
|
|
|
|
} else {
|
2017-12-09 10:32:34 -06:00
|
|
|
PropertyDescriptor desc_for_sandbox(value);
|
|
|
|
define_prop_on_sandbox(&desc_for_sandbox);
|
2017-10-17 17:27:27 +02:00
|
|
|
}
|
2024-05-01 18:50:02 +02:00
|
|
|
// TODO(https://github.com/nodejs/node/issues/52634): this should return
|
|
|
|
// kYes to behave according to the expected semantics.
|
|
|
|
return Intercepted::kNo;
|
2017-10-17 17:27:27 +02:00
|
|
|
}
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kNo;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::PropertyDeleterCallback(
|
|
|
|
Local<Name> property, const PropertyCallbackInfo<Boolean>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2015-07-07 15:27:14 -07:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
|
2017-02-09 17:46:13 +01:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
if (success.FromMaybe(false)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Delete failed on the sandbox, intercept and do not delete on
|
|
|
|
// the global object.
|
|
|
|
args.GetReturnValue().Set(false);
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kYes;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
|
|
|
void ContextifyContext::PropertyEnumeratorCallback(
|
|
|
|
const PropertyCallbackInfo<Array>& args) {
|
2024-08-30 12:22:58 +01:00
|
|
|
// Named enumerator will be invoked on Object.keys,
|
|
|
|
// Object.getOwnPropertyNames, Object.getOwnPropertySymbols,
|
|
|
|
// Object.getOwnPropertyDescriptors, for...in, etc. operations.
|
|
|
|
// Named enumerator should return all own non-indices property names,
|
|
|
|
// including string properties and symbol properties. V8 will filter the
|
|
|
|
// result array to match the expected symbol-only, enumerable-only with
|
|
|
|
// NamedPropertyQueryCallback.
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2022-08-16 23:22:32 +08:00
|
|
|
if (IsStillInitializing(ctx)) return;
|
2015-07-07 15:27:14 -07:00
|
|
|
|
2018-10-14 18:20:40 -04:00
|
|
|
Local<Array> properties;
|
2024-08-30 12:22:58 +01:00
|
|
|
// Only get own named properties, exclude indices.
|
2024-06-20 10:14:57 +01:00
|
|
|
if (!ctx->sandbox()
|
|
|
|
->GetPropertyNames(
|
|
|
|
ctx->context(),
|
2024-08-30 12:22:58 +01:00
|
|
|
KeyCollectionMode::kOwnOnly,
|
|
|
|
static_cast<PropertyFilter>(PropertyFilter::ALL_PROPERTIES),
|
2024-06-20 10:14:57 +01:00
|
|
|
IndexFilter::kSkipIndices)
|
|
|
|
.ToLocal(&properties))
|
2018-10-14 18:20:40 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(properties);
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-06-20 10:14:57 +01:00
|
|
|
// static
|
|
|
|
void ContextifyContext::IndexedPropertyEnumeratorCallback(
|
|
|
|
const PropertyCallbackInfo<Array>& args) {
|
2024-08-30 12:22:58 +01:00
|
|
|
// Indexed enumerator will be invoked on Object.keys,
|
|
|
|
// Object.getOwnPropertyNames, Object.getOwnPropertyDescriptors, for...in,
|
|
|
|
// etc. operations. Indexed enumerator should return all own non-indices index
|
|
|
|
// properties. V8 will filter the result array to match the expected
|
|
|
|
// enumerable-only with IndexedPropertyQueryCallback.
|
|
|
|
|
2024-06-20 10:14:57 +01:00
|
|
|
Isolate* isolate = args.GetIsolate();
|
|
|
|
HandleScope scope(isolate);
|
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
|
|
|
Local<Context> context = ctx->context();
|
|
|
|
|
|
|
|
// Still initializing
|
|
|
|
if (IsStillInitializing(ctx)) return;
|
|
|
|
|
|
|
|
Local<Array> properties;
|
|
|
|
|
2024-08-30 12:22:58 +01:00
|
|
|
// Only get own index properties.
|
|
|
|
if (!ctx->sandbox()
|
|
|
|
->GetPropertyNames(
|
|
|
|
context,
|
|
|
|
KeyCollectionMode::kOwnOnly,
|
|
|
|
static_cast<PropertyFilter>(PropertyFilter::SKIP_SYMBOLS),
|
|
|
|
IndexFilter::kIncludeIndices)
|
|
|
|
.ToLocal(&properties))
|
|
|
|
return;
|
2024-06-20 10:14:57 +01:00
|
|
|
|
|
|
|
std::vector<v8::Global<Value>> properties_vec;
|
|
|
|
if (FromV8Array(context, properties, &properties_vec).IsNothing()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Filter out non-number property names.
|
|
|
|
std::vector<Local<Value>> indices;
|
|
|
|
for (uint32_t i = 0; i < properties->Length(); i++) {
|
|
|
|
Local<Value> prop = properties_vec[i].Get(isolate);
|
|
|
|
if (!prop->IsNumber()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
indices.push_back(prop);
|
|
|
|
}
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(
|
|
|
|
Array::New(args.GetIsolate(), indices.data(), indices.size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
Intercepted ContextifyContext::IndexedPropertyQueryCallback(
|
|
|
|
uint32_t index, const PropertyCallbackInfo<Integer>& args) {
|
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
|
|
|
|
|
|
|
// Still initializing
|
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ContextifyContext::PropertyQueryCallback(
|
|
|
|
Uint32ToName(ctx->context(), index), args);
|
|
|
|
}
|
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::IndexedPropertyGetterCallback(
|
|
|
|
uint32_t index, const PropertyCallbackInfo<Value>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
return ContextifyContext::PropertyGetterCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Uint32ToName(ctx->context(), index), args);
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::IndexedPropertySetterCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
uint32_t index,
|
|
|
|
Local<Value> value,
|
2024-05-01 18:50:02 +02:00
|
|
|
const PropertyCallbackInfo<void>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
return ContextifyContext::PropertySetterCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Uint32ToName(ctx->context(), index), value, args);
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::IndexedPropertyDescriptorCallback(
|
|
|
|
uint32_t index, const PropertyCallbackInfo<Value>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
return ContextifyContext::PropertyDescriptorCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Uint32ToName(ctx->context(), index), args);
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::IndexedPropertyDefinerCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
uint32_t index,
|
|
|
|
const PropertyDescriptor& desc,
|
2024-05-01 18:50:02 +02:00
|
|
|
const PropertyCallbackInfo<void>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
return ContextifyContext::PropertyDefinerCallback(
|
2017-12-09 10:32:34 -06:00
|
|
|
Uint32ToName(ctx->context(), index), desc, args);
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// static
|
2024-05-01 18:50:02 +02:00
|
|
|
Intercepted ContextifyContext::IndexedPropertyDeleterCallback(
|
|
|
|
uint32_t index, const PropertyCallbackInfo<Boolean>& args) {
|
2018-05-01 17:24:41 +02:00
|
|
|
ContextifyContext* ctx = ContextifyContext::Get(args);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Still initializing
|
2024-05-01 18:50:02 +02:00
|
|
|
if (IsStillInitializing(ctx)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2024-05-01 18:50:02 +02:00
|
|
|
if (success.FromMaybe(false)) {
|
|
|
|
return Intercepted::kNo;
|
|
|
|
}
|
2017-10-17 17:27:27 +02:00
|
|
|
|
2017-12-09 10:32:34 -06:00
|
|
|
// Delete failed on the sandbox, intercept and do not delete on
|
|
|
|
// the global object.
|
|
|
|
args.GetReturnValue().Set(false);
|
2024-05-01 18:50:02 +02:00
|
|
|
return Intercepted::kYes;
|
2017-12-09 10:32:34 -06:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
void ContextifyScript::CreatePerIsolateProperties(
|
|
|
|
IsolateData* isolate_data, Local<ObjectTemplate> target) {
|
|
|
|
Isolate* isolate = isolate_data->isolate();
|
|
|
|
Local<String> class_name = FIXED_ONE_BYTE_STRING(isolate, "ContextifyScript");
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2022-08-02 00:01:02 +08:00
|
|
|
Local<FunctionTemplate> script_tmpl = NewFunctionTemplate(isolate, New);
|
2020-02-25 14:37:33 -08:00
|
|
|
script_tmpl->InstanceTemplate()->SetInternalFieldCount(
|
|
|
|
ContextifyScript::kInternalFieldCount);
|
2018-08-17 17:26:34 -05:00
|
|
|
script_tmpl->SetClassName(class_name);
|
2022-08-02 00:01:02 +08:00
|
|
|
SetProtoMethod(isolate, script_tmpl, "createCachedData", CreateCachedData);
|
|
|
|
SetProtoMethod(isolate, script_tmpl, "runInContext", RunInContext);
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
target->Set(isolate, "ContextifyScript", script_tmpl);
|
|
|
|
isolate_data->set_script_context_constructor_template(script_tmpl);
|
2018-08-17 17:26:34 -05:00
|
|
|
}
|
2018-05-14 14:24:58 -07:00
|
|
|
|
2021-05-14 00:58:19 +08:00
|
|
|
void ContextifyScript::RegisterExternalReferences(
|
|
|
|
ExternalReferenceRegistry* registry) {
|
|
|
|
registry->Register(New);
|
|
|
|
registry->Register(CreateCachedData);
|
|
|
|
registry->Register(RunInContext);
|
|
|
|
}
|
|
|
|
|
2024-03-31 22:27:33 +02:00
|
|
|
ContextifyScript* ContextifyScript::New(Environment* env,
|
|
|
|
Local<Object> object) {
|
|
|
|
return cppgc::MakeGarbageCollected<ContextifyScript>(
|
|
|
|
env->isolate()->GetCppHeap()->GetAllocationHandle(), env, object);
|
|
|
|
}
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
Isolate* isolate = env->isolate();
|
|
|
|
Local<Context> context = env->context();
|
2016-01-20 19:34:19 -05:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args.IsConstructCall());
|
2016-01-20 19:34:19 -05:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
const int argc = args.Length();
|
|
|
|
CHECK_GE(argc, 2);
|
2016-01-20 19:34:19 -05:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[0]->IsString());
|
|
|
|
Local<String> code = args[0].As<String>();
|
2017-07-17 13:06:23 +08:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[1]->IsString());
|
|
|
|
Local<String> filename = args[1].As<String>();
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2021-01-30 13:30:19 +01:00
|
|
|
int line_offset = 0;
|
|
|
|
int column_offset = 0;
|
2018-09-18 01:28:41 -04:00
|
|
|
Local<ArrayBufferView> cached_data_buf;
|
2018-08-17 17:26:34 -05:00
|
|
|
bool produce_cached_data = false;
|
|
|
|
Local<Context> parsing_context = context;
|
|
|
|
|
2023-10-05 03:27:11 +02:00
|
|
|
Local<Symbol> id_symbol;
|
2018-08-17 17:26:34 -05:00
|
|
|
if (argc > 2) {
|
|
|
|
// new ContextifyScript(code, filename, lineOffset, columnOffset,
|
2023-10-05 02:11:04 +02:00
|
|
|
// cachedData, produceCachedData, parsingContext,
|
2023-10-05 03:27:11 +02:00
|
|
|
// hostDefinedOptionId)
|
2023-10-05 02:11:04 +02:00
|
|
|
CHECK_EQ(argc, 8);
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[2]->IsNumber());
|
2021-01-30 13:30:19 +01:00
|
|
|
line_offset = args[2].As<Int32>()->Value();
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[3]->IsNumber());
|
2021-01-30 13:30:19 +01:00
|
|
|
column_offset = args[3].As<Int32>()->Value();
|
2018-08-17 17:26:34 -05:00
|
|
|
if (!args[4]->IsUndefined()) {
|
2018-09-18 01:28:41 -04:00
|
|
|
CHECK(args[4]->IsArrayBufferView());
|
|
|
|
cached_data_buf = args[4].As<ArrayBufferView>();
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[5]->IsBoolean());
|
|
|
|
produce_cached_data = args[5]->IsTrue();
|
|
|
|
if (!args[6]->IsUndefined()) {
|
|
|
|
CHECK(args[6]->IsObject());
|
|
|
|
ContextifyContext* sandbox =
|
|
|
|
ContextifyContext::ContextFromContextifiedSandbox(
|
|
|
|
env, args[6].As<Object>());
|
|
|
|
CHECK_NOT_NULL(sandbox);
|
|
|
|
parsing_context = sandbox->context();
|
2016-01-20 19:34:19 -05:00
|
|
|
}
|
2023-10-05 03:27:11 +02:00
|
|
|
CHECK(args[7]->IsSymbol());
|
|
|
|
id_symbol = args[7].As<Symbol>();
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
|
|
|
|
2024-03-31 22:27:33 +02:00
|
|
|
ContextifyScript* contextify_script = New(env, args.This());
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
|
|
|
|
TRACING_CATEGORY_NODE2(vm, script)) != 0) {
|
|
|
|
Utf8Value fn(isolate, filename);
|
2022-05-05 23:53:41 +08:00
|
|
|
TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script),
|
|
|
|
"ContextifyScript::New",
|
|
|
|
"filename",
|
|
|
|
TRACE_STR_COPY(*fn));
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
ScriptCompiler::CachedData* cached_data = nullptr;
|
|
|
|
if (!cached_data_buf.IsEmpty()) {
|
2022-08-02 21:04:53 -07:00
|
|
|
uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data());
|
2018-08-17 17:26:34 -05:00
|
|
|
cached_data = new ScriptCompiler::CachedData(
|
|
|
|
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
|
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
Local<PrimitiveArray> host_defined_options =
|
|
|
|
PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
|
2023-06-21 16:01:50 +02:00
|
|
|
host_defined_options->Set(
|
|
|
|
isolate, loader::HostDefinedOptions::kID, id_symbol);
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2024-05-15 09:16:00 +02:00
|
|
|
ScriptOrigin origin(filename,
|
|
|
|
line_offset, // line offset
|
|
|
|
column_offset, // column offset
|
|
|
|
true, // is cross origin
|
|
|
|
-1, // script id
|
|
|
|
Local<Value>(), // source map URL
|
|
|
|
false, // is opaque (?)
|
|
|
|
false, // is WASM
|
|
|
|
false, // is ES Module
|
2018-08-17 17:26:34 -05:00
|
|
|
host_defined_options);
|
|
|
|
ScriptCompiler::Source source(code, origin, cached_data);
|
|
|
|
ScriptCompiler::CompileOptions compile_options =
|
|
|
|
ScriptCompiler::kNoCompileOptions;
|
|
|
|
|
|
|
|
if (source.GetCachedData() != nullptr)
|
|
|
|
compile_options = ScriptCompiler::kConsumeCodeCache;
|
|
|
|
|
2018-11-30 08:13:45 -06:00
|
|
|
TryCatchScope try_catch(env);
|
2019-03-20 22:52:28 +08:00
|
|
|
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
|
2018-08-17 17:26:34 -05:00
|
|
|
Context::Scope scope(parsing_context);
|
|
|
|
|
2022-09-27 00:55:59 +08:00
|
|
|
MaybeLocal<UnboundScript> maybe_v8_script =
|
|
|
|
ScriptCompiler::CompileUnboundScript(isolate, &source, compile_options);
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2022-09-27 00:55:59 +08:00
|
|
|
Local<UnboundScript> v8_script;
|
|
|
|
if (!maybe_v8_script.ToLocal(&v8_script)) {
|
2019-06-15 08:07:15 +08:00
|
|
|
errors::DecorateErrorStack(env, try_catch);
|
2018-08-17 17:26:34 -05:00
|
|
|
no_abort_scope.Close();
|
2019-02-15 14:33:23 +01:00
|
|
|
if (!try_catch.HasTerminated())
|
|
|
|
try_catch.ReThrow();
|
2022-05-05 23:53:41 +08:00
|
|
|
TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script),
|
|
|
|
"ContextifyScript::New");
|
2018-08-17 17:26:34 -05:00
|
|
|
return;
|
|
|
|
}
|
2023-06-23 18:32:57 +02:00
|
|
|
|
2024-03-31 22:27:33 +02:00
|
|
|
contextify_script->set_unbound_script(v8_script);
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2023-01-25 21:06:55 +01:00
|
|
|
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data;
|
|
|
|
if (produce_cached_data) {
|
|
|
|
new_cached_data.reset(ScriptCompiler::CreateCodeCache(v8_script));
|
2018-04-25 12:22:20 -05:00
|
|
|
}
|
2022-09-27 00:55:59 +08:00
|
|
|
|
2023-06-21 16:01:50 +02:00
|
|
|
if (contextify_script->object()
|
|
|
|
->SetPrivate(context, env->host_defined_option_symbol(), id_symbol)
|
|
|
|
.IsNothing()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-25 21:06:55 +01:00
|
|
|
if (StoreCodeCacheResult(env,
|
|
|
|
args.This(),
|
|
|
|
compile_options,
|
|
|
|
source,
|
|
|
|
produce_cached_data,
|
|
|
|
std::move(new_cached_data))
|
|
|
|
.IsNothing()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (args.This()
|
|
|
|
->Set(env->context(),
|
|
|
|
env->source_map_url_string(),
|
|
|
|
v8_script->GetSourceMappingURL())
|
|
|
|
.IsNothing())
|
|
|
|
return;
|
2022-09-27 00:55:59 +08:00
|
|
|
|
2022-05-05 23:53:41 +08:00
|
|
|
TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
|
2018-08-17 17:26:34 -05:00
|
|
|
}
|
2018-04-25 12:22:20 -05:00
|
|
|
|
2024-09-17 09:53:54 +02:00
|
|
|
Maybe<void> StoreCodeCacheResult(
|
2023-01-25 21:06:55 +01:00
|
|
|
Environment* env,
|
|
|
|
Local<Object> target,
|
|
|
|
ScriptCompiler::CompileOptions compile_options,
|
|
|
|
const v8::ScriptCompiler::Source& source,
|
|
|
|
bool produce_cached_data,
|
|
|
|
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data) {
|
|
|
|
Local<Context> context;
|
|
|
|
if (!target->GetCreationContext().ToLocal(&context)) {
|
2024-09-17 09:53:54 +02:00
|
|
|
return Nothing<void>();
|
2023-01-25 21:06:55 +01:00
|
|
|
}
|
|
|
|
if (compile_options == ScriptCompiler::kConsumeCodeCache) {
|
|
|
|
if (target
|
|
|
|
->Set(
|
|
|
|
context,
|
|
|
|
env->cached_data_rejected_string(),
|
|
|
|
Boolean::New(env->isolate(), source.GetCachedData()->rejected))
|
|
|
|
.IsNothing()) {
|
2024-09-17 09:53:54 +02:00
|
|
|
return Nothing<void>();
|
2023-01-25 21:06:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (produce_cached_data) {
|
|
|
|
bool cached_data_produced = new_cached_data != nullptr;
|
|
|
|
if (cached_data_produced) {
|
|
|
|
MaybeLocal<Object> buf =
|
|
|
|
Buffer::Copy(env,
|
|
|
|
reinterpret_cast<const char*>(new_cached_data->data),
|
|
|
|
new_cached_data->length);
|
|
|
|
if (target->Set(context, env->cached_data_string(), buf.ToLocalChecked())
|
|
|
|
.IsNothing()) {
|
2024-09-17 09:53:54 +02:00
|
|
|
return Nothing<void>();
|
2023-01-25 21:06:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (target
|
|
|
|
->Set(context,
|
|
|
|
env->cached_data_produced_string(),
|
|
|
|
Boolean::New(env->isolate(), cached_data_produced))
|
|
|
|
.IsNothing()) {
|
2024-09-17 09:53:54 +02:00
|
|
|
return Nothing<void>();
|
2023-01-25 21:06:55 +01:00
|
|
|
}
|
|
|
|
}
|
2024-09-17 09:53:54 +02:00
|
|
|
return JustVoid();
|
2023-01-25 21:06:55 +01:00
|
|
|
}
|
|
|
|
|
2023-07-26 15:40:35 +05:30
|
|
|
// TODO(RaisinTen): Reuse in ContextifyContext::CompileFunction().
|
|
|
|
MaybeLocal<Function> CompileFunction(Local<Context> context,
|
|
|
|
Local<String> filename,
|
|
|
|
Local<String> content,
|
|
|
|
std::vector<Local<String>>* parameters) {
|
2024-05-15 09:16:00 +02:00
|
|
|
ScriptOrigin script_origin(filename, 0, 0, true);
|
2023-07-26 15:40:35 +05:30
|
|
|
ScriptCompiler::Source script_source(content, script_origin);
|
|
|
|
|
|
|
|
return ScriptCompiler::CompileFunction(context,
|
|
|
|
&script_source,
|
|
|
|
parameters->size(),
|
|
|
|
parameters->data(),
|
|
|
|
0,
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
bool ContextifyScript::InstanceOf(Environment* env,
|
|
|
|
const Local<Value>& value) {
|
|
|
|
return !value.IsEmpty() &&
|
|
|
|
env->script_context_constructor_template()->HasInstance(value);
|
|
|
|
}
|
2018-04-25 12:22:20 -05:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
void ContextifyScript::CreateCachedData(
|
|
|
|
const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
ContextifyScript* wrapped_script;
|
2024-03-31 22:27:33 +02:00
|
|
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This());
|
2018-08-17 17:26:34 -05:00
|
|
|
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
|
2024-03-31 22:27:33 +02:00
|
|
|
ScriptCompiler::CreateCodeCache(wrapped_script->unbound_script()));
|
2018-08-17 17:26:34 -05:00
|
|
|
if (!cached_data) {
|
|
|
|
args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
|
|
|
|
} else {
|
|
|
|
MaybeLocal<Object> buf = Buffer::Copy(
|
|
|
|
env,
|
|
|
|
reinterpret_cast<const char*>(cached_data->data),
|
|
|
|
cached_data->length);
|
|
|
|
args.GetReturnValue().Set(buf.ToLocalChecked());
|
|
|
|
}
|
|
|
|
}
|
2016-09-06 20:42:30 +02:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
ContextifyScript* wrapped_script;
|
2024-03-31 22:27:33 +02:00
|
|
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This());
|
2014-10-08 14:34:51 +04:00
|
|
|
|
2019-01-30 23:13:45 +01:00
|
|
|
CHECK_EQ(args.Length(), 5);
|
2022-07-11 17:08:41 +09:00
|
|
|
CHECK(args[0]->IsObject() || args[0]->IsNull());
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2022-07-11 17:08:41 +09:00
|
|
|
Local<Context> context;
|
2023-08-16 22:18:46 +02:00
|
|
|
v8::MicrotaskQueue* microtask_queue = nullptr;
|
2014-02-05 13:46:00 +04:00
|
|
|
|
2022-07-11 17:08:41 +09:00
|
|
|
if (args[0]->IsObject()) {
|
|
|
|
Local<Object> sandbox = args[0].As<Object>();
|
|
|
|
// Get the context from the sandbox
|
|
|
|
ContextifyContext* contextify_context =
|
|
|
|
ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
|
|
|
|
CHECK_NOT_NULL(contextify_context);
|
|
|
|
CHECK_EQ(contextify_context->env(), env);
|
|
|
|
|
|
|
|
context = contextify_context->context();
|
|
|
|
if (context.IsEmpty()) return;
|
|
|
|
|
|
|
|
microtask_queue = contextify_context->microtask_queue();
|
|
|
|
} else {
|
|
|
|
context = env->context();
|
|
|
|
}
|
2018-05-14 14:24:58 -07:00
|
|
|
|
2022-05-05 23:53:41 +08:00
|
|
|
TRACE_EVENT0(TRACING_CATEGORY_NODE2(vm, script), "RunInContext");
|
2018-03-16 15:23:39 +01:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[1]->IsNumber());
|
|
|
|
int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
|
2018-03-16 15:23:39 +01:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[2]->IsBoolean());
|
|
|
|
bool display_errors = args[2]->IsTrue();
|
2018-03-16 15:23:39 +01:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
CHECK(args[3]->IsBoolean());
|
|
|
|
bool break_on_sigint = args[3]->IsTrue();
|
|
|
|
|
2019-01-30 23:13:45 +01:00
|
|
|
CHECK(args[4]->IsBoolean());
|
|
|
|
bool break_on_first_line = args[4]->IsTrue();
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
// Do the eval within the context
|
2022-08-16 23:22:32 +08:00
|
|
|
EvalMachine(context,
|
|
|
|
env,
|
2018-08-17 17:26:34 -05:00
|
|
|
timeout,
|
|
|
|
display_errors,
|
|
|
|
break_on_sigint,
|
2019-01-30 23:13:45 +01:00
|
|
|
break_on_first_line,
|
2022-07-11 17:08:41 +09:00
|
|
|
microtask_queue,
|
2018-08-17 17:26:34 -05:00
|
|
|
args);
|
|
|
|
}
|
2018-05-14 14:24:58 -07:00
|
|
|
|
2022-08-16 23:22:32 +08:00
|
|
|
bool ContextifyScript::EvalMachine(Local<Context> context,
|
|
|
|
Environment* env,
|
2018-08-17 17:26:34 -05:00
|
|
|
const int64_t timeout,
|
|
|
|
const bool display_errors,
|
|
|
|
const bool break_on_sigint,
|
2019-01-30 23:13:45 +01:00
|
|
|
const bool break_on_first_line,
|
2023-08-16 22:18:46 +02:00
|
|
|
MicrotaskQueue* mtask_queue,
|
2018-08-17 17:26:34 -05:00
|
|
|
const FunctionCallbackInfo<Value>& args) {
|
2022-08-16 23:22:32 +08:00
|
|
|
Context::Scope context_scope(context);
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
if (!env->can_call_into_js())
|
|
|
|
return false;
|
2024-06-18 18:02:42 +02:00
|
|
|
if (!ContextifyScript::InstanceOf(env, args.This())) {
|
2020-10-02 14:23:11 -07:00
|
|
|
THROW_ERR_INVALID_THIS(
|
|
|
|
env,
|
2018-08-17 17:26:34 -05:00
|
|
|
"Script methods can only be called on script instances.");
|
|
|
|
return false;
|
|
|
|
}
|
2022-08-16 23:22:32 +08:00
|
|
|
|
2018-11-30 08:13:45 -06:00
|
|
|
TryCatchScope try_catch(env);
|
2018-08-17 17:26:34 -05:00
|
|
|
ContextifyScript* wrapped_script;
|
2024-03-31 22:27:33 +02:00
|
|
|
ASSIGN_OR_RETURN_UNWRAP_CPPGC(&wrapped_script, args.This(), false);
|
|
|
|
Local<Script> script =
|
|
|
|
wrapped_script->unbound_script()->BindToCurrentContext();
|
2018-08-17 17:26:34 -05:00
|
|
|
|
2019-01-30 23:13:45 +01:00
|
|
|
#if HAVE_INSPECTOR
|
|
|
|
if (break_on_first_line) {
|
2024-09-30 14:04:16 -04:00
|
|
|
if (!env->permission()->is_granted(env,
|
|
|
|
permission::PermissionScope::kInspector,
|
|
|
|
"PauseOnNextJavascriptStatement"))
|
|
|
|
[[unlikely]] {
|
2024-06-11 02:35:55 +08:00
|
|
|
node::permission::Permission::ThrowAccessDenied(
|
|
|
|
env,
|
|
|
|
permission::PermissionScope::kInspector,
|
|
|
|
"PauseOnNextJavascriptStatement");
|
|
|
|
if (display_errors) {
|
|
|
|
// We should decorate non-termination exceptions
|
|
|
|
errors::DecorateErrorStack(env, try_catch);
|
|
|
|
}
|
|
|
|
try_catch.ReThrow();
|
|
|
|
return false;
|
|
|
|
}
|
2019-01-30 23:13:45 +01:00
|
|
|
env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
MaybeLocal<Value> result;
|
|
|
|
bool timed_out = false;
|
|
|
|
bool received_signal = false;
|
2020-06-23 00:33:04 +02:00
|
|
|
auto run = [&]() {
|
2022-08-16 23:22:32 +08:00
|
|
|
MaybeLocal<Value> result = script->Run(context);
|
2023-08-16 22:18:46 +02:00
|
|
|
if (!result.IsEmpty() && mtask_queue != nullptr)
|
2020-06-23 00:33:04 +02:00
|
|
|
mtask_queue->PerformCheckpoint(env->isolate());
|
|
|
|
return result;
|
|
|
|
};
|
2018-08-17 17:26:34 -05:00
|
|
|
if (break_on_sigint && timeout != -1) {
|
|
|
|
Watchdog wd(env->isolate(), timeout, &timed_out);
|
|
|
|
SigintWatchdog swd(env->isolate(), &received_signal);
|
2020-06-23 00:33:04 +02:00
|
|
|
result = run();
|
2018-08-17 17:26:34 -05:00
|
|
|
} else if (break_on_sigint) {
|
|
|
|
SigintWatchdog swd(env->isolate(), &received_signal);
|
2020-06-23 00:33:04 +02:00
|
|
|
result = run();
|
2018-08-17 17:26:34 -05:00
|
|
|
} else if (timeout != -1) {
|
|
|
|
Watchdog wd(env->isolate(), timeout, &timed_out);
|
2020-06-23 00:33:04 +02:00
|
|
|
result = run();
|
2018-08-17 17:26:34 -05:00
|
|
|
} else {
|
2020-06-23 00:33:04 +02:00
|
|
|
result = run();
|
2016-01-25 22:44:17 -05:00
|
|
|
}
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
// Convert the termination exception into a regular exception.
|
|
|
|
if (timed_out || received_signal) {
|
2018-06-12 09:01:46 -04:00
|
|
|
if (!env->is_main_thread() && env->is_stopping())
|
2019-02-15 14:33:23 +01:00
|
|
|
return false;
|
2018-08-17 17:26:34 -05:00
|
|
|
env->isolate()->CancelTerminateExecution();
|
|
|
|
// It is possible that execution was terminated by another timeout in
|
|
|
|
// which this timeout is nested, so check whether one of the watchdogs
|
|
|
|
// from this invocation is responsible for termination.
|
|
|
|
if (timed_out) {
|
|
|
|
node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
|
|
|
|
} else if (received_signal) {
|
|
|
|
node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
2018-08-17 17:26:34 -05:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
if (try_catch.HasCaught()) {
|
|
|
|
if (!timed_out && !received_signal && display_errors) {
|
|
|
|
// We should decorate non-termination exceptions
|
2019-06-15 08:07:15 +08:00
|
|
|
errors::DecorateErrorStack(env, try_catch);
|
2017-05-18 17:12:41 -05:00
|
|
|
}
|
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
// If there was an exception thrown during script execution, re-throw it.
|
|
|
|
// If one of the above checks threw, re-throw the exception instead of
|
|
|
|
// letting try_catch catch it.
|
|
|
|
// If execution has been terminated, but not by one of the watchdogs from
|
|
|
|
// this invocation, this will re-throw a `null` value.
|
2019-02-15 14:33:23 +01:00
|
|
|
if (!try_catch.HasTerminated())
|
|
|
|
try_catch.ReThrow();
|
2016-06-22 23:32:24 +02:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
return false;
|
|
|
|
}
|
2016-06-22 23:32:24 +02:00
|
|
|
|
2018-08-17 17:26:34 -05:00
|
|
|
args.GetReturnValue().Set(result.ToLocalChecked());
|
|
|
|
return true;
|
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2024-03-31 22:27:33 +02:00
|
|
|
Local<UnboundScript> ContextifyScript::unbound_script() const {
|
|
|
|
return script_.Get(env()->isolate());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContextifyScript::set_unbound_script(Local<UnboundScript> script) {
|
|
|
|
script_.Reset(env()->isolate(), script);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ContextifyScript::Trace(cppgc::Visitor* visitor) const {
|
|
|
|
CppgcMixin::Trace(visitor);
|
|
|
|
visitor->Trace(script_);
|
|
|
|
}
|
|
|
|
|
|
|
|
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object) {
|
|
|
|
CppgcMixin::Wrap(this, env, object);
|
2018-08-17 17:26:34 -05:00
|
|
|
}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2023-06-21 16:01:50 +02:00
|
|
|
ContextifyScript::~ContextifyScript() {}
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
|
2018-06-28 12:05:19 +05:30
|
|
|
void ContextifyContext::CompileFunction(
|
|
|
|
const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
Isolate* isolate = env->isolate();
|
|
|
|
Local<Context> context = env->context();
|
|
|
|
|
|
|
|
// Argument 1: source code
|
|
|
|
CHECK(args[0]->IsString());
|
|
|
|
Local<String> code = args[0].As<String>();
|
|
|
|
|
|
|
|
// Argument 2: filename
|
|
|
|
CHECK(args[1]->IsString());
|
|
|
|
Local<String> filename = args[1].As<String>();
|
|
|
|
|
|
|
|
// Argument 3: line offset
|
|
|
|
CHECK(args[2]->IsNumber());
|
2021-01-30 13:30:19 +01:00
|
|
|
int line_offset = args[2].As<Int32>()->Value();
|
2018-06-28 12:05:19 +05:30
|
|
|
|
|
|
|
// Argument 4: column offset
|
|
|
|
CHECK(args[3]->IsNumber());
|
2021-01-30 13:30:19 +01:00
|
|
|
int column_offset = args[3].As<Int32>()->Value();
|
2018-06-28 12:05:19 +05:30
|
|
|
|
|
|
|
// Argument 5: cached data (optional)
|
2018-09-18 01:28:41 -04:00
|
|
|
Local<ArrayBufferView> cached_data_buf;
|
2018-06-28 12:05:19 +05:30
|
|
|
if (!args[4]->IsUndefined()) {
|
2018-09-18 01:28:41 -04:00
|
|
|
CHECK(args[4]->IsArrayBufferView());
|
|
|
|
cached_data_buf = args[4].As<ArrayBufferView>();
|
2018-06-28 12:05:19 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
// Argument 6: produce cache data
|
|
|
|
CHECK(args[5]->IsBoolean());
|
|
|
|
bool produce_cached_data = args[5]->IsTrue();
|
|
|
|
|
|
|
|
// Argument 7: parsing context (optional)
|
|
|
|
Local<Context> parsing_context;
|
|
|
|
if (!args[6]->IsUndefined()) {
|
|
|
|
CHECK(args[6]->IsObject());
|
|
|
|
ContextifyContext* sandbox =
|
|
|
|
ContextifyContext::ContextFromContextifiedSandbox(
|
|
|
|
env, args[6].As<Object>());
|
|
|
|
CHECK_NOT_NULL(sandbox);
|
|
|
|
parsing_context = sandbox->context();
|
|
|
|
} else {
|
|
|
|
parsing_context = context;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Argument 8: context extensions (optional)
|
|
|
|
Local<Array> context_extensions_buf;
|
|
|
|
if (!args[7]->IsUndefined()) {
|
|
|
|
CHECK(args[7]->IsArray());
|
|
|
|
context_extensions_buf = args[7].As<Array>();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Argument 9: params for the function (optional)
|
|
|
|
Local<Array> params_buf;
|
|
|
|
if (!args[8]->IsUndefined()) {
|
|
|
|
CHECK(args[8]->IsArray());
|
|
|
|
params_buf = args[8].As<Array>();
|
|
|
|
}
|
|
|
|
|
2023-10-05 03:27:11 +02:00
|
|
|
// Argument 10: host-defined option symbol
|
|
|
|
CHECK(args[9]->IsSymbol());
|
|
|
|
Local<Symbol> id_symbol = args[9].As<Symbol>();
|
|
|
|
|
2018-06-28 12:05:19 +05:30
|
|
|
// Read cache from cached data buffer
|
|
|
|
ScriptCompiler::CachedData* cached_data = nullptr;
|
|
|
|
if (!cached_data_buf.IsEmpty()) {
|
2022-08-02 21:04:53 -07:00
|
|
|
uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data());
|
2018-06-28 12:05:19 +05:30
|
|
|
cached_data = new ScriptCompiler::CachedData(
|
|
|
|
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
|
|
|
|
}
|
|
|
|
|
2018-11-07 22:17:09 +05:30
|
|
|
Local<PrimitiveArray> host_defined_options =
|
2024-04-19 16:29:08 +02:00
|
|
|
loader::ModuleWrap::GetHostDefinedOptions(isolate, id_symbol);
|
|
|
|
|
2024-05-15 09:16:00 +02:00
|
|
|
ScriptOrigin origin(filename,
|
2024-04-19 16:29:08 +02:00
|
|
|
line_offset, // line offset
|
|
|
|
column_offset, // column offset
|
|
|
|
true, // is cross origin
|
|
|
|
-1, // script id
|
|
|
|
Local<Value>(), // source map URL
|
|
|
|
false, // is opaque (?)
|
|
|
|
false, // is WASM
|
|
|
|
false, // is ES Module
|
|
|
|
host_defined_options);
|
|
|
|
ScriptCompiler::Source source(code, origin, cached_data);
|
|
|
|
|
|
|
|
ScriptCompiler::CompileOptions options;
|
|
|
|
if (source.GetCachedData() != nullptr) {
|
|
|
|
options = ScriptCompiler::kConsumeCodeCache;
|
|
|
|
} else {
|
|
|
|
options = ScriptCompiler::kNoCompileOptions;
|
|
|
|
}
|
2018-06-28 12:05:19 +05:30
|
|
|
|
|
|
|
Context::Scope scope(parsing_context);
|
|
|
|
|
|
|
|
// Read context extensions from buffer
|
|
|
|
std::vector<Local<Object>> context_extensions;
|
|
|
|
if (!context_extensions_buf.IsEmpty()) {
|
|
|
|
for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
|
|
|
|
Local<Value> val;
|
|
|
|
if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
|
|
|
|
CHECK(val->IsObject());
|
|
|
|
context_extensions.push_back(val.As<Object>());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read params from params buffer
|
|
|
|
std::vector<Local<String>> params;
|
|
|
|
if (!params_buf.IsEmpty()) {
|
|
|
|
for (uint32_t n = 0; n < params_buf->Length(); n++) {
|
|
|
|
Local<Value> val;
|
|
|
|
if (!params_buf->Get(context, n).ToLocal(&val)) return;
|
|
|
|
CHECK(val->IsString());
|
|
|
|
params.push_back(val.As<String>());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-18 07:32:34 -07:00
|
|
|
TryCatchScope try_catch(env);
|
|
|
|
Local<Object> result = CompileFunctionAndCacheResult(env,
|
|
|
|
parsing_context,
|
|
|
|
&source,
|
|
|
|
params,
|
|
|
|
context_extensions,
|
|
|
|
options,
|
|
|
|
produce_cached_data,
|
|
|
|
id_symbol,
|
|
|
|
try_catch);
|
|
|
|
|
|
|
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
|
|
|
try_catch.ReThrow();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result.IsEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
args.GetReturnValue().Set(result);
|
|
|
|
}
|
|
|
|
|
2024-03-12 03:18:53 +08:00
|
|
|
static std::vector<Local<String>> GetCJSParameters(IsolateData* data) {
|
|
|
|
return {
|
|
|
|
data->exports_string(),
|
|
|
|
data->require_string(),
|
|
|
|
data->module_string(),
|
|
|
|
data->__filename_string(),
|
|
|
|
data->__dirname_string(),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-10-18 07:32:34 -07:00
|
|
|
Local<Object> ContextifyContext::CompileFunctionAndCacheResult(
|
|
|
|
Environment* env,
|
|
|
|
Local<Context> parsing_context,
|
|
|
|
ScriptCompiler::Source* source,
|
|
|
|
std::vector<Local<String>> params,
|
|
|
|
std::vector<Local<Object>> context_extensions,
|
|
|
|
ScriptCompiler::CompileOptions options,
|
|
|
|
bool produce_cached_data,
|
|
|
|
Local<Symbol> id_symbol,
|
|
|
|
const TryCatchScope& try_catch) {
|
2022-08-10 09:35:43 +00:00
|
|
|
MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunction(
|
|
|
|
parsing_context,
|
2023-10-18 07:32:34 -07:00
|
|
|
source,
|
2022-08-10 09:35:43 +00:00
|
|
|
params.size(),
|
|
|
|
params.data(),
|
|
|
|
context_extensions.size(),
|
|
|
|
context_extensions.data(),
|
|
|
|
options,
|
|
|
|
v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason);
|
2018-06-28 12:05:19 +05:30
|
|
|
|
2020-06-16 13:18:42 +02:00
|
|
|
Local<Function> fn;
|
|
|
|
if (!maybe_fn.ToLocal(&fn)) {
|
2019-02-15 14:33:23 +01:00
|
|
|
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
|
2019-06-15 08:07:15 +08:00
|
|
|
errors::DecorateErrorStack(env, try_catch);
|
2023-10-18 07:32:34 -07:00
|
|
|
return Object::New(env->isolate());
|
2019-02-15 14:33:23 +01:00
|
|
|
}
|
2018-06-28 12:05:19 +05:30
|
|
|
}
|
2023-10-18 07:32:34 -07:00
|
|
|
|
|
|
|
Local<Context> context = env->context();
|
2023-06-21 16:01:50 +02:00
|
|
|
if (fn->SetPrivate(context, env->host_defined_option_symbol(), id_symbol)
|
|
|
|
.IsNothing()) {
|
2023-10-18 07:32:34 -07:00
|
|
|
return Object::New(env->isolate());
|
2019-07-20 19:35:24 +02:00
|
|
|
}
|
2019-07-19 09:30:09 -05:00
|
|
|
|
2023-10-18 07:32:34 -07:00
|
|
|
Isolate* isolate = env->isolate();
|
2019-07-19 09:30:09 -05:00
|
|
|
Local<Object> result = Object::New(isolate);
|
|
|
|
if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
|
2023-10-18 07:32:34 -07:00
|
|
|
return Object::New(env->isolate());
|
2022-09-27 00:55:59 +08:00
|
|
|
if (result
|
|
|
|
->Set(parsing_context,
|
|
|
|
env->source_map_url_string(),
|
|
|
|
fn->GetScriptOrigin().SourceMapUrl())
|
|
|
|
.IsNothing())
|
2023-10-18 07:32:34 -07:00
|
|
|
return Object::New(env->isolate());
|
2018-06-28 12:05:19 +05:30
|
|
|
|
2023-01-25 21:06:55 +01:00
|
|
|
std::unique_ptr<ScriptCompiler::CachedData> new_cached_data;
|
2018-06-28 12:05:19 +05:30
|
|
|
if (produce_cached_data) {
|
2023-01-25 21:06:55 +01:00
|
|
|
new_cached_data.reset(ScriptCompiler::CreateCodeCacheForFunction(fn));
|
|
|
|
}
|
|
|
|
if (StoreCodeCacheResult(env,
|
|
|
|
result,
|
|
|
|
options,
|
2023-10-18 07:32:34 -07:00
|
|
|
*source,
|
2023-01-25 21:06:55 +01:00
|
|
|
produce_cached_data,
|
|
|
|
std::move(new_cached_data))
|
|
|
|
.IsNothing()) {
|
2023-10-18 07:32:34 -07:00
|
|
|
return Object::New(env->isolate());
|
2018-06-28 12:05:19 +05:30
|
|
|
}
|
|
|
|
|
2023-10-18 07:32:34 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// When compiling as CommonJS source code that contains ESM syntax, the
|
|
|
|
// following error messages are returned:
|
|
|
|
// - `import` statements: "Cannot use import statement outside a module"
|
|
|
|
// - `export` statements: "Unexpected token 'export'"
|
|
|
|
// - `import.meta` references: "Cannot use 'import.meta' outside a module"
|
|
|
|
// Dynamic `import()` is permitted in CommonJS, so it does not error.
|
|
|
|
// While top-level `await` is not permitted in CommonJS, it returns the same
|
|
|
|
// error message as when `await` is used in a sync function, so we don't use it
|
|
|
|
// as a disambiguation.
|
2024-03-20 08:48:05 -07:00
|
|
|
static std::vector<std::string_view> esm_syntax_error_messages = {
|
2023-10-18 07:32:34 -07:00
|
|
|
"Cannot use import statement outside a module", // `import` statements
|
|
|
|
"Unexpected token 'export'", // `export` statements
|
|
|
|
"Cannot use 'import.meta' outside a module"}; // `import.meta` references
|
|
|
|
|
2024-03-12 06:37:51 -07:00
|
|
|
// Another class of error messages that we need to check for are syntax errors
|
|
|
|
// where the syntax throws when parsed as CommonJS but succeeds when parsed as
|
|
|
|
// ESM. So far, the cases we've found are:
|
|
|
|
// - CommonJS module variables (`module`, `exports`, `require`, `__filename`,
|
|
|
|
// `__dirname`): if the user writes code such as `const module =` in the top
|
|
|
|
// level of a CommonJS module, it will throw a syntax error; but the same
|
|
|
|
// code is valid in ESM.
|
|
|
|
// - Top-level `await`: if the user writes `await` at the top level of a
|
|
|
|
// CommonJS module, it will throw a syntax error; but the same code is valid
|
|
|
|
// in ESM.
|
2024-03-20 08:48:05 -07:00
|
|
|
static std::vector<std::string_view> throws_only_in_cjs_error_messages = {
|
2024-03-12 06:37:51 -07:00
|
|
|
"Identifier 'module' has already been declared",
|
|
|
|
"Identifier 'exports' has already been declared",
|
|
|
|
"Identifier 'require' has already been declared",
|
|
|
|
"Identifier '__filename' has already been declared",
|
|
|
|
"Identifier '__dirname' has already been declared",
|
|
|
|
"await is only valid in async functions and "
|
|
|
|
"the top level bodies of modules"};
|
|
|
|
|
2024-07-05 21:58:35 +02:00
|
|
|
// If cached_data is provided, it would be used for the compilation and
|
|
|
|
// the on-disk compilation cache from NODE_COMPILE_CACHE (if configured)
|
|
|
|
// would be ignored.
|
|
|
|
static MaybeLocal<Function> CompileFunctionForCJSLoader(
|
|
|
|
Environment* env,
|
|
|
|
Local<Context> context,
|
|
|
|
Local<String> code,
|
|
|
|
Local<String> filename,
|
|
|
|
bool* cache_rejected,
|
|
|
|
bool is_cjs_scope,
|
|
|
|
ScriptCompiler::CachedData* cached_data) {
|
2024-04-19 16:29:08 +02:00
|
|
|
Isolate* isolate = context->GetIsolate();
|
|
|
|
EscapableHandleScope scope(isolate);
|
2024-03-12 03:18:53 +08:00
|
|
|
|
|
|
|
Local<Symbol> symbol = env->vm_dynamic_import_default_internal();
|
2024-04-19 16:29:08 +02:00
|
|
|
Local<PrimitiveArray> hdo =
|
|
|
|
loader::ModuleWrap::GetHostDefinedOptions(isolate, symbol);
|
2024-05-15 09:16:00 +02:00
|
|
|
ScriptOrigin origin(filename,
|
2024-03-12 03:18:53 +08:00
|
|
|
0, // line offset
|
|
|
|
0, // column offset
|
|
|
|
true, // is cross origin
|
|
|
|
-1, // script id
|
|
|
|
Local<Value>(), // source map URL
|
|
|
|
false, // is opaque
|
|
|
|
false, // is WASM
|
|
|
|
false, // is ES Module
|
|
|
|
hdo);
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
|
|
|
|
CompileCacheEntry* cache_entry = nullptr;
|
2024-07-05 21:58:35 +02:00
|
|
|
if (cached_data == nullptr && env->use_compile_cache()) {
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
cache_entry = env->compile_cache_handler()->GetOrInsert(
|
|
|
|
code, filename, CachedCodeType::kCommonJS);
|
|
|
|
}
|
|
|
|
if (cache_entry != nullptr && cache_entry->cache != nullptr) {
|
|
|
|
// source will take ownership of cached_data.
|
|
|
|
cached_data = cache_entry->CopyCache();
|
|
|
|
}
|
|
|
|
|
2024-03-12 03:18:53 +08:00
|
|
|
ScriptCompiler::Source source(code, origin, cached_data);
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
ScriptCompiler::CompileOptions options;
|
|
|
|
if (cached_data == nullptr) {
|
|
|
|
options = ScriptCompiler::kNoCompileOptions;
|
|
|
|
} else {
|
|
|
|
options = ScriptCompiler::kConsumeCodeCache;
|
|
|
|
}
|
2024-03-12 03:18:53 +08:00
|
|
|
|
2024-05-25 05:51:47 +03:00
|
|
|
std::vector<Local<String>> params;
|
|
|
|
if (is_cjs_scope) {
|
|
|
|
params = GetCJSParameters(env->isolate_data());
|
|
|
|
}
|
2024-03-12 03:18:53 +08:00
|
|
|
MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunction(
|
|
|
|
context,
|
|
|
|
&source,
|
|
|
|
params.size(),
|
|
|
|
params.data(),
|
|
|
|
0, /* context extensions size */
|
|
|
|
nullptr, /* context extensions data */
|
|
|
|
// TODO(joyeecheung): allow optional eager compilation.
|
2024-04-19 16:29:08 +02:00
|
|
|
options);
|
2024-03-12 03:18:53 +08:00
|
|
|
|
|
|
|
Local<Function> fn;
|
|
|
|
if (!maybe_fn.ToLocal(&fn)) {
|
2024-04-19 16:29:08 +02:00
|
|
|
return scope.EscapeMaybe(MaybeLocal<Function>());
|
2024-03-12 03:18:53 +08:00
|
|
|
}
|
|
|
|
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
if (options == ScriptCompiler::kConsumeCodeCache) {
|
2024-04-19 16:29:08 +02:00
|
|
|
*cache_rejected = source.GetCachedData()->rejected;
|
2024-03-12 03:18:53 +08:00
|
|
|
}
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
if (cache_entry != nullptr) {
|
2024-04-19 16:29:08 +02:00
|
|
|
env->compile_cache_handler()->MaybeSave(cache_entry, fn, *cache_rejected);
|
|
|
|
}
|
|
|
|
return scope.Escape(fn);
|
|
|
|
}
|
|
|
|
|
2024-04-29 22:21:53 +02:00
|
|
|
static bool warned_about_require_esm = false;
|
|
|
|
// TODO(joyeecheung): this was copied from the warning previously emitted in the
|
|
|
|
// JS land, but it's not very helpful. There should be specific information
|
|
|
|
// about which file or which package.json to update.
|
|
|
|
const char* require_esm_warning =
|
|
|
|
"To load an ES module, set \"type\": \"module\" in the package.json or use "
|
|
|
|
"the .mjs extension.";
|
|
|
|
|
|
|
|
static bool ShouldRetryAsESM(Realm* realm,
|
|
|
|
Local<String> message,
|
|
|
|
Local<String> code,
|
|
|
|
Local<String> resource_name);
|
|
|
|
|
2024-04-19 16:29:08 +02:00
|
|
|
static void CompileFunctionForCJSLoader(
|
|
|
|
const FunctionCallbackInfo<Value>& args) {
|
|
|
|
CHECK(args[0]->IsString());
|
|
|
|
CHECK(args[1]->IsString());
|
2024-04-29 22:21:53 +02:00
|
|
|
CHECK(args[2]->IsBoolean());
|
|
|
|
CHECK(args[3]->IsBoolean());
|
2024-04-19 16:29:08 +02:00
|
|
|
Local<String> code = args[0].As<String>();
|
|
|
|
Local<String> filename = args[1].As<String>();
|
2024-07-05 21:58:35 +02:00
|
|
|
bool is_sea_main = args[2].As<Boolean>()->Value();
|
2024-04-29 22:21:53 +02:00
|
|
|
bool should_detect_module = args[3].As<Boolean>()->Value();
|
|
|
|
|
2024-04-19 16:29:08 +02:00
|
|
|
Isolate* isolate = args.GetIsolate();
|
|
|
|
Local<Context> context = isolate->GetCurrentContext();
|
2024-04-29 22:21:53 +02:00
|
|
|
Realm* realm = Realm::GetCurrent(context);
|
|
|
|
Environment* env = realm->env();
|
2024-04-19 16:29:08 +02:00
|
|
|
|
|
|
|
bool cache_rejected = false;
|
|
|
|
Local<Function> fn;
|
2024-04-29 22:21:53 +02:00
|
|
|
Local<Value> cjs_exception;
|
|
|
|
Local<Message> cjs_message;
|
|
|
|
|
2024-07-05 21:58:35 +02:00
|
|
|
ScriptCompiler::CachedData* cached_data = nullptr;
|
|
|
|
#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION
|
|
|
|
if (is_sea_main) {
|
|
|
|
sea::SeaResource sea = sea::FindSingleExecutableResource();
|
|
|
|
// Use the "main" field in SEA config for the filename.
|
|
|
|
Local<Value> filename_from_sea;
|
|
|
|
if (!ToV8Value(context, sea.code_path).ToLocal(&filename_from_sea)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
filename = filename_from_sea.As<String>();
|
|
|
|
if (sea.use_code_cache()) {
|
|
|
|
std::string_view data = sea.code_cache.value();
|
|
|
|
cached_data = new ScriptCompiler::CachedData(
|
|
|
|
reinterpret_cast<const uint8_t*>(data.data()),
|
|
|
|
static_cast<int>(data.size()),
|
|
|
|
v8::ScriptCompiler::CachedData::BufferNotOwned);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-19 16:29:08 +02:00
|
|
|
{
|
2024-04-29 22:21:53 +02:00
|
|
|
ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env());
|
2024-04-19 16:29:08 +02:00
|
|
|
TryCatchScope try_catch(env);
|
|
|
|
if (!CompileFunctionForCJSLoader(
|
2024-07-05 21:58:35 +02:00
|
|
|
env, context, code, filename, &cache_rejected, true, cached_data)
|
2024-04-19 16:29:08 +02:00
|
|
|
.ToLocal(&fn)) {
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
CHECK(!try_catch.HasTerminated());
|
2024-04-29 22:21:53 +02:00
|
|
|
cjs_exception = try_catch.Exception();
|
|
|
|
cjs_message = try_catch.Message();
|
|
|
|
errors::DecorateErrorStack(env, cjs_exception, cjs_message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool can_parse_as_esm = false;
|
|
|
|
if (!cjs_exception.IsEmpty()) {
|
|
|
|
// Use the URL to match what would be used in the origin if it's going to
|
|
|
|
// be reparsed as ESM.
|
|
|
|
Utf8Value filename_utf8(isolate, filename);
|
|
|
|
std::string url = url::FromFilePath(filename_utf8.ToStringView());
|
|
|
|
Local<String> url_value;
|
|
|
|
if (!String::NewFromUtf8(isolate, url.c_str()).ToLocal(&url_value)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
can_parse_as_esm =
|
|
|
|
ShouldRetryAsESM(realm, cjs_message->Get(), code, url_value);
|
|
|
|
if (!can_parse_as_esm) {
|
|
|
|
// The syntax error is not related to ESM, throw the original error.
|
|
|
|
isolate->ThrowException(cjs_exception);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!should_detect_module) {
|
|
|
|
bool should_throw = true;
|
|
|
|
if (!warned_about_require_esm) {
|
|
|
|
// This needs to call process.emit('warning') in JS which can throw if
|
|
|
|
// the user listener throws. In that case, don't try to throw the syntax
|
|
|
|
// error.
|
|
|
|
should_throw =
|
|
|
|
ProcessEmitWarningSync(env, require_esm_warning).IsJust();
|
|
|
|
}
|
|
|
|
if (should_throw) {
|
|
|
|
isolate->ThrowException(cjs_exception);
|
|
|
|
}
|
2024-04-19 16:29:08 +02:00
|
|
|
return;
|
|
|
|
}
|
module: implement NODE_COMPILE_CACHE for automatic on-disk code caching
This patch implements automatic on-disk code caching that can be enabled
via an environment variable NODE_COMPILE_CACHE.
When set, whenever Node.js compiles a CommonJS or a ECMAScript Module,
it will use on-disk [V8 code cache][] persisted in the specified
directory to speed up the compilation. This may slow down the first
load of a module graph, but subsequent loads of the same module graph
may get a significant speedup if the contents of the modules do not
change. Locally, this speeds up loading of
test/fixtures/snapshot/typescript.js from ~130ms to ~80ms.
To clean up the generated code cache, simply remove the directory.
It will be recreated the next time the same directory is used for
`NODE_COMPILE_CACHE`.
Compilation cache generated by one version of Node.js may not be used
by a different version of Node.js. Cache generated by different versions
of Node.js will be stored separately if the same directory is used
to persist the cache, so they can co-exist.
Caveat: currently when using this with V8 JavaScript code coverage, the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
running tests to generate precise coverage.
Implementation details:
There is one cache file per module on disk. The directory layout
is:
- Compile cache directory (from NODE_COMPILE_CACHE)
- 8b23c8fe: CRC32 hash of CachedDataVersionTag + NODE_VERESION
- 2ea3424d:
- 10860e5a: CRC32 hash of filename + module type
- 431e9adc: ...
- ...
Inside the cache file, there is a header followed by the actual
cache content:
```
[uint32_t] code size
[uint32_t] code hash
[uint32_t] cache size
[uint32_t] cache hash
... compile cache content ...
```
When reading the cache file, we'll also check if the code size
and code hash match the code that the module loader is loading
and whether the cache size and cache hash match the file content
read. If they don't match, or if V8 rejects the cache passed,
we'll ignore the mismatch cache, and regenerate the cache after
compilation succeeds and rewrite it to disk.
PR-URL: https://github.com/nodejs/node/pull/52535
Refs: https://github.com/nodejs/node/issues/47472
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com>
2024-02-29 02:09:16 +01:00
|
|
|
}
|
2024-03-12 03:18:53 +08:00
|
|
|
|
2024-04-29 22:21:53 +02:00
|
|
|
Local<Value> undefined = v8::Undefined(isolate);
|
2024-03-12 03:18:53 +08:00
|
|
|
std::vector<Local<Name>> names = {
|
|
|
|
env->cached_data_rejected_string(),
|
|
|
|
env->source_map_url_string(),
|
|
|
|
env->function_string(),
|
2024-04-29 22:21:53 +02:00
|
|
|
FIXED_ONE_BYTE_STRING(isolate, "canParseAsESM"),
|
2024-03-12 03:18:53 +08:00
|
|
|
};
|
|
|
|
std::vector<Local<Value>> values = {
|
|
|
|
Boolean::New(isolate, cache_rejected),
|
2024-04-29 22:21:53 +02:00
|
|
|
fn.IsEmpty() ? undefined : fn->GetScriptOrigin().SourceMapUrl(),
|
|
|
|
fn.IsEmpty() ? undefined : fn.As<Value>(),
|
|
|
|
Boolean::New(isolate, can_parse_as_esm),
|
2024-03-12 03:18:53 +08:00
|
|
|
};
|
|
|
|
Local<Object> result = Object::New(
|
|
|
|
isolate, v8::Null(isolate), names.data(), values.data(), names.size());
|
|
|
|
args.GetReturnValue().Set(result);
|
|
|
|
}
|
|
|
|
|
2024-04-29 22:21:53 +02:00
|
|
|
bool ShouldRetryAsESM(Realm* realm,
|
|
|
|
Local<String> message,
|
|
|
|
Local<String> code,
|
|
|
|
Local<String> resource_name) {
|
2024-04-19 16:29:08 +02:00
|
|
|
Isolate* isolate = realm->isolate();
|
|
|
|
|
|
|
|
Utf8Value message_value(isolate, message);
|
|
|
|
auto message_view = message_value.ToStringView();
|
|
|
|
|
|
|
|
// These indicates that the file contains syntaxes that are only valid in
|
|
|
|
// ESM. So it must be true.
|
|
|
|
for (const auto& error_message : esm_syntax_error_messages) {
|
|
|
|
if (message_view.find(error_message) != std::string_view::npos) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the error message is allowed in ESM but not in CommonJS. If it
|
|
|
|
// is the case, let's check if file can be compiled as ESM.
|
|
|
|
bool maybe_valid_in_esm = false;
|
|
|
|
for (const auto& error_message : throws_only_in_cjs_error_messages) {
|
|
|
|
if (message_view.find(error_message) != std::string_view::npos) {
|
|
|
|
maybe_valid_in_esm = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!maybe_valid_in_esm) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cache_rejected = false;
|
|
|
|
TryCatchScope try_catch(realm->env());
|
|
|
|
ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env());
|
|
|
|
Local<v8::Module> module;
|
|
|
|
Local<PrimitiveArray> hdo = loader::ModuleWrap::GetHostDefinedOptions(
|
|
|
|
isolate, realm->isolate_data()->source_text_module_default_hdo());
|
|
|
|
if (loader::ModuleWrap::CompileSourceTextModule(
|
2024-04-29 22:21:53 +02:00
|
|
|
realm, code, resource_name, 0, 0, hdo, std::nullopt, &cache_rejected)
|
2024-04-19 16:29:08 +02:00
|
|
|
.ToLocal(&module)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ShouldRetryAsESM(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Realm* realm = Realm::GetCurrent(args);
|
|
|
|
|
|
|
|
CHECK_EQ(args.Length(), 3); // message, code, resource_name
|
|
|
|
CHECK(args[0]->IsString());
|
|
|
|
Local<String> message = args[0].As<String>();
|
|
|
|
CHECK(args[1]->IsString());
|
|
|
|
Local<String> code = args[1].As<String>();
|
|
|
|
CHECK(args[2]->IsString());
|
|
|
|
Local<String> resource_name = args[2].As<String>();
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(
|
|
|
|
ShouldRetryAsESM(realm, message, code, resource_name));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ContainsModuleSyntax(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Isolate* isolate = args.GetIsolate();
|
|
|
|
Local<Context> context = isolate->GetCurrentContext();
|
|
|
|
Realm* realm = Realm::GetCurrent(context);
|
|
|
|
Environment* env = realm->env();
|
|
|
|
|
|
|
|
CHECK_GE(args.Length(), 2);
|
|
|
|
|
|
|
|
// Argument 1: source code
|
|
|
|
CHECK(args[0]->IsString());
|
|
|
|
Local<String> code = args[0].As<String>();
|
|
|
|
|
|
|
|
// Argument 2: filename
|
|
|
|
CHECK(args[1]->IsString());
|
|
|
|
Local<String> filename = args[1].As<String>();
|
|
|
|
|
2024-05-25 05:51:47 +03:00
|
|
|
// Argument 3: resource name (URL for ES module).
|
2024-04-19 16:29:08 +02:00
|
|
|
Local<String> resource_name = filename;
|
|
|
|
if (args[2]->IsString()) {
|
|
|
|
resource_name = args[2].As<String>();
|
|
|
|
}
|
2024-05-25 05:51:47 +03:00
|
|
|
// Argument 4: flag to indicate if CJS variables should not be in scope
|
|
|
|
// (they should be for normal CommonJS modules, but not for the
|
|
|
|
// CommonJS eval scope).
|
|
|
|
bool cjs_var = !args[3]->IsString();
|
2024-04-19 16:29:08 +02:00
|
|
|
|
|
|
|
bool cache_rejected = false;
|
|
|
|
Local<String> message;
|
|
|
|
{
|
|
|
|
Local<Function> fn;
|
|
|
|
TryCatchScope try_catch(env);
|
|
|
|
ShouldNotAbortOnUncaughtScope no_abort_scope(env);
|
|
|
|
if (CompileFunctionForCJSLoader(
|
2024-07-05 21:58:35 +02:00
|
|
|
env, context, code, filename, &cache_rejected, cjs_var, nullptr)
|
2024-04-19 16:29:08 +02:00
|
|
|
.ToLocal(&fn)) {
|
|
|
|
args.GetReturnValue().Set(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CHECK(try_catch.HasCaught());
|
|
|
|
message = try_catch.Message()->Get();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool result = ShouldRetryAsESM(realm, message, code, resource_name);
|
|
|
|
args.GetReturnValue().Set(result);
|
|
|
|
}
|
|
|
|
|
2019-04-18 10:58:58 +08:00
|
|
|
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
int ret = SigintWatchdogHelper::GetInstance()->Start();
|
|
|
|
args.GetReturnValue().Set(ret == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
|
|
|
|
args.GetReturnValue().Set(had_pending_signals);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
|
|
|
|
args.GetReturnValue().Set(ret);
|
|
|
|
}
|
2018-06-28 12:05:19 +05:30
|
|
|
|
2020-02-08 01:49:43 +08:00
|
|
|
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
CHECK(args[0]->IsInt32());
|
2020-04-22 10:28:20 +08:00
|
|
|
CHECK(args[1]->IsInt32());
|
2020-02-08 01:49:43 +08:00
|
|
|
int32_t mode = args[0].As<v8::Int32>()->Value();
|
2020-04-22 10:28:20 +08:00
|
|
|
int32_t execution = args[1].As<v8::Int32>()->Value();
|
2020-02-08 01:49:43 +08:00
|
|
|
Isolate* isolate = args.GetIsolate();
|
2020-04-22 10:28:20 +08:00
|
|
|
|
|
|
|
Local<Context> current_context = isolate->GetCurrentContext();
|
2020-03-04 19:43:37 +08:00
|
|
|
Local<Promise::Resolver> resolver;
|
2020-04-22 10:28:20 +08:00
|
|
|
if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
|
|
|
|
std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
|
2020-03-04 19:43:37 +08:00
|
|
|
v8::MeasureMemoryDelegate::Default(
|
2020-04-22 10:28:20 +08:00
|
|
|
isolate,
|
|
|
|
current_context,
|
|
|
|
resolver,
|
|
|
|
static_cast<v8::MeasureMemoryMode>(mode));
|
|
|
|
isolate->MeasureMemory(std::move(delegate),
|
|
|
|
static_cast<v8::MeasureMemoryExecution>(execution));
|
2022-08-21 03:53:42 -05:00
|
|
|
Local<Promise> promise = resolver->GetPromise();
|
2020-03-04 19:43:37 +08:00
|
|
|
|
2020-02-08 01:49:43 +08:00
|
|
|
args.GetReturnValue().Set(promise);
|
|
|
|
}
|
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
void CreatePerIsolateProperties(IsolateData* isolate_data,
|
2023-05-06 18:07:19 +02:00
|
|
|
Local<ObjectTemplate> target) {
|
2023-04-28 18:30:47 +02:00
|
|
|
Isolate* isolate = isolate_data->isolate();
|
2023-05-06 18:07:19 +02:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
ContextifyContext::CreatePerIsolateProperties(isolate_data, target);
|
|
|
|
ContextifyScript::CreatePerIsolateProperties(isolate_data, target);
|
2019-04-18 10:58:58 +08:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
SetMethod(isolate, target, "startSigintWatchdog", StartSigintWatchdog);
|
|
|
|
SetMethod(isolate, target, "stopSigintWatchdog", StopSigintWatchdog);
|
2019-04-18 10:58:58 +08:00
|
|
|
// Used in tests.
|
2022-08-02 00:01:02 +08:00
|
|
|
SetMethodNoSideEffect(
|
2023-04-28 18:30:47 +02:00
|
|
|
isolate, target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
|
2019-07-20 19:35:24 +02:00
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
SetMethod(isolate, target, "measureMemory", MeasureMemory);
|
2024-03-12 03:18:53 +08:00
|
|
|
SetMethod(isolate,
|
|
|
|
target,
|
|
|
|
"compileFunctionForCJSLoader",
|
|
|
|
CompileFunctionForCJSLoader);
|
2024-04-19 16:29:08 +02:00
|
|
|
|
|
|
|
SetMethod(isolate, target, "containsModuleSyntax", ContainsModuleSyntax);
|
|
|
|
SetMethod(isolate, target, "shouldRetryAsESM", ShouldRetryAsESM);
|
2023-04-28 18:30:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void CreatePerContextProperties(Local<Object> target,
|
|
|
|
Local<Value> unused,
|
|
|
|
Local<Context> context,
|
|
|
|
void* priv) {
|
|
|
|
Environment* env = Environment::GetCurrent(context);
|
|
|
|
Isolate* isolate = env->isolate();
|
2020-02-08 01:49:43 +08:00
|
|
|
|
|
|
|
Local<Object> constants = Object::New(env->isolate());
|
|
|
|
Local<Object> measure_memory = Object::New(env->isolate());
|
2020-04-22 10:28:20 +08:00
|
|
|
Local<Object> memory_execution = Object::New(env->isolate());
|
|
|
|
|
|
|
|
{
|
|
|
|
Local<Object> memory_mode = Object::New(env->isolate());
|
|
|
|
MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
|
|
|
|
MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
|
|
|
|
NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
|
|
|
|
NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
|
|
|
|
READONLY_PROPERTY(measure_memory, "mode", memory_mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
|
|
|
|
MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
|
|
|
|
NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
|
|
|
|
NODE_DEFINE_CONSTANT(memory_execution, EAGER);
|
|
|
|
READONLY_PROPERTY(measure_memory, "execution", memory_execution);
|
|
|
|
}
|
|
|
|
|
2020-02-08 01:49:43 +08:00
|
|
|
READONLY_PROPERTY(constants, "measureMemory", measure_memory);
|
2020-04-22 10:28:20 +08:00
|
|
|
|
2020-02-08 01:49:43 +08:00
|
|
|
target->Set(context, env->constants_string(), constants).Check();
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
}
|
|
|
|
|
2021-05-14 00:58:19 +08:00
|
|
|
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|
|
|
ContextifyContext::RegisterExternalReferences(registry);
|
|
|
|
ContextifyScript::RegisterExternalReferences(registry);
|
|
|
|
|
2024-03-12 03:18:53 +08:00
|
|
|
registry->Register(CompileFunctionForCJSLoader);
|
2021-05-14 00:58:19 +08:00
|
|
|
registry->Register(StartSigintWatchdog);
|
|
|
|
registry->Register(StopSigintWatchdog);
|
|
|
|
registry->Register(WatchdogHasPendingSigint);
|
|
|
|
registry->Register(MeasureMemory);
|
2024-04-19 16:29:08 +02:00
|
|
|
registry->Register(ContainsModuleSyntax);
|
|
|
|
registry->Register(ShouldRetryAsESM);
|
2021-05-14 00:58:19 +08:00
|
|
|
}
|
2017-12-09 10:32:34 -06:00
|
|
|
} // namespace contextify
|
vm, core, module: re-do vm to fix known issues
As documented in #3042 and in [1], the existing vm implementation has
many problems. All of these are solved by @brianmcd's [contextify][2]
package. This commit uses contextify as a conceptual base and its code
core to overhaul the vm module and fix its many edge cases and caveats.
Functionally, this fixes #3042. In particular:
- A context is now indistinguishable from the object it is based on
(the "sandbox"). A context is simply a sandbox that has been marked
by the vm module, via `vm.createContext`, with special internal
information that allows scripts to be run inside of it.
- Consequently, items added to the context from anywhere are
immediately visible to all code that can access that context, both
inside and outside the virtual machine.
This commit also smooths over the API very slightly:
- Parameter defaults are now uniformly triggered via `undefined`, per
ES6 semantics and previous discussion at [3].
- Several undocumented and problematic features have been removed, e.g.
the conflation of `vm.Script` with `vm` itself, and the fact that
`Script` instances also had all static `vm` methods. The API is now
exactly as documented (although arguably the existence of the
`vm.Script` export is not yet documented, just the `Script` class
itself).
In terms of implementation, this replaces node_script.cc with
node_contextify.cc, which is derived originally from [4] (see [5]) but
has since undergone extensive modifications and iterations to expose
the most useful C++ API and use the coding conventions and utilities of
Node core.
The bindings exposed by `process.binding('contextify')`
(node_contextify.cc) replace those formerly exposed by
`process.binding('evals')` (node_script.cc). They are:
- ContextifyScript(code, [filename]), with methods:
- runInThisContext()
- runInContext(sandbox, [timeout])
- makeContext(sandbox)
From this, the vm.js file builds the entire documented vm module API.
node.js and module.js were modified to use this new native binding, or
the vm module itself where possible. This introduces an extra line or
two into the stack traces of module compilation (and thus into most
stack traces), explaining the changed tests.
The tests were also updated slightly, with all vm-related simple tests
consolidated as test/simple/test-vm-* (some of them were formerly
test/simple/test-script-*). At the same time they switched from
`common.debug` to `console.error` and were updated to use
`assert.throws` instead of rolling their own error-testing methods.
New tests were also added, of course, demonstrating the new
capabilities and fixes.
[1]: http://nodejs.org/docs/v0.10.16/api/vm.html#vm_caveats
[2]: https://github.com/brianmcd/contextify
[3]: https://github.com/joyent/node/issues/5323#issuecomment-20250726
[4]: https://github.com/kkoopa/contextify/blob/bf123f3ef960f0943d1e30bda02e3163a004e964/src/contextify.cc
[5]: https://gist.github.com/domenic/6068120
2013-07-27 00:34:12 -04:00
|
|
|
} // namespace node
|
|
|
|
|
2023-04-28 18:30:47 +02:00
|
|
|
NODE_BINDING_CONTEXT_AWARE_INTERNAL(
|
|
|
|
contextify, node::contextify::CreatePerContextProperties)
|
|
|
|
NODE_BINDING_PER_ISOLATE_INIT(contextify,
|
|
|
|
node::contextify::CreatePerIsolateProperties)
|
2022-11-21 01:37:56 +08:00
|
|
|
NODE_BINDING_EXTERNAL_REFERENCE(contextify,
|
|
|
|
node::contextify::RegisterExternalReferences)
|