@@ -25,14 +25,21 @@ using namespace v8;
25
25
#define USE_OWN_LEGACY_PROCESS_INITIALIZATION 1
26
26
#endif
27
27
28
+ // 20.0.0 will have https://github.com/nodejs/node/pull/45888, possibly the PR
29
+ // will be backported to older versions but for now this is the one where we
30
+ // can be sure of its presence.
31
+ #if NODE_VERSION_AT_LEAST(20, 0, 0)
32
+ #define NODE_VERSION_SUPPORTS_EMBEDDER_SNAPSHOT 1
33
+ #endif
34
+
28
35
// 18.1.0 is the current minimum version that has https://github.com/nodejs/node/pull/42809,
29
36
// which introduced crashes when using workers, and later 18.9.0 is the current
30
37
// minimum version to contain https://github.com/nodejs/node/pull/44252, which
31
38
// introcued crashes when using the vm module.
32
39
// We should be able to remove this restriction again once Node.js stops relying
33
40
// on global state for determining whether snapshots are enabled or not
34
41
// (after https://github.com/nodejs/node/pull/45888, hopefully).
35
- #if NODE_VERSION_AT_LEAST(18, 1, 0)
42
+ #if NODE_VERSION_AT_LEAST(18, 1, 0) && !defined(NODE_VERSION_SUPPORTS_EMBEDDER_SNAPSHOT)
36
43
#define PASS_NO_NODE_SNAPSHOT_OPTION 1
37
44
#endif
38
45
@@ -45,6 +52,7 @@ void TearDownOncePerProcess();
45
52
namespace boxednode {
46
53
Local<String> GetBoxednodeMainScriptSource (Isolate* isolate);
47
54
Local<Uint8Array> GetBoxednodeCodeCacheBuffer (Isolate* isolate);
55
+ std::vector<char > GetBoxednodeSnapshotBlobVector ();
48
56
}
49
57
50
58
extern " C" {
@@ -53,11 +61,86 @@ typedef void (*register_boxednode_linked_module)(const void**, const void**);
53
61
REPLACE_DECLARE_LINKED_MODULES
54
62
}
55
63
64
+ #if __cplusplus >= 201703L
65
+ [[maybe_unused]]
66
+ #endif
56
67
static register_boxednode_linked_module boxednode_linked_modules[] = {
57
68
REPLACE_DEFINE_LINKED_MODULES
58
69
nullptr // Make sure the array is not empty, for MSVC
59
70
};
60
71
72
+ static MaybeLocal<Value> LoadBoxednodeEnvironment (Local<Context> context) {
73
+ Environment* env = GetCurrentEnvironment (context);
74
+ return LoadEnvironment (env,
75
+ #ifdef BOXEDNODE_CONSUME_SNAPSHOT
76
+ node::StartExecutionCallback{}
77
+ #else
78
+ [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
79
+ Isolate* isolate = context->GetIsolate ();
80
+ HandleScope handle_scope (isolate);
81
+ Local<Value> entrypoint_name = String::NewFromUtf8 (
82
+ isolate,
83
+ REPLACE_WITH_ENTRY_POINT)
84
+ .ToLocalChecked ();
85
+ Local<Value> entrypoint_ret;
86
+ if (!info.native_require ->Call (
87
+ context,
88
+ Null (isolate),
89
+ 1 ,
90
+ &entrypoint_name
91
+ ).ToLocal (&entrypoint_ret)) {
92
+ return {}; // JS exception.
93
+ }
94
+ assert (entrypoint_ret->IsFunction ());
95
+ Local<Value> trampoline_args[] = {
96
+ boxednode::GetBoxednodeMainScriptSource (isolate),
97
+ String::NewFromUtf8Literal (isolate, BOXEDNODE_CODE_CACHE_MODE),
98
+ boxednode::GetBoxednodeCodeCacheBuffer (isolate),
99
+ };
100
+ if (entrypoint_ret.As <Function>()->Call (
101
+ context,
102
+ Null (isolate),
103
+ sizeof (trampoline_args) / sizeof (trampoline_args[0 ]),
104
+ trampoline_args).IsEmpty ()) {
105
+ return {}; // JS exception.
106
+ }
107
+ return Null (isolate);
108
+ }
109
+ #endif
110
+ );
111
+ }
112
+
113
+ #ifdef BOXEDNODE_GENERATE_SNAPSHOT
114
+ static int RunNodeInstance (MultiIsolatePlatform* platform,
115
+ const std::vector<std::string>& args,
116
+ const std::vector<std::string>& exec_args) {
117
+ int exit_code = 0 ;
118
+ std::vector<std::string> errors;
119
+ std::unique_ptr<CommonEnvironmentSetup> setup =
120
+ CommonEnvironmentSetup::CreateForSnapshotting (platform, &errors, args, exec_args);
121
+
122
+ Isolate* isolate = setup->isolate ();
123
+
124
+ {
125
+ Locker locker (isolate);
126
+ Isolate::Scope isolate_scope (isolate);
127
+
128
+ HandleScope handle_scope (isolate);
129
+ Local<Context> context = setup->context ();
130
+ Context::Scope context_scope (context);
131
+ if (LoadBoxednodeEnvironment (context).IsEmpty ())
132
+ return 1 ;
133
+ exit_code = SpinEventLoop (setup->env ()).FromMaybe (1 );
134
+ }
135
+
136
+ {
137
+ FILE* fp = fopen (" intermediate.out" , " wb" );
138
+ setup->CreateSnapshot ()->ToFile (fp);
139
+ fclose (fp);
140
+ }
141
+ return exit_code;
142
+ }
143
+ #else // BOXEDNODE_GENERATE_SNAPSHOT
61
144
static int RunNodeInstance (MultiIsolatePlatform* platform,
62
145
const std::vector<std::string>& args,
63
146
const std::vector<std::string>& exec_args) {
@@ -81,7 +164,13 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
81
164
std::shared_ptr<ArrayBufferAllocator> allocator =
82
165
ArrayBufferAllocator::Create ();
83
166
84
- #if NODE_VERSION_AT_LEAST(14, 0, 0)
167
+ #ifdef BOXEDNODE_CONSUME_SNAPSHOT
168
+ std::vector<char > snapshot_blob_vec = boxednode::GetBoxednodeSnapshotBlobVector ();
169
+ assert (EmbedderSnapshotData::CanUseCustomSnapshotPerIsolate ());
170
+ node::EmbedderSnapshotData::Pointer snapshot_blob =
171
+ EmbedderSnapshotData::FromBlob (snapshot_blob_vec);
172
+ Isolate* isolate = NewIsolate (allocator, loop, platform, snapshot_blob.get ());
173
+ #elif NODE_VERSION_AT_LEAST(14, 0, 0)
85
174
Isolate* isolate = NewIsolate (allocator, loop, platform);
86
175
#else
87
176
Isolate* isolate = NewIsolate (allocator.get (), loop, platform);
@@ -98,12 +187,19 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
98
187
// Create a node::IsolateData instance that will later be released using
99
188
// node::FreeIsolateData().
100
189
std::unique_ptr<IsolateData, decltype (&node::FreeIsolateData)> isolate_data (
101
- node::CreateIsolateData (isolate, loop, platform, allocator.get ()),
190
+ node::CreateIsolateData (isolate, loop, platform, allocator.get ()
191
+ #ifdef BOXEDNODE_CONSUME_SNAPSHOT
192
+ , snapshot_blob.get ()
193
+ #endif
194
+ ),
102
195
node::FreeIsolateData);
103
196
104
- // Set up a new v8::Context.
105
197
HandleScope handle_scope (isolate);
106
- Local<Context> context = node::NewContext (isolate);
198
+ Local<Context> context;
199
+ #ifndef BOXEDNODE_CONSUME_SNAPSHOT
200
+ // Set up a new v8::Context.
201
+ context = node::NewContext (isolate);
202
+
107
203
if (context.IsEmpty ()) {
108
204
fprintf (stderr, " %s: Failed to initialize V8 Context\n " , args[0 ].c_str ());
109
205
return 1 ;
@@ -112,12 +208,20 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
112
208
// The v8::Context needs to be entered when node::CreateEnvironment() and
113
209
// node::LoadEnvironment() are being called.
114
210
Context::Scope context_scope (context);
211
+ #endif
115
212
116
213
// Create a node::Environment instance that will later be released using
117
214
// node::FreeEnvironment().
118
215
std::unique_ptr<Environment, decltype (&node::FreeEnvironment)> env (
119
216
node::CreateEnvironment (isolate_data.get (), context, args, exec_args),
120
217
node::FreeEnvironment);
218
+ #ifdef BOXEDNODE_CONSUME_SNAPSHOT
219
+ assert (context.IsEmpty ());
220
+ context = GetMainContext (env.get ());
221
+ assert (!context.IsEmpty ());
222
+ Context::Scope context_scope (context);
223
+ #endif
224
+ assert (isolate->InContext ());
121
225
122
226
const void * node_mod;
123
227
const void * napi_mod;
@@ -144,27 +248,9 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
144
248
// `module.createRequire()` is being used to create one that is able to
145
249
// load files from the disk, and uses the standard CommonJS file loader
146
250
// instead of the internal-only `require` function.
147
- Local<Value> loadenv_ret;
148
- if (!node::LoadEnvironment (
149
- env.get (),
150
- " const path = require('path');\n "
151
- " if (process.argv[2] === '--') process.argv.splice(2, 1);\n "
152
- " return require(" REPLACE_WITH_ENTRY_POINT " )" ).ToLocal (&loadenv_ret)) {
251
+ if (LoadBoxednodeEnvironment (context).IsEmpty ()) {
153
252
return 1 ; // There has been a JS exception.
154
253
}
155
- assert (loadenv_ret->IsFunction ());
156
- Local<Value> trampoline_args[] = {
157
- boxednode::GetBoxednodeMainScriptSource (isolate),
158
- String::NewFromUtf8Literal (isolate, BOXEDNODE_CODE_CACHE_MODE),
159
- boxednode::GetBoxednodeCodeCacheBuffer (isolate),
160
- };
161
- if (loadenv_ret.As <Function>()->Call (
162
- context,
163
- Null (isolate),
164
- sizeof (trampoline_args) / sizeof (trampoline_args[0 ]),
165
- trampoline_args).IsEmpty ()) {
166
- return 1 ; // JS exception.
167
- }
168
254
169
255
{
170
256
// SealHandleScope protects against handle leaks from callbacks.
@@ -221,13 +307,14 @@ static int RunNodeInstance(MultiIsolatePlatform* platform,
221
307
222
308
return exit_code;
223
309
}
310
+ #endif // BOXEDNODE_GENERATE_SNAPSHOT
224
311
225
312
static int BoxednodeMain (std::vector<std::string> args) {
226
313
std::vector<std::string> exec_args;
227
314
std::vector<std::string> errors;
228
315
229
316
if (args.size () > 0 ) {
230
- args.insert (args.begin () + 1 , " --" );
317
+ args.insert (args.begin () + 1 , " --" );
231
318
#ifdef PASS_NO_NODE_SNAPSHOT_OPTION
232
319
args.insert (args.begin () + 1 , " --no-node-snapshot" );
233
320
#endif
@@ -260,6 +347,12 @@ static int BoxednodeMain(std::vector<std::string> args) {
260
347
exec_args = result->exec_args ();
261
348
#endif
262
349
350
+ #ifdef BOXEDNODE_CONSUME_SNAPSHOT
351
+ if (args.size () > 0 ) {
352
+ args.insert (args.begin () + 1 , " --boxednode-snapshot-argv-fixup" );
353
+ }
354
+ #endif
355
+
263
356
// Create a v8::Platform instance. `MultiIsolatePlatform::Create()` is a way
264
357
// to create a v8::Platform instance that Node.js can use when creating
265
358
// Worker threads. When no `MultiIsolatePlatform` instance is present,
0 commit comments