@@ -113,12 +113,26 @@ ContextifyContext::ContextifyContext(
113
113
const ContextOptions& options)
114
114
: env_(env),
115
115
microtask_queue_wrap_ (options.microtask_queue_wrap) {
116
- MaybeLocal<Context> v8_context = CreateV8Context (env, sandbox_obj, options);
116
+ Local<ObjectTemplate> object_template = env->contextify_global_template ();
117
+ if (object_template.IsEmpty ()) {
118
+ object_template = CreateGlobalTemplate (env->isolate ());
119
+ env->set_contextify_global_template (object_template);
120
+ }
121
+
122
+ MicrotaskQueue* queue =
123
+ microtask_queue ()
124
+ ? microtask_queue ().get ()
125
+ : env->isolate ()->GetCurrentContext ()->GetMicrotaskQueue ();
117
126
118
- // Allocation failure, maximum call stack size reached, termination, etc.
119
- if (v8_context.IsEmpty ()) return ;
127
+ Local<Context> v8_context;
128
+ if (!(CreateV8Context (env->isolate (), object_template, queue)
129
+ .ToLocal (&v8_context)) ||
130
+ !InitializeContext (v8_context, env, sandbox_obj, options)) {
131
+ // Allocation failure, maximum call stack size reached, termination, etc.
132
+ return ;
133
+ }
120
134
121
- context_.Reset (env->isolate (), v8_context. ToLocalChecked () );
135
+ context_.Reset (env->isolate (), v8_context);
122
136
context_.SetWeak (this , WeakCallback, WeakCallbackType::kParameter );
123
137
env->AddCleanupHook (CleanupHook, this );
124
138
}
@@ -140,49 +154,21 @@ void ContextifyContext::CleanupHook(void* arg) {
140
154
delete self;
141
155
}
142
156
143
-
144
- // This is an object that just keeps an internal pointer to this
145
- // ContextifyContext. It's passed to the NamedPropertyHandler. If we
146
- // pass the main JavaScript context object we're embedded in, then the
147
- // NamedPropertyHandler will store a reference to it forever and keep it
148
- // from getting gc'd.
149
- MaybeLocal<Object> ContextifyContext::CreateDataWrapper (Environment* env) {
150
- Local<Object> wrapper;
151
- if (!env->script_data_constructor_function ()
152
- ->NewInstance (env->context ())
153
- .ToLocal (&wrapper)) {
154
- return MaybeLocal<Object>();
155
- }
156
-
157
- wrapper->SetAlignedPointerInInternalField (ContextifyContext::kSlot , this );
158
- return wrapper;
159
- }
160
-
161
- MaybeLocal<Context> ContextifyContext::CreateV8Context (
162
- Environment* env,
163
- Local<Object> sandbox_obj,
164
- const ContextOptions& options) {
165
- EscapableHandleScope scope (env->isolate ());
166
- Local<FunctionTemplate> function_template =
167
- FunctionTemplate::New (env->isolate ());
168
-
169
- function_template->SetClassName (sandbox_obj->GetConstructorName ());
157
+ Local<ObjectTemplate> ContextifyContext::CreateGlobalTemplate (
158
+ Isolate* isolate) {
159
+ Local<FunctionTemplate> function_template = FunctionTemplate::New (isolate);
170
160
171
161
Local<ObjectTemplate> object_template =
172
162
function_template->InstanceTemplate ();
173
163
174
- Local<Object> data_wrapper;
175
- if (!CreateDataWrapper (env).ToLocal (&data_wrapper))
176
- return MaybeLocal<Context>();
177
-
178
164
NamedPropertyHandlerConfiguration config (
179
165
PropertyGetterCallback,
180
166
PropertySetterCallback,
181
167
PropertyDescriptorCallback,
182
168
PropertyDeleterCallback,
183
169
PropertyEnumeratorCallback,
184
170
PropertyDefinerCallback,
185
- data_wrapper ,
171
+ {} ,
186
172
PropertyHandlerFlags::kHasNoSideEffect );
187
173
188
174
IndexedPropertyHandlerConfiguration indexed_config (
@@ -192,33 +178,48 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
192
178
IndexedPropertyDeleterCallback,
193
179
PropertyEnumeratorCallback,
194
180
IndexedPropertyDefinerCallback,
195
- data_wrapper ,
181
+ {} ,
196
182
PropertyHandlerFlags::kHasNoSideEffect );
197
183
198
184
object_template->SetHandler (config);
199
185
object_template->SetHandler (indexed_config);
200
- Local<Context> ctx = Context::New (
201
- env->isolate (),
202
- nullptr , // extensions
203
- object_template,
204
- {}, // global object
205
- {}, // deserialization callback
206
- microtask_queue () ?
207
- microtask_queue ().get () :
208
- env->isolate ()->GetCurrentContext ()->GetMicrotaskQueue ());
186
+
187
+ return object_template;
188
+ }
189
+
190
+ MaybeLocal<Context> ContextifyContext::CreateV8Context (
191
+ Isolate* isolate,
192
+ Local<ObjectTemplate> object_template,
193
+ MicrotaskQueue* queue) {
194
+ EscapableHandleScope scope (isolate);
195
+
196
+ Local<Context> ctx = Context::New (isolate,
197
+ nullptr , // extensions
198
+ object_template,
199
+ {}, // global object
200
+ {}, // deserialization callback
201
+ queue);
209
202
if (ctx.IsEmpty ()) return MaybeLocal<Context>();
210
- // Only partially initialize the context - the primordials are left out
211
- // and only initialized when necessary.
212
- if (InitializeContextRuntime (ctx).IsNothing ()) {
213
- return MaybeLocal<Context>();
214
- }
215
203
216
- if (ctx.IsEmpty ()) {
217
- return MaybeLocal<Context>();
204
+ return scope.Escape (ctx);
205
+ }
206
+
207
+ bool ContextifyContext::InitializeContext (Local<Context> ctx,
208
+ Environment* env,
209
+ Local<Object> sandbox_obj,
210
+ const ContextOptions& options) {
211
+ HandleScope scope (env->isolate ());
212
+
213
+ // This only initializes part of the context. The primordials are
214
+ // only initilaized when needed because even deserializing them slows
215
+ // things down significantly and they are only needed in rare occasions
216
+ // in the vm contexts.
217
+ if (InitializeContextRuntime (ctx).IsNothing ()) {
218
+ return false ;
218
219
}
219
220
220
- Local<Context> context = env->context ();
221
- ctx->SetSecurityToken (context ->GetSecurityToken ());
221
+ Local<Context> main_context = env->context ();
222
+ ctx->SetSecurityToken (main_context ->GetSecurityToken ());
222
223
223
224
// We need to tie the lifetime of the sandbox object with the lifetime of
224
225
// newly created context. We do this by making them hold references to each
@@ -227,11 +228,9 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
227
228
// directly in an Object, we instead hold onto the new context's global
228
229
// object instead (which then has a reference to the context).
229
230
ctx->SetEmbedderData (ContextEmbedderIndex::kSandboxObject , sandbox_obj);
230
- sandbox_obj->SetPrivate (context,
231
- env->contextify_global_private_symbol (),
232
- ctx->Global ());
231
+ sandbox_obj->SetPrivate (
232
+ main_context, env->contextify_global_private_symbol (), ctx->Global ());
233
233
234
- Utf8Value name_val (env->isolate (), options.name );
235
234
// Delegate the code generation validation to
236
235
// node::ModifyCodeGenerationFromStrings.
237
236
ctx->AllowCodeGenerationFromStrings (false );
@@ -240,30 +239,39 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
240
239
ctx->SetEmbedderData (ContextEmbedderIndex::kAllowWasmCodeGeneration ,
241
240
options.allow_code_gen_wasm );
242
241
242
+ Utf8Value name_val (env->isolate (), options.name );
243
243
ContextInfo info (*name_val);
244
-
245
244
if (!options.origin .IsEmpty ()) {
246
245
Utf8Value origin_val (env->isolate (), options.origin );
247
246
info.origin = *origin_val;
248
247
}
249
248
249
+ {
250
+ Context::Scope context_scope (ctx);
251
+ Local<String> ctor_name = sandbox_obj->GetConstructorName ();
252
+ if (!ctor_name->Equals (ctx, env->object_string ()).FromMaybe (false ) &&
253
+ ctx->Global ()
254
+ ->DefineOwnProperty (
255
+ ctx,
256
+ v8::Symbol::GetToStringTag (env->isolate ()),
257
+ ctor_name,
258
+ static_cast <v8::PropertyAttribute>(v8::DontEnum))
259
+ .IsNothing ()) {
260
+ return false ;
261
+ }
262
+ }
263
+
250
264
env->AssignToContext (ctx, info);
251
265
252
- return scope.Escape (ctx);
266
+ // This should only be done after the initial initializations of the context
267
+ // global object is finished.
268
+ ctx->SetAlignedPointerInEmbedderData (ContextEmbedderIndex::kContextifyContext ,
269
+ this );
270
+ return true ;
253
271
}
254
272
255
-
256
273
void ContextifyContext::Init (Environment* env, Local<Object> target) {
257
- Isolate* isolate = env->isolate ();
258
274
Local<Context> context = env->context ();
259
-
260
- Local<FunctionTemplate> function_template =
261
- NewFunctionTemplate (isolate, nullptr );
262
- function_template->InstanceTemplate ()->SetInternalFieldCount (
263
- ContextifyContext::kInternalFieldCount );
264
- env->set_script_data_constructor_function (
265
- function_template->GetFunction (env->context ()).ToLocalChecked ());
266
-
267
275
SetMethod (context, target, " makeContext" , MakeContext);
268
276
SetMethod (context, target, " isContext" , IsContext);
269
277
SetMethod (context, target, " compileFunction" , CompileFunction);
@@ -274,6 +282,17 @@ void ContextifyContext::RegisterExternalReferences(
274
282
registry->Register (MakeContext);
275
283
registry->Register (IsContext);
276
284
registry->Register (CompileFunction);
285
+ registry->Register (PropertyGetterCallback);
286
+ registry->Register (PropertySetterCallback);
287
+ registry->Register (PropertyDescriptorCallback);
288
+ registry->Register (PropertyDeleterCallback);
289
+ registry->Register (PropertyEnumeratorCallback);
290
+ registry->Register (PropertyDefinerCallback);
291
+ registry->Register (IndexedPropertyGetterCallback);
292
+ registry->Register (IndexedPropertySetterCallback);
293
+ registry->Register (IndexedPropertyDescriptorCallback);
294
+ registry->Register (IndexedPropertyDeleterCallback);
295
+ registry->Register (IndexedPropertyDefinerCallback);
277
296
}
278
297
279
298
// makeContext(sandbox, name, origin, strings, wasm);
@@ -323,8 +342,8 @@ void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
323
342
return ;
324
343
}
325
344
326
- if ( context_ptr->context (). IsEmpty ())
327
- return ;
345
+ Local<Context> new_context = context_ptr->context ();
346
+ if (new_context. IsEmpty ()) return ;
328
347
329
348
sandbox->SetPrivate (
330
349
env->context (),
@@ -371,10 +390,20 @@ ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
371
390
// static
372
391
template <typename T>
373
392
ContextifyContext* ContextifyContext::Get (const PropertyCallbackInfo<T>& args) {
374
- Local<Value> data = args.Data ();
393
+ Local<Context> context;
394
+ if (!args.This ()->GetCreationContext ().ToLocal (&context)) {
395
+ return nullptr ;
396
+ }
397
+ if (!ContextEmbedderTag::IsNodeContext (context)) {
398
+ return nullptr ;
399
+ }
375
400
return static_cast <ContextifyContext*>(
376
- data.As <Object>()->GetAlignedPointerFromInternalField (
377
- ContextifyContext::kSlot ));
401
+ context->GetAlignedPointerFromEmbedderData (
402
+ ContextEmbedderIndex::kContextifyContext ));
403
+ }
404
+
405
+ bool ContextifyContext::IsStillInitializing (const ContextifyContext* ctx) {
406
+ return ctx == nullptr || ctx->context_ .IsEmpty ();
378
407
}
379
408
380
409
// static
@@ -384,8 +413,7 @@ void ContextifyContext::PropertyGetterCallback(
384
413
ContextifyContext* ctx = ContextifyContext::Get (args);
385
414
386
415
// Still initializing
387
- if (ctx->context_ .IsEmpty ())
388
- return ;
416
+ if (IsStillInitializing (ctx)) return ;
389
417
390
418
Local<Context> context = ctx->context ();
391
419
Local<Object> sandbox = ctx->sandbox ();
@@ -413,8 +441,7 @@ void ContextifyContext::PropertySetterCallback(
413
441
ContextifyContext* ctx = ContextifyContext::Get (args);
414
442
415
443
// Still initializing
416
- if (ctx->context_ .IsEmpty ())
417
- return ;
444
+ if (IsStillInitializing (ctx)) return ;
418
445
419
446
Local<Context> context = ctx->context ();
420
447
PropertyAttribute attributes = PropertyAttribute::None;
@@ -466,8 +493,7 @@ void ContextifyContext::PropertyDescriptorCallback(
466
493
ContextifyContext* ctx = ContextifyContext::Get (args);
467
494
468
495
// Still initializing
469
- if (ctx->context_ .IsEmpty ())
470
- return ;
496
+ if (IsStillInitializing (ctx)) return ;
471
497
472
498
Local<Context> context = ctx->context ();
473
499
@@ -489,8 +515,7 @@ void ContextifyContext::PropertyDefinerCallback(
489
515
ContextifyContext* ctx = ContextifyContext::Get (args);
490
516
491
517
// Still initializing
492
- if (ctx->context_ .IsEmpty ())
493
- return ;
518
+ if (IsStillInitializing (ctx)) return ;
494
519
495
520
Local<Context> context = ctx->context ();
496
521
Isolate* isolate = context->GetIsolate ();
@@ -550,8 +575,7 @@ void ContextifyContext::PropertyDeleterCallback(
550
575
ContextifyContext* ctx = ContextifyContext::Get (args);
551
576
552
577
// Still initializing
553
- if (ctx->context_ .IsEmpty ())
554
- return ;
578
+ if (IsStillInitializing (ctx)) return ;
555
579
556
580
Maybe<bool > success = ctx->sandbox ()->Delete (ctx->context (), property);
557
581
@@ -569,8 +593,7 @@ void ContextifyContext::PropertyEnumeratorCallback(
569
593
ContextifyContext* ctx = ContextifyContext::Get (args);
570
594
571
595
// Still initializing
572
- if (ctx->context_ .IsEmpty ())
573
- return ;
596
+ if (IsStillInitializing (ctx)) return ;
574
597
575
598
Local<Array> properties;
576
599
@@ -587,8 +610,7 @@ void ContextifyContext::IndexedPropertyGetterCallback(
587
610
ContextifyContext* ctx = ContextifyContext::Get (args);
588
611
589
612
// Still initializing
590
- if (ctx->context_ .IsEmpty ())
591
- return ;
613
+ if (IsStillInitializing (ctx)) return ;
592
614
593
615
ContextifyContext::PropertyGetterCallback (
594
616
Uint32ToName (ctx->context (), index ), args);
@@ -602,8 +624,7 @@ void ContextifyContext::IndexedPropertySetterCallback(
602
624
ContextifyContext* ctx = ContextifyContext::Get (args);
603
625
604
626
// Still initializing
605
- if (ctx->context_ .IsEmpty ())
606
- return ;
627
+ if (IsStillInitializing (ctx)) return ;
607
628
608
629
ContextifyContext::PropertySetterCallback (
609
630
Uint32ToName (ctx->context (), index ), value, args);
@@ -616,8 +637,7 @@ void ContextifyContext::IndexedPropertyDescriptorCallback(
616
637
ContextifyContext* ctx = ContextifyContext::Get (args);
617
638
618
639
// Still initializing
619
- if (ctx->context_ .IsEmpty ())
620
- return ;
640
+ if (IsStillInitializing (ctx)) return ;
621
641
622
642
ContextifyContext::PropertyDescriptorCallback (
623
643
Uint32ToName (ctx->context (), index ), args);
@@ -631,8 +651,7 @@ void ContextifyContext::IndexedPropertyDefinerCallback(
631
651
ContextifyContext* ctx = ContextifyContext::Get (args);
632
652
633
653
// Still initializing
634
- if (ctx->context_ .IsEmpty ())
635
- return ;
654
+ if (IsStillInitializing (ctx)) return ;
636
655
637
656
ContextifyContext::PropertyDefinerCallback (
638
657
Uint32ToName (ctx->context (), index ), desc, args);
@@ -645,8 +664,7 @@ void ContextifyContext::IndexedPropertyDeleterCallback(
645
664
ContextifyContext* ctx = ContextifyContext::Get (args);
646
665
647
666
// Still initializing
648
- if (ctx->context_ .IsEmpty ())
649
- return ;
667
+ if (IsStillInitializing (ctx)) return ;
650
668
651
669
Maybe<bool > success = ctx->sandbox ()->Delete (ctx->context (), index );
652
670
@@ -891,8 +909,8 @@ void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
891
909
bool break_on_first_line = args[4 ]->IsTrue ();
892
910
893
911
// Do the eval within the context
894
- Context::Scope context_scope (context);
895
- EvalMachine ( env,
912
+ EvalMachine (context,
913
+ env,
896
914
timeout,
897
915
display_errors,
898
916
break_on_sigint,
@@ -901,13 +919,16 @@ void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
901
919
args);
902
920
}
903
921
904
- bool ContextifyScript::EvalMachine (Environment* env,
922
+ bool ContextifyScript::EvalMachine (Local<Context> context,
923
+ Environment* env,
905
924
const int64_t timeout,
906
925
const bool display_errors,
907
926
const bool break_on_sigint,
908
927
const bool break_on_first_line,
909
928
std::shared_ptr<MicrotaskQueue> mtask_queue,
910
929
const FunctionCallbackInfo<Value>& args) {
930
+ Context::Scope context_scope (context);
931
+
911
932
if (!env->can_call_into_js ())
912
933
return false ;
913
934
if (!ContextifyScript::InstanceOf (env, args.Holder ())) {
@@ -916,6 +937,7 @@ bool ContextifyScript::EvalMachine(Environment* env,
916
937
" Script methods can only be called on script instances." );
917
938
return false ;
918
939
}
940
+
919
941
TryCatchScope try_catch (env);
920
942
Isolate::SafeForTerminationScope safe_for_termination (env->isolate ());
921
943
ContextifyScript* wrapped_script;
@@ -934,7 +956,7 @@ bool ContextifyScript::EvalMachine(Environment* env,
934
956
bool timed_out = false ;
935
957
bool received_signal = false ;
936
958
auto run = [&]() {
937
- MaybeLocal<Value> result = script->Run (env-> context () );
959
+ MaybeLocal<Value> result = script->Run (context);
938
960
if (!result.IsEmpty () && mtask_queue)
939
961
mtask_queue->PerformCheckpoint (env->isolate ());
940
962
return result;
0 commit comments