Revision: 23163
Author: [email protected]
Date: Mon Aug 18 14:26:30 2014 UTC
Log: Rewriting SetOwnPropertyIgnoreAttributes using the LookupIterator
BUG=
[email protected]
Review URL: https://codereview.chromium.org/468493002
http://code.google.com/p/v8/source/detail?r=23163
Modified:
/branches/bleeding_edge/src/lookup.cc
/branches/bleeding_edge/src/lookup.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime.cc
=======================================
--- /branches/bleeding_edge/src/lookup.cc Wed Aug 6 08:02:21 2014 UTC
+++ /branches/bleeding_edge/src/lookup.cc Mon Aug 18 14:26:30 2014 UTC
@@ -124,6 +124,31 @@
}
CHECK(HasProperty());
}
+
+
+void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
+ PropertyAttributes
attributes) {
+ DCHECK(has_property_);
+ DCHECK(HolderIsReceiverOrHiddenPrototype());
+ Handle<JSObject> holder = GetHolder<JSObject>();
+ if (property_encoding_ != DICTIONARY) {
+ holder_map_ = Map::ReconfigureDataProperty(holder_map_,
descriptor_number(),
+ attributes);
+ JSObject::MigrateToMap(holder, holder_map_);
+ }
+
+ // Reload property information and update the descriptor if in dictionary
+ // mode.
+ if (holder_map_->is_dictionary_map()) {
+ property_encoding_ = DICTIONARY;
+ PropertyDetails details(attributes, NORMAL, 0);
+ JSObject::SetNormalizedProperty(holder, name(), value, details);
+ } else {
+ property_encoding_ = DESCRIPTOR;
+ }
+
+ CHECK(HasProperty());
+}
void LookupIterator::TransitionToDataProperty(
@@ -136,10 +161,6 @@
// observable.
Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
- // Properties have to be added to context extension objects through
- // SetOwnPropertyIgnoreAttributes.
- DCHECK(!receiver->IsJSContextExtensionObject());
-
if (receiver->IsJSGlobalProxy()) {
PrototypeIterator iter(isolate(), receiver);
receiver =
@@ -162,6 +183,8 @@
bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
+ // Optimization that only works if configuration_ is not mutable.
+ if (!check_derived()) return true;
DisallowHeapAllocation no_gc;
Handle<Object> receiver = GetReceiver();
if (!receiver->IsJSReceiver()) return false;
@@ -180,6 +203,16 @@
} while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
return false;
}
+
+
+bool LookupIterator::HolderIsNonGlobalHiddenPrototype() const {
+ if (!HolderIsReceiverOrHiddenPrototype()) return false;
+ Handle<Object> receiver = GetReceiver();
+ Handle<JSReceiver> holder = GetHolder<JSReceiver>();
+ if (receiver.is_identical_to(holder)) return false;
+ if (receiver->IsJSGlobalProxy()) return !holder->IsJSGlobalObject();
+ return true;
+}
Handle<Object> LookupIterator::FetchValue() const {
=======================================
--- /branches/bleeding_edge/src/lookup.h Tue Aug 12 15:28:20 2014 UTC
+++ /branches/bleeding_edge/src/lookup.h Mon Aug 18 14:26:30 2014 UTC
@@ -15,15 +15,15 @@
class LookupIterator V8_FINAL BASE_EMBEDDED {
public:
enum Configuration {
- CHECK_OWN_REAL = 0,
- CHECK_HIDDEN = 1 << 0,
- CHECK_DERIVED = 1 << 1,
- CHECK_INTERCEPTOR = 1 << 2,
+ CHECK_OWN_REAL = 0,
+ CHECK_HIDDEN = 1 << 0,
+ CHECK_DERIVED = 1 << 1,
+ CHECK_INTERCEPTOR = 1 << 2,
CHECK_ACCESS_CHECK = 1 << 3,
- CHECK_ALL = CHECK_HIDDEN | CHECK_DERIVED |
- CHECK_INTERCEPTOR | CHECK_ACCESS_CHECK,
- SKIP_INTERCEPTOR = CHECK_ALL ^ CHECK_INTERCEPTOR,
- CHECK_OWN = CHECK_ALL ^ CHECK_DERIVED
+ CHECK_HIDDEN_ACCESS = CHECK_HIDDEN | CHECK_ACCESS_CHECK,
+ SKIP_INTERCEPTOR = CHECK_HIDDEN_ACCESS | CHECK_DERIVED,
+ CHECK_ALL = SKIP_INTERCEPTOR | CHECK_INTERCEPTOR,
+ CHECK_OWN = CHECK_HIDDEN_ACCESS | CHECK_INTERCEPTOR
};
enum State {
@@ -90,7 +90,7 @@
Heap* heap() const { return isolate_->heap(); }
Factory* factory() const { return isolate_->factory(); }
Handle<Object> GetReceiver() const {
- return Handle<Object>::cast(maybe_receiver_.ToHandleChecked());
+ return maybe_receiver_.ToHandleChecked();
}
Handle<Map> holder_map() const { return holder_map_; }
template <class T>
@@ -100,16 +100,7 @@
}
Handle<JSReceiver> GetRoot() const;
bool HolderIsReceiverOrHiddenPrototype() const;
-
- /* Dynamically reduce the trapped types. */
- void skip_interceptor() {
- configuration_ = static_cast<Configuration>(
- configuration_ & ~CHECK_INTERCEPTOR);
- }
- void skip_access_check() {
- configuration_ = static_cast<Configuration>(
- configuration_ & ~CHECK_ACCESS_CHECK);
- }
+ bool HolderIsNonGlobalHiddenPrototype() const;
/* ACCESS_CHECK */
bool HasAccess(v8::AccessType access_type) const;
@@ -123,6 +114,8 @@
void TransitionToDataProperty(Handle<Object> value,
PropertyAttributes attributes,
Object::StoreFromKeyed store_mode);
+ void ReconfigureDataProperty(Handle<Object> value,
+ PropertyAttributes attributes);
PropertyKind property_kind() const {
DCHECK(has_property_);
return property_kind_;
@@ -196,6 +189,8 @@
}
}
+ // If configuration_ becomes mutable, update
+ // HolderIsReceiverOrHiddenPrototype.
Configuration configuration_;
State state_;
bool has_property_;
=======================================
--- /branches/bleeding_edge/src/objects.cc Mon Aug 18 07:54:19 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Mon Aug 18 14:26:30 2014 UTC
@@ -575,8 +575,6 @@
static bool FindAllCanReadHolder(LookupIterator* it) {
- it->skip_interceptor();
- it->skip_access_check();
for (; it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::PROPERTY &&
it->HasProperty() &&
@@ -618,8 +616,6 @@
static bool FindAllCanWriteHolder(LookupIterator* it) {
- it->skip_interceptor();
- it->skip_access_check();
for (; it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
it->property_kind() == LookupIterator::ACCESSOR) {
@@ -672,21 +668,6 @@
DCHECK(!value->IsPropertyCell() && !value->IsCell());
return value;
}
-
-
-void JSObject::SetNormalizedProperty(Handle<JSObject> object,
- const LookupResult* result,
- Handle<Object> value) {
- DCHECK(!object->HasFastProperties());
- NameDictionary* property_dictionary = object->property_dictionary();
- if (object->IsGlobalObject()) {
- Handle<PropertyCell> cell(PropertyCell::cast(
- property_dictionary->ValueAt(result->GetDictionaryEntry())));
- PropertyCell::SetValueInferType(cell, value);
- } else {
- property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
- }
-}
void JSObject::SetNormalizedProperty(Handle<JSObject> object,
@@ -1821,37 +1802,6 @@
ConstantDescriptor new_constant_desc(name, constant, attributes);
return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
}
-
-
-void JSObject::AddFastProperty(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes,
- StoreFromKeyed store_mode,
- TransitionFlag flag) {
- DCHECK(!object->IsJSGlobalProxy());
-
- MaybeHandle<Map> maybe_map;
- if (value->IsJSFunction()) {
- maybe_map = Map::CopyWithConstant(
- handle(object->map()), name, value, attributes, flag);
- } else if (!object->map()->TooManyFastProperties(store_mode)) {
- Isolate* isolate = object->GetIsolate();
- Representation representation = value->OptimalRepresentation();
- maybe_map = Map::CopyWithField(
- handle(object->map(), isolate), name,
- value->OptimalType(isolate, representation),
- attributes, representation, flag);
- }
-
- Handle<Map> new_map;
- if (!maybe_map.ToHandle(&new_map)) {
- NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
- return;
- }
-
- JSObject::MigrateToNewProperty(object, new_map, value);
-}
void JSObject::AddSlowProperty(Handle<JSObject> object,
@@ -1886,45 +1836,6 @@
}
-MaybeHandle<Object> JSObject::AddPropertyInternal(
- Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
- PropertyAttributes attributes, JSReceiver::StoreFromKeyed store_mode,
- ExtensibilityCheck extensibility_check, TransitionFlag
transition_flag) {
- DCHECK(!object->IsJSGlobalProxy());
- Isolate* isolate = object->GetIsolate();
-
- if (!name->IsUniqueName()) {
- name = isolate->factory()->InternalizeString(
- Handle<String>::cast(name));
- }
-
- if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
- !object->map()->is_extensible()) {
- Handle<Object> args[1] = {name};
- Handle<Object> error = isolate->factory()->NewTypeError(
- "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw<Object>(error);
- }
-
- if (object->HasFastProperties()) {
- AddFastProperty(object, name, value, attributes, store_mode,
- transition_flag);
- }
-
- if (!object->HasFastProperties()) {
- AddSlowProperty(object, name, value, attributes);
- }
-
- if (object->map()->is_observed() &&
- *name != isolate->heap()->hidden_string()) {
- Handle<Object> old_value = isolate->factory()->the_hole_value();
- EnqueueChangeRecord(object, "add", name, old_value);
- }
-
- return value;
-}
-
-
Context* JSObject::GetCreationContext() {
Object* constructor = this->map()->constructor();
JSFunction* function;
@@ -1957,23 +1868,6 @@
isolate->factory()->undefined_value(),
argc, args).Assert();
}
-
-
-static void ReplaceSlowProperty(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes) {
- NameDictionary* dictionary = object->property_dictionary();
- int old_index = dictionary->FindEntry(name);
- int new_enumeration_index = 0; // 0 means "Use the next available
index."
- if (old_index != -1) {
- // All calls to ReplaceSlowProperty have had all transitions removed.
- new_enumeration_index =
dictionary->DetailsAt(old_index).dictionary_index();
- }
-
- PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
- JSObject::SetNormalizedProperty(object, name, value, new_details);
-}
const char* Representation::Mnemonic() const {
@@ -3029,7 +2923,8 @@
if (done) break;
}
- return AddDataProperty(it, value, NONE, strict_mode, store_mode);
+ return AddDataProperty(it, value, NONE, strict_mode, store_mode,
+ PERFORM_EXTENSIBILITY_CHECK);
}
@@ -3084,7 +2979,8 @@
Handle<Object> value,
PropertyAttributes attributes,
StrictMode strict_mode,
- StoreFromKeyed store_mode) {
+ StoreFromKeyed store_mode,
+ ExtensibilityCheck check) {
DCHECK(!it->GetReceiver()->IsJSProxy());
if (!it->GetReceiver()->IsJSObject()) {
// TODO(verwaest): Throw a TypeError with a more specific message.
@@ -3102,7 +2998,8 @@
Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
}
- if (!receiver->map()->is_extensible()) {
+ if (check == PERFORM_EXTENSIBILITY_CHECK &&
+ !receiver->map()->is_extensible()) {
if (strict_mode == SLOPPY) return value;
Handle<Object> args[1] = {it->name()};
@@ -3941,45 +3838,6 @@
}
return true;
}
-
-
-MaybeHandle<Object> JSObject::SetPropertyUsingTransition(
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes) {
- Handle<Map> transition_map(lookup->GetTransitionTarget());
- int descriptor = transition_map->LastAdded();
-
- Handle<DescriptorArray>
descriptors(transition_map->instance_descriptors());
- PropertyDetails details = descriptors->GetDetails(descriptor);
-
- if (details.type() == CALLBACKS || attributes != details.attributes()) {
- // AddPropertyInternal will either normalize the object, or create a
new
- // fast copy of the map. If we get a fast copy of the map, all field
- // representations will be tagged since the transition is omitted.
- return JSObject::AddPropertyInternal(
- object, name, value, attributes,
- JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
- JSReceiver::OMIT_EXTENSIBILITY_CHECK, OMIT_TRANSITION);
- }
-
- // Keep the target CONSTANT if the same value is stored.
- // TODO(verwaest): Also support keeping the placeholder
- // (value->IsUninitialized) as constant.
- if (!lookup->CanHoldValue(value)) {
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
- transition_map = Map::GeneralizeRepresentation(
- transition_map, descriptor,
- field_representation, field_type, FORCE_FIELD);
- }
-
- JSObject::MigrateToNewProperty(object, transition_map, value);
- return value;
-}
void JSObject::MigrateToNewProperty(Handle<JSObject> object,
@@ -4010,65 +3868,6 @@
FastPropertyAtPut(index, value);
}
}
-
-
-void JSObject::SetPropertyToField(LookupResult* lookup, Handle<Object>
value) {
- if (lookup->type() == CONSTANT || !lookup->CanHoldValue(value)) {
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
- JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
- lookup->GetDescriptorIndex(),
- field_representation,
field_type);
- }
- lookup->holder()->WriteToField(lookup->GetDescriptorIndex(), *value);
-}
-
-
-void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes) {
- Handle<JSObject> object(lookup->holder());
- if
(object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) {
- JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
- } else if (object->map()->is_prototype_map()) {
- JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
- }
-
- if (!object->HasFastProperties()) {
- ReplaceSlowProperty(object, name, value, attributes);
- ReoptimizeIfPrototype(object);
- return;
- }
-
- int descriptor_index = lookup->GetDescriptorIndex();
- if (lookup->GetAttributes() == attributes) {
- JSObject::GeneralizeFieldRepresentation(object, descriptor_index,
- Representation::Tagged(),
-
HeapType::Any(lookup->isolate()));
- } else {
- Handle<Map> old_map(object->map());
- Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
- descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
- JSObject::MigrateToMap(object, new_map);
- }
-
- object->WriteToField(descriptor_index, *value);
-}
-
-
-void JSObject::SetPropertyToFieldWithAttributes(LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes
attributes) {
- if (lookup->GetAttributes() == attributes) {
- if (value->IsUninitialized()) return;
- SetPropertyToField(lookup, value);
- } else {
- ConvertAndSetOwnProperty(lookup, name, value, attributes);
- }
-}
void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
@@ -4100,156 +3899,123 @@
StoreFromKeyed store_from_keyed,
ExecutableAccessorInfoHandling handling) {
DCHECK(!value->IsTheHole());
- Isolate* isolate = object->GetIsolate();
+ LookupIterator it(object, name, LookupIterator::CHECK_HIDDEN_ACCESS);
+ bool is_observed = object->map()->is_observed() &&
+ *name != it.isolate()->heap()->hidden_string();
+ for (; it.IsFound(); it.Next()) {
+ switch (it.state()) {
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::JSPROXY:
+ case LookupIterator::INTERCEPTOR:
+ UNREACHABLE();
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
+ case LookupIterator::ACCESS_CHECK:
+ if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
+ return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
+ }
+ break;
- LookupResult lookup(isolate);
- object->LookupOwn(name, &lookup, true);
- if (!lookup.IsFound()) {
- object->map()->LookupTransition(*object, *name, &lookup);
- }
+ case LookupIterator::PROPERTY: {
+ if (!it.HasProperty()) break;
+ if (it.HolderIsNonGlobalHiddenPrototype()) break;
+ PropertyDetails details = it.property_details();
+ Handle<Object> old_value =
it.isolate()->factory()->the_hole_value();
+ switch (it.property_kind()) {
+ case LookupIterator::ACCESSOR: {
+ // Ensure the context isn't changed after calling into
accessors.
+ AssertNoContextChange ncc(it.isolate());
- // Check access rights if needed.
- if (object->IsAccessCheckNeeded()) {
- if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
- LookupIterator it(object, name, LookupIterator::CHECK_OWN);
- return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
- }
- }
+ Handle<Object> accessors = it.GetAccessors();
- if (object->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, object);
- if (iter.IsAtEnd()) return value;
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return SetOwnPropertyIgnoreAttributes(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), name,
- value, attributes, extensibility_check);
- }
+ if (is_observed && accessors->IsAccessorInfo()) {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ it.isolate(), old_value,
+ GetPropertyWithAccessor(it.GetReceiver(), it.name(),
+ it.GetHolder<JSObject>(),
accessors),
+ Object);
+ }
- if (lookup.IsInterceptor() ||
- (lookup.IsDescriptorOrDictionary() && lookup.type() == CALLBACKS)) {
- object->LookupOwnRealNamedProperty(name, &lookup);
- }
+ // Special handling for ExecutableAccessorInfo, which behaves
like a
+ // data property.
+ if (handling == DONT_FORCE_FIELD &&
+ accessors->IsExecutableAccessorInfo()) {
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ it.isolate(), result,
+ JSObject::SetPropertyWithAccessor(
+ it.GetReceiver(), it.name(), value,
+ it.GetHolder<JSObject>(), accessors, STRICT),
+ Object);
+ DCHECK(result->SameValue(*value));
- // Check for accessor in prototype chain removed here in clone.
- if (!lookup.IsFound()) {
- object->map()->LookupTransition(*object, *name, &lookup);
- TransitionFlag flag = lookup.IsFound()
- ? OMIT_TRANSITION : INSERT_TRANSITION;
- // Neither properties nor transitions found.
- return AddPropertyInternal(object, name, value, attributes,
- store_from_keyed, extensibility_check,
flag);
- }
+ if (details.attributes() == attributes) {
+ // Regular property update if the attributes match.
+ if (is_observed && !old_value->SameValue(*value)) {
+ // If we are setting the prototype of a function and are
+ // observed, don't send change records because the
prototype
+ // handles that itself.
+ if (!object->IsJSFunction() ||
+
!Name::Equals(it.isolate()->factory()->prototype_string(),
+ name) ||
+ !Handle<JSFunction>::cast(object)
+ ->should_have_prototype()) {
+ EnqueueChangeRecord(object, "update", name, old_value);
+ }
+ }
+ return value;
+ }
- Handle<Object> old_value = isolate->factory()->the_hole_value();
- PropertyAttributes old_attributes = ABSENT;
- bool is_observed = object->map()->is_observed() &&
- *name != isolate->heap()->hidden_string();
- if (is_observed && lookup.IsProperty()) {
- if (lookup.IsDataProperty()) {
- old_value = Object::GetPropertyOrElement(object,
name).ToHandleChecked();
- }
- old_attributes = lookup.GetAttributes();
- }
+ // Reconfigure the accessor if attributes mismatch.
+ Handle<ExecutableAccessorInfo> new_data =
+ Accessors::CloneAccessor(
+ it.isolate(),
+ Handle<ExecutableAccessorInfo>::cast(accessors));
+ new_data->set_property_attributes(attributes);
+ // By clearing the setter we don't have to introduce a
lookup to
+ // the setter, simply make it unavailable to reflect the
+ // attributes.
+ if (attributes & READ_ONLY) new_data->clear_setter();
+ SetPropertyCallback(object, name, new_data, attributes);
+ if (is_observed) {
+ if (old_value->SameValue(*value)) {
+ old_value = it.isolate()->factory()->the_hole_value();
+ }
+ EnqueueChangeRecord(object, "reconfigure", name,
old_value);
+ }
+ return value;
+ }
- bool executed_set_prototype = false;
+ // Regular accessor. Reconfigure to data property.
+ break;
+ }
- // Check of IsReadOnly removed from here in clone.
- if (lookup.IsTransition()) {
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result,
- SetPropertyUsingTransition(
- handle(lookup.holder()), &lookup, name, value, attributes),
- Object);
- } else {
- switch (lookup.type()) {
- case NORMAL:
- ReplaceSlowProperty(object, name, value, attributes);
- break;
- case FIELD:
- SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
- break;
- case CONSTANT:
- // Only replace the constant if necessary.
- if (lookup.GetAttributes() != attributes ||
- *value != lookup.GetConstant()) {
- SetPropertyToFieldWithAttributes(&lookup, name, value,
attributes);
+ case LookupIterator::DATA:
+ // Regular property update if the attributes match.
+ if (details.attributes() == attributes) {
+ return SetDataProperty(&it, value);
+ }
+ // Reconfigure the data property if the attributes mismatch.
+ if (is_observed) old_value = it.GetDataValue();
}
- break;
- case CALLBACKS:
- {
- Handle<Object> callback(lookup.GetCallbackObject(), isolate);
- if (callback->IsExecutableAccessorInfo() &&
- handling == DONT_FORCE_FIELD) {
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result, JSObject::SetPropertyWithAccessor(
- object, name, value,
handle(lookup.holder()),
- callback, STRICT),
- Object);
- if (attributes != lookup.GetAttributes()) {
- Handle<ExecutableAccessorInfo> new_data =
- Accessors::CloneAccessor(
- isolate,
Handle<ExecutableAccessorInfo>::cast(callback));
- new_data->set_property_attributes(attributes);
- if (attributes & READ_ONLY) {
- // This way we don't have to introduce a lookup to the
setter,
- // simply make it unavailable to reflect the attributes.
- new_data->clear_setter();
- }
+ it.ReconfigureDataProperty(value, attributes);
+ it.PrepareForDataProperty(value);
+ it.WriteDataValue(value);
- SetPropertyCallback(object, name, new_data, attributes);
+ if (is_observed) {
+ if (old_value->SameValue(*value)) {
+ old_value = it.isolate()->factory()->the_hole_value();
}
- if (is_observed) {
- // If we are setting the prototype of a function and are
observed,
- // don't send change records because the prototype handles that
- // itself.
- executed_set_prototype = object->IsJSFunction() &&
- String::Equals(isolate->factory()->prototype_string(),
- Handle<String>::cast(name)) &&
- Handle<JSFunction>::cast(object)->should_have_prototype();
- }
- } else {
- ConvertAndSetOwnProperty(&lookup, name, value, attributes);
+ EnqueueChangeRecord(object, "reconfigure", name, old_value);
}
- break;
- }
- case NONEXISTENT:
- case HANDLER:
- case INTERCEPTOR:
- UNREACHABLE();
- }
- }
- if (is_observed && !executed_set_prototype) {
- if (lookup.IsTransition()) {
- EnqueueChangeRecord(object, "add", name, old_value);
- } else if (old_value->IsTheHole()) {
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
- } else {
- LookupResult new_lookup(isolate);
- object->LookupOwn(name, &new_lookup, true);
- bool value_changed = false;
- if (new_lookup.IsDataProperty()) {
- Handle<Object> new_value =
- Object::GetPropertyOrElement(object, name).ToHandleChecked();
- value_changed = !old_value->SameValue(*new_value);
- }
- if (new_lookup.GetAttributes() != old_attributes) {
- if (!value_changed) old_value =
isolate->factory()->the_hole_value();
- EnqueueChangeRecord(object, "reconfigure", name, old_value);
- } else if (value_changed) {
- EnqueueChangeRecord(object, "update", name, old_value);
+ return value;
}
}
}
- return value;
+ return AddDataProperty(&it, value, attributes, STRICT, store_from_keyed,
+ extensibility_check);
}
@@ -7409,6 +7175,18 @@
return result;
}
+
+
+Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
+ PropertyAttributes attributes) {
+ // Dictionaries have to be reconfigured in-place.
+ DCHECK(!map->is_dictionary_map());
+
+ // For now, give up on transitioning and just create a unique map.
+ // TODO(verwaest/ishell): Cache transitions with different attributes.
+ return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
+ attributes, "attributes
mismatch");
+}
Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Aug 18 12:35:34 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Mon Aug 18 14:26:30 2014 UTC
@@ -247,6 +247,14 @@
};
+// Internal properties (e.g. the hidden properties dictionary) might
+// be added even though the receiver is non-extensible.
+enum ExtensibilityCheck {
+ PERFORM_EXTENSIBILITY_CHECK,
+ OMIT_EXTENSIBILITY_CHECK
+};
+
+
// Indicates how aggressively the prototype should be optimized.
FAST_PROTOTYPE
// will give the fastest result by tailoring the map to the prototype, but
that
// will cause polymorphism with other objects. REGULAR_PROTOTYPE is to be
used
@@ -1492,7 +1500,8 @@
LookupIterator* it, Handle<Object> value);
MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
LookupIterator* it, Handle<Object> value, PropertyAttributes
attributes,
- StrictMode strict_mode, StoreFromKeyed store_mode);
+ StrictMode strict_mode, StoreFromKeyed store_mode,
+ ExtensibilityCheck check);
MUST_USE_RESULT static inline MaybeHandle<Object> GetPropertyOrElement(
Handle<Object> object,
Handle<Name> key);
@@ -1936,13 +1945,6 @@
FORCE_DELETION
};
- // Internal properties (e.g. the hidden properties dictionary) might
- // be added even though the receiver is non-extensible.
- enum ExtensibilityCheck {
- PERFORM_EXTENSIBILITY_CHECK,
- OMIT_EXTENSIBILITY_CHECK
- };
-
DECLARE_CAST(JSReceiver)
MUST_USE_RESULT static MaybeHandle<Object> SetElement(
@@ -2172,12 +2174,6 @@
static Handle<Object> GetNormalizedProperty(Handle<JSObject> object,
const LookupResult* result);
- // Sets the property value in a normalized object given a lookup result.
- // Handles the special representation of JS global objects.
- static void SetNormalizedProperty(Handle<JSObject> object,
- const LookupResult* result,
- Handle<Object> value);
-
// Sets the property value in a normalized object given (key, value,
details).
// Handles the special representation of JS global objects.
static void SetNormalizedProperty(Handle<JSObject> object,
@@ -2621,17 +2617,6 @@
Handle<Map> new_map,
int expected_additional_properties);
- static void SetPropertyToField(LookupResult* lookup, Handle<Object>
value);
-
- static void ConvertAndSetOwnProperty(LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes);
-
- static void SetPropertyToFieldWithAttributes(LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes
attributes);
static void GeneralizeFieldRepresentation(Handle<JSObject> object,
int modify_index,
Representation
new_representation,
@@ -2705,29 +2690,9 @@
StrictMode strict_mode,
bool check_prototype = true);
- MUST_USE_RESULT static MaybeHandle<Object> SetPropertyUsingTransition(
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes);
MUST_USE_RESULT static MaybeHandle<Object>
SetPropertyWithFailedAccessCheck(
LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
- // Add a property to an object.
- MUST_USE_RESULT static MaybeHandle<Object> AddPropertyInternal(
- Handle<JSObject> object, Handle<Name> name, Handle<Object> value,
- PropertyAttributes attributes, StoreFromKeyed store_mode,
- ExtensibilityCheck extensibility_check, TransitionFlag flag);
-
- // Add a property to a fast-case object.
- static void AddFastProperty(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- PropertyAttributes attributes,
- StoreFromKeyed store_mode,
- TransitionFlag flag);
-
// Add a property to a slow-case object.
static void AddSlowProperty(Handle<JSObject> object,
Handle<Name> name,
@@ -6517,6 +6482,8 @@
Handle<Object> value,
PropertyAttributes
attributes,
StoreFromKeyed store_mode);
+ static Handle<Map> ReconfigureDataProperty(Handle<Map> map, int
descriptor,
+ PropertyAttributes
attributes);
inline void AppendDescriptor(Descriptor* desc);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Mon Aug 18 08:51:35 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc Mon Aug 18 14:26:30 2014 UTC
@@ -5041,10 +5041,8 @@
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
JSObject::SetOwnPropertyIgnoreAttributes(
- js_object, name, obj_value, attr,
- JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
- JSReceiver::MAY_BE_STORE_FROM_KEYED,
- JSObject::DONT_FORCE_FIELD));
+ js_object, name, obj_value, attr, PERFORM_EXTENSIBILITY_CHECK,
+ JSReceiver::MAY_BE_STORE_FROM_KEYED,
JSObject::DONT_FORCE_FIELD));
return *result;
}
@@ -5198,7 +5196,7 @@
} else {
if (name->IsString()) name =
String::Flatten(Handle<String>::cast(name));
return JSObject::SetOwnPropertyIgnoreAttributes(
- js_object, name, value, attr,
JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
+ js_object, name, value, attr, PERFORM_EXTENSIBILITY_CHECK,
store_from_keyed);
}
}
@@ -5214,7 +5212,7 @@
SLOPPY, false, DEFINE_PROPERTY);
} else {
return JSObject::SetOwnPropertyIgnoreAttributes(
- js_object, name, value, attr,
JSReceiver::PERFORM_EXTENSIBILITY_CHECK,
+ js_object, name, value, attr, PERFORM_EXTENSIBILITY_CHECK,
store_from_keyed);
}
}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.