@@ -118,8 +118,9 @@ Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
118118
119119} // anonymous namespace
120120
121- BaseObjectPtr<ContextifyContext> ContextifyContext::New (
122- Environment* env, Local<Object> sandbox_obj, ContextOptions* options) {
121+ ContextifyContext* ContextifyContext::New (Environment* env,
122+ Local<Object> sandbox_obj,
123+ ContextOptions* options) {
123124 Local<ObjectTemplate> object_template;
124125 HandleScope scope (env->isolate ());
125126 CHECK_IMPLIES (sandbox_obj.IsEmpty (), options->vanilla );
@@ -140,43 +141,56 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
140141 if (!(CreateV8Context (env->isolate (), object_template, snapshot_data, queue)
141142 .ToLocal (&v8_context))) {
142143 // Allocation failure, maximum call stack size reached, termination, etc.
143- return BaseObjectPtr<ContextifyContext>() ;
144+ return nullptr ;
144145 }
145146 return New (v8_context, env, sandbox_obj, options);
146147}
147148
148- void ContextifyContext::MemoryInfo (MemoryTracker* tracker) const {}
149+ void ContextifyContext::Trace (cppgc::Visitor* visitor) const {
150+ CppgcMixin::Trace (visitor);
151+ visitor->Trace (context_);
152+ }
149153
150154ContextifyContext::ContextifyContext (Environment* env,
151155 Local<Object> wrapper,
152156 Local<Context> v8_context,
153157 ContextOptions* options)
154- : BaseObject(env, wrapper),
155- microtask_queue_ (options->own_microtask_queue
158+ : microtask_queue_(options->own_microtask_queue
156159 ? options->own_microtask_queue.release()
157160 : nullptr ) {
161+ CppgcMixin::Wrap (this , env, wrapper);
162+
158163 context_.Reset (env->isolate (), v8_context);
159164 // This should only be done after the initial initializations of the context
160165 // global object is finished.
161166 DCHECK_NULL (v8_context->GetAlignedPointerFromEmbedderData (
162167 ContextEmbedderIndex::kContextifyContext ));
163168 v8_context->SetAlignedPointerInEmbedderData (
164169 ContextEmbedderIndex::kContextifyContext , this );
165- // It's okay to make this reference weak - V8 would create an internal
166- // reference to this context via the constructor of the wrapper.
167- // As long as the wrapper is alive, it's constructor is alive, and so
168- // is the context.
169- context_.SetWeak ();
170170}
171171
172- ContextifyContext::~ContextifyContext ( ) {
173- Isolate* isolate = env () ->isolate ();
172+ void ContextifyContext::CleanEnvResource (Environment* env ) {
173+ Isolate* isolate = env->isolate ();
174174 HandleScope scope (isolate);
175175
176- env ()->UnassignFromContext (PersistentToLocal::Weak (isolate, context_));
176+ // PurgeTrackedEmptyContexts() is all we need because when the
177+ // wrapper is unreachable, the v8::Context is also already going
178+ // away and there's no point to reset its internal pointers.
179+ // In the context list, the global handle to the original
180+ // context should have already been empty and will be removed
181+ // in PurgeTrackedEmptyContexts().
182+ // TODO(joyeecheung): consider just using a default destructor.
183+ // We don't even need to purge the empty contexts in the
184+ // destructors if TrackContext() purges them, restricting the
185+ // amount of empty contexts in the list.
186+ env->PurgeTrackedEmptyContexts ();
177187 context_.Reset ();
178188}
179189
190+ ContextifyContext::~ContextifyContext () {
191+ Clean ();
192+ }
193+
180194void ContextifyContext::InitializeGlobalTemplates (IsolateData* isolate_data) {
181195 DCHECK (isolate_data->contextify_wrapper_template ().IsEmpty ());
182196 Local<FunctionTemplate> global_func_template =
@@ -251,19 +265,18 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
251265 return scope.Escape (ctx);
252266}
253267
254- BaseObjectPtr<ContextifyContext> ContextifyContext::New (
255- Local<Context> v8_context,
256- Environment* env,
257- Local<Object> sandbox_obj,
258- ContextOptions* options) {
268+ ContextifyContext* ContextifyContext::New (Local<Context> v8_context,
269+ Environment* env,
270+ Local<Object> sandbox_obj,
271+ ContextOptions* options) {
259272 HandleScope scope (env->isolate ());
260273 CHECK_IMPLIES (sandbox_obj.IsEmpty (), options->vanilla );
261274 // This only initializes part of the context. The primordials are
262275 // only initialized when needed because even deserializing them slows
263276 // things down significantly and they are only needed in rare occasions
264277 // in the vm contexts.
265278 if (InitializeContextRuntime (v8_context).IsNothing ()) {
266- return BaseObjectPtr<ContextifyContext>() ;
279+ return nullptr ;
267280 }
268281
269282 Local<Context> main_context = env->context ();
@@ -300,7 +313,7 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
300313 info.origin = *origin_val;
301314 }
302315
303- BaseObjectPtr< ContextifyContext> result;
316+ ContextifyContext* result;
304317 Local<Object> wrapper;
305318 {
306319 Context::Scope context_scope (v8_context);
@@ -315,7 +328,7 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
315328 ctor_name,
316329 static_cast <v8::PropertyAttribute>(v8::DontEnum))
317330 .IsNothing ()) {
318- return BaseObjectPtr<ContextifyContext>() ;
331+ return nullptr ;
319332 }
320333 }
321334
@@ -328,21 +341,23 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
328341 env->host_defined_option_symbol (),
329342 options->host_defined_options_id )
330343 .IsNothing ()) {
331- return BaseObjectPtr<ContextifyContext>() ;
344+ return nullptr ;
332345 }
333346
334347 env->AssignToContext (v8_context, nullptr , info);
335348
336349 if (!env->contextify_wrapper_template ()
337350 ->NewInstance (v8_context)
338351 .ToLocal (&wrapper)) {
339- return BaseObjectPtr<ContextifyContext>() ;
352+ return nullptr ;
340353 }
341354
342- result =
343- MakeBaseObject<ContextifyContext>(env, wrapper, v8_context, options);
344- // The only strong reference to the wrapper will come from the sandbox.
345- result->MakeWeak ();
355+ result = cppgc::MakeGarbageCollected<ContextifyContext>(
356+ env->isolate ()->GetCppHeap ()->GetAllocationHandle (),
357+ env,
358+ wrapper,
359+ v8_context,
360+ options);
346361 }
347362
348363 Local<Object> wrapper_holder =
@@ -352,7 +367,7 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
352367 ->SetPrivate (
353368 v8_context, env->contextify_context_private_symbol (), wrapper)
354369 .IsNothing ()) {
355- return BaseObjectPtr<ContextifyContext>() ;
370+ return nullptr ;
356371 }
357372
358373 // Assign host_defined_options_id to the sandbox object or the global object
@@ -364,7 +379,7 @@ BaseObjectPtr<ContextifyContext> ContextifyContext::New(
364379 env->host_defined_option_symbol (),
365380 options->host_defined_options_id )
366381 .IsNothing ()) {
367- return BaseObjectPtr<ContextifyContext>() ;
382+ return nullptr ;
368383 }
369384 return result;
370385}
@@ -438,7 +453,7 @@ void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
438453 options.host_defined_options_id = args[6 ].As <Symbol>();
439454
440455 TryCatchScope try_catch (env);
441- BaseObjectPtr< ContextifyContext> context_ptr =
456+ ContextifyContext* context_ptr =
442457 ContextifyContext::New (env, sandbox, &options);
443458
444459 if (try_catch.HasCaught ()) {
@@ -469,6 +484,10 @@ ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
469484
470485template <typename T>
471486ContextifyContext* ContextifyContext::Get (const PropertyCallbackInfo<T>& args) {
487+ // TODO(joyeecheung): it should be fine to simply use
488+ // args.GetIsolate()->GetCurrentContext() and take the pointer at
489+ // ContextEmbedderIndex::kContextifyContext, as V8 is supposed to
490+ // push the creation context before invoking these callbacks.
472491 return Get (args.This ());
473492}
474493
0 commit comments