Skip to content

Commit

Permalink
src: bootstrap Web [Exposed=*] APIs in the shadow realm
Browse files Browse the repository at this point in the history
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 <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
legendecas committed Mar 15, 2023
1 parent 41b1867 commit e6b4d30
Show file tree
Hide file tree
Showing 21 changed files with 595 additions and 191 deletions.
14 changes: 12 additions & 2 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
if (env == nullptr) {
return exception->ToString(context).FromMaybe(Local<Value>());
}
// TODO(legendecas): Per-realm prepareStackTrace callback.
// If we are in a Realm that is not the principal Realm (e.g. ShadowRealm),
// skip the prepareStackTrace callback to avoid passing the JS objects (
// the exception and trace) across the realm boundary with the
// `Error.prepareStackTrace` override.
Realm* current_realm = Realm::GetCurrent(context);
if (current_realm != nullptr &&
current_realm->kind() != Realm::Kind::kPrincipal) {
return exception->ToString(context).FromMaybe(Local<Value>());
}
Local<Function> prepare = env->prepare_stack_trace_callback();
if (prepare.IsEmpty()) {
return exception->ToString(context).FromMaybe(Local<Value>());
Expand All @@ -81,8 +91,8 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
// is what ReThrow gives us). Just returning the empty MaybeLocal would leave
// us with a pending exception.
TryCatchScope try_catch(env);
MaybeLocal<Value> result = prepare->Call(
context, Undefined(env->isolate()), arraysize(args), args);
MaybeLocal<Value> result =
prepare->Call(context, Undefined(env->isolate()), arraysize(args), args);
if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
try_catch.ReThrow();
}
Expand Down
3 changes: 3 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,7 @@ void Environment::set_process_exit_handler(
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
#define V(TypeName, PropertyName) \
inline \
v8::Local<TypeName> IsolateData::PropertyName() const { \
Expand All @@ -799,7 +800,9 @@ void Environment::set_process_exit_handler(
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
#undef V
#undef VR
#undef VS
#undef VY
#undef VP
Expand Down
21 changes: 20 additions & 1 deletion src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,16 @@ IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) {
#define VP(PropertyName, StringValue) V(Private, PropertyName)
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(String, PropertyName)
#define VR(PropertyName, TypeName) V(Private, per_realm_##PropertyName)
#define V(TypeName, PropertyName) \
info.primitive_values.push_back( \
creator->AddData(PropertyName##_.Get(isolate)));
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
#undef V
#undef VR
#undef VY
#undef VS
#undef VP
Expand Down Expand Up @@ -338,6 +341,7 @@ void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
#define VP(PropertyName, StringValue) V(Private, PropertyName)
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(String, PropertyName)
#define VR(PropertyName, TypeName) V(Private, per_realm_##PropertyName)
#define V(TypeName, PropertyName) \
do { \
MaybeLocal<TypeName> maybe_field = \
Expand All @@ -352,7 +356,9 @@ void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
#undef V
#undef VR
#undef VY
#undef VS
#undef VP
Expand Down Expand Up @@ -421,6 +427,19 @@ void IsolateData::CreateProperties() {
.ToLocalChecked()));
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
#undef V
#define V(PropertyName, TypeName) \
per_realm_##PropertyName##_.Set( \
isolate_, \
Private::New( \
isolate_, \
String::NewFromOneByte( \
isolate_, \
reinterpret_cast<const uint8_t*>("per_realm_" #PropertyName), \
NewStringType::kInternalized, \
sizeof("per_realm_" #PropertyName) - 1) \
.ToLocalChecked()));
PER_REALM_STRONG_PERSISTENT_VALUES(V)
#undef V
#define V(PropertyName, StringValue) \
PropertyName##_.Set( \
isolate_, \
Expand Down Expand Up @@ -786,7 +805,7 @@ Environment::Environment(IsolateData* isolate_data,

void Environment::InitializeMainContext(Local<Context> context,
const EnvSerializeInfo* env_info) {
principal_realm_ = std::make_unique<Realm>(
principal_realm_ = std::make_unique<PrincipalRealm>(
this, context, MAYBE_FIELD_PTR(env_info, principal_realm));
AssignToContext(context, principal_realm_.get(), ContextInfo(""));
if (env_info != nullptr) {
Expand Down
8 changes: 7 additions & 1 deletion src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,15 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
#define V(TypeName, PropertyName) \
inline v8::Local<TypeName> PropertyName() const;
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
#undef V
#undef VR
#undef VY
#undef VS
#undef VP
Expand Down Expand Up @@ -184,6 +187,7 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
#define VR(PropertyName, TypeName) V(v8::Private, per_realm_##PropertyName)
#define VM(PropertyName) V(v8::FunctionTemplate, PropertyName##_binding)
#define VT(PropertyName, TypeName) V(TypeName, PropertyName)
#define V(TypeName, PropertyName) \
Expand All @@ -192,9 +196,11 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
PER_ISOLATE_SYMBOL_PROPERTIES(VY)
PER_ISOLATE_STRING_PROPERTIES(VS)
PER_ISOLATE_TEMPLATE_PROPERTIES(VT)
PER_REALM_STRONG_PERSISTENT_VALUES(VR)
NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM)
#undef V
#undef VM
#undef VR
#undef VT
#undef VS
#undef VY
Expand Down Expand Up @@ -1139,7 +1145,7 @@ class Environment : public MemoryRetainer {
std::function<void(Environment*, ExitCode)> process_exit_handler_{
DefaultProcessExitHandlerInternal};

std::unique_ptr<Realm> principal_realm_ = nullptr;
std::unique_ptr<PrincipalRealm> principal_realm_ = nullptr;

builtins::BuiltinLoader builtin_loader_;
StartExecutionCallback embedder_entry_point_;
Expand Down
1 change: 0 additions & 1 deletion src/env_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@
V(message_port, v8::Object) \
V(builtin_module_require, v8::Function) \
V(performance_entry_callback, v8::Function) \
V(performance_entry_template, v8::Function) \
V(prepare_stack_trace_callback, v8::Function) \
V(process_object, v8::Object) \
V(primordials, v8::Object) \
Expand Down
39 changes: 22 additions & 17 deletions src/histogram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ using v8::Local;
using v8::Map;
using v8::Number;
using v8::Object;
using v8::ObjectTemplate;
using v8::String;
using v8::Uint32;
using v8::Value;
Expand Down Expand Up @@ -213,7 +214,7 @@ void HistogramBase::Add(const FunctionCallbackInfo<Value>& args) {
HistogramBase* histogram;
ASSIGN_OR_RETURN_UNWRAP(&histogram, args.Holder());

CHECK(GetConstructorTemplate(env)->HasInstance(args[0]));
CHECK(GetConstructorTemplate(env->isolate_data())->HasInstance(args[0]));
HistogramBase* other;
ASSIGN_OR_RETURN_UNWRAP(&other, args[0]);

Expand All @@ -225,9 +226,10 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
Environment* env,
const Histogram::Options& options) {
Local<Object> obj;
if (!GetConstructorTemplate(env)
->InstanceTemplate()
->NewInstance(env->context()).ToLocal(&obj)) {
if (!GetConstructorTemplate(env->isolate_data())
->InstanceTemplate()
->NewInstance(env->context())
.ToLocal(&obj)) {
return BaseObjectPtr<HistogramBase>();
}

Expand All @@ -238,9 +240,10 @@ BaseObjectPtr<HistogramBase> HistogramBase::Create(
Environment* env,
std::shared_ptr<Histogram> histogram) {
Local<Object> obj;
if (!GetConstructorTemplate(env)
->InstanceTemplate()
->NewInstance(env->context()).ToLocal(&obj)) {
if (!GetConstructorTemplate(env->isolate_data())
->InstanceTemplate()
->NewInstance(env->context())
.ToLocal(&obj)) {
return BaseObjectPtr<HistogramBase>();
}
return MakeBaseObject<HistogramBase>(env, obj, std::move(histogram));
Expand Down Expand Up @@ -278,15 +281,14 @@ void HistogramBase::New(const FunctionCallbackInfo<Value>& args) {
}

Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
Environment* env) {
Local<FunctionTemplate> tmpl = env->histogram_ctor_template();
IsolateData* isolate_data) {
Local<FunctionTemplate> tmpl = isolate_data->histogram_ctor_template();
if (tmpl.IsEmpty()) {
Isolate* isolate = env->isolate();
Isolate* isolate = isolate_data->isolate();
tmpl = NewFunctionTemplate(isolate, New);
Local<String> classname =
FIXED_ONE_BYTE_STRING(env->isolate(), "Histogram");
Local<String> classname = FIXED_ONE_BYTE_STRING(isolate, "Histogram");
tmpl->SetClassName(classname);
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
tmpl->Inherit(BaseObject::GetConstructorTemplate(isolate_data));

tmpl->InstanceTemplate()->SetInternalFieldCount(
HistogramBase::kInternalFieldCount);
Expand All @@ -311,7 +313,7 @@ Local<FunctionTemplate> HistogramBase::GetConstructorTemplate(
SetProtoMethod(isolate, tmpl, "record", Record);
SetProtoMethod(isolate, tmpl, "recordDelta", RecordDelta);
SetProtoMethod(isolate, tmpl, "add", Add);
env->set_histogram_ctor_template(tmpl);
isolate_data->set_histogram_ctor_template(tmpl);
}
return tmpl;
}
Expand Down Expand Up @@ -339,9 +341,12 @@ void HistogramBase::RegisterExternalReferences(
registry->Register(Add);
}

void HistogramBase::Initialize(Environment* env, Local<Object> target) {
SetConstructorFunction(
env->context(), target, "Histogram", GetConstructorTemplate(env));
void HistogramBase::Initialize(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
SetConstructorFunction(isolate_data->isolate(),
target,
"Histogram",
GetConstructorTemplate(isolate_data));
}

BaseObjectPtr<BaseObject> HistogramBase::HistogramTransferData::Deserialize(
Expand Down
5 changes: 3 additions & 2 deletions src/histogram.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ class HistogramImpl {
class HistogramBase : public BaseObject, public HistogramImpl {
public:
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
static void Initialize(Environment* env, v8::Local<v8::Object> target);
IsolateData* isolate_data);
static void Initialize(IsolateData* isolate_data,
v8::Local<v8::ObjectTemplate> target);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

static BaseObjectPtr<HistogramBase> Create(
Expand Down
6 changes: 0 additions & 6 deletions src/node_binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@
#define NODE_BUILTIN_OPENSSL_BINDINGS(V)
#endif

#if NODE_HAVE_I18N_SUPPORT
#define NODE_BUILTIN_ICU_BINDINGS(V) V(icu)
#else
#define NODE_BUILTIN_ICU_BINDINGS(V)
#endif

#if HAVE_INSPECTOR
#define NODE_BUILTIN_PROFILER_BINDINGS(V) V(profiler)
#else
Expand Down
12 changes: 11 additions & 1 deletion src/node_binding.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@ static_assert(static_cast<int>(NM_F_LINKED) ==
static_cast<int>(node::ModuleFlags::kLinked),
"NM_F_LINKED != node::ModuleFlags::kLinked");

#if NODE_HAVE_I18N_SUPPORT
#define NODE_BUILTIN_ICU_BINDINGS(V) V(icu)
#else
#define NODE_BUILTIN_ICU_BINDINGS(V)
#endif

#define NODE_BINDINGS_WITH_PER_ISOLATE_INIT(V) \
V(builtins) \
V(worker)
V(performance) \
V(worker) \
NODE_BUILTIN_ICU_BINDINGS(V)

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

// Define a per-isolate initialization function for a node internal binding.
// The modname should be registered in the NODE_BINDINGS_WITH_PER_ISOLATE_INIT
// list.
#define NODE_BINDING_PER_ISOLATE_INIT(modname, per_isolate_func) \
void _register_isolate_##modname(node::IsolateData* isolate_data, \
v8::Local<v8::FunctionTemplate> target) { \
Expand Down
7 changes: 5 additions & 2 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1150,11 +1150,14 @@ static void IsAscii(const FunctionCallbackInfo<Value>& args) {
}

void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Realm* realm = Realm::GetCurrent(args);

// TODO(legendecas): Remove this check once the binding supports sub-realms.
CHECK_EQ(realm->kind(), Realm::Kind::kPrincipal);

CHECK(args[0]->IsObject());
Local<Object> proto = args[0].As<Object>();
env->set_buffer_prototype_object(proto);
realm->set_buffer_prototype_object(proto);
}

void GetZeroFillToggle(const FunctionCallbackInfo<Value>& args) {
Expand Down
42 changes: 24 additions & 18 deletions src/node_i18n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,36 +859,41 @@ static void GetStringWidth(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(width);
}

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

SetMethod(isolate, proto, "toUnicode", ToUnicode);
SetMethod(isolate, proto, "toASCII", ToASCII);
SetMethod(isolate, proto, "getStringWidth", GetStringWidth);

// One-shot converters
SetMethod(context, target, "icuErrName", ICUErrorName);
SetMethod(context, target, "transcode", Transcode);
SetMethod(isolate, proto, "icuErrName", ICUErrorName);
SetMethod(isolate, proto, "transcode", Transcode);

// ConverterObject
{
Local<FunctionTemplate> t = NewFunctionTemplate(env->isolate(), nullptr);
t->Inherit(BaseObject::GetConstructorTemplate(env));
Local<FunctionTemplate> t = NewFunctionTemplate(isolate, nullptr);
t->Inherit(BaseObject::GetConstructorTemplate(isolate_data));
t->InstanceTemplate()->SetInternalFieldCount(
ConverterObject::kInternalFieldCount);
Local<String> converter_string =
FIXED_ONE_BYTE_STRING(env->isolate(), "Converter");
FIXED_ONE_BYTE_STRING(isolate, "Converter");
t->SetClassName(converter_string);
env->set_i18n_converter_template(t->InstanceTemplate());
isolate_data->set_i18n_converter_template(t->InstanceTemplate());
}

SetMethod(context, target, "getConverter", ConverterObject::Create);
SetMethod(context, target, "decode", ConverterObject::Decode);
SetMethod(context, target, "hasConverter", ConverterObject::Has);
SetMethod(isolate, proto, "getConverter", ConverterObject::Create);
SetMethod(isolate, proto, "decode", ConverterObject::Decode);
SetMethod(isolate, proto, "hasConverter", ConverterObject::Has);
}

void CreatePerContextProperties(Local<Object> target,
Local<Value> unused,
Local<Context> context,
void* priv) {}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(ToUnicode);
registry->Register(ToASCII);
Expand All @@ -903,7 +908,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
} // namespace i18n
} // namespace node

NODE_BINDING_CONTEXT_AWARE_INTERNAL(icu, node::i18n::Initialize)
NODE_BINDING_CONTEXT_AWARE_INTERNAL(icu, node::i18n::CreatePerContextProperties)
NODE_BINDING_PER_ISOLATE_INIT(icu, node::i18n::CreatePerIsolateProperties)
NODE_BINDING_EXTERNAL_REFERENCE(icu, node::i18n::RegisterExternalReferences)

#endif // NODE_HAVE_I18N_SUPPORT
Loading

0 comments on commit e6b4d30

Please sign in to comment.