Skip to content

Commit ccc76bb

Browse files
joyeecheungmarco-ippolito
authored andcommitted
src: simplify embedder entry point execution
Previously we wrapped the embedder entry point callback into a binding and then invoke the binding from JS land which was a bit convoluted. Now we just call it directly from C++. The main scripts that needed to tail call the embedder callback now return the arguments in an array so that the C++ land can extract the arguments and pass them to the callback. We also set `PauseOnNextJavascriptStatement()` for --inspect-brk and mark the bootstrap complete milestone directly in C++ for these execution modes. PR-URL: #51557 Reviewed-By: Daniel Lemire <daniel@lemire.me> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 275cea0 commit ccc76bb

File tree

6 files changed

+54
-60
lines changed

6 files changed

+54
-60
lines changed

lib/internal/main/embedding.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
'use strict';
22
const {
33
prepareMainThreadExecution,
4-
markBootstrapComplete,
54
} = require('internal/process/pre_execution');
65
const { isExperimentalSeaWarningNeeded } = internalBinding('sea');
76
const { emitExperimentalWarning } = require('internal/util');
87
const { embedderRequire, embedderRunCjs } = require('internal/util/embedding');
9-
const { runEmbedderEntryPoint } = internalBinding('mksnapshot');
108

119
prepareMainThreadExecution(false, true);
12-
markBootstrapComplete();
1310

1411
if (isExperimentalSeaWarningNeeded()) {
1512
emitExperimentalWarning('Single executable application');
1613
}
1714

18-
return runEmbedderEntryPoint(process, embedderRequire, embedderRunCjs);
15+
return [process, embedderRequire, embedderRunCjs];

lib/internal/main/mksnapshot.js

+2-13
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const {
1111

1212
const { BuiltinModule: { normalizeRequirableId } } = require('internal/bootstrap/realm');
1313
const {
14-
runEmbedderEntryPoint,
1514
compileSerializeMain,
1615
anonymousMainPath,
1716
} = internalBinding('mksnapshot');
@@ -20,9 +19,6 @@ const { isExperimentalSeaWarningNeeded } = internalBinding('sea');
2019

2120
const { emitExperimentalWarning } = require('internal/util');
2221
const { emitWarningSync } = require('internal/process/warning');
23-
const {
24-
getOptionValue,
25-
} = require('internal/options');
2622

2723
const {
2824
initializeCallbacks,
@@ -179,18 +175,11 @@ function main() {
179175
return fn(requireForUserSnapshot, filename, dirname);
180176
}
181177

182-
const serializeMainArgs = [process, requireForUserSnapshot, minimalRunCjs];
183-
184178
if (isExperimentalSeaWarningNeeded()) {
185179
emitExperimentalWarning('Single executable application');
186180
}
187181

188-
if (getOptionValue('--inspect-brk')) {
189-
internalBinding('inspector').callAndPauseOnStart(
190-
runEmbedderEntryPoint, undefined, ...serializeMainArgs);
191-
} else {
192-
runEmbedderEntryPoint(...serializeMainArgs);
193-
}
182+
return [process, requireForUserSnapshot, minimalRunCjs];
194183
}
195184

196-
main();
185+
return main();

src/env-inl.h

-8
Original file line numberDiff line numberDiff line change
@@ -430,14 +430,6 @@ inline builtins::BuiltinLoader* Environment::builtin_loader() {
430430
return &builtin_loader_;
431431
}
432432

433-
inline const StartExecutionCallback& Environment::embedder_entry_point() const {
434-
return embedder_entry_point_;
435-
}
436-
437-
inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
438-
embedder_entry_point_ = std::move(fn);
439-
}
440-
441433
inline double Environment::new_async_id() {
442434
async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
443435
return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];

src/env.h

-4
Original file line numberDiff line numberDiff line change
@@ -999,9 +999,6 @@ class Environment : public MemoryRetainer {
999999

10001000
#endif // HAVE_INSPECTOR
10011001

1002-
inline const StartExecutionCallback& embedder_entry_point() const;
1003-
inline void set_embedder_entry_point(StartExecutionCallback&& fn);
1004-
10051002
inline void set_process_exit_handler(
10061003
std::function<void(Environment*, ExitCode)>&& handler);
10071004

@@ -1212,7 +1209,6 @@ class Environment : public MemoryRetainer {
12121209
std::unique_ptr<PrincipalRealm> principal_realm_ = nullptr;
12131210

12141211
builtins::BuiltinLoader builtin_loader_;
1215-
StartExecutionCallback embedder_entry_point_;
12161212

12171213
// Used by allocate_managed_buffer() and release_managed_buffer() to keep
12181214
// track of the BackingStore for a given pointer.

src/node.cc

+51-9
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,10 @@
131131

132132
namespace node {
133133

134+
using v8::Array;
135+
using v8::Context;
134136
using v8::EscapableHandleScope;
137+
using v8::Function;
135138
using v8::Isolate;
136139
using v8::Local;
137140
using v8::MaybeLocal;
@@ -278,26 +281,65 @@ MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
278281
return scope.EscapeMaybe(realm->ExecuteBootstrapper(main_script_id));
279282
}
280283

284+
// Convert the result returned by an intermediate main script into
285+
// StartExecutionCallbackInfo. Currently the result is an array containing
286+
// [process, requireFunction, cjsRunner]
287+
std::optional<StartExecutionCallbackInfo> CallbackInfoFromArray(
288+
Local<Context> context, Local<Value> result) {
289+
CHECK(result->IsArray());
290+
Local<Array> args = result.As<Array>();
291+
CHECK_EQ(args->Length(), 3);
292+
Local<Value> process_obj, require_fn, runcjs_fn;
293+
if (!args->Get(context, 0).ToLocal(&process_obj) ||
294+
!args->Get(context, 1).ToLocal(&require_fn) ||
295+
!args->Get(context, 2).ToLocal(&runcjs_fn)) {
296+
return std::nullopt;
297+
}
298+
CHECK(process_obj->IsObject());
299+
CHECK(require_fn->IsFunction());
300+
CHECK(runcjs_fn->IsFunction());
301+
node::StartExecutionCallbackInfo info{process_obj.As<Object>(),
302+
require_fn.As<Function>(),
303+
runcjs_fn.As<Function>()};
304+
return info;
305+
}
306+
281307
MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
282308
InternalCallbackScope callback_scope(
283309
env,
284310
Object::New(env->isolate()),
285311
{ 1, 0 },
286312
InternalCallbackScope::kSkipAsyncHooks);
287313

314+
// Only snapshot builder or embedder applications set the
315+
// callback.
288316
if (cb != nullptr) {
289317
EscapableHandleScope scope(env->isolate());
290-
// TODO(addaleax): pass the callback to the main script more directly,
291-
// e.g. by making StartExecution(env, builtin) parametrizable
292-
env->set_embedder_entry_point(std::move(cb));
293-
auto reset_entry_point =
294-
OnScopeLeave([&]() { env->set_embedder_entry_point({}); });
295318

296-
const char* entry = env->isolate_data()->is_building_snapshot()
297-
? "internal/main/mksnapshot"
298-
: "internal/main/embedding";
319+
Local<Value> result;
320+
if (env->isolate_data()->is_building_snapshot()) {
321+
if (!StartExecution(env, "internal/main/mksnapshot").ToLocal(&result)) {
322+
return MaybeLocal<Value>();
323+
}
324+
} else {
325+
if (!StartExecution(env, "internal/main/embedding").ToLocal(&result)) {
326+
return MaybeLocal<Value>();
327+
}
328+
}
329+
330+
auto info = CallbackInfoFromArray(env->context(), result);
331+
if (!info.has_value()) {
332+
MaybeLocal<Value>();
333+
}
334+
#if HAVE_INSPECTOR
335+
if (env->options()->debug_options().break_first_line) {
336+
env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
337+
}
338+
#endif
299339

300-
return scope.EscapeMaybe(StartExecution(env, entry));
340+
env->performance_state()->Mark(
341+
performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
342+
return scope.EscapeMaybe(cb(info.value()));
301343
}
302344

303345
CHECK(!env->isolate_data()->is_building_snapshot());

src/node_snapshotable.cc

-22
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ using v8::FunctionCallbackInfo;
4141
using v8::HandleScope;
4242
using v8::Isolate;
4343
using v8::Local;
44-
using v8::MaybeLocal;
4544
using v8::Object;
4645
using v8::ObjectTemplate;
4746
using v8::ScriptCompiler;
@@ -1411,25 +1410,6 @@ void SerializeSnapshotableObjects(Realm* realm,
14111410
});
14121411
}
14131412

1414-
static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
1415-
Environment* env = Environment::GetCurrent(args);
1416-
Local<Value> process_obj = args[0];
1417-
Local<Value> require_fn = args[1];
1418-
Local<Value> runcjs_fn = args[2];
1419-
CHECK(process_obj->IsObject());
1420-
CHECK(require_fn->IsFunction());
1421-
CHECK(runcjs_fn->IsFunction());
1422-
1423-
const node::StartExecutionCallback& callback = env->embedder_entry_point();
1424-
node::StartExecutionCallbackInfo info{process_obj.As<Object>(),
1425-
require_fn.As<Function>(),
1426-
runcjs_fn.As<Function>()};
1427-
MaybeLocal<Value> retval = callback(info);
1428-
if (!retval.IsEmpty()) {
1429-
args.GetReturnValue().Set(retval.ToLocalChecked());
1430-
}
1431-
}
1432-
14331413
void CompileSerializeMain(const FunctionCallbackInfo<Value>& args) {
14341414
CHECK(args[0]->IsString());
14351415
Local<String> filename = args[0].As<String>();
@@ -1553,7 +1533,6 @@ void CreatePerContextProperties(Local<Object> target,
15531533
void CreatePerIsolateProperties(IsolateData* isolate_data,
15541534
Local<ObjectTemplate> target) {
15551535
Isolate* isolate = isolate_data->isolate();
1556-
SetMethod(isolate, target, "runEmbedderEntryPoint", RunEmbedderEntryPoint);
15571536
SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain);
15581537
SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback);
15591538
SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback);
@@ -1566,7 +1545,6 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
15661545
}
15671546

15681547
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1569-
registry->Register(RunEmbedderEntryPoint);
15701548
registry->Register(CompileSerializeMain);
15711549
registry->Register(SetSerializeCallback);
15721550
registry->Register(SetDeserializeCallback);

0 commit comments

Comments
 (0)