xref: /third_party/node/lib/internal/vm.js (revision 1cb0ef41)
1'use strict';
2
3const {
4  ReflectApply,
5  Symbol,
6} = primordials;
7
8const {
9  ContextifyScript,
10  compileFunction,
11  isContext: _isContext,
12} = internalBinding('contextify');
13const {
14  runInContext,
15} = ContextifyScript.prototype;
16const {
17  default_host_defined_options,
18  vm_dynamic_import_missing_flag,
19} = internalBinding('symbols');
20const {
21  validateFunction,
22  validateObject,
23} = require('internal/validators');
24
25const {
26  getOptionValue,
27} = require('internal/options');
28
29
30function isContext(object) {
31  validateObject(object, 'object', { __proto__: null, allowArray: true });
32
33  return _isContext(object);
34}
35
36function getHostDefinedOptionId(importModuleDynamically, filename) {
37  if (importModuleDynamically !== undefined) {
38    // Check that it's either undefined or a function before we pass
39    // it into the native constructor.
40    validateFunction(importModuleDynamically,
41                     'options.importModuleDynamically');
42  }
43  if (importModuleDynamically === undefined) {
44    // We need a default host defined options that are the same for all
45    // scripts not needing custom module callbacks so that the isolate
46    // compilation cache can be hit.
47    return default_host_defined_options;
48  }
49  // We should've thrown here immediately when we introduced
50  // --experimental-vm-modules and importModuleDynamically, but since
51  // users are already using this callback to throw a similar error,
52  // we also defer the error to the time when an actual import() is called
53  // to avoid breaking them. To ensure that the isolate compilation
54  // cache can still be hit, use a constant sentinel symbol here.
55  if (!getOptionValue('--experimental-vm-modules')) {
56    return vm_dynamic_import_missing_flag;
57  }
58
59  return Symbol(filename);
60}
61
62function registerImportModuleDynamically(referrer, importModuleDynamically) {
63  const { importModuleDynamicallyWrap } = require('internal/vm/module');
64  const { registerModule } = require('internal/modules/esm/utils');
65  registerModule(referrer, {
66    __proto__: null,
67    importModuleDynamically:
68      importModuleDynamicallyWrap(importModuleDynamically),
69  });
70}
71
72function internalCompileFunction(
73  code, filename, lineOffset, columnOffset,
74  cachedData, produceCachedData, parsingContext, contextExtensions,
75  params, hostDefinedOptionId, importModuleDynamically) {
76  const result = compileFunction(
77    code,
78    filename,
79    lineOffset,
80    columnOffset,
81    cachedData,
82    produceCachedData,
83    parsingContext,
84    contextExtensions,
85    params,
86    hostDefinedOptionId,
87  );
88
89  if (produceCachedData) {
90    result.function.cachedDataProduced = result.cachedDataProduced;
91  }
92
93  if (result.cachedData) {
94    result.function.cachedData = result.cachedData;
95  }
96
97  if (typeof result.cachedDataRejected === 'boolean') {
98    result.function.cachedDataRejected = result.cachedDataRejected;
99  }
100
101  if (importModuleDynamically !== undefined) {
102    registerImportModuleDynamically(result.function, importModuleDynamically);
103  }
104
105  return result;
106}
107
108function makeContextifyScript(code,
109                              filename,
110                              lineOffset,
111                              columnOffset,
112                              cachedData,
113                              produceCachedData,
114                              parsingContext,
115                              hostDefinedOptionId,
116                              importModuleDynamically) {
117  let script;
118  // Calling `ReThrow()` on a native TryCatch does not generate a new
119  // abort-on-uncaught-exception check. A dummy try/catch in JS land
120  // protects against that.
121  try { // eslint-disable-line no-useless-catch
122    script = new ContextifyScript(code,
123                                  filename,
124                                  lineOffset,
125                                  columnOffset,
126                                  cachedData,
127                                  produceCachedData,
128                                  parsingContext,
129                                  hostDefinedOptionId);
130  } catch (e) {
131    throw e; /* node-do-not-add-exception-line */
132  }
133
134  if (importModuleDynamically !== undefined) {
135    registerImportModuleDynamically(script, importModuleDynamically);
136  }
137  return script;
138}
139
140// Internal version of vm.Script.prototype.runInThisContext() which skips
141// argument validation.
142function runScriptInThisContext(script, displayErrors, breakOnFirstLine) {
143  return ReflectApply(
144    runInContext,
145    script,
146    [
147      null,                // sandbox - use current context
148      -1,                  // timeout
149      displayErrors,       // displayErrors
150      false,               // breakOnSigint
151      breakOnFirstLine,    // breakOnFirstLine
152    ],
153  );
154}
155
156module.exports = {
157  getHostDefinedOptionId,
158  internalCompileFunction,
159  isContext,
160  makeContextifyScript,
161  registerImportModuleDynamically,
162  runScriptInThisContext,
163};
164