Check published FunctionTemplateInfo is immutable

This CL generalized the previous check that a FunctionTemplateInfo
instance is not changed after being instantiated to a check for
immutability after being published. A FTI is considered published once
it is instantiated (set in a SharedFunctionInfo) or set as an accessor
on a JSObject. The published state is tracked in the flags field.
TurboFan relies on this immutabilty for concurrent access.

The immutability requirement was already met before this CL, but this
change enforces this by adding necessary checks.

Change-Id: I4d214e7aed8e04339072c2870caef1c28c772ed5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2718147
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73221}
This commit is contained in:
Nico Hartmann 2021-03-03 15:54:49 +01:00 committed by Commit Bot
parent 7535b91f7c
commit 1040aef36f
5 changed files with 29 additions and 17 deletions

View File

@ -531,6 +531,7 @@ MaybeHandle<JSFunction> InstantiateFunction(
}
return MaybeHandle<JSFunction>();
}
data->set_published(true);
return function;
}
@ -626,6 +627,8 @@ void ApiNatives::AddAccessorProperty(Isolate* isolate,
Handle<FunctionTemplateInfo> getter,
Handle<FunctionTemplateInfo> setter,
PropertyAttributes attributes) {
if (!getter.is_null()) getter->set_published(true);
if (!setter.is_null()) setter->set_published(true);
PropertyDetails details(kAccessor, attributes, PropertyConstness::kMutable);
auto details_handle = handle(details.AsSmi(), isolate);
Handle<Object> data[] = {name, details_handle, getter, setter};

View File

@ -1180,15 +1180,16 @@ void FunctionTemplate::SetPrototypeProviderTemplate(
result);
}
static void EnsureNotInstantiated(i::Handle<i::FunctionTemplateInfo> info,
const char* func) {
Utils::ApiCheck(!info->instantiated(), func,
static void EnsureNotPublished(i::Handle<i::FunctionTemplateInfo> info,
const char* func) {
DCHECK_IMPLIES(info->instantiated(), info->published());
Utils::ApiCheck(!info->published(), func,
"FunctionTemplate already instantiated");
}
void FunctionTemplate::Inherit(v8::Local<FunctionTemplate> value) {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::Inherit");
EnsureNotPublished(info, "v8::FunctionTemplate::Inherit");
i::Isolate* i_isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
Utils::ApiCheck(info->GetPrototypeProviderTemplate().IsUndefined(i_isolate),
@ -1288,7 +1289,7 @@ void FunctionTemplate::SetCallHandler(FunctionCallback callback,
SideEffectType side_effect_type,
const CFunction* c_function) {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::SetCallHandler");
EnsureNotPublished(info, "v8::FunctionTemplate::SetCallHandler");
i::Isolate* isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
@ -1378,7 +1379,7 @@ Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
void FunctionTemplate::SetLength(int length) {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::SetLength");
EnsureNotPublished(info, "v8::FunctionTemplate::SetLength");
auto isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
info->set_length(length);
@ -1386,7 +1387,7 @@ void FunctionTemplate::SetLength(int length) {
void FunctionTemplate::SetClassName(Local<String> name) {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::SetClassName");
EnsureNotPublished(info, "v8::FunctionTemplate::SetClassName");
auto isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
info->set_class_name(*Utils::OpenHandle(*name));
@ -1394,7 +1395,7 @@ void FunctionTemplate::SetClassName(Local<String> name) {
void FunctionTemplate::SetAcceptAnyReceiver(bool value) {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::SetAcceptAnyReceiver");
EnsureNotPublished(info, "v8::FunctionTemplate::SetAcceptAnyReceiver");
auto isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
info->set_accept_any_receiver(value);
@ -1402,7 +1403,7 @@ void FunctionTemplate::SetAcceptAnyReceiver(bool value) {
void FunctionTemplate::ReadOnlyPrototype() {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::ReadOnlyPrototype");
EnsureNotPublished(info, "v8::FunctionTemplate::ReadOnlyPrototype");
auto isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
info->set_read_only_prototype(true);
@ -1410,7 +1411,7 @@ void FunctionTemplate::ReadOnlyPrototype() {
void FunctionTemplate::RemovePrototype() {
auto info = Utils::OpenHandle(this);
EnsureNotInstantiated(info, "v8::FunctionTemplate::RemovePrototype");
EnsureNotPublished(info, "v8::FunctionTemplate::RemovePrototype");
auto isolate = info->GetIsolate();
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
info->set_remove_prototype(true);
@ -1638,7 +1639,7 @@ static void ObjectTemplateSetNamedPropertyHandler(
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, templ);
EnsureNotInstantiated(cons, "ObjectTemplateSetNamedPropertyHandler");
EnsureNotPublished(cons, "ObjectTemplateSetNamedPropertyHandler");
auto obj =
CreateNamedInterceptorInfo(isolate, getter, setter, query, descriptor,
remover, enumerator, definer, data, flags);
@ -1658,7 +1659,7 @@ void ObjectTemplate::MarkAsUndetectable() {
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, this);
EnsureNotInstantiated(cons, "v8::ObjectTemplate::MarkAsUndetectable");
EnsureNotPublished(cons, "v8::ObjectTemplate::MarkAsUndetectable");
cons->set_undetectable(true);
}
@ -1668,7 +1669,7 @@ void ObjectTemplate::SetAccessCheckCallback(AccessCheckCallback callback,
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, this);
EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetAccessCheckCallback");
EnsureNotPublished(cons, "v8::ObjectTemplate::SetAccessCheckCallback");
i::Handle<i::Struct> struct_info = isolate->factory()->NewStruct(
i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld);
@ -1697,8 +1698,8 @@ void ObjectTemplate::SetAccessCheckCallbackAndHandler(
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, this);
EnsureNotInstantiated(
cons, "v8::ObjectTemplate::SetAccessCheckCallbackWithHandler");
EnsureNotPublished(cons,
"v8::ObjectTemplate::SetAccessCheckCallbackWithHandler");
i::Handle<i::Struct> struct_info = isolate->factory()->NewStruct(
i::ACCESS_CHECK_INFO_TYPE, i::AllocationType::kOld);
@ -1733,7 +1734,7 @@ void ObjectTemplate::SetHandler(
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, this);
EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetHandler");
EnsureNotPublished(cons, "v8::ObjectTemplate::SetHandler");
auto obj = CreateIndexedInterceptorInfo(
isolate, config.getter, config.setter, config.query, config.descriptor,
config.deleter, config.enumerator, config.definer, config.data,
@ -1747,7 +1748,7 @@ void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(isolate);
i::HandleScope scope(isolate);
auto cons = EnsureConstructor(isolate, this);
EnsureNotInstantiated(cons, "v8::ObjectTemplate::SetCallAsFunctionHandler");
EnsureNotPublished(cons, "v8::ObjectTemplate::SetCallAsFunctionHandler");
i::Handle<i::CallHandlerInfo> obj = isolate->factory()->NewCallHandlerInfo();
SET_FIELD_WRAPPED(isolate, obj, set_callback, callback);
SET_FIELD_WRAPPED(isolate, obj, set_js_callback, obj->redirected_callback());

View File

@ -37,6 +37,7 @@ BOOL_ACCESSORS(FunctionTemplateInfo, flag, remove_prototype,
BOOL_ACCESSORS(FunctionTemplateInfo, flag, do_not_cache, DoNotCacheBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, accept_any_receiver,
AcceptAnyReceiverBit::kShift)
BOOL_ACCESSORS(FunctionTemplateInfo, flag, published, PublishedBit::kShift)
RELEASE_ACQUIRE_ACCESSORS(FunctionTemplateInfo, call_code, HeapObject,
kCallCodeOffset)

View File

@ -109,6 +109,12 @@ class FunctionTemplateInfo
// If not set an access may be performed on calling the associated JSFunction.
DECL_BOOLEAN_ACCESSORS(accept_any_receiver)
// This flag is used to check that the FunctionTemplateInfo instance is not
// changed after it became visible to TurboFan (either set in a
// SharedFunctionInfo or an accessor), because TF relies on immutability to
// safely read concurrently.
DECL_BOOLEAN_ACCESSORS(published)
// End flag bits ---------------------
// Dispatched behavior.

View File

@ -35,6 +35,7 @@ bitfield struct FunctionTemplateInfoFlags extends uint31 {
remove_prototype: bool: 1 bit;
do_not_cache: bool: 1 bit;
accept_any_receiver: bool: 1 bit;
published: bool: 1 bit;
}
@generateCppClass