GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — vm: introduce vanilla contexts via vm.constants.DONT_CONTEXTIFY · nodejs/node@2d90340

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • doc/api
    • vm.md
  • lib
    • vm.js
  • src
    • env_properties.h
    • node_contextify.cc
    • node_contextify.h
  • test/parallel
    • test-vm-context-dont-contextify.js
  • tools/doc
    • type-parser.mjs
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/vm.md‎

Copy file name to clipboardExpand all lines: doc/api/vm.md
+143-23Lines changed: 143 additions & 23 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ overhead.
228228
<!-- YAML
229229
added: v0.3.1
230230
changes:
231+
- version: REPLACEME
232+
pr-url: https://github.com/nodejs/node/pull/54394
233+
description: The `contextObject` argument now accepts `vm.constants.DONT_CONTEXTIFY`.
231234
- version: v14.6.0
232235
pr-url: https://github.com/nodejs/node/pull/34023
233236
description: The `microtaskMode` option is supported now.
@@ -239,8 +242,9 @@ changes:
239242
description: The `breakOnSigint` option is supported now.
240243
-->
241244

242-
* `contextObject` {Object} An object that will be [contextified][]. If
243-
`undefined`, a new object will be created.
245+
* `contextObject` {Object|vm.constants.DONT\_CONTEXTIFY|undefined}
246+
Either [`vm.constants.DONT_CONTEXTIFY`][] or an object that will be [contextified][].
247+
If `undefined`, an empty contextified object will be created for backwards compatibility.
244248
* `options` {Object}
245249
* `displayErrors` {boolean} When `true`, if an [`Error`][] occurs
246250
while compiling the `code`, the line of code causing the error is attached
@@ -274,9 +278,16 @@ changes:
274278
`breakOnSigint` scopes in that case.
275279
* Returns: {any} the result of the very last statement executed in the script.
276280

277-
First contextifies the given `contextObject`, runs the compiled code contained
278-
by the `vm.Script` object within the created context, and returns the result.
279-
Running code does not have access to local scope.
281+
This method is a shortcut to `script.runInContext(vm.createContext(options), options)`.
282+
It does several things at once:
283+
284+
1. Creates a new context.
285+
2. If `contextObject` is an object, [contextifies][contextified] it with the new context.
286+
If `contextObject` is undefined, creates a new object and [contextifies][contextified] it.
287+
If `contextObject` is [`vm.constants.DONT_CONTEXTIFY`][], don't [contextify][contextified] anything.
288+
3. Runs the compiled code contained by the `vm.Script` object within the created context. The code
289+
does not have access to the scope in which this method is called.
290+
4. Returns the result.
280291

281292
The following example compiles code that sets a global variable, then executes
282293
the code multiple times in different contexts. The globals are set on and
@@ -294,6 +305,12 @@ contexts.forEach((context) => {
294305

295306
console.log(contexts);
296307
// Prints: [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
308+
309+
// This would throw if the context is created from a contextified object.
310+
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary
311+
// global objects that can be frozen.
312+
const freezeScript = new vm.Script('Object.freeze(globalThis); globalThis;');
313+
const frozenContext = freezeScript.runInNewContext(vm.constants.DONT_CONTEXTIFY);
297314
```
298315

299316
### `script.runInThisContext([options])`
@@ -1063,6 +1080,10 @@ For detailed information, see
10631080
<!-- YAML
10641081
added: v0.3.1
10651082
changes:
1083+
- version:
1084+
- REPLACEME
1085+
pr-url: https://github.com/nodejs/node/pull/54394
1086+
description: The `contextObject` argument now accepts `vm.constants.DONT_CONTEXTIFY`.
10661087
- version:
10671088
- v20.12.0
10681089
pr-url: https://github.com/nodejs/node/pull/51244
@@ -1083,7 +1104,9 @@ changes:
10831104
description: The `codeGeneration` option is supported now.
10841105
-->
10851106

1086-
* `contextObject` {Object}
1107+
* `contextObject` {Object|vm.constants.DONT\_CONTEXTIFY|undefined}
1108+
Either [`vm.constants.DONT_CONTEXTIFY`][] or an object that will be [contextified][].
1109+
If `undefined`, an empty contextified object will be created for backwards compatibility.
10871110
* `options` {Object}
10881111
* `name` {string} Human-readable name of the newly created context.
10891112
**Default:** `'VM Context i'`, where `i` is an ascending numerical index of
@@ -1113,10 +1136,10 @@ changes:
11131136
[Support of dynamic `import()` in compilation APIs][].
11141137
* Returns: {Object} contextified object.
11151138

1116-
If given a `contextObject`, the `vm.createContext()` method will [prepare that
1139+
If the given `contextObject` is an object, the `vm.createContext()` method will [prepare that
11171140
object][contextified] and return a reference to it so that it can be used in
11181141
calls to [`vm.runInContext()`][] or [`script.runInContext()`][]. Inside such
1119-
scripts, the `contextObject` will be the global object, retaining all of its
1142+
scripts, the global object will be wrapped by the `contextObject`, retaining all of its
11201143
existing properties but also having the built-in objects and functions any
11211144
standard [global object][] has. Outside of scripts run by the vm module, global
11221145
variables will remain unchanged.
@@ -1141,6 +1164,11 @@ console.log(global.globalVar);
11411164
If `contextObject` is omitted (or passed explicitly as `undefined`), a new,
11421165
empty [contextified][] object will be returned.
11431166

1167+
When the global object in the newly created context is [contextified][], it has some quirks
1168+
compared to ordinary global objects. For example, it cannot be frozen. To create a context
1169+
without the contextifying quirks, pass [`vm.constants.DONT_CONTEXTIFY`][] as the `contextObject`
1170+
argument. See the documentation of [`vm.constants.DONT_CONTEXTIFY`][] for details.
1171+
11441172
The `vm.createContext()` method is primarily useful for creating a single
11451173
context that can be used to run multiple scripts. For instance, if emulating a
11461174
web browser, the method can be used to create a single context representing a
@@ -1160,7 +1188,8 @@ added: v0.11.7
11601188
* Returns: {boolean}
11611189
11621190
Returns `true` if the given `object` object has been [contextified][] using
1163-
[`vm.createContext()`][].
1191+
[`vm.createContext()`][], or if it's the global object of a context created
1192+
using [`vm.constants.DONT_CONTEXTIFY`][].
11641193

11651194
## `vm.measureMemory([options])`
11661195

@@ -1320,6 +1349,10 @@ console.log(contextObject);
13201349
<!-- YAML
13211350
added: v0.3.1
13221351
changes:
1352+
- version:
1353+
- REPLACEME
1354+
pr-url: https://github.com/nodejs/node/pull/54394
1355+
description: The `contextObject` argument now accepts `vm.constants.DONT_CONTEXTIFY`.
13231356
- version:
13241357
- v20.12.0
13251358
pr-url: https://github.com/nodejs/node/pull/51244
@@ -1343,8 +1376,9 @@ changes:
13431376
-->
13441377
13451378
* `code` {string} The JavaScript code to compile and run.
1346-
* `contextObject` {Object} An object that will be [contextified][]. If
1347-
`undefined`, a new object will be created.
1379+
* `contextObject` {Object|vm.constants.DONT\_CONTEXTIFY|undefined}
1380+
Either [`vm.constants.DONT_CONTEXTIFY`][] or an object that will be [contextified][].
1381+
If `undefined`, an empty contextified object will be created for backwards compatibility.
13481382
* `options` {Object|string}
13491383
* `filename` {string} Specifies the filename used in stack traces produced
13501384
by this script. **Default:** `'evalmachine.<anonymous>'`.
@@ -1394,13 +1428,21 @@ changes:
13941428
`breakOnSigint` scopes in that case.
13951429
* Returns: {any} the result of the very last statement executed in the script.
13961430

1397-
The `vm.runInNewContext()` first contextifies the given `contextObject` (or
1398-
creates a new `contextObject` if passed as `undefined`), compiles the `code`,
1399-
runs it within the created context, then returns the result. Running code
1400-
does not have access to the local scope.
1401-
1431+
This method is a shortcut to
1432+
`(new vm.Script(code, options)).runInContext(vm.createContext(options), options)`.
14021433
If `options` is a string, then it specifies the filename.
14031434

1435+
It does several things at once:
1436+
1437+
1. Creates a new context.
1438+
2. If `contextObject` is an object, [contextifies][contextified] it with the new context.
1439+
If `contextObject` is undefined, creates a new object and [contextifies][contextified] it.
1440+
If `contextObject` is [`vm.constants.DONT_CONTEXTIFY`][], don't [contextify][contextified] anything.
1441+
3. Compiles the code as a`vm.Script`
1442+
4. Runs the compield code within the created context. The code does not have access to the scope in
1443+
which this method is called.
1444+
5. Returns the result.
1445+
14041446
The following example compiles and executes code that increments a global
14051447
variable and sets a new one. These globals are contained in the `contextObject`.
14061448
@@ -1415,6 +1457,11 @@ const contextObject = {
14151457
vm.runInNewContext('count += 1; name = "kitty"', contextObject);
14161458
console.log(contextObject);
14171459
// Prints: { animal: 'cat', count: 3, name: 'kitty' }
1460+
1461+
// This would throw if the context is created from a contextified object.
1462+
// vm.constants.DONT_CONTEXTIFY allows creating contexts with ordinary global objects that
1463+
// can be frozen.
1464+
const frozenContext = vm.runInNewContext('Object.freeze(globalThis); globalThis;', vm.constants.DONT_CONTEXTIFY);
14181465
```
14191466
14201467
## `vm.runInThisContext(code[, options])`
@@ -1541,13 +1588,85 @@ According to the [V8 Embedder's Guide][]:
15411588
> JavaScript applications to run in a single instance of V8. You must explicitly
15421589
> specify the context in which you want any JavaScript code to be run.
15431590
1544-
When the method `vm.createContext()` is called, the `contextObject` argument
1545-
(or a newly-created object if `contextObject` is `undefined`) is associated
1546-
internally with a new instance of a V8 Context. This V8 Context provides the
1547-
`code` run using the `node:vm` module's methods with an isolated global
1548-
environment within which it can operate. The process of creating the V8 Context
1549-
and associating it with the `contextObject` is what this document refers to as
1550-
"contextifying" the object.
1591+
When the method `vm.createContext()` is called with an object, the `contextObject` argument
1592+
will be used to wrap the global object of a new instance of a V8 Context
1593+
(if `contextObject` is `undefined`, a new object will be created from the current context
1594+
before its contextified). This V8 Context provides the `code` run using the `node:vm`
1595+
module's methods with an isolated global environment within which it can operate.
1596+
The process of creating the V8 Context and associating it with the `contextObject`
1597+
in the outer context is what this document refers to as "contextifying" the object.
1598+
1599+
The contextifying would introduce some quirks to the `globalThis` value in the context.
1600+
For example, it cannot be frozen, and it is not reference equal to the `contextObject`
1601+
in the outer context.
1602+
1603+
```js
1604+
const vm = require('node:vm');
1605+
1606+
// An undefined `contextObject` option makes the global object contextified.
1607+
const context = vm.createContext();
1608+
console.log(vm.runInContext('globalThis', context) === context); // false
1609+
// A contextified global object cannot be frozen.
1610+
try {
1611+
vm.runInContext('Object.freeze(globalThis);', context);
1612+
} catch (e) {
1613+
console.log(e); // TypeError: Cannot freeze
1614+
}
1615+
console.log(vm.runInContext('globalThis.foo = 1; foo;', context)); // 1
1616+
```
1617+
1618+
To create a context with an ordinary global object and get access to a global proxy in
1619+
the outer context with fewer quirks, specify `vm.constants.DONT_CONTEXTIFY` as the
1620+
`contextObject` argument.
1621+
1622+
### `vm.constants.DONT_CONTEXTIFY`
1623+
1624+
This constant, when used as the `contextObject` argument in vm APIs, instructs Node.js to create
1625+
a context without wrapping its global object with another object in a Node.js-specific manner.
1626+
As a result, the `globalThis` value inside the new context would behave more closely to an ordinary
1627+
one.
1628+
1629+
```js
1630+
const vm = require('node:vm');
1631+
1632+
// Use vm.constants.DONT_CONTEXTIFY to freeze the global object.
1633+
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY);
1634+
vm.runInContext('Object.freeze(globalThis);', context);
1635+
try {
1636+
vm.runInContext('bar = 1; bar;', context);
1637+
} catch (e) {
1638+
console.log(e); // Uncaught ReferenceError: bar is not defined
1639+
}
1640+
```
1641+
1642+
When `vm.constants.DONT_CONTEXTIFY` is used as the `contextObject` argument to [`vm.createContext()`][],
1643+
the returned object is a proxy-like object to the global object in the newly created context with
1644+
fewer Node.js-specific quirks. It is reference equal to the `globalThis` value in the new context,
1645+
can be modified from outside the context, and can be used to access built-ins in the new context directly.
1646+
1647+
```js
1648+
const vm = require('node:vm');
1649+
1650+
const context = vm.createContext(vm.constants.DONT_CONTEXTIFY);
1651+
1652+
// Returned object is reference equal to globalThis in the new context.
1653+
console.log(vm.runInContext('globalThis', context) === context); // true
1654+
1655+
// Can be used to access globals in the new context directly.
1656+
console.log(context.Array); // [Function: Array]
1657+
vm.runInContext('foo = 1;', context);
1658+
console.log(context.foo); // 1
1659+
context.bar = 1;
1660+
console.log(vm.runInContext('bar;', context)); // 1
1661+
1662+
// Can be frozen and it affects the inner context.
1663+
Object.freeze(context);
1664+
try {
1665+
vm.runInContext('baz = 1; baz;', context);
1666+
} catch (e) {
1667+
console.log(e); // Uncaught ReferenceError: baz is not defined
1668+
}
1669+
```
15511670

15521671
## Timeout interactions with asynchronous tasks and Promises
15531672

@@ -1837,6 +1956,7 @@ const { Script, SyntheticModule } = require('node:vm');
18371956
[`script.runInThisContext()`]: #scriptruninthiscontextoptions
18381957
[`url.origin`]: url.md#urlorigin
18391958
[`vm.compileFunction()`]: #vmcompilefunctioncode-params-options
1959+
[`vm.constants.DONT_CONTEXTIFY`]: #vmconstantsdont_contextify
18401960
[`vm.createContext()`]: #vmcreatecontextcontextobject-options
18411961
[`vm.runInContext()`]: #vmrunincontextcode-contextifiedobject-options
18421962
[`vm.runInThisContext()`]: #vmruninthiscontextcode-options
Collapse file

‎lib/vm.js‎

Copy file name to clipboardExpand all lines: lib/vm.js
+6-4Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ const {
6565
} = require('internal/vm');
6666
const {
6767
vm_dynamic_import_main_context_default,
68+
vm_context_no_contextify,
6869
} = internalBinding('symbols');
6970
const kParsingContext = Symbol('script parsing context');
7071

@@ -222,7 +223,7 @@ function getContextOptions(options) {
222223

223224
let defaultContextNameIndex = 1;
224225
function createContext(contextObject = {}, options = kEmptyObject) {
225-
if (isContext(contextObject)) {
226+
if (contextObject !== vm_context_no_contextify && isContext(contextObject)) {
226227
return contextObject;
227228
}
228229

@@ -258,10 +259,10 @@ function createContext(contextObject = {}, options = kEmptyObject) {
258259
const hostDefinedOptionId =
259260
getHostDefinedOptionId(importModuleDynamically, name);
260261

261-
makeContext(contextObject, name, origin, strings, wasm, microtaskQueue, hostDefinedOptionId);
262+
const result = makeContext(contextObject, name, origin, strings, wasm, microtaskQueue, hostDefinedOptionId);
262263
// Register the context scope callback after the context was initialized.
263-
registerImportModuleDynamically(contextObject, importModuleDynamically);
264-
return contextObject;
264+
registerImportModuleDynamically(result, importModuleDynamically);
265+
return result;
265266
}
266267

267268
function createScript(code, options) {
@@ -394,6 +395,7 @@ function measureMemory(options = kEmptyObject) {
394395
const vmConstants = {
395396
__proto__: null,
396397
USE_MAIN_CONTEXT_DEFAULT_LOADER: vm_dynamic_import_main_context_default,
398+
DONT_CONTEXTIFY: vm_context_no_contextify,
397399
};
398400

399401
ObjectFreeze(vmConstants);
Collapse file

‎src/env_properties.h‎

Copy file name to clipboardExpand all lines: src/env_properties.h
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
V(resource_symbol, "resource_symbol") \
5353
V(trigger_async_id_symbol, "trigger_async_id_symbol") \
5454
V(source_text_module_default_hdo, "source_text_module_default_hdo") \
55+
V(vm_context_no_contextify, "vm_context_no_contextify") \
5556
V(vm_dynamic_import_default_internal, "vm_dynamic_import_default_internal") \
5657
V(vm_dynamic_import_main_context_default, \
5758
"vm_dynamic_import_main_context_default") \

0 commit comments

Comments
0 (0)
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.