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:
parent
181ac2b0dc
commit
4710442941
13
include/v8.h
13
include/v8.h
@ -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.
|
||||
|
20
src/api.cc
20
src/api.cc
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user