GeezerVison is showing github.com — vm: use internal versions of compileFunction and Script · nodejs/node@3697c19
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/cjs/loader.js +40-33Lines changed: 40 additions & 33 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -52,6 +52,7 @@ const { | 52 | 52 | SafeMap, | 53 | 53 | SafeWeakMap, | 54 | 54 | String, | | 55 | + Symbol, | 55 | 56 | StringPrototypeCharAt, | 56 | 57 | StringPrototypeCharCodeAt, | 57 | 58 | StringPrototypeEndsWith, | @@ -84,7 +85,12 @@ const { | 84 | 85 | setOwnProperty, | 85 | 86 | getLazy, | 86 | 87 | } = require('internal/util'); | 87 | | -const { internalCompileFunction } = require('internal/vm'); | | 88 | +const { | | 89 | + internalCompileFunction, | | 90 | + makeContextifyScript, | | 91 | + runScriptInThisContext, | | 92 | +} = require('internal/vm'); | | 93 | + | 88 | 94 | const assert = require('internal/assert'); | 89 | 95 | const fs = require('fs'); | 90 | 96 | const path = require('path'); | @@ -1240,7 +1246,6 @@ Module.prototype.require = function(id) { | 1240 | 1246 | let resolvedArgv; | 1241 | 1247 | let hasPausedEntry = false; | 1242 | 1248 | /** @type {import('vm').Script} */ | 1243 | | -let Script; | 1244 | 1249 |
| 1245 | 1250 | /** | 1246 | 1251 | * Wraps the given content in a script and runs it in a new context. | @@ -1250,47 +1255,49 @@ let Script; | 1250 | 1255 | * @param {object} codeCache The SEA code cache | 1251 | 1256 | */ | 1252 | 1257 | function wrapSafe(filename, content, cjsModuleInstance, codeCache) { | | 1258 | + const hostDefinedOptionId = Symbol(`cjs:${filename}`); | | 1259 | + async function importModuleDynamically(specifier, _, importAttributes) { | | 1260 | + const cascadedLoader = getCascadedLoader(); | | 1261 | + return cascadedLoader.import(specifier, normalizeReferrerURL(filename), | | 1262 | + importAttributes); | | 1263 | + } | 1253 | 1264 | if (patched) { | 1254 | | - const wrapper = Module.wrap(content); | 1255 | | - if (Script === undefined) { | 1256 | | - ({ Script } = require('vm')); | 1257 | | - } | 1258 | | - const script = new Script(wrapper, { | 1259 | | - filename, | 1260 | | - lineOffset: 0, | 1261 | | - importModuleDynamically: async (specifier, _, importAttributes) => { | 1262 | | - const cascadedLoader = getCascadedLoader(); | 1263 | | - return cascadedLoader.import(specifier, normalizeReferrerURL(filename), | 1264 | | - importAttributes); | 1265 | | - }, | 1266 | | - }); | | 1265 | + const wrapped = Module.wrap(content); | | 1266 | + const script = makeContextifyScript( | | 1267 | + wrapped, // code | | 1268 | + filename, // filename | | 1269 | + 0, // lineOffset | | 1270 | + 0, // columnOffset | | 1271 | + undefined, // cachedData | | 1272 | + false, // produceCachedData | | 1273 | + undefined, // parsingContext | | 1274 | + hostDefinedOptionId, // hostDefinedOptionId | | 1275 | + importModuleDynamically, // importModuleDynamically | | 1276 | + ); | 1267 | 1277 |
| 1268 | 1278 | // Cache the source map for the module if present. | 1269 | 1279 | if (script.sourceMapURL) { | 1270 | 1280 | maybeCacheSourceMap(filename, content, this, false, undefined, script.sourceMapURL); | 1271 | 1281 | } | 1272 | 1282 |
| 1273 | | - return script.runInThisContext({ | 1274 | | - displayErrors: true, | 1275 | | - }); | | 1283 | + return runScriptInThisContext(script, true, false); | 1276 | 1284 | } | 1277 | 1285 |
| | 1286 | + const params = [ 'exports', 'require', 'module', '__filename', '__dirname' ]; | 1278 | 1287 | try { | 1279 | | - const result = internalCompileFunction(content, [ | 1280 | | - 'exports', | 1281 | | - 'require', | 1282 | | - 'module', | 1283 | | - '__filename', | 1284 | | - '__dirname', | 1285 | | - ], { | 1286 | | - filename, | 1287 | | - cachedData: codeCache, | 1288 | | - importModuleDynamically(specifier, _, importAttributes) { | 1289 | | - const cascadedLoader = getCascadedLoader(); | 1290 | | - return cascadedLoader.import(specifier, normalizeReferrerURL(filename), | 1291 | | - importAttributes); | 1292 | | - }, | 1293 | | - }); | | 1288 | + const result = internalCompileFunction( | | 1289 | + content, // code, | | 1290 | + filename, // filename | | 1291 | + 0, // lineOffset | | 1292 | + 0, // columnOffset, | | 1293 | + codeCache, // cachedData | | 1294 | + false, // produceCachedData | | 1295 | + undefined, // parsingContext | | 1296 | + undefined, // contextExtensions | | 1297 | + params, // params | | 1298 | + hostDefinedOptionId, // hostDefinedOptionId | | 1299 | + importModuleDynamically, // importModuleDynamically | | 1300 | + ); | 1294 | 1301 |
| 1295 | 1302 | // The code cache is used for SEAs only. | 1296 | 1303 | if (codeCache && | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/modules/esm/translators.js +23-12Lines changed: 23 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -15,6 +15,7 @@ const { | 15 | 15 | StringPrototypeReplaceAll, | 16 | 16 | StringPrototypeSlice, | 17 | 17 | StringPrototypeStartsWith, | | 18 | + Symbol, | 18 | 19 | SyntaxErrorPrototype, | 19 | 20 | globalThis: { WebAssembly }, | 20 | 21 | } = primordials; | @@ -192,19 +193,29 @@ function enrichCJSError(err, content, filename) { | 192 | 193 | */ | 193 | 194 | function loadCJSModule(module, source, url, filename) { | 194 | 195 | let compiledWrapper; | | 196 | + async function importModuleDynamically(specifier, _, importAttributes) { | | 197 | + return asyncESM.esmLoader.import(specifier, url, importAttributes); | | 198 | + } | 195 | 199 | try { | 196 | | - compiledWrapper = internalCompileFunction(source, [ | 197 | | - 'exports', | 198 | | - 'require', | 199 | | - 'module', | 200 | | - '__filename', | 201 | | - '__dirname', | 202 | | - ], { | 203 | | - filename, | 204 | | - importModuleDynamically(specifier, _, importAttributes) { | 205 | | - return asyncESM.esmLoader.import(specifier, url, importAttributes); | 206 | | - }, | 207 | | - }).function; | | 200 | + compiledWrapper = internalCompileFunction( | | 201 | + source, // code, | | 202 | + filename, // filename | | 203 | + 0, // lineOffset | | 204 | + 0, // columnOffset, | | 205 | + undefined, // cachedData | | 206 | + false, // produceCachedData | | 207 | + undefined, // parsingContext | | 208 | + undefined, // contextExtensions | | 209 | + [ // params | | 210 | + 'exports', | | 211 | + 'require', | | 212 | + 'module', | | 213 | + '__filename', | | 214 | + '__dirname', | | 215 | + ], | | 216 | + Symbol(`cjs:${filename}`), // hostDefinedOptionsId | | 217 | + importModuleDynamically, // importModuleDynamically | | 218 | + ).function; | 208 | 219 | } catch (err) { | 209 | 220 | enrichCJSError(err, source, url); | 210 | 221 | throw err; | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/process/execution.js +23-12Lines changed: 23 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | 'use strict'; | 2 | 2 |
| 3 | 3 | const { | | 4 | + Symbol, | 4 | 5 | RegExpPrototypeExec, | 5 | 6 | globalThis, | 6 | 7 | } = primordials; | @@ -25,7 +26,9 @@ const { | 25 | 26 | emitAfter, | 26 | 27 | popAsyncContext, | 27 | 28 | } = require('internal/async_hooks'); | 28 | | - | | 29 | +const { | | 30 | + makeContextifyScript, runScriptInThisContext, | | 31 | +} = require('internal/vm'); | 29 | 32 | // shouldAbortOnUncaughtToggle is a typed array for faster | 30 | 33 | // communication with JS. | 31 | 34 | const { shouldAbortOnUncaughtToggle } = internalBinding('util'); | @@ -53,7 +56,6 @@ function evalModule(source, print) { | 53 | 56 |
| 54 | 57 | function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) { | 55 | 58 | const CJSModule = require('internal/modules/cjs/loader').Module; | 56 | | - const { kVmBreakFirstLineSymbol } = require('internal/util'); | 57 | 59 | const { pathToFileURL } = require('internal/url'); | 58 | 60 |
| 59 | 61 | const cwd = tryGetCwd(); | @@ -79,16 +81,25 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) { | 79 | 81 | `; | 80 | 82 | globalThis.__filename = name; | 81 | 83 | RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs. | 82 | | - const result = module._compile(script, `${name}-wrapper`)(() => | 83 | | - require('vm').runInThisContext(body, { | 84 | | - filename: name, | 85 | | - displayErrors: true, | 86 | | - [kVmBreakFirstLineSymbol]: !!breakFirstLine, | 87 | | - importModuleDynamically(specifier, _, importAttributes) { | 88 | | - const loader = asyncESM.esmLoader; | 89 | | - return loader.import(specifier, baseUrl, importAttributes); | 90 | | - }, | 91 | | - })); | | 84 | + const result = module._compile(script, `${name}-wrapper`)(() => { | | 85 | + const hostDefinedOptionId = Symbol(name); | | 86 | + async function importModuleDynamically(specifier, _, importAttributes) { | | 87 | + const loader = asyncESM.esmLoader; | | 88 | + return loader.import(specifier, baseUrl, importAttributes); | | 89 | + } | | 90 | + const script = makeContextifyScript( | | 91 | + body, // code | | 92 | + name, // filename, | | 93 | + 0, // lineOffset | | 94 | + 0, // columnOffset, | | 95 | + undefined, // cachedData | | 96 | + false, // produceCachedData | | 97 | + undefined, // parsingContext | | 98 | + hostDefinedOptionId, // hostDefinedOptionId | | 99 | + importModuleDynamically, // importModuleDynamically | | 100 | + ); | | 101 | + return runScriptInThisContext(script, true, !!breakFirstLine); | | 102 | + }); | 92 | 103 | if (print) { | 93 | 104 | const { log } = require('internal/console/global'); | 94 | 105 | log(result); | |
Collapse file Copy file name to clipboard +69-62Lines changed: 69 additions & 62 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 1 | 1 | 'use strict'; | 2 | 2 |
| 3 | 3 | const { | 4 | | - ArrayPrototypeForEach, | | 4 | + ReflectApply, | 5 | 5 | Symbol, | 6 | 6 | } = primordials; | 7 | 7 |
| 8 | 8 | const { | | 9 | + ContextifyScript, | 9 | 10 | compileFunction, | 10 | 11 | isContext: _isContext, | 11 | 12 | } = internalBinding('contextify'); | | 13 | +const { | | 14 | + runInContext, | | 15 | +} = ContextifyScript.prototype; | 12 | 16 | const { | 13 | 17 | default_host_defined_options, | 14 | 18 | } = internalBinding('symbols'); | 15 | 19 | const { | 16 | | - validateArray, | 17 | | - validateBoolean, | 18 | | - validateBuffer, | 19 | 20 | validateFunction, | 20 | 21 | validateObject, | 21 | | - validateString, | 22 | | - validateStringArray, | 23 | 22 | kValidateObjectAllowArray, | 24 | | - kValidateObjectAllowNullable, | 25 | | - validateInt32, | 26 | 23 | } = require('internal/validators'); | 27 | | -const { | 28 | | - ERR_INVALID_ARG_TYPE, | 29 | | -} = require('internal/errors').codes; | 30 | 24 |
| 31 | 25 | function isContext(object) { | 32 | 26 | validateObject(object, 'object', kValidateObjectAllowArray); | @@ -50,49 +44,20 @@ function getHostDefinedOptionId(importModuleDynamically, filename) { | 50 | 44 | return Symbol(filename); | 51 | 45 | } | 52 | 46 |
| 53 | | -function internalCompileFunction(code, params, options) { | 54 | | - validateString(code, 'code'); | 55 | | - if (params !== undefined) { | 56 | | - validateStringArray(params, 'params'); | 57 | | - } | 58 | | - const { | 59 | | - filename = '', | 60 | | - columnOffset = 0, | 61 | | - lineOffset = 0, | 62 | | - cachedData = undefined, | 63 | | - produceCachedData = false, | 64 | | - parsingContext = undefined, | 65 | | - contextExtensions = [], | 66 | | - importModuleDynamically, | 67 | | - } = options; | 68 | | - | 69 | | - validateString(filename, 'options.filename'); | 70 | | - validateInt32(columnOffset, 'options.columnOffset'); | 71 | | - validateInt32(lineOffset, 'options.lineOffset'); | 72 | | - if (cachedData !== undefined) | 73 | | - validateBuffer(cachedData, 'options.cachedData'); | 74 | | - validateBoolean(produceCachedData, 'options.produceCachedData'); | 75 | | - if (parsingContext !== undefined) { | 76 | | - if ( | 77 | | - typeof parsingContext !== 'object' || | 78 | | - parsingContext === null || | 79 | | - !isContext(parsingContext) | 80 | | - ) { | 81 | | - throw new ERR_INVALID_ARG_TYPE( | 82 | | - 'options.parsingContext', | 83 | | - 'Context', | 84 | | - parsingContext, | 85 | | - ); | 86 | | - } | 87 | | - } | 88 | | - validateArray(contextExtensions, 'options.contextExtensions'); | 89 | | - ArrayPrototypeForEach(contextExtensions, (extension, i) => { | 90 | | - const name = `options.contextExtensions[${i}]`; | 91 | | - validateObject(extension, name, kValidateObjectAllowNullable); | | 47 | +function registerImportModuleDynamically(referrer, importModuleDynamically) { | | 48 | + const { importModuleDynamicallyWrap } = require('internal/vm/module'); | | 49 | + const { registerModule } = require('internal/modules/esm/utils'); | | 50 | + registerModule(referrer, { | | 51 | + __proto__: null, | | 52 | + importModuleDynamically: | | 53 | + importModuleDynamicallyWrap(importModuleDynamically), | 92 | 54 | }); | | 55 | +} | 93 | 56 |
| 94 | | - const hostDefinedOptionId = | 95 | | - getHostDefinedOptionId(importModuleDynamically, filename); | | 57 | +function internalCompileFunction( | | 58 | + code, filename, lineOffset, columnOffset, | | 59 | + cachedData, produceCachedData, parsingContext, contextExtensions, | | 60 | + params, hostDefinedOptionId, importModuleDynamically) { | 96 | 61 | const result = compileFunction( | 97 | 62 | code, | 98 | 63 | filename, | @@ -119,23 +84,65 @@ function internalCompileFunction(code, params, options) { | 119 | 84 | } | 120 | 85 |
| 121 | 86 | if (importModuleDynamically !== undefined) { | 122 | | - validateFunction(importModuleDynamically, | 123 | | - 'options.importModuleDynamically'); | 124 | | - const { importModuleDynamicallyWrap } = require('internal/vm/module'); | 125 | | - const wrapped = importModuleDynamicallyWrap(importModuleDynamically); | 126 | | - const func = result.function; | 127 | | - const { registerModule } = require('internal/modules/esm/utils'); | 128 | | - registerModule(func, { | 129 | | - __proto__: null, | 130 | | - importModuleDynamically: wrapped, | 131 | | - }); | | 87 | + registerImportModuleDynamically(result.function, importModuleDynamically); | 132 | 88 | } | 133 | 89 |
| 134 | 90 | return result; | 135 | 91 | } | 136 | 92 |
| | 93 | +function makeContextifyScript(code, | | 94 | + filename, | | 95 | + lineOffset, | | 96 | + columnOffset, | | 97 | + cachedData, | | 98 | + produceCachedData, | | 99 | + parsingContext, | | 100 | + hostDefinedOptionId, | | 101 | + importModuleDynamically) { | | 102 | + let script; | | 103 | + // Calling `ReThrow()` on a native TryCatch does not generate a new | | 104 | + // abort-on-uncaught-exception check. A dummy try/catch in JS land | | 105 | + // protects against that. | | 106 | + try { // eslint-disable-line no-useless-catch | | 107 | + script = new ContextifyScript(code, | | 108 | + filename, | | 109 | + lineOffset, | | 110 | + columnOffset, | | 111 | + cachedData, | | 112 | + produceCachedData, | | 113 | + parsingContext, | | 114 | + hostDefinedOptionId); | | 115 | + } catch (e) { | | 116 | + throw e; /* node-do-not-add-exception-line */ | | 117 | + } | | 118 | + | | 119 | + if (importModuleDynamically !== undefined) { | | 120 | + registerImportModuleDynamically(script, importModuleDynamically); | | 121 | + } | | 122 | + return script; | | 123 | +} | | 124 | + | | 125 | +// Internal version of vm.Script.prototype.runInThisContext() which skips | | 126 | +// argument validation. | | 127 | +function runScriptInThisContext(script, displayErrors, breakOnFirstLine) { | | 128 | + return ReflectApply( | | 129 | + runInContext, | | 130 | + script, | | 131 | + [ | | 132 | + null, // sandbox - use current context | | 133 | + -1, // timeout | | 134 | + displayErrors, // displayErrors | | 135 | + false, // breakOnSigint | | 136 | + breakOnFirstLine, // breakOnFirstLine | | 137 | + ], | | 138 | + ); | | 139 | +} | | 140 | + | 137 | 141 | module.exports = { | 138 | 142 | getHostDefinedOptionId, | 139 | 143 | internalCompileFunction, | 140 | 144 | isContext, | | 145 | + makeContextifyScript, | | 146 | + registerImportModuleDynamically, | | 147 | + runScriptInThisContext, | 141 | 148 | }; |
|