@@ -42,7 +42,6 @@ using v8::ArrayBufferView;
4242using v8::Boolean;
4343using v8::Context;
4444using v8::EscapableHandleScope;
45- using v8::External;
4645using v8::Function;
4746using v8::FunctionCallbackInfo;
4847using v8::FunctionTemplate;
@@ -108,62 +107,77 @@ Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
108107
109108} // anonymous namespace
110109
111- ContextifyContext::ContextifyContext (
110+ BaseObjectPtr< ContextifyContext> ContextifyContext::New (
112111 Environment* env,
113112 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 ());
117116 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 ());
122118 bool use_node_snapshot = per_process::cli_options->node_snapshot ;
123119 const SnapshotData* snapshot_data =
124120 use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData () : nullptr ;
125121
126122 MicrotaskQueue* queue =
127- microtask_queue ()
128- ? microtask_queue ().get ()
123+ options. microtask_queue_wrap
124+ ? options. microtask_queue_wrap -> microtask_queue ().get ()
129125 : env->isolate ()->GetCurrentContext ()->GetMicrotaskQueue ();
130126
131127 Local<Context> v8_context;
132128 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))) {
135130 // Allocation failure, maximum call stack size reached, termination, etc.
136- return ;
131+ return BaseObjectPtr<ContextifyContext>() ;
137132 }
133+ return New (v8_context, env, sandbox_obj, options);
134+ }
138135
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+ }
142141}
143142
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+ }
144162
145163ContextifyContext::~ContextifyContext () {
146- env ()->RemoveCleanupHook (CleanupHook, this );
147164 Isolate* isolate = env ()->isolate ();
148165 HandleScope scope (isolate);
149166
150167 env ()->async_hooks ()
151168 ->RemoveContext (PersistentToLocal::Weak (isolate, context_));
169+ context_.Reset ();
152170}
153171
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 ();
167181
168182 NamedPropertyHandlerConfiguration config (
169183 PropertyGetterCallback,
@@ -185,10 +199,15 @@ Local<ObjectTemplate> ContextifyContext::CreateGlobalTemplate(
185199 {},
186200 PropertyHandlerFlags::kHasNoSideEffect );
187201
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);
190205
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);
192211}
193212
194213MaybeLocal<Context> ContextifyContext::CreateV8Context (
@@ -218,43 +237,45 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
218237 .ToLocal (&ctx)) {
219238 return MaybeLocal<Context>();
220239 }
240+
221241 return scope.Escape (ctx);
222242}
223243
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) {
228249 HandleScope scope (env->isolate ());
229-
230250 // This only initializes part of the context. The primordials are
231251 // only initilaized when needed because even deserializing them slows
232252 // things down significantly and they are only needed in rare occasions
233253 // in the vm contexts.
234- if (InitializeContextRuntime (ctx ).IsNothing ()) {
235- return false ;
254+ if (InitializeContextRuntime (v8_context ).IsNothing ()) {
255+ return BaseObjectPtr<ContextifyContext>() ;
236256 }
237257
238258 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 ());
240261
241262 // We need to tie the lifetime of the sandbox object with the lifetime of
242263 // newly created context. We do this by making them hold references to each
243264 // 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);
250270
251271 // Delegate the code generation validation to
252272 // 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 );
258279
259280 Utf8Value name_val (env->isolate (), options.name );
260281 ContextInfo info (*name_val);
@@ -263,28 +284,43 @@ bool ContextifyContext::InitializeContext(Local<Context> ctx,
263284 info.origin = *origin_val;
264285 }
265286
287+ BaseObjectPtr<ContextifyContext> result;
288+ Local<Object> wrapper;
266289 {
267- Context::Scope context_scope (ctx );
290+ Context::Scope context_scope (v8_context );
268291 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
271294 ->DefineOwnProperty (
272- ctx ,
295+ v8_context ,
273296 v8::Symbol::GetToStringTag (env->isolate ()),
274297 ctor_name,
275298 static_cast <v8::PropertyAttribute>(v8::DontEnum))
276299 .IsNothing ()) {
277- return false ;
300+ return BaseObjectPtr<ContextifyContext>() ;
278301 }
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 ();
279314 }
280315
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+ }
282322
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;
288324}
289325
290326void ContextifyContext::Init (Environment* env, Local<Object> target) {
@@ -350,22 +386,14 @@ void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
350386 }
351387
352388 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);
355391
356392 if (try_catch.HasCaught ()) {
357393 if (!try_catch.HasTerminated ())
358394 try_catch.ReThrow ();
359395 return ;
360396 }
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 ()));
369397}
370398
371399
@@ -392,23 +420,24 @@ void ContextifyContext::WeakCallback(
392420ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox (
393421 Environment* env,
394422 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>());
403429 }
404430 return nullptr ;
405431}
406432
407- // static
408433template <typename T>
409434ContextifyContext* ContextifyContext::Get (const PropertyCallbackInfo<T>& args) {
435+ return Get (args.This ());
436+ }
437+
438+ ContextifyContext* ContextifyContext::Get (Local<Object> object) {
410439 Local<Context> context;
411- if (!args. This () ->GetCreationContext ().ToLocal (&context)) {
440+ if (!object ->GetCreationContext ().ToLocal (&context)) {
412441 return nullptr ;
413442 }
414443 if (!ContextEmbedderTag::IsNodeContext (context)) {
0 commit comments