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