Commit 997cd3d9 authored by verwaest's avatar verwaest Committed by Commit bot

[api] Default native data property setter to replace the setter if the property is writable.

BUG=chromium:580584
LOG=y

Review URL: https://codereview.chromium.org/1632603002

Cr-Commit-Position: refs/heads/master@{#33551}
parent 57d202d8
This diff is collapsed.
...@@ -44,6 +44,12 @@ class AccessorInfo; ...@@ -44,6 +44,12 @@ class AccessorInfo;
V(ScriptIsEmbedderDebugScript) \ V(ScriptIsEmbedderDebugScript) \
V(StringLength) V(StringLength)
#define ACCESSOR_SETTER_LIST(V) \
V(ReconfigureToDataProperty) \
V(ObservedReconfigureToDataProperty) \
V(ArrayLengthSetter) \
V(FunctionPrototypeSetter)
// Accessors contains all predefined proxy accessors. // Accessors contains all predefined proxy accessors.
class Accessors : public AllStatic { class Accessors : public AllStatic {
...@@ -53,16 +59,18 @@ class Accessors : public AllStatic { ...@@ -53,16 +59,18 @@ class Accessors : public AllStatic {
static void name##Getter( \ static void name##Getter( \
v8::Local<v8::Name> name, \ v8::Local<v8::Name> name, \
const v8::PropertyCallbackInfo<v8::Value>& info); \ const v8::PropertyCallbackInfo<v8::Value>& info); \
static void name##Setter( \
v8::Local<v8::Name> name, \
v8::Local<v8::Value> value, \
const v8::PropertyCallbackInfo<void>& info); \
static Handle<AccessorInfo> name##Info( \ static Handle<AccessorInfo> name##Info( \
Isolate* isolate, \ Isolate* isolate, \
PropertyAttributes attributes); PropertyAttributes attributes);
ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION) ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION)
#undef ACCESSOR_INFO_DECLARATION #undef ACCESSOR_INFO_DECLARATION
#define ACCESSOR_SETTER_DECLARATION(name) \
static void name(v8::Local<v8::Name> name, v8::Local<v8::Value> value, \
const v8::PropertyCallbackInfo<void>& info);
ACCESSOR_SETTER_LIST(ACCESSOR_SETTER_DECLARATION)
#undef ACCESSOR_SETTER_DECLARATION
enum DescriptorId { enum DescriptorId {
#define ACCESSOR_INFO_DECLARATION(name) \ #define ACCESSOR_INFO_DECLARATION(name) \
k##name##Getter, \ k##name##Getter, \
......
...@@ -202,14 +202,12 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj, ...@@ -202,14 +202,12 @@ MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
return obj; return obj;
} }
MaybeHandle<JSObject> InstantiateObject(Isolate* isolate, MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
Handle<ObjectTemplateInfo> data) { Handle<ObjectTemplateInfo> info) {
// Enter a new scope. Recursion could otherwise create a lot of handles. // Enter a new scope. Recursion could otherwise create a lot of handles.
HandleScope scope(isolate); HandleScope scope(isolate);
// Fast path. // Fast path.
Handle<JSObject> result; Handle<JSObject> result;
auto info = Handle<ObjectTemplateInfo>::cast(data);
auto constructor = handle(info->constructor(), isolate); auto constructor = handle(info->constructor(), isolate);
Handle<JSFunction> cons; Handle<JSFunction> cons;
if (constructor->IsUndefined()) { if (constructor->IsUndefined()) {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "include/v8-experimental.h" #include "include/v8-experimental.h"
#include "include/v8-profiler.h" #include "include/v8-profiler.h"
#include "include/v8-testing.h" #include "include/v8-testing.h"
#include "src/accessors.h"
#include "src/api-experimental.h" #include "src/api-experimental.h"
#include "src/api-natives.h" #include "src/api-natives.h"
#include "src/assert-scope.h" #include "src/assert-scope.h"
...@@ -1118,20 +1119,23 @@ static i::Handle<i::AccessorInfo> SetAccessorInfoProperties( ...@@ -1118,20 +1119,23 @@ static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
return obj; return obj;
} }
template <typename Getter, typename Setter> template <typename Getter, typename Setter>
static i::Handle<i::AccessorInfo> MakeAccessorInfo( static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Local<Name> name, Getter getter, Setter setter, v8::Local<Value> data, v8::Local<Name> name, Getter getter, Setter setter, v8::Local<Value> data,
v8::AccessControl settings, v8::PropertyAttribute attributes, v8::AccessControl settings, v8::PropertyAttribute attributes,
v8::Local<AccessorSignature> signature) { v8::Local<AccessorSignature> signature, bool is_special_data_property) {
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate(); i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
i::Handle<i::AccessorInfo> obj = isolate->factory()->NewAccessorInfo(); i::Handle<i::AccessorInfo> obj = isolate->factory()->NewAccessorInfo();
SET_FIELD_WRAPPED(obj, set_getter, getter); SET_FIELD_WRAPPED(obj, set_getter, getter);
if (is_special_data_property && setter == nullptr) {
setter = reinterpret_cast<Setter>(&i::Accessors::ReconfigureToDataProperty);
}
SET_FIELD_WRAPPED(obj, set_setter, setter); SET_FIELD_WRAPPED(obj, set_setter, setter);
if (data.IsEmpty()) { if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate)); data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
} }
obj->set_data(*Utils::OpenHandle(*data)); obj->set_data(*Utils::OpenHandle(*data));
obj->set_is_special_data_property(is_special_data_property);
return SetAccessorInfoProperties(obj, name, settings, attributes, signature); return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
} }
...@@ -1277,22 +1281,18 @@ static inline i::Handle<i::TemplateInfo> GetTemplateInfo( ...@@ -1277,22 +1281,18 @@ static inline i::Handle<i::TemplateInfo> GetTemplateInfo(
return Utils::OpenHandle(object_template); return Utils::OpenHandle(object_template);
} }
template <typename Getter, typename Setter, typename Data, typename Template>
template<typename Getter, typename Setter, typename Data, typename Template> static bool TemplateSetAccessor(Template* template_obj, v8::Local<Name> name,
static bool TemplateSetAccessor( Getter getter, Setter setter, Data data,
Template* template_obj,
v8::Local<Name> name,
Getter getter,
Setter setter,
Data data,
AccessControl settings, AccessControl settings,
PropertyAttribute attribute, PropertyAttribute attribute,
v8::Local<AccessorSignature> signature) { v8::Local<AccessorSignature> signature,
bool is_special_data_property) {
auto isolate = Utils::OpenHandle(template_obj)->GetIsolate(); auto isolate = Utils::OpenHandle(template_obj)->GetIsolate();
ENTER_V8(isolate); ENTER_V8(isolate);
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
auto obj = MakeAccessorInfo(name, getter, setter, data, settings, attribute, auto obj = MakeAccessorInfo(name, getter, setter, data, settings, attribute,
signature); signature, is_special_data_property);
if (obj.is_null()) return false; if (obj.is_null()) return false;
auto info = GetTemplateInfo(isolate, template_obj); auto info = GetTemplateInfo(isolate, template_obj);
i::ApiNatives::AddNativeDataProperty(isolate, info, obj); i::ApiNatives::AddNativeDataProperty(isolate, info, obj);
...@@ -1307,8 +1307,8 @@ void Template::SetNativeDataProperty(v8::Local<String> name, ...@@ -1307,8 +1307,8 @@ void Template::SetNativeDataProperty(v8::Local<String> name,
PropertyAttribute attribute, PropertyAttribute attribute,
v8::Local<AccessorSignature> signature, v8::Local<AccessorSignature> signature,
AccessControl settings) { AccessControl settings) {
TemplateSetAccessor( TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
this, name, getter, setter, data, settings, attribute, signature); signature, true);
} }
...@@ -1319,8 +1319,8 @@ void Template::SetNativeDataProperty(v8::Local<Name> name, ...@@ -1319,8 +1319,8 @@ void Template::SetNativeDataProperty(v8::Local<Name> name,
PropertyAttribute attribute, PropertyAttribute attribute,
v8::Local<AccessorSignature> signature, v8::Local<AccessorSignature> signature,
AccessControl settings) { AccessControl settings) {
TemplateSetAccessor( TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
this, name, getter, setter, data, settings, attribute, signature); signature, true);
} }
...@@ -1342,8 +1342,8 @@ void ObjectTemplate::SetAccessor(v8::Local<String> name, ...@@ -1342,8 +1342,8 @@ void ObjectTemplate::SetAccessor(v8::Local<String> name,
v8::Local<Value> data, AccessControl settings, v8::Local<Value> data, AccessControl settings,
PropertyAttribute attribute, PropertyAttribute attribute,
v8::Local<AccessorSignature> signature) { v8::Local<AccessorSignature> signature) {
TemplateSetAccessor( TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
this, name, getter, setter, data, settings, attribute, signature); signature, i::FLAG_disable_old_api_accessors);
} }
...@@ -1353,8 +1353,8 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name, ...@@ -1353,8 +1353,8 @@ void ObjectTemplate::SetAccessor(v8::Local<Name> name,
v8::Local<Value> data, AccessControl settings, v8::Local<Value> data, AccessControl settings,
PropertyAttribute attribute, PropertyAttribute attribute,
v8::Local<AccessorSignature> signature) { v8::Local<AccessorSignature> signature) {
TemplateSetAccessor( TemplateSetAccessor(this, name, getter, setter, data, settings, attribute,
this, name, getter, setter, data, settings, attribute, signature); signature, i::FLAG_disable_old_api_accessors);
} }
...@@ -3919,7 +3919,7 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self, ...@@ -3919,7 +3919,7 @@ static Maybe<bool> ObjectSetAccessor(Local<Context> context, Object* self,
i::Handle<i::JSObject>::cast(Utils::OpenHandle(self)); i::Handle<i::JSObject>::cast(Utils::OpenHandle(self));
v8::Local<AccessorSignature> signature; v8::Local<AccessorSignature> signature;
auto info = MakeAccessorInfo(name, getter, setter, data, settings, attributes, auto info = MakeAccessorInfo(name, getter, setter, data, settings, attributes,
signature); signature, i::FLAG_disable_old_api_accessors);
if (info.is_null()) return Nothing<bool>(); if (info.is_null()) return Nothing<bool>();
bool fast = obj->HasFastProperties(); bool fast = obj->HasFastProperties();
i::Handle<i::Object> result; i::Handle<i::Object> result;
......
...@@ -867,6 +867,10 @@ DEFINE_INT(external_allocation_limit_incremental_time, 1, ...@@ -867,6 +867,10 @@ DEFINE_INT(external_allocation_limit_incremental_time, 1,
"Time spent in incremental marking steps (in ms) once the external " "Time spent in incremental marking steps (in ms) once the external "
"allocation limit is reached") "allocation limit is reached")
DEFINE_BOOL(disable_old_api_accessors, false,
"Disable old-style API accessors whose setters trigger through the "
"prototype chain")
// //
// Dev shell flags // Dev shell flags
// //
......
...@@ -237,6 +237,9 @@ class LookupIterator final BASE_EMBEDDED { ...@@ -237,6 +237,9 @@ class LookupIterator final BASE_EMBEDDED {
DCHECK(has_property_); DCHECK(has_property_);
return property_details_; return property_details_;
} }
PropertyAttributes property_attributes() const {
return property_details().attributes();
}
bool IsConfigurable() const { return property_details().IsConfigurable(); } bool IsConfigurable() const { return property_details().IsConfigurable(); }
bool IsReadOnly() const { return property_details().IsReadOnly(); } bool IsReadOnly() const { return property_details().IsReadOnly(); }
Representation representation() const { Representation representation() const {
......
...@@ -1192,7 +1192,6 @@ bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate, ...@@ -1192,7 +1192,6 @@ bool AccessorInfo::IsCompatibleReceiverMap(Isolate* isolate,
->IsTemplateFor(*map); ->IsTemplateFor(*map);
} }
Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
Handle<Object> value, Handle<Object> value,
ShouldThrow should_throw) { ShouldThrow should_throw) {
...@@ -1217,11 +1216,10 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it, ...@@ -1217,11 +1216,10 @@ Maybe<bool> Object::SetPropertyWithAccessor(LookupIterator* it,
v8::AccessorNameSetterCallback call_fun = v8::AccessorNameSetterCallback call_fun =
v8::ToCData<v8::AccessorNameSetterCallback>(info->setter()); v8::ToCData<v8::AccessorNameSetterCallback>(info->setter());
// TODO(verwaest): We should not get here anymore once all AccessorInfos are
// marked as special_data_property. They cannot both be writable and not
// have a setter.
if (call_fun == nullptr) return Just(true); if (call_fun == nullptr) return Just(true);
// TODO(verwaest): Shouldn't this case be unreachable (at least in the long
// run?) Should we have AccessorInfo with missing setter that are
// "writable"? If they aren't writable, shouldn't we have bailed out already
// earlier?
LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name)); LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder, PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder,
...@@ -1350,7 +1348,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck( ...@@ -1350,7 +1348,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
Handle<JSObject> checked = it->GetHolder<JSObject>(); Handle<JSObject> checked = it->GetHolder<JSObject>();
while (AllCanRead(it)) { while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) { if (it->state() == LookupIterator::ACCESSOR) {
return Just(it->property_details().attributes()); return Just(it->property_attributes());
} }
DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state()); DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
auto result = GetPropertyAttributesWithInterceptor(it); auto result = GetPropertyAttributesWithInterceptor(it);
...@@ -4219,8 +4217,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, ...@@ -4219,8 +4217,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
should_throw); should_throw);
case LookupIterator::DATA: { case LookupIterator::DATA: {
PropertyDetails details = own_lookup.property_details(); if (own_lookup.IsReadOnly()) {
if (details.IsReadOnly()) {
return WriteToReadOnlyProperty(&own_lookup, value, should_throw); return WriteToReadOnlyProperty(&own_lookup, value, should_throw);
} }
return SetDataProperty(&own_lookup, value); return SetDataProperty(&own_lookup, value);
...@@ -5268,18 +5265,23 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( ...@@ -5268,18 +5265,23 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
// Special handling for AccessorInfo, which behaves like a data // Special handling for AccessorInfo, which behaves like a data
// property. // property.
if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) { if (accessors->IsAccessorInfo() && handling == DONT_FORCE_FIELD) {
PropertyDetails details = it->property_details(); PropertyAttributes current_attributes = it->property_attributes();
// Ensure the context isn't changed after calling into accessors. // Ensure the context isn't changed after calling into accessors.
AssertNoContextChange ncc(it->isolate()); AssertNoContextChange ncc(it->isolate());
// Update the attributes before calling the setter. The setter may
// later change the shape of the property.
if (current_attributes != attributes) {
it->TransitionToAccessorPair(accessors, attributes);
}
Maybe<bool> result = Maybe<bool> result =
JSObject::SetPropertyWithAccessor(it, value, should_throw); JSObject::SetPropertyWithAccessor(it, value, should_throw);
if (result.IsNothing() || !result.FromJust()) return result;
if (details.attributes() == attributes) return Just(true); if (current_attributes == attributes || result.IsNothing()) {
return result;
}
// Reconfigure the accessor if attributes mismatch.
it->TransitionToAccessorPair(accessors, attributes);
} else { } else {
it->ReconfigureDataProperty(value, attributes); it->ReconfigureDataProperty(value, attributes);
} }
...@@ -5299,10 +5301,9 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( ...@@ -5299,10 +5301,9 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
should_throw); should_throw);
case LookupIterator::DATA: { case LookupIterator::DATA: {
PropertyDetails details = it->property_details();
Handle<Object> old_value = it->factory()->the_hole_value(); Handle<Object> old_value = it->factory()->the_hole_value();
// Regular property update if the attributes match. // Regular property update if the attributes match.
if (details.attributes() == attributes) { if (it->property_attributes() == attributes) {
return SetDataProperty(it, value); return SetDataProperty(it, value);
} }
...@@ -5458,7 +5459,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( ...@@ -5458,7 +5459,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
return Just(ABSENT); return Just(ABSENT);
case LookupIterator::ACCESSOR: case LookupIterator::ACCESSOR:
case LookupIterator::DATA: case LookupIterator::DATA:
return Just(it->property_details().attributes()); return Just(it->property_attributes());
} }
} }
return Just(ABSENT); return Just(ABSENT);
...@@ -7201,7 +7202,7 @@ Maybe<bool> JSProxy::AddPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy, ...@@ -7201,7 +7202,7 @@ Maybe<bool> JSProxy::AddPrivateProperty(Isolate* isolate, Handle<JSProxy> proxy,
if (it.IsFound()) { if (it.IsFound()) {
DCHECK_EQ(LookupIterator::DATA, it.state()); DCHECK_EQ(LookupIterator::DATA, it.state());
DCHECK_EQ(DONT_ENUM, it.property_details().attributes()); DCHECK_EQ(DONT_ENUM, it.property_attributes());
it.WriteDataValue(value); it.WriteDataValue(value);
return Just(true); return Just(true);
} }
......
...@@ -268,8 +268,13 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) { ...@@ -268,8 +268,13 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
static const AccessorRefTable accessors[] = { static const AccessorRefTable accessors[] = {
#define ACCESSOR_INFO_DECLARATION(name) \ #define ACCESSOR_INFO_DECLARATION(name) \
{ FUNCTION_ADDR(&Accessors::name##Getter), "Accessors::" #name "Getter" } \ { FUNCTION_ADDR(&Accessors::name##Getter), "Accessors::" #name "Getter" } \
, {FUNCTION_ADDR(&Accessors::name##Setter), "Accessors::" #name "Setter"}, ,
ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION) ACCESSOR_INFO_LIST(ACCESSOR_INFO_DECLARATION)
#undef ACCESSOR_INFO_DECLARATION
#define ACCESSOR_SETTER_DECLARATION(name) \
{ FUNCTION_ADDR(&Accessors::name), "Accessors::" #name } \
,
ACCESSOR_SETTER_LIST(ACCESSOR_SETTER_DECLARATION)
#undef ACCESSOR_INFO_DECLARATION #undef ACCESSOR_INFO_DECLARATION
}; };
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function f() { return arguments }
// Reconfiguring function.name should update both the attributes and the value.
Object.defineProperty(f, "name", {
writable: true, configurable: true, value: 10});
assertEquals({value: 10, writable: true, enumerable: false, configurable: true},
Object.getOwnPropertyDescriptor(f, "name"));
var args = f();
// Setting a value for arguments[Symbol.iterator] should not affect the
// attributes.
args[Symbol.iterator] = 10;
assertEquals({value: 10, writable: true, configurable: true, enumerable: false},
Object.getOwnPropertyDescriptor(args, Symbol.iterator));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment