@@ -108,62 +108,151 @@ Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
108
108
109
109
} // anonymous namespace
110
110
111
- ContextifyContext::ContextifyContext (
111
+ BaseObjectPtr< ContextifyContext> ContextifyContext::New (
112
112
Environment* env,
113
113
Local<Object> sandbox_obj,
114
- const ContextOptions& options)
115
- : env_ (env),
116
- microtask_queue_wrap_ (options.microtask_queue_wrap) {
114
+ const ContextOptions& options) {
115
+ HandleScope scope (env-> isolate ());
116
+ InitializeGlobalTemplates (env-> isolate_data ());
117
117
Local<ObjectTemplate> object_template = env->contextify_global_template ();
118
- if (object_template.IsEmpty ()) {
119
- object_template = CreateGlobalTemplate (env->isolate ());
120
- env->set_contextify_global_template (object_template);
121
- }
118
+ DCHECK (!object_template.IsEmpty ());
122
119
bool use_node_snapshot = per_process::cli_options->node_snapshot ;
123
120
const SnapshotData* snapshot_data =
124
121
use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData () : nullptr ;
125
122
126
123
MicrotaskQueue* queue =
127
- microtask_queue ()
128
- ? microtask_queue ().get ()
124
+ options. microtask_queue_wrap
125
+ ? options. microtask_queue_wrap -> microtask_queue ().get ()
129
126
: env->isolate ()->GetCurrentContext ()->GetMicrotaskQueue ();
130
127
131
128
Local<Context> v8_context;
132
129
if (!(CreateV8Context (env->isolate (), object_template, snapshot_data, queue)
133
- .ToLocal (&v8_context)) ||
134
- !InitializeContext (v8_context, env, sandbox_obj, options)) {
130
+ .ToLocal (&v8_context))) {
135
131
// Allocation failure, maximum call stack size reached, termination, etc.
136
- return ;
132
+ return BaseObjectPtr<ContextifyContext>() ;
137
133
}
138
134
139
- context_.Reset (env->isolate (), v8_context);
140
- context_.SetWeak (this , WeakCallback, WeakCallbackType::kParameter );
141
- env->AddCleanupHook (CleanupHook, this );
135
+ // This only initializes part of the context. The primordials are
136
+ // only initilaized when needed because even deserializing them slows
137
+ // things down significantly and they are only needed in rare occasions
138
+ // in the vm contexts.
139
+ if (InitializeContextRuntime (v8_context).IsNothing ()) {
140
+ return BaseObjectPtr<ContextifyContext>();
141
+ }
142
+
143
+ Local<Context> main_context = env->context ();
144
+ Local<Object> new_context_global = v8_context->Global ();
145
+ v8_context->SetSecurityToken (main_context->GetSecurityToken ());
146
+
147
+ // We need to tie the lifetime of the sandbox object with the lifetime of
148
+ // newly created context. We do this by making them hold references to each
149
+ // other. The context can directly hold a reference to the sandbox as an
150
+ // embedder data field. The sandbox uses a private symbol to hold a reference
151
+ // to the ContextifyContext wrapper which in turn internally references
152
+ // the context from its constructor.
153
+ v8_context->SetEmbedderData (ContextEmbedderIndex::kSandboxObject ,
154
+ sandbox_obj);
155
+
156
+ // Delegate the code generation validation to
157
+ // node::ModifyCodeGenerationFromStrings.
158
+ v8_context->AllowCodeGenerationFromStrings (false );
159
+ v8_context->SetEmbedderData (
160
+ ContextEmbedderIndex::kAllowCodeGenerationFromStrings ,
161
+ options.allow_code_gen_strings );
162
+ v8_context->SetEmbedderData (ContextEmbedderIndex::kAllowWasmCodeGeneration ,
163
+ options.allow_code_gen_wasm );
164
+
165
+ Utf8Value name_val (env->isolate (), options.name );
166
+ ContextInfo info (*name_val);
167
+ if (!options.origin .IsEmpty ()) {
168
+ Utf8Value origin_val (env->isolate (), options.origin );
169
+ info.origin = *origin_val;
170
+ }
171
+
172
+ BaseObjectPtr<ContextifyContext> result;
173
+ Local<Object> wrapper;
174
+ {
175
+ Context::Scope context_scope (v8_context);
176
+ Local<String> ctor_name = sandbox_obj->GetConstructorName ();
177
+ if (!ctor_name->Equals (v8_context, env->object_string ()).FromMaybe (false ) &&
178
+ new_context_global
179
+ ->DefineOwnProperty (
180
+ v8_context,
181
+ v8::Symbol::GetToStringTag (env->isolate ()),
182
+ ctor_name,
183
+ static_cast <v8::PropertyAttribute>(v8::DontEnum))
184
+ .IsNothing ()) {
185
+ return BaseObjectPtr<ContextifyContext>();
186
+ }
187
+ env->AssignToContext (v8_context, nullptr , info);
188
+
189
+ if (!env->contextify_wrapper_template ()
190
+ ->NewInstance (v8_context)
191
+ .ToLocal (&wrapper)) {
192
+ return BaseObjectPtr<ContextifyContext>();
193
+ }
194
+
195
+ result =
196
+ MakeBaseObject<ContextifyContext>(env, wrapper, v8_context, options);
197
+ // The only strong reference to the wrapper will come from the sandbox.
198
+ result->MakeWeak ();
199
+ }
200
+
201
+ if (sandbox_obj
202
+ ->SetPrivate (
203
+ v8_context, env->contextify_context_private_symbol (), wrapper)
204
+ .IsNothing ()) {
205
+ return BaseObjectPtr<ContextifyContext>();
206
+ }
207
+
208
+ return result;
142
209
}
143
210
211
+ void ContextifyContext::MemoryInfo (MemoryTracker* tracker) const {
212
+ if (microtask_queue_wrap_) {
213
+ tracker->TrackField (" microtask_queue_wrap" ,
214
+ microtask_queue_wrap_->object ());
215
+ }
216
+ }
217
+
218
+ ContextifyContext::ContextifyContext (Environment* env,
219
+ Local<Object> wrapper,
220
+ Local<Context> v8_context,
221
+ const ContextOptions& options)
222
+ : BaseObject(env, wrapper),
223
+ microtask_queue_wrap_ (options.microtask_queue_wrap) {
224
+ context_.Reset (env->isolate (), v8_context);
225
+ // This should only be done after the initial initializations of the context
226
+ // global object is finished.
227
+ DCHECK_NULL (v8_context->GetAlignedPointerFromEmbedderData (
228
+ ContextEmbedderIndex::kContextifyContext ));
229
+ v8_context->SetAlignedPointerInEmbedderData (
230
+ ContextEmbedderIndex::kContextifyContext , this );
231
+ // It's okay to make this reference weak - V8 would create an internal
232
+ // reference to this context via the constructor of the wrapper.
233
+ // As long as the wrapper is alive, it's constructor is alive, and so
234
+ // is the context.
235
+ context_.SetWeak ();
236
+ }
144
237
145
238
ContextifyContext::~ContextifyContext () {
146
- env ()->RemoveCleanupHook (CleanupHook, this );
147
239
Isolate* isolate = env ()->isolate ();
148
240
HandleScope scope (isolate);
149
241
150
242
env ()->async_hooks ()
151
243
->RemoveContext (PersistentToLocal::Weak (isolate, context_));
244
+ context_.Reset ();
152
245
}
153
246
154
-
155
- void ContextifyContext::CleanupHook (void * arg) {
156
- ContextifyContext* self = static_cast <ContextifyContext*>(arg);
157
- self->context_ .Reset ();
158
- delete self;
159
- }
160
-
161
- Local<ObjectTemplate> ContextifyContext::CreateGlobalTemplate (
162
- Isolate* isolate) {
163
- Local<FunctionTemplate> function_template = FunctionTemplate::New (isolate);
164
-
165
- Local<ObjectTemplate> object_template =
166
- function_template->InstanceTemplate ();
247
+ void ContextifyContext::InitializeGlobalTemplates (IsolateData* isolate_data) {
248
+ if (!isolate_data->contextify_global_template ().IsEmpty ()) {
249
+ return ;
250
+ }
251
+ DCHECK (isolate_data->contextify_wrapper_template ().IsEmpty ());
252
+ Local<FunctionTemplate> global_func_template =
253
+ FunctionTemplate::New (isolate_data->isolate ());
254
+ Local<ObjectTemplate> global_object_template =
255
+ global_func_template->InstanceTemplate ();
167
256
168
257
NamedPropertyHandlerConfiguration config (
169
258
PropertyGetterCallback,
@@ -185,10 +274,15 @@ Local<ObjectTemplate> ContextifyContext::CreateGlobalTemplate(
185
274
{},
186
275
PropertyHandlerFlags::kHasNoSideEffect );
187
276
188
- object_template->SetHandler (config);
189
- object_template->SetHandler (indexed_config);
277
+ global_object_template->SetHandler (config);
278
+ global_object_template->SetHandler (indexed_config);
279
+ isolate_data->set_contextify_global_template (global_object_template);
190
280
191
- return object_template;
281
+ Local<FunctionTemplate> wrapper_func_template =
282
+ BaseObject::MakeLazilyInitializedJSTemplate (isolate_data);
283
+ Local<ObjectTemplate> wrapper_object_template =
284
+ wrapper_func_template->InstanceTemplate ();
285
+ isolate_data->set_contextify_wrapper_template (wrapper_object_template);
192
286
}
193
287
194
288
MaybeLocal<Context> ContextifyContext::CreateV8Context (
@@ -218,73 +312,8 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
218
312
.ToLocal (&ctx)) {
219
313
return MaybeLocal<Context>();
220
314
}
221
- return scope.Escape (ctx);
222
- }
223
-
224
- bool ContextifyContext::InitializeContext (Local<Context> ctx,
225
- Environment* env,
226
- Local<Object> sandbox_obj,
227
- const ContextOptions& options) {
228
- HandleScope scope (env->isolate ());
229
-
230
- // This only initializes part of the context. The primordials are
231
- // only initilaized when needed because even deserializing them slows
232
- // things down significantly and they are only needed in rare occasions
233
- // in the vm contexts.
234
- if (InitializeContextRuntime (ctx).IsNothing ()) {
235
- return false ;
236
- }
237
-
238
- Local<Context> main_context = env->context ();
239
- ctx->SetSecurityToken (main_context->GetSecurityToken ());
240
-
241
- // We need to tie the lifetime of the sandbox object with the lifetime of
242
- // newly created context. We do this by making them hold references to each
243
- // other. The context can directly hold a reference to the sandbox as an
244
- // embedder data field. However, we cannot hold a reference to a v8::Context
245
- // directly in an Object, we instead hold onto the new context's global
246
- // object instead (which then has a reference to the context).
247
- ctx->SetEmbedderData (ContextEmbedderIndex::kSandboxObject , sandbox_obj);
248
- sandbox_obj->SetPrivate (
249
- main_context, env->contextify_global_private_symbol (), ctx->Global ());
250
-
251
- // Delegate the code generation validation to
252
- // node::ModifyCodeGenerationFromStrings.
253
- ctx->AllowCodeGenerationFromStrings (false );
254
- ctx->SetEmbedderData (ContextEmbedderIndex::kAllowCodeGenerationFromStrings ,
255
- options.allow_code_gen_strings );
256
- ctx->SetEmbedderData (ContextEmbedderIndex::kAllowWasmCodeGeneration ,
257
- options.allow_code_gen_wasm );
258
-
259
- Utf8Value name_val (env->isolate (), options.name );
260
- ContextInfo info (*name_val);
261
- if (!options.origin .IsEmpty ()) {
262
- Utf8Value origin_val (env->isolate (), options.origin );
263
- info.origin = *origin_val;
264
- }
265
-
266
- {
267
- Context::Scope context_scope (ctx);
268
- Local<String> ctor_name = sandbox_obj->GetConstructorName ();
269
- if (!ctor_name->Equals (ctx, env->object_string ()).FromMaybe (false ) &&
270
- ctx->Global ()
271
- ->DefineOwnProperty (
272
- ctx,
273
- v8::Symbol::GetToStringTag (env->isolate ()),
274
- ctor_name,
275
- static_cast <v8::PropertyAttribute>(v8::DontEnum))
276
- .IsNothing ()) {
277
- return false ;
278
- }
279
- }
280
-
281
- env->AssignToContext (ctx, nullptr , info);
282
315
283
- // This should only be done after the initial initializations of the context
284
- // global object is finished.
285
- ctx->SetAlignedPointerInEmbedderData (ContextEmbedderIndex::kContextifyContext ,
286
- this );
287
- return true ;
316
+ return scope.Escape (ctx);
288
317
}
289
318
290
319
void ContextifyContext::Init (Environment* env, Local<Object> target) {
@@ -350,22 +379,20 @@ void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
350
379
}
351
380
352
381
TryCatchScope try_catch (env);
353
- std::unique_ptr <ContextifyContext> context_ptr =
354
- std::make_unique<ContextifyContext> (env, sandbox, options);
382
+ BaseObjectPtr <ContextifyContext> context_ptr =
383
+ ContextifyContext::New (env, sandbox, options);
355
384
356
385
if (try_catch.HasCaught ()) {
357
386
if (!try_catch.HasTerminated ())
358
387
try_catch.ReThrow ();
359
388
return ;
360
389
}
361
390
391
+ if (context_ptr.get () == nullptr ) {
392
+ return ;
393
+ }
362
394
Local<Context> new_context = context_ptr->context ();
363
395
if (new_context.IsEmpty ()) return ;
364
-
365
- sandbox->SetPrivate (
366
- env->context (),
367
- env->contextify_context_private_symbol (),
368
- External::New (env->isolate (), context_ptr.release ()));
369
396
}
370
397
371
398
@@ -392,23 +419,24 @@ void ContextifyContext::WeakCallback(
392
419
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox (
393
420
Environment* env,
394
421
const Local<Object>& sandbox) {
395
- MaybeLocal<Value> maybe_value =
396
- sandbox->GetPrivate (env->context (),
397
- env->contextify_context_private_symbol ());
398
- Local<Value> context_external_v;
399
- if (maybe_value.ToLocal (&context_external_v) &&
400
- context_external_v->IsExternal ()) {
401
- Local<External> context_external = context_external_v.As <External>();
402
- return static_cast <ContextifyContext*>(context_external->Value ());
422
+ Local<Value> context_global;
423
+ if (sandbox
424
+ ->GetPrivate (env->context (), env->contextify_context_private_symbol ())
425
+ .ToLocal (&context_global) &&
426
+ context_global->IsObject ()) {
427
+ return Unwrap<ContextifyContext>(context_global.As <Object>());
403
428
}
404
429
return nullptr ;
405
430
}
406
431
407
- // static
408
432
template <typename T>
409
433
ContextifyContext* ContextifyContext::Get (const PropertyCallbackInfo<T>& args) {
434
+ return Get (args.This ());
435
+ }
436
+
437
+ ContextifyContext* ContextifyContext::Get (Local<Object> object) {
410
438
Local<Context> context;
411
- if (!args. This () ->GetCreationContext ().ToLocal (&context)) {
439
+ if (!object ->GetCreationContext ().ToLocal (&context)) {
412
440
return nullptr ;
413
441
}
414
442
if (!ContextEmbedderTag::IsNodeContext (context)) {
0 commit comments