Skip to content

Commit e6b4d30

Browse files
committed
src: bootstrap Web [Exposed=*] APIs in the shadow realm
This is the initial work to bootstrap Web interfaces that are defined with extended attributes `[Exposed=*]`. The ShadowRealm instances are garbage-collected once it is unreachable. However, V8 can not infer the reference cycles between the per-realm strong persistent function handles and the realm's context handle. To allow the context to be gc-ed once it is not reachable, the per-realm persistent handles are attached to the context's global object and the persistent handles are set as weak. PR-URL: #46809 Refs: #42528 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Joyee Cheung <[email protected]>
1 parent 41b1867 commit e6b4d30

21 files changed

+595
-191
lines changed

src/api/environment.cc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
6767
if (env == nullptr) {
6868
return exception->ToString(context).FromMaybe(Local<Value>());
6969
}
70+
// TODO(legendecas): Per-realm prepareStackTrace callback.
71+
// If we are in a Realm that is not the principal Realm (e.g. ShadowRealm),
72+
// skip the prepareStackTrace callback to avoid passing the JS objects (
73+
// the exception and trace) across the realm boundary with the
74+
// `Error.prepareStackTrace` override.
75+
Realm* current_realm = Realm::GetCurrent(context);
76+
if (current_realm != nullptr &&
77+
current_realm->kind() != Realm::Kind::kPrincipal) {
78+
return exception->ToString(context).FromMaybe(Local<Value>());
79+
}
7080
Local<Function> prepare = env->prepare_stack_trace_callback();
7181
if (prepare.IsEmpty()) {
7282
return exception->ToString(context).FromMaybe(Local<Value>());
@@ -81,8 +91,8 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
8191
// is what ReThrow gives us). Just returning the empty MaybeLocal would leave
8292
// us with a pending exception.
8393
TryCatchScope try_catch(env);
84-
MaybeLocal<Value> result = prepare->Call(
85-
context, Undefined(env->isolate()), arraysize(args), args);
94+
MaybeLocal<Value> result =
95+
prepare->Call(context, Undefined(env->isolate()), arraysize(args), args);
8696
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
8797
try_catch.ReThrow();
8898
}

src/env-inl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,7 @@ void Environment::set_process_exit_handler(
791791
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
792792
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
793793
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
794+
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
794795
#define V(TypeName, PropertyName) \
795796
inline \
796797
v8::Local<TypeName> IsolateData::PropertyName() const { \
@@ -799,7 +800,9 @@ void Environment::set_process_exit_handler(
799800
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
800801
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
801802
PER_ISOLATE_STRING_PROPERTIES(VS)
803+
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
802804
#undef V
805+
#undef VR
803806
#undef VS
804807
#undef VY
805808
#undef VP

src/env.cc

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,13 +299,16 @@ IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) {
299299
#define VP(PropertyName, StringValue) V(Private, PropertyName)
300300
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
301301
#define VS(PropertyName, StringValue) V(String, PropertyName)
302+
#define VR(PropertyName, TypeName) V(Private, per_realm_##PropertyName)
302303
#define V(TypeName, PropertyName) \
303304
info.primitive_values.push_back( \
304305
creator->AddData(PropertyName##_.Get(isolate)));
305306
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
306307
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
307308
PER_ISOLATE_STRING_PROPERTIES(VS)
309+
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
308310
#undef V
311+
#undef VR
309312
#undef VY
310313
#undef VS
311314
#undef VP
@@ -338,6 +341,7 @@ void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
338341
#define VP(PropertyName, StringValue) V(Private, PropertyName)
339342
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
340343
#define VS(PropertyName, StringValue) V(String, PropertyName)
344+
#define VR(PropertyName, TypeName) V(Private, per_realm_##PropertyName)
341345
#define V(TypeName, PropertyName) \
342346
do { \
343347
MaybeLocal<TypeName> maybe_field = \
@@ -352,7 +356,9 @@ void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
352356
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
353357
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
354358
PER_ISOLATE_STRING_PROPERTIES(VS)
359+
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
355360
#undef V
361+
#undef VR
356362
#undef VY
357363
#undef VS
358364
#undef VP
@@ -421,6 +427,19 @@ void IsolateData::CreateProperties() {
421427
.ToLocalChecked()));
422428
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
423429
#undef V
430+
#define V(PropertyName, TypeName) \
431+
per_realm_##PropertyName##_.Set( \
432+
isolate_, \
433+
Private::New( \
434+
isolate_, \
435+
String::NewFromOneByte( \
436+
isolate_, \
437+
reinterpret_cast<const uint8_t*>("per_realm_" #PropertyName), \
438+
NewStringType::kInternalized, \
439+
sizeof("per_realm_" #PropertyName) - 1) \
440+
.ToLocalChecked()));
441+
PER_REALM_STRONG_PERSISTENT_VALUES(V)
442+
#undef V
424443
#define V(PropertyName, StringValue) \
425444
PropertyName##_.Set( \
426445
isolate_, \
@@ -786,7 +805,7 @@ Environment::Environment(IsolateData* isolate_data,
786805

787806
void Environment::InitializeMainContext(Local<Context> context,
788807
const EnvSerializeInfo* env_info) {
789-
principal_realm_ = std::make_unique<Realm>(
808+
principal_realm_ = std::make_unique<PrincipalRealm>(
790809
this, context, MAYBE_FIELD_PTR(env_info, principal_realm));
791810
AssignToContext(context, principal_realm_.get(), ContextInfo(""));
792811
if (env_info != nullptr) {

src/env.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,15 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
147147
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
148148
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
149149
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
150+
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
150151
#define V(TypeName, PropertyName) \
151152
inline v8::Local<TypeName> PropertyName() const;
152153
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
153154
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
154155
PER_ISOLATE_STRING_PROPERTIES(VS)
156+
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
155157
#undef V
158+
#undef VR
156159
#undef VY
157160
#undef VS
158161
#undef VP
@@ -184,6 +187,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
184187
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
185188
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
186189
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
190+
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
187191
#define VM(PropertyName) V(v8::FunctionTemplate, PropertyName##_binding)
188192
#define VT(PropertyName, TypeName) V(TypeName, PropertyName)
189193
#define V(TypeName, PropertyName) \
@@ -192,9 +196,11 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
192196
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
193197
PER_ISOLATE_STRING_PROPERTIES(VS)
194198
PER_ISOLATE_TEMPLATE_PROPERTIES(VT)
199+
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
195200
NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM)
196201
#undef V
197202
#undef VM
203+
#undef VR
198204
#undef VT
199205
#undef VS
200206
#undef VY
@@ -1139,7 +1145,7 @@ class Environment : public MemoryRetainer {
11391145
std::function<void(Environment*, ExitCode)> process_exit_handler_{
11401146
DefaultProcessExitHandlerInternal};
11411147

1142-
std::unique_ptr<Realm> principal_realm_ = nullptr;
1148+
std::unique_ptr<PrincipalRealm> principal_realm_ = nullptr;
11431149

11441150
builtins::BuiltinLoader builtin_loader_;
11451151
StartExecutionCallback embedder_entry_point_;

src/env_properties.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,6 @@
414414
V(message_port, v8::Object) \
415415
V(builtin_module_require, v8::Function) \
416416
V(performance_entry_callback, v8::Function) \
417-
V(performance_entry_template, v8::Function) \
418417
V(prepare_stack_trace_callback, v8::Function) \
419418
V(process_object, v8::Object) \
420419
V(primordials, v8::Object) \

src/histogram.cc

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ using v8::Local;
1616
using v8::Map;
1717
using v8::Number;
1818
using v8::Object;
19+
using v8::ObjectTemplate;
1920
using v8::String;
2021
using v8::Uint32;
2122
using v8::Value;
@@ -213,7 +214,7 @@ void HistogramBase::Add(const FunctionCallbackInfo<Value>& args) {
213214
HistogramBase* histogram;
214215
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());
215216

216-
CHECK(GetConstructorTemplate(env)->HasInstance(args[0]));
217+
CHECK(GetConstructorTemplate(env->isolate_data())->HasInstance(args[0]));
217218
HistogramBase* other;
218219
ASSIGN_OR_RETURN_UNWRAP(&other, args[0]);
219220

@@ -225,9 +226,10 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
225226
Environment* env,
226227
const Histogram::Options& options) {
227228
Local<Object> obj;
228-
if (!GetConstructorTemplate(env)
229-
->InstanceTemplate()
230-
->NewInstance(env->context()).ToLocal(&obj)) {
229+
if (!GetConstructorTemplate(env->isolate_data())
230+
->InstanceTemplate()
231+
->NewInstance(env->context())
232+
.ToLocal(&obj)) {
231233
return BaseObjectPtr<HistogramBase>();
232234
}
233235

@@ -238,9 +240,10 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
238240
Environment* env,
239241
std::shared_ptr<Histogram> histogram) {
240242
Local<Object> obj;
241-
if (!GetConstructorTemplate(env)
242-
->InstanceTemplate()
243-
->NewInstance(env->context()).ToLocal(&obj)) {
243+
if (!GetConstructorTemplate(env->isolate_data())
244+
->InstanceTemplate()
245+
->NewInstance(env->context())
246+
.ToLocal(&obj)) {
244247
return BaseObjectPtr<HistogramBase>();
245248
}
246249
return MakeBaseObject<HistogramBase>(env, obj, std::move(histogram));
@@ -278,15 +281,14 @@ void HistogramBase::New(const FunctionCallbackInfo<Value>& args) {
278281
}
279282

280283
Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
281-
Environment* env) {
282-
Local<FunctionTemplate> tmpl = env->histogram_ctor_template();
284+
IsolateData* isolate_data) {
285+
Local<FunctionTemplate> tmpl = isolate_data->histogram_ctor_template();
283286
if (tmpl.IsEmpty()) {
284-
Isolate* isolate = env->isolate();
287+
Isolate* isolate = isolate_data->isolate();
285288
tmpl = NewFunctionTemplate(isolate, New);
286-
Local<String> classname =
287-
FIXED_ONE_BYTE_STRING(env->isolate(), "Histogram");
289+
Local<String> classname = FIXED_ONE_BYTE_STRING(isolate, "Histogram");
288290
tmpl->SetClassName(classname);
289-
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
291+
tmpl->Inherit(BaseObject::GetConstructorTemplate(isolate_data));
290292

291293
tmpl->InstanceTemplate()->SetInternalFieldCount(
292294
HistogramBase::kInternalFieldCount);
@@ -311,7 +313,7 @@ Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
311313
SetProtoMethod(isolate, tmpl, "record", Record);
312314
SetProtoMethod(isolate, tmpl, "recordDelta", RecordDelta);
313315
SetProtoMethod(isolate, tmpl, "add", Add);
314-
env->set_histogram_ctor_template(tmpl);
316+
isolate_data->set_histogram_ctor_template(tmpl);
315317
}
316318
return tmpl;
317319
}
@@ -339,9 +341,12 @@ void HistogramBase::RegisterExternalReferences(
339341
registry->Register(Add);
340342
}
341343

342-
void HistogramBase::Initialize(Environment* env, Local<Object> target) {
343-
SetConstructorFunction(
344-
env->context(), target, "Histogram", GetConstructorTemplate(env));
344+
void HistogramBase::Initialize(IsolateData* isolate_data,
345+
Local<ObjectTemplate> target) {
346+
SetConstructorFunction(isolate_data->isolate(),
347+
target,
348+
"Histogram",
349+
GetConstructorTemplate(isolate_data));
345350
}
346351

347352
BaseObjectPtr<BaseObject> HistogramBase::HistogramTransferData::Deserialize(

src/histogram.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,9 @@ class HistogramImpl {
8484
class HistogramBase : public BaseObject, public HistogramImpl {
8585
public:
8686
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
87-
Environment* env);
88-
static void Initialize(Environment* env, v8::Local<v8::Object> target);
87+
IsolateData* isolate_data);
88+
static void Initialize(IsolateData* isolate_data,
89+
v8::Local<v8::ObjectTemplate> target);
8990
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
9091

9192
static BaseObjectPtr<HistogramBase> Create(

src/node_binding.cc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@
1414
#define NODE_BUILTIN_OPENSSL_BINDINGS(V)
1515
#endif
1616

17-
#if NODE_HAVE_I18N_SUPPORT
18-
#define NODE_BUILTIN_ICU_BINDINGS(V) V(icu)
19-
#else
20-
#define NODE_BUILTIN_ICU_BINDINGS(V)
21-
#endif
22-
2317
#if HAVE_INSPECTOR
2418
#define NODE_BUILTIN_PROFILER_BINDINGS(V) V(profiler)
2519
#else

src/node_binding.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,17 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
2424
static_cast<int>(node::ModuleFlags::kLinked),
2525
"NM_F_LINKED != node::ModuleFlags::kLinked");
2626

27+
#if NODE_HAVE_I18N_SUPPORT
28+
#define NODE_BUILTIN_ICU_BINDINGS(V) V(icu)
29+
#else
30+
#define NODE_BUILTIN_ICU_BINDINGS(V)
31+
#endif
32+
2733
#define NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) \
2834
V(builtins) \
29-
V(worker)
35+
V(performance) \
36+
V(worker) \
37+
NODE_BUILTIN_ICU_BINDINGS(V)
3038

3139
#define NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
3240
static node::node_module _module = { \
@@ -56,6 +64,8 @@ namespace node {
5664
NODE_BINDING_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL)
5765

5866
// Define a per-isolate initialization function for a node internal binding.
67+
// The modname should be registered in the NODE_BINDINGS_WITH_PER_ISOLATE_INIT
68+
// list.
5969
#define NODE_BINDING_PER_ISOLATE_INIT(modname, per_isolate_func) \
6070
void _register_isolate_##modname(node::IsolateData* isolate_data, \
6171
v8::Local<v8::FunctionTemplate> target) { \

src/node_buffer.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,11 +1150,14 @@ static void IsAscii(const FunctionCallbackInfo<Value>& args) {
11501150
}
11511151

11521152
void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
1153-
Environment* env = Environment::GetCurrent(args);
1153+
Realm* realm = Realm::GetCurrent(args);
1154+
1155+
// TODO(legendecas): Remove this check once the binding supports sub-realms.
1156+
CHECK_EQ(realm->kind(), Realm::Kind::kPrincipal);
11541157

11551158
CHECK(args[0]->IsObject());
11561159
Local<Object> proto = args[0].As<Object>();
1157-
env->set_buffer_prototype_object(proto);
1160+
realm->set_buffer_prototype_object(proto);
11581161
}
11591162

11601163
void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {

src/node_i18n.cc

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -859,36 +859,41 @@ static void GetStringWidth(const FunctionCallbackInfo<Value>& args) {
859859
args.GetReturnValue().Set(width);
860860
}
861861

862-
void Initialize(Local<Object> target,
863-
Local<Value> unused,
864-
Local<Context> context,
865-
void* priv) {
866-
Environment* env = Environment::GetCurrent(context);
867-
SetMethod(context, target, "toUnicode", ToUnicode);
868-
SetMethod(context, target, "toASCII", ToASCII);
869-
SetMethod(context, target, "getStringWidth", GetStringWidth);
862+
static void CreatePerIsolateProperties(IsolateData* isolate_data,
863+
Local<FunctionTemplate> target) {
864+
Isolate* isolate = isolate_data->isolate();
865+
Local<ObjectTemplate> proto = target->PrototypeTemplate();
866+
867+
SetMethod(isolate, proto, "toUnicode", ToUnicode);
868+
SetMethod(isolate, proto, "toASCII", ToASCII);
869+
SetMethod(isolate, proto, "getStringWidth", GetStringWidth);
870870

871871
// One-shot converters
872-
SetMethod(context, target, "icuErrName", ICUErrorName);
873-
SetMethod(context, target, "transcode", Transcode);
872+
SetMethod(isolate, proto, "icuErrName", ICUErrorName);
873+
SetMethod(isolate, proto, "transcode", Transcode);
874874

875875
// ConverterObject
876876
{
877-
Local<FunctionTemplate> t = NewFunctionTemplate(env->isolate(), nullptr);
878-
t->Inherit(BaseObject::GetConstructorTemplate(env));
877+
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, nullptr);
878+
t->Inherit(BaseObject::GetConstructorTemplate(isolate_data));
879879
t->InstanceTemplate()->SetInternalFieldCount(
880880
ConverterObject::kInternalFieldCount);
881881
Local<String> converter_string =
882-
FIXED_ONE_BYTE_STRING(env->isolate(), "Converter");
882+
FIXED_ONE_BYTE_STRING(isolate, "Converter");
883883
t->SetClassName(converter_string);
884-
env->set_i18n_converter_template(t->InstanceTemplate());
884+
isolate_data->set_i18n_converter_template(t->InstanceTemplate());
885885
}
886886

887-
SetMethod(context, target, "getConverter", ConverterObject::Create);
888-
SetMethod(context, target, "decode", ConverterObject::Decode);
889-
SetMethod(context, target, "hasConverter", ConverterObject::Has);
887+
SetMethod(isolate, proto, "getConverter", ConverterObject::Create);
888+
SetMethod(isolate, proto, "decode", ConverterObject::Decode);
889+
SetMethod(isolate, proto, "hasConverter", ConverterObject::Has);
890890
}
891891

892+
void CreatePerContextProperties(Local<Object> target,
893+
Local<Value> unused,
894+
Local<Context> context,
895+
void* priv) {}
896+
892897
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
893898
registry->Register(ToUnicode);
894899
registry->Register(ToASCII);
@@ -903,7 +908,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
903908
} // namespace i18n
904909
} // namespace node
905910

906-
NODE_BINDING_CONTEXT_AWARE_INTERNAL(icu, node::i18n::Initialize)
911+
NODE_BINDING_CONTEXT_AWARE_INTERNAL(icu, node::i18n::CreatePerContextProperties)
912+
NODE_BINDING_PER_ISOLATE_INIT(icu, node::i18n::CreatePerIsolateProperties)
907913
NODE_BINDING_EXTERNAL_REFERENCE(icu, node::i18n::RegisterExternalReferences)
908914

909915
#endif // NODE_HAVE_I18N_SUPPORT

0 commit comments

Comments
 (0)