Implement v8::Object::SetLazyDataProperty.

It is analogous to Template::SetLazyDataProperty, but for a single
existing object. Similar to how SetNativeDataProperty exists on both.

Bug: v8:7303
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I634358ee455e28150198bd87a2bd79dc59e3e449
Reviewed-on: https://chromium-review.googlesource.com/867474
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Jeremy Roman <jbroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50841}
This commit is contained in:
Jeremy Roman 2018-01-16 14:00:27 -05:00 committed by Commit Bot
parent 181ac2b0dc
commit 4710442941
3 changed files with 63 additions and 5 deletions

View File

@ -3198,6 +3198,19 @@ class V8_EXPORT Object : public Value {
AccessorNameSetterCallback setter = nullptr,
Local<Value> data = Local<Value>(), PropertyAttribute attributes = None);
/**
* Attempts to create a property with the given name which behaves like a data
* property, except that the provided getter is invoked (and provided with the
* data value) to supply its value the first time it is read. After the
* property is accessed once, it is replaced with an ordinary data property.
*
* Analogous to Template::SetLazyDataProperty.
*/
V8_WARN_UNUSED_RESULT Maybe<bool> SetLazyDataProperty(
Local<Context> context, Local<Name> name,
AccessorNameGetterCallback getter, Local<Value> data = Local<Value>(),
PropertyAttribute attributes = None);
/**
* Functionality for private properties.
* This is an experimental feature, use at your own risk.

View File

@ -4765,14 +4765,14 @@ Maybe<bool> v8::Object::Has(Local<Context> context, uint32_t index) {
return maybe;
}
template <typename Getter, typename Setter, typename Data>
static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self,
Local<Name> name, Getter getter,
Setter setter, Data data,
AccessControl settings,
PropertyAttribute attributes,
bool is_special_data_property) {
bool is_special_data_property,
bool replace_on_access) {
auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
ENTER_V8_NO_SCRIPT(isolate, context, Object, SetAccessor, Nothing<bool>(),
i::HandleScope);
@ -4782,7 +4782,7 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self,
v8::Local<AccessorSignature> signature;
i::Handle<i::AccessorInfo> info =
MakeAccessorInfo(isolate, name, getter, setter, data, settings, signature,
is_special_data_property, false);
is_special_data_property, replace_on_access);
if (info.is_null()) return Nothing<bool>();
bool fast = obj->HasFastProperties();
i::Handle<i::Object> result;
@ -4808,7 +4808,7 @@ Maybe<bool> Object::SetAccessor(Local<Context> context, Local<Name> name,
PropertyAttribute attribute) {
return ObjectSetAccessor(context, this, name, getter, setter,
data.FromMaybe(Local<Value>()), settings, attribute,
i::FLAG_disable_old_api_accessors);
i::FLAG_disable_old_api_accessors, false);
}
@ -4838,7 +4838,17 @@ Maybe<bool> Object::SetNativeDataProperty(v8::Local<v8::Context> context,
v8::Local<Value> data,
PropertyAttribute attributes) {
return ObjectSetAccessor(context, this, name, getter, setter, data, DEFAULT,
attributes, true);
attributes, true, false);
}
Maybe<bool> Object::SetLazyDataProperty(v8::Local<v8::Context> context,
v8::Local<Name> name,
AccessorNameGetterCallback getter,
v8::Local<Value> data,
PropertyAttribute attributes) {
return ObjectSetAccessor(context, this, name, getter,
static_cast<AccessorNameSetterCallback>(nullptr),
data, DEFAULT, attributes, true, true);
}
Maybe<bool> v8::Object::HasOwnProperty(Local<Context> context,

View File

@ -821,3 +821,38 @@ TEST(Regress609134) {
"var a = 42;"
"for (var i = 0; i<3; i++) { a.foo; }");
}
TEST(ObjectSetLazyDataProperty) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> obj = v8::Object::New(isolate);
CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
// Despite getting the property multiple times, the getter should only be
// called once and data property reads should continue to produce the same
// value.
static int getter_call_count;
getter_call_count = 0;
auto result = obj->SetLazyDataProperty(
env.local(), v8_str("foo"),
[](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
getter_call_count++;
info.GetReturnValue().Set(getter_call_count);
});
CHECK(result.FromJust());
CHECK_EQ(0, getter_call_count);
for (int i = 0; i < 2; i++) {
ExpectInt32("obj.foo", 1);
CHECK_EQ(1, getter_call_count);
}
// Setting should overwrite the data property.
result = obj->SetLazyDataProperty(
env.local(), v8_str("bar"),
[](Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
CHECK(false);
});
CHECK(result.FromJust());
ExpectInt32("obj.bar = -1; obj.bar;", -1);
}