@@ -328,7 +328,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
328328 // when the handle_scope is freed.
329329 // We also maintain our own "scope_arena" which allows us to have
330330 // all page related memory easily managed.
331- pub fn startScope (self : * Executor , global : anytype , state : State , module_loader : anytype ) ! * Scope {
331+ pub fn startScope (self : * Executor , global : anytype , state : State , module_loader : anytype , enter : bool ) ! * Scope {
332332 std .debug .assert (self .scope == null );
333333
334334 const ModuleLoader = switch (@typeInfo (@TypeOf (module_loader ))) {
@@ -345,61 +345,76 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
345345 const isolate = env .isolate ;
346346 const Global = @TypeOf (global .* );
347347
348- var handle_scope : v8.HandleScope = undefined ;
349- v8 .HandleScope .init (& handle_scope , isolate );
350- errdefer handle_scope .deinit ();
348+ var context : v8.Context = blk : {
349+ var handle_scope : v8.HandleScope = undefined ;
350+ v8 .HandleScope .init (& handle_scope , isolate );
351+ defer handle_scope .deinit ();
351352
352- const js_global = v8 .FunctionTemplate .initDefault (isolate );
353- attachClass (Global , isolate , js_global );
353+ const js_global = v8 .FunctionTemplate .initDefault (isolate );
354+ attachClass (Global , isolate , js_global );
354355
355- const global_template = js_global .getInstanceTemplate ();
356- global_template .setInternalFieldCount (1 );
356+ const global_template = js_global .getInstanceTemplate ();
357+ global_template .setInternalFieldCount (1 );
357358
358- // All the FunctionTemplates that we created and setup in Env.init
359- // are now going to get associated with our global instance.
360- const templates = & self .env .templates ;
361- inline for (Types , 0.. ) | s , i | {
362- const Struct = @field (types , s .name );
363- const class_name = v8 .String .initUtf8 (isolate , comptime classNameForStruct (Struct ));
364- global_template .set (class_name .toName (), templates [i ], v8 .PropertyAttribute .None );
365- }
359+ // All the FunctionTemplates that we created and setup in Env.init
360+ // are now going to get associated with our global instance.
361+ const templates = & self .env .templates ;
362+ inline for (Types , 0.. ) | s , i | {
363+ const Struct = @field (types , s .name );
364+ const class_name = v8 .String .initUtf8 (isolate , comptime classNameForStruct (Struct ));
365+ global_template .set (class_name .toName (), templates [i ], v8 .PropertyAttribute .None );
366+ }
366367
367- // The global object (Window) has already been hooked into the v8
368- // engine when the Env was initialized - like every other type.
369- // But the V8 global is its own FunctionTemplate instance so even
370- // though it's also a Window, we need to set the prototype for this
371- // specific instance of the the Window.
372- if (@hasDecl (Global , "prototype" )) {
373- const proto_type = Receiver (@typeInfo (Global .prototype ).pointer .child );
374- const proto_name = @typeName (proto_type );
375- const proto_index = @field (TYPE_LOOKUP , proto_name ).index ;
376- js_global .inherit (templates [proto_index ]);
377- }
368+ // The global object (Window) has already been hooked into the v8
369+ // engine when the Env was initialized - like every other type.
370+ // But the V8 global is its own FunctionTemplate instance so even
371+ // though it's also a Window, we need to set the prototype for this
372+ // specific instance of the the Window.
373+ if (@hasDecl (Global , "prototype" )) {
374+ const proto_type = Receiver (@typeInfo (Global .prototype ).pointer .child );
375+ const proto_name = @typeName (proto_type );
376+ const proto_index = @field (TYPE_LOOKUP , proto_name ).index ;
377+ js_global .inherit (templates [proto_index ]);
378+ }
378379
379- const context = v8 .Context .init (isolate , global_template , null );
380- context .enter ();
381- errdefer context .exit ();
380+ const context_local = v8 .Context .init (isolate , global_template , null );
381+ const context = v8 .Persistent (v8 .Context ).init (isolate , context_local ).castToContext ();
382+ context .enter ();
383+ errdefer if (enter ) context .exit ();
384+ defer if (! enter ) context .exit ();
385+
386+ // This shouldn't be necessary, but it is:
387+ // https://groups.google.com/g/v8-users/c/qAQQBmbi--8
388+ // TODO: see if newer V8 engines have a way around this.
389+ inline for (Types , 0.. ) | s , i | {
390+ const Struct = @field (types , s .name );
391+
392+ if (@hasDecl (Struct , "prototype" )) {
393+ const proto_type = Receiver (@typeInfo (Struct .prototype ).pointer .child );
394+ const proto_name = @typeName (proto_type );
395+ if (@hasField (TypeLookup , proto_name ) == false ) {
396+ @compileError ("Type '" ++ @typeName (Struct ) ++ "' defines an unknown prototype: " ++ proto_name );
397+ }
382398
383- // This shouldn't be necessary, but it is:
384- // https://groups.google.com/g/v8-users/c/qAQQBmbi--8
385- // TODO: see if newer V8 engines have a way around this.
386- inline for (Types , 0.. ) | s , i | {
387- const Struct = @field (types , s .name );
399+ const proto_index = @field (TYPE_LOOKUP , proto_name ).index ;
400+ const proto_obj = templates [proto_index ].getFunction (context ).toObject ();
388401
389- if (@hasDecl (Struct , "prototype" )) {
390- const proto_type = Receiver (@typeInfo (Struct .prototype ).pointer .child );
391- const proto_name = @typeName (proto_type );
392- if (@hasField (TypeLookup , proto_name ) == false ) {
393- @compileError ("Type '" ++ @typeName (Struct ) ++ "' defines an unknown prototype: " ++ proto_name );
402+ const self_obj = templates [i ].getFunction (context ).toObject ();
403+ _ = self_obj .setPrototype (context , proto_obj );
394404 }
395-
396- const proto_index = @field (TYPE_LOOKUP , proto_name ).index ;
397- const proto_obj = templates [proto_index ].getFunction (context ).toObject ();
398-
399- const self_obj = templates [i ].getFunction (context ).toObject ();
400- _ = self_obj .setPrototype (context , proto_obj );
401405 }
406+ break :blk context ;
407+ };
408+
409+ // For a Page we only create one HandleScope, it is stored in the main World (enter==true). A page can have multple contexts, 1 for each World.
410+ // The main Context/Scope that enters and holds the HandleScope should therefore always be created first. Following other worlds for this page
411+ // like isolated Worlds, will thereby place their objects on the main page's HandleScope. Note: In the furure the number of context will multiply multiple frames support
412+ var handle_scope : ? v8.HandleScope = null ;
413+ if (enter ) {
414+ handle_scope = @as (v8 .HandleScope , undefined );
415+ v8 .HandleScope .init (& handle_scope .? , isolate );
402416 }
417+ errdefer if (enter ) handle_scope .? .deinit ();
403418
404419 self .scope = Scope {
405420 .state = state ,
@@ -453,8 +468,9 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
453468 pub const Scope = struct {
454469 state : State ,
455470 isolate : v8.Isolate ,
471+ // This context is a persistent object. The persistent needs to be recovered and reset.
456472 context : v8.Context ,
457- handle_scope : v8.HandleScope ,
473+ handle_scope : ? v8.HandleScope ,
458474
459475 // references the Env.template array
460476 templates : []v8.FunctionTemplate ,
@@ -506,8 +522,12 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
506522 for (self .callbacks .items ) | * cb | {
507523 cb .deinit ();
508524 }
509- self .context .exit ();
510- self .handle_scope .deinit ();
525+ if (self .handle_scope ) | * scope | {
526+ scope .deinit ();
527+ self .context .exit ();
528+ }
529+ var presistent_context = v8 .Persistent (v8 .Context ).recoverCast (self .context );
530+ presistent_context .deinit ();
511531 }
512532
513533 fn trackCallback (self : * Scope , pf : PersistentFunction ) ! void {
0 commit comments