Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1c4d7eb

Browse filesBrowse files
joyeecheungaddaleax
authored andcommitted
process: move eval and exception bootstrap ito process/execution.js
This patch: - Moves `tryGetCwd`, `evalScript` and `fatalException` from `bootstrap/node.js` into `process/execution.js` so that they do have to be passed into the worker thread setup function, instead the worker code can require them when necessary. - Moves `setUncaughtExceptionCaptureCallback` and `hasUncaughtExceptionCaptureCallback` along with the two global state `exceptionHandlerState` and `shouldAbortOnUncaughtToggle` info `process.execution.js` as those are only used by the fatalException and these two accessors as one self-contained unit. PR-URL: #25199 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 7be4a39 commit 1c4d7eb
Copy full SHA for 1c4d7eb

File tree

Expand file treeCollapse file tree

12 files changed

+199
-162
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

12 files changed

+199
-162
lines changed
Open diff view settings
Collapse file

‎lib/internal/bootstrap/node.js‎

Copy file name to clipboardExpand all lines: lib/internal/bootstrap/node.js
+26-101Lines changed: 26 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,30 @@
1818

1919
const { internalBinding, NativeModule } = loaderExports;
2020

21-
const exceptionHandlerState = { captureFn: null };
2221
let getOptionValue;
2322

2423
function startup() {
2524
setupTraceCategoryState();
2625

2726
setupProcessObject();
2827

29-
// Do this good and early, since it handles errors.
30-
setupProcessFatal();
28+
// TODO(joyeecheung): this does not have to done so early, any fatal errors
29+
// thrown before user code execution should simply crash the process
30+
// and we do not care about any clean up at that point. We don't care
31+
// about emitting any events if the process crash upon bootstrap either.
32+
{
33+
const {
34+
fatalException,
35+
setUncaughtExceptionCaptureCallback,
36+
hasUncaughtExceptionCaptureCallback
37+
} = NativeModule.require('internal/process/execution');
38+
39+
process._fatalException = fatalException;
40+
process.setUncaughtExceptionCaptureCallback =
41+
setUncaughtExceptionCaptureCallback;
42+
process.hasUncaughtExceptionCaptureCallback =
43+
hasUncaughtExceptionCaptureCallback;
44+
}
3145

3246
setupGlobalVariables();
3347

@@ -83,20 +97,14 @@ function startup() {
8397
process.reallyExit = rawMethods.reallyExit;
8498
process._kill = rawMethods._kill;
8599

86-
const wrapped = perThreadSetup.wrapProcessMethods(
87-
rawMethods, exceptionHandlerState
88-
);
100+
const wrapped = perThreadSetup.wrapProcessMethods(rawMethods);
89101
process._rawDebug = wrapped._rawDebug;
90102
process.hrtime = wrapped.hrtime;
91103
process.hrtime.bigint = wrapped.hrtimeBigInt;
92104
process.cpuUsage = wrapped.cpuUsage;
93105
process.memoryUsage = wrapped.memoryUsage;
94106
process.kill = wrapped.kill;
95107
process.exit = wrapped.exit;
96-
process.setUncaughtExceptionCaptureCallback =
97-
wrapped.setUncaughtExceptionCaptureCallback;
98-
process.hasUncaughtExceptionCaptureCallback =
99-
wrapped.hasUncaughtExceptionCaptureCallback;
100108
}
101109

102110
NativeModule.require('internal/process/warning').setup();
@@ -311,7 +319,7 @@ function startExecution() {
311319
// This means we are in a Worker context, and any script execution
312320
// will be directed by the worker module.
313321
if (internalBinding('worker').getEnvMessagePort() !== undefined) {
314-
NativeModule.require('internal/worker').setupChild(evalScript);
322+
NativeModule.require('internal/worker').setupChild();
315323
return;
316324
}
317325

@@ -382,7 +390,9 @@ function executeUserCode() {
382390
addBuiltinLibsToObject
383391
} = NativeModule.require('internal/modules/cjs/helpers');
384392
addBuiltinLibsToObject(global);
385-
evalScript('[eval]', wrapForBreakOnFirstLine(getOptionValue('--eval')));
393+
const source = getOptionValue('--eval');
394+
const { evalScript } = NativeModule.require('internal/process/execution');
395+
evalScript('[eval]', source, process._breakFirstLine);
386396
return;
387397
}
388398

@@ -436,7 +446,8 @@ function executeUserCode() {
436446

437447
// User passed '-e' or '--eval' along with `-i` or `--interactive`
438448
if (process._eval != null) {
439-
evalScript('[eval]', wrapForBreakOnFirstLine(process._eval));
449+
const { evalScript } = NativeModule.require('internal/process/execution');
450+
evalScript('[eval]', process._eval, process._breakFirstLine);
440451
}
441452
return;
442453
}
@@ -458,7 +469,8 @@ function readAndExecuteStdin() {
458469
checkScriptSyntax(code, '[stdin]');
459470
} else {
460471
process._eval = code;
461-
evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval));
472+
const { evalScript } = NativeModule.require('internal/process/execution');
473+
evalScript('[stdin]', process._eval, process._breakFirstLine);
462474
}
463475
});
464476
}
@@ -654,93 +666,6 @@ function setupDOMException() {
654666

655667
function noop() {}
656668

657-
function setupProcessFatal() {
658-
const {
659-
executionAsyncId,
660-
clearDefaultTriggerAsyncId,
661-
clearAsyncIdStack,
662-
hasAsyncIdStack,
663-
afterHooksExist,
664-
emitAfter
665-
} = NativeModule.require('internal/async_hooks');
666-
667-
process._fatalException = (er) => {
668-
// It's possible that defaultTriggerAsyncId was set for a constructor
669-
// call that threw and was never cleared. So clear it now.
670-
clearDefaultTriggerAsyncId();
671-
672-
if (exceptionHandlerState.captureFn !== null) {
673-
exceptionHandlerState.captureFn(er);
674-
} else if (!process.emit('uncaughtException', er)) {
675-
// If someone handled it, then great. otherwise, die in C++ land
676-
// since that means that we'll exit the process, emit the 'exit' event.
677-
try {
678-
if (!process._exiting) {
679-
process._exiting = true;
680-
process.exitCode = 1;
681-
process.emit('exit', 1);
682-
}
683-
} catch {
684-
// Nothing to be done about it at this point.
685-
}
686-
try {
687-
const { kExpandStackSymbol } = NativeModule.require('internal/util');
688-
if (typeof er[kExpandStackSymbol] === 'function')
689-
er[kExpandStackSymbol]();
690-
} catch {
691-
// Nothing to be done about it at this point.
692-
}
693-
return false;
694-
}
695-
696-
// If we handled an error, then make sure any ticks get processed
697-
// by ensuring that the next Immediate cycle isn't empty.
698-
NativeModule.require('timers').setImmediate(noop);
699-
700-
// Emit the after() hooks now that the exception has been handled.
701-
if (afterHooksExist()) {
702-
do {
703-
emitAfter(executionAsyncId());
704-
} while (hasAsyncIdStack());
705-
// Or completely empty the id stack.
706-
} else {
707-
clearAsyncIdStack();
708-
}
709-
710-
return true;
711-
};
712-
}
713-
714-
function wrapForBreakOnFirstLine(source) {
715-
if (!process._breakFirstLine)
716-
return source;
717-
const fn = `function() {\n\n${source};\n\n}`;
718-
return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`;
719-
}
720-
721-
function evalScript(name, body) {
722-
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
723-
const path = NativeModule.require('path');
724-
const { tryGetCwd } = NativeModule.require('internal/util');
725-
const cwd = tryGetCwd(path);
726-
727-
const module = new CJSModule(name);
728-
module.filename = path.join(cwd, name);
729-
module.paths = CJSModule._nodeModulePaths(cwd);
730-
const script = `global.__filename = ${JSON.stringify(name)};\n` +
731-
'global.exports = exports;\n' +
732-
'global.module = module;\n' +
733-
'global.__dirname = __dirname;\n' +
734-
'global.require = require;\n' +
735-
'return require("vm").runInThisContext(' +
736-
`${JSON.stringify(body)}, { filename: ` +
737-
`${JSON.stringify(name)}, displayErrors: true });\n`;
738-
const result = module._compile(script, `${name}-wrapper`);
739-
if (getOptionValue('--print')) console.log(result);
740-
// Handle any nextTicks added in the first tick of the program.
741-
process._tickCallback();
742-
}
743-
744669
function checkScriptSyntax(source, filename) {
745670
const CJSModule = NativeModule.require('internal/modules/cjs/loader');
746671
const vm = NativeModule.require('vm');
Collapse file

‎lib/internal/console/inspector.js‎

Copy file name to clipboardExpand all lines: lib/internal/console/inspector.js
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
'use strict';
22

3-
const path = require('path');
43
const CJSModule = require('internal/modules/cjs/loader');
54
const { makeRequireFunction } = require('internal/modules/cjs/helpers');
6-
const { tryGetCwd } = require('internal/util');
5+
const { tryGetCwd } = require('internal/process/execution');
76
const { addCommandLineAPI, consoleCall } = internalBinding('inspector');
87

98
// Wrap a console implemented by Node.js with features from the VM inspector
109
function addInspectorApis(consoleFromNode, consoleFromVM) {
1110
// Setup inspector command line API.
12-
const cwd = tryGetCwd(path);
11+
const cwd = tryGetCwd();
1312
const consoleAPIModule = new CJSModule('<inspector console>');
1413
consoleAPIModule.paths =
1514
CJSModule._nodeModulePaths(cwd).concat(CJSModule.globalPaths);
Collapse file

‎lib/internal/process/execution.js‎

Copy file name to clipboard
+149Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
const {
6+
codes: {
7+
ERR_INVALID_ARG_TYPE,
8+
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET
9+
}
10+
} = require('internal/errors');
11+
12+
const {
13+
executionAsyncId,
14+
clearDefaultTriggerAsyncId,
15+
clearAsyncIdStack,
16+
hasAsyncIdStack,
17+
afterHooksExist,
18+
emitAfter
19+
} = require('internal/async_hooks');
20+
21+
// shouldAbortOnUncaughtToggle is a typed array for faster
22+
// communication with JS.
23+
const { shouldAbortOnUncaughtToggle } = internalBinding('util');
24+
25+
function tryGetCwd() {
26+
try {
27+
return process.cwd();
28+
} catch {
29+
// getcwd(3) can fail if the current working directory has been deleted.
30+
// Fall back to the directory name of the (absolute) executable path.
31+
// It's not really correct but what are the alternatives?
32+
return path.dirname(process.execPath);
33+
}
34+
}
35+
36+
function evalScript(name, body, breakFristLine) {
37+
const CJSModule = require('internal/modules/cjs/loader');
38+
if (breakFristLine) {
39+
const fn = `function() {\n\n${body};\n\n}`;
40+
body = `process.binding('inspector').callAndPauseOnStart(${fn}, {})`;
41+
}
42+
43+
const cwd = tryGetCwd();
44+
45+
const module = new CJSModule(name);
46+
module.filename = path.join(cwd, name);
47+
module.paths = CJSModule._nodeModulePaths(cwd);
48+
const script = `global.__filename = ${JSON.stringify(name)};\n` +
49+
'global.exports = exports;\n' +
50+
'global.module = module;\n' +
51+
'global.__dirname = __dirname;\n' +
52+
'global.require = require;\n' +
53+
'return require("vm").runInThisContext(' +
54+
`${JSON.stringify(body)}, { filename: ` +
55+
`${JSON.stringify(name)}, displayErrors: true });\n`;
56+
const result = module._compile(script, `${name}-wrapper`);
57+
if (require('internal/options').getOptionValue('--print')) {
58+
console.log(result);
59+
}
60+
// Handle any nextTicks added in the first tick of the program.
61+
process._tickCallback();
62+
}
63+
64+
const exceptionHandlerState = { captureFn: null };
65+
66+
function setUncaughtExceptionCaptureCallback(fn) {
67+
if (fn === null) {
68+
exceptionHandlerState.captureFn = fn;
69+
shouldAbortOnUncaughtToggle[0] = 1;
70+
return;
71+
}
72+
if (typeof fn !== 'function') {
73+
throw new ERR_INVALID_ARG_TYPE('fn', ['Function', 'null'], fn);
74+
}
75+
if (exceptionHandlerState.captureFn !== null) {
76+
throw new ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET();
77+
}
78+
exceptionHandlerState.captureFn = fn;
79+
shouldAbortOnUncaughtToggle[0] = 0;
80+
}
81+
82+
function hasUncaughtExceptionCaptureCallback() {
83+
return exceptionHandlerState.captureFn !== null;
84+
}
85+
86+
function noop() {}
87+
88+
// XXX(joyeecheung): for some reason this cannot be defined at the top-level
89+
// and exported to be written to process._fatalException, it has to be
90+
// returned as an *anonymous function* wrapped inside a factory function,
91+
// otherwise it breaks the test-timers.setInterval async hooks test -
92+
// this may indicate that node::FatalException should fix up the callback scope
93+
// before calling into process._fatalException, or this function should
94+
// take extra care of the async hooks before it schedules a setImmediate.
95+
function createFatalException() {
96+
return (er) => {
97+
// It's possible that defaultTriggerAsyncId was set for a constructor
98+
// call that threw and was never cleared. So clear it now.
99+
clearDefaultTriggerAsyncId();
100+
101+
if (exceptionHandlerState.captureFn !== null) {
102+
exceptionHandlerState.captureFn(er);
103+
} else if (!process.emit('uncaughtException', er)) {
104+
// If someone handled it, then great. otherwise, die in C++ land
105+
// since that means that we'll exit the process, emit the 'exit' event.
106+
try {
107+
if (!process._exiting) {
108+
process._exiting = true;
109+
process.exitCode = 1;
110+
process.emit('exit', 1);
111+
}
112+
} catch {
113+
// Nothing to be done about it at this point.
114+
}
115+
try {
116+
const { kExpandStackSymbol } = require('internal/util');
117+
if (typeof er[kExpandStackSymbol] === 'function')
118+
er[kExpandStackSymbol]();
119+
} catch {
120+
// Nothing to be done about it at this point.
121+
}
122+
return false;
123+
}
124+
125+
// If we handled an error, then make sure any ticks get processed
126+
// by ensuring that the next Immediate cycle isn't empty.
127+
require('timers').setImmediate(noop);
128+
129+
// Emit the after() hooks now that the exception has been handled.
130+
if (afterHooksExist()) {
131+
do {
132+
emitAfter(executionAsyncId());
133+
} while (hasAsyncIdStack());
134+
// Or completely empty the id stack.
135+
} else {
136+
clearAsyncIdStack();
137+
}
138+
139+
return true;
140+
};
141+
}
142+
143+
module.exports = {
144+
tryGetCwd,
145+
evalScript,
146+
fatalException: createFatalException(),
147+
setUncaughtExceptionCaptureCallback,
148+
hasUncaughtExceptionCaptureCallback
149+
};

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.