Add a native data property that replaces itself with a real data property
This is useful for things that don't ever change, but we don't want to eagerly compute the result. Doing this from the embedder is difficult, using DefineOwnProperty would read the property to get the property descriptor, creating an endless recursion. R=verwaest@chromium.org,haraken@chromium.org BUG= Review-Url: https://codereview.chromium.org/2449783006 Cr-Commit-Position: refs/heads/master@{#40648}
This commit is contained in:
parent
e12f9a113a
commit
f074215082
@ -4685,6 +4685,14 @@ class V8_EXPORT Template : public Data {
|
||||
Local<AccessorSignature> signature = Local<AccessorSignature>(),
|
||||
AccessControl settings = DEFAULT);
|
||||
|
||||
/**
|
||||
* Like SetNativeDataProperty, but V8 will replace the native data property
|
||||
* with a real data property on first access.
|
||||
*/
|
||||
void SetLazyDataProperty(Local<Name> name, AccessorNameGetterCallback getter,
|
||||
Local<Value> data = Local<Value>(),
|
||||
PropertyAttribute attribute = None);
|
||||
|
||||
/**
|
||||
* During template instantiation, sets the value with the intrinsic property
|
||||
* from the correct context.
|
||||
|
@ -29,6 +29,7 @@ Handle<AccessorInfo> Accessors::MakeAccessor(
|
||||
info->set_all_can_write(false);
|
||||
info->set_is_special_data_property(true);
|
||||
info->set_is_sloppy(false);
|
||||
info->set_replace_on_access(false);
|
||||
name = factory->InternalizeName(name);
|
||||
info->set_name(*name);
|
||||
Handle<Object> get = v8::FromCData(isolate, getter);
|
||||
|
36
src/api.cc
36
src/api.cc
@ -1297,10 +1297,13 @@ template <typename Getter, typename Setter>
|
||||
i::Handle<i::AccessorInfo> MakeAccessorInfo(
|
||||
v8::Local<Name> name, Getter getter, Setter setter, v8::Local<Value> data,
|
||||
v8::AccessControl settings, v8::PropertyAttribute attributes,
|
||||
v8::Local<AccessorSignature> signature, bool is_special_data_property) {
|
||||
v8::Local<AccessorSignature> signature, bool is_special_data_property,
|
||||
bool replace_on_access) {
|
||||
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
|
||||
i::Handle<i::AccessorInfo> obj = isolate->factory()->NewAccessorInfo();
|
||||
SET_FIELD_WRAPPED(obj, set_getter, getter);
|
||||
DCHECK_IMPLIES(replace_on_access,
|
||||
is_special_data_property && setter == nullptr);
|
||||
if (is_special_data_property && setter == nullptr) {
|
||||
setter = reinterpret_cast<Setter>(&i::Accessors::ReconfigureToDataProperty);
|
||||
}
|
||||
@ -1312,6 +1315,7 @@ i::Handle<i::AccessorInfo> MakeAccessorInfo(
|
||||
}
|
||||
obj->set_data(*Utils::OpenHandle(*data));
|
||||
obj->set_is_special_data_property(is_special_data_property);
|
||||
obj->set_replace_on_access(replace_on_access);
|
||||
return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
|
||||
}
|
||||
|
||||
@ -1463,20 +1467,21 @@ static i::Handle<i::FunctionTemplateInfo> EnsureConstructor(
|
||||
return constructor;
|
||||
}
|
||||
|
||||
|
||||
template <typename Getter, typename Setter, typename Data, typename Template>
|
||||
static bool TemplateSetAccessor(Template* template_obj, v8::Local<Name> name,
|
||||
Getter getter, Setter setter, Data data,
|
||||
AccessControl settings,
|
||||
PropertyAttribute attribute,
|
||||
v8::Local<AccessorSignature> signature,
|
||||
bool is_special_data_property) {
|
||||
bool is_special_data_property,
|
||||
bool replace_on_access) {
|
||||
auto info = Utils::OpenHandle(template_obj);
|
||||
auto isolate = info->GetIsolate();
|
||||
ENTER_V8(isolate);
|
||||
i::HandleScope scope(isolate);
|
||||
auto obj = MakeAccessorInfo(name, getter, setter, data, settings, attribute,
|
||||
signature, is_special_data_property);
|
||||
auto obj =
|
||||
MakeAccessorInfo(name, getter, setter, data, settings, attribute,
|
||||
signature, is_special_data_property, replace_on_access);
|
||||
if (obj.is_null()) return false;
|
||||
i::ApiNatives::AddNativeDataProperty(isolate, info, obj);
|
||||
return true;
|
||||
@ -1491,7 +1496,7 @@ void Template::SetNativeDataProperty(v8::Local<String> name,
|
||||
v8::Local<AccessorSignature> signature,
|
||||
AccessControl settings) {
|
||||
TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
|
||||
signature, true);
|
||||
signature, true, false);
|
||||
}
|
||||
|
||||
|
||||
@ -1503,9 +1508,17 @@ void Template::SetNativeDataProperty(v8::Local<Name> name,
|
||||
v8::Local<AccessorSignature> signature,
|
||||
AccessControl settings) {
|
||||
TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
|
||||
signature, true);
|
||||
signature, true, false);
|
||||
}
|
||||
|
||||
void Template::SetLazyDataProperty(v8::Local<Name> name,
|
||||
AccessorNameGetterCallback getter,
|
||||
v8::Local<Value> data,
|
||||
PropertyAttribute attribute) {
|
||||
TemplateSetAccessor(
|
||||
this, name, getter, static_cast<AccessorNameSetterCallback>(nullptr),
|
||||
data, DEFAULT, attribute, Local<AccessorSignature>(), true, true);
|
||||
}
|
||||
|
||||
void Template::SetIntrinsicDataProperty(Local<Name> name, Intrinsic intrinsic,
|
||||
PropertyAttribute attribute) {
|
||||
@ -1526,7 +1539,7 @@ void ObjectTemplate::SetAccessor(v8::Local<String> name,
|
||||
PropertyAttribute attribute,
|
||||
v8::Local<AccessorSignature> signature) {
|
||||
TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
|
||||
signature, i::FLAG_disable_old_api_accessors);
|
||||
signature, i::FLAG_disable_old_api_accessors, false);
|
||||
}
|
||||
|
||||
|
||||
@ -1537,7 +1550,7 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name,
|
||||
PropertyAttribute attribute,
|
||||
v8::Local<AccessorSignature> signature) {
|
||||
TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
|
||||
signature, i::FLAG_disable_old_api_accessors);
|
||||
signature, i::FLAG_disable_old_api_accessors, false);
|
||||
}
|
||||
|
||||
template <typename Getter, typename Setter, typename Query, typename Descriptor,
|
||||
@ -4488,8 +4501,9 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self,
|
||||
i::Handle<i::JSObject> obj =
|
||||
i::Handle<i::JSObject>::cast(Utils::OpenHandle(self));
|
||||
v8::Local<AccessorSignature> signature;
|
||||
auto info = MakeAccessorInfo(name, getter, setter, data, settings, attributes,
|
||||
signature, i::FLAG_disable_old_api_accessors);
|
||||
auto info =
|
||||
MakeAccessorInfo(name, getter, setter, data, settings, attributes,
|
||||
signature, i::FLAG_disable_old_api_accessors, false);
|
||||
if (info.is_null()) return Nothing<bool>();
|
||||
bool fast = obj->HasFastProperties();
|
||||
i::Handle<i::Object> result;
|
||||
|
@ -7724,6 +7724,14 @@ void AccessorInfo::set_is_special_data_property(bool value) {
|
||||
set_flag(BooleanBit::set(flag(), kSpecialDataProperty, value));
|
||||
}
|
||||
|
||||
bool AccessorInfo::replace_on_access() {
|
||||
return BooleanBit::get(flag(), kReplaceOnAccess);
|
||||
}
|
||||
|
||||
void AccessorInfo::set_replace_on_access(bool value) {
|
||||
set_flag(BooleanBit::set(flag(), kReplaceOnAccess, value));
|
||||
}
|
||||
|
||||
bool AccessorInfo::is_sloppy() { return BooleanBit::get(flag(), kIsSloppy); }
|
||||
|
||||
void AccessorInfo::set_is_sloppy(bool value) {
|
||||
|
@ -1352,8 +1352,14 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(LookupIterator* it) {
|
||||
Handle<Object> result = args.Call(call_fun, name);
|
||||
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
||||
if (result.is_null()) return isolate->factory()->undefined_value();
|
||||
// Rebox handle before return.
|
||||
return handle(*result, isolate);
|
||||
Handle<Object> reboxed_result = handle(*result, isolate);
|
||||
if (info->replace_on_access() && receiver->IsJSReceiver()) {
|
||||
args.Call(reinterpret_cast<GenericNamedPropertySetterCallback>(
|
||||
&Accessors::ReconfigureToDataProperty),
|
||||
name, result);
|
||||
RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
|
||||
}
|
||||
return reboxed_result;
|
||||
}
|
||||
|
||||
// Regular accessor.
|
||||
|
@ -11217,6 +11217,9 @@ class AccessorInfo: public Struct {
|
||||
inline bool is_special_data_property();
|
||||
inline void set_is_special_data_property(bool value);
|
||||
|
||||
inline bool replace_on_access();
|
||||
inline void set_replace_on_access(bool value);
|
||||
|
||||
inline bool is_sloppy();
|
||||
inline void set_is_sloppy(bool value);
|
||||
|
||||
@ -11258,7 +11261,8 @@ class AccessorInfo: public Struct {
|
||||
static const int kAllCanWriteBit = 1;
|
||||
static const int kSpecialDataProperty = 2;
|
||||
static const int kIsSloppy = 3;
|
||||
class AttributesField : public BitField<PropertyAttributes, 4, 3> {};
|
||||
static const int kReplaceOnAccess = 4;
|
||||
class AttributesField : public BitField<PropertyAttributes, 5, 3> {};
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user