@@ -328,7 +328,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
328
328
// when the handle_scope is freed.
329
329
// We also maintain our own "scope_arena" which allows us to have
330
330
// 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 {
332
332
std .debug .assert (self .scope == null );
333
333
334
334
const ModuleLoader = switch (@typeInfo (@TypeOf (module_loader ))) {
@@ -345,61 +345,76 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
345
345
const isolate = env .isolate ;
346
346
const Global = @TypeOf (global .* );
347
347
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 ();
351
352
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 );
354
355
355
- const global_template = js_global .getInstanceTemplate ();
356
- global_template .setInternalFieldCount (1 );
356
+ const global_template = js_global .getInstanceTemplate ();
357
+ global_template .setInternalFieldCount (1 );
357
358
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
+ }
366
367
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
+ }
378
379
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
+ }
382
398
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 ();
388
401
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 );
394
404
}
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 );
401
405
}
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 );
402
416
}
417
+ errdefer if (enter ) handle_scope .? .deinit ();
403
418
404
419
self .scope = Scope {
405
420
.state = state ,
@@ -453,8 +468,9 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
453
468
pub const Scope = struct {
454
469
state : State ,
455
470
isolate : v8.Isolate ,
471
+ // This context is a persistent object. The persistent needs to be recovered and reset.
456
472
context : v8.Context ,
457
- handle_scope : v8.HandleScope ,
473
+ handle_scope : ? v8.HandleScope ,
458
474
459
475
// references the Env.template array
460
476
templates : []v8.FunctionTemplate ,
@@ -506,8 +522,12 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
506
522
for (self .callbacks .items ) | * cb | {
507
523
cb .deinit ();
508
524
}
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 ();
511
531
}
512
532
513
533
fn trackCallback (self : * Scope , pf : PersistentFunction ) ! void {
0 commit comments