Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(850)

Unified Diff: src/objects.cc

Issue 490533002: Use LookupIterator to transition to accessors (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/runtime.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index ac4982d4fe4088e7fcd90c286b9f9c4c4689d405..e8c38385ea29e2330345bf8cabc115f6518432f0 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -6102,51 +6102,6 @@ void JSObject::DefineElementAccessor(Handle<JSObject> object,
}
-Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
- Handle<Name> name) {
- Isolate* isolate = object->GetIsolate();
- LookupResult result(isolate);
- object->LookupOwnRealNamedProperty(name, &result);
- if (result.IsPropertyCallbacks()) {
- // Note that the result can actually have IsDontDelete() == true when we
- // e.g. have to fall back to the slow case while adding a setter after
- // successfully reusing a map transition for a getter. Nevertheless, this is
- // OK, because the assertion only holds for the whole addition of both
- // accessors, not for the addition of each part. See first comment in
- // DefinePropertyAccessor below.
- Object* obj = result.GetCallbackObject();
- if (obj->IsAccessorPair()) {
- return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
- }
- }
- return isolate->factory()->NewAccessorPair();
-}
-
-
-void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> getter,
- Handle<Object> setter,
- PropertyAttributes attributes) {
- // We could assert that the property is configurable here, but we would need
- // to do a lookup, which seems to be a bit of overkill.
- bool only_attribute_changes = getter->IsNull() && setter->IsNull();
- if (object->HasFastProperties() && !only_attribute_changes &&
- (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors)) {
- bool getterOk = getter->IsNull() ||
- DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
- bool setterOk = !getterOk || setter->IsNull() ||
- DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
- if (getterOk && setterOk) return;
- }
-
- Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
- accessors->SetComponents(*getter, *setter);
-
- SetPropertyCallback(object, name, accessors, attributes);
-}
-
-
bool Map::DictionaryElementsInPrototypeChainOnly() {
if (IsDictionaryElementsKind(elements_kind())) {
return false;
@@ -6305,7 +6260,19 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
if (is_element) {
DefineElementAccessor(object, index, getter, setter, attributes);
} else {
- DefinePropertyAccessor(object, name, getter, setter, attributes);
+ DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
+ getter->IsNull());
+ DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
+ setter->IsNull());
+ // At least one of the accessors needs to be a new value.
+ DCHECK(!getter->IsNull() || !setter->IsNull());
+ LookupIterator it(object, name, LookupIterator::CHECK_PROPERTY);
+ if (!getter->IsNull()) {
+ it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
+ }
+ if (!setter->IsNull()) {
+ it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
+ }
}
if (is_observed) {
@@ -6317,111 +6284,6 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
}
-static bool TryAccessorTransition(Handle<JSObject> self,
- Handle<Map> transitioned_map,
- int target_descriptor,
- AccessorComponent component,
- Handle<Object> accessor,
- PropertyAttributes attributes) {
- DescriptorArray* descs = transitioned_map->instance_descriptors();
- PropertyDetails details = descs->GetDetails(target_descriptor);
-
- // If the transition target was not callbacks, fall back to the slow case.
- if (details.type() != CALLBACKS) return false;
- Object* descriptor = descs->GetCallbacksObject(target_descriptor);
- if (!descriptor->IsAccessorPair()) return false;
-
- Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
- PropertyAttributes target_attributes = details.attributes();
-
- // Reuse transition if adding same accessor with same attributes.
- if (target_accessor == *accessor && target_attributes == attributes) {
- JSObject::MigrateToMap(self, transitioned_map);
- return true;
- }
-
- // If either not the same accessor, or not the same attributes, fall back to
- // the slow case.
- return false;
-}
-
-
-bool JSObject::DefineFastAccessor(Handle<JSObject> object,
- Handle<Name> name,
- AccessorComponent component,
- Handle<Object> accessor,
- PropertyAttributes attributes) {
- DCHECK(accessor->IsSpecFunction() || accessor->IsUndefined());
- Isolate* isolate = object->GetIsolate();
- LookupResult result(isolate);
- object->LookupOwn(name, &result);
-
- if (result.IsFound() && !result.IsPropertyCallbacks()) {
- return false;
- }
-
- // Return success if the same accessor with the same attributes already exist.
- AccessorPair* source_accessors = NULL;
- if (result.IsPropertyCallbacks()) {
- Object* callback_value = result.GetCallbackObject();
- if (callback_value->IsAccessorPair()) {
- source_accessors = AccessorPair::cast(callback_value);
- Object* entry = source_accessors->get(component);
- if (entry == *accessor && result.GetAttributes() == attributes) {
- return true;
- }
- } else {
- return false;
- }
-
- int descriptor_number = result.GetDescriptorIndex();
-
- object->map()->LookupTransition(*object, *name, &result);
-
- if (result.IsFound()) {
- Handle<Map> target(result.GetTransitionTarget());
- DCHECK(target->NumberOfOwnDescriptors() ==
- object->map()->NumberOfOwnDescriptors());
- // This works since descriptors are sorted in order of addition.
- DCHECK(Name::Equals(
- handle(object->map()->instance_descriptors()->GetKey(
- descriptor_number)),
- name));
- return TryAccessorTransition(object, target, descriptor_number,
- component, accessor, attributes);
- }
- } else {
- // If not, lookup a transition.
- object->map()->LookupTransition(*object, *name, &result);
-
- // If there is a transition, try to follow it.
- if (result.IsFound()) {
- Handle<Map> target(result.GetTransitionTarget());
- int descriptor_number = target->LastAdded();
- DCHECK(Name::Equals(name,
- handle(target->instance_descriptors()->GetKey(descriptor_number))));
- return TryAccessorTransition(object, target, descriptor_number,
- component, accessor, attributes);
- }
- }
-
- // If there is no transition yet, add a transition to the a new accessor pair
- // containing the accessor. Allocate a new pair if there were no source
- // accessors. Otherwise, copy the pair and modify the accessor.
- Handle<AccessorPair> accessors = source_accessors != NULL
- ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
- : isolate->factory()->NewAccessorPair();
- accessors->set(component, *accessor);
-
- CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
- Handle<Map> new_map = Map::CopyInsertDescriptor(
- handle(object->map()), &new_accessors_desc, INSERT_TRANSITION);
-
- JSObject::MigrateToMap(object, new_map);
- return true;
-}
-
-
MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
Handle<AccessorInfo> info) {
Isolate* isolate = object->GetIsolate();
@@ -7062,6 +6924,101 @@ Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
}
+Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
+ Handle<Name> name,
+ AccessorComponent component,
+ Handle<Object> accessor,
+ PropertyAttributes attributes) {
+ Isolate* isolate = name->GetIsolate();
+
+ // Dictionary maps can always have additional data properties.
+ if (map->is_dictionary_map()) {
+ // For global objects, property cells are inlined. We need to change the
+ // map.
+ if (map->IsGlobalObjectMap()) return Copy(map);
+ return map;
+ }
+
+ // Migrate to the newest map before transitioning to the new property.
+ if (map->is_deprecated()) map = Update(map);
+
+ PropertyNormalizationMode mode = map->is_prototype_map()
+ ? KEEP_INOBJECT_PROPERTIES
+ : CLEAR_INOBJECT_PROPERTIES;
+
+ int index = map->SearchTransition(*name);
+ if (index != TransitionArray::kNotFound) {
+ Handle<Map> transition(map->GetTransition(index));
+ DescriptorArray* descriptors = transition->instance_descriptors();
+ // Fast path, assume that we're modifying the last added descriptor.
+ int descriptor = transition->LastAdded();
+ if (descriptors->GetKey(descriptor) != *name) {
+ // If not, search for the descriptor.
+ descriptor = descriptors->SearchWithCache(*name, *transition);
+ }
+
+ if (descriptors->GetDetails(descriptor).type() != CALLBACKS) {
+ return Map::Normalize(map, mode);
+ }
+
+ // TODO(verwaest): Handle attributes better.
+ if (descriptors->GetDetails(descriptor).attributes() != attributes) {
+ return Map::Normalize(map, mode);
+ }
+
+ Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
+ if (!maybe_pair->IsAccessorPair()) {
+ return Map::Normalize(map, mode);
+ }
+
+ Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
+ if (pair->get(component) != *accessor) {
+ return Map::Normalize(map, mode);
+ }
+
+ return transition;
+ }
+
+ Handle<AccessorPair> pair;
+ DescriptorArray* old_descriptors = map->instance_descriptors();
+ int descriptor = old_descriptors->SearchWithCache(*name, *map);
+ if (descriptor != DescriptorArray::kNotFound) {
+ PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
+ if (old_details.type() != CALLBACKS) {
+ return Map::Normalize(map, mode);
+ }
+
+ if (old_details.attributes() != attributes) {
+ return Map::Normalize(map, mode);
+ }
+
+ Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
+ if (!maybe_pair->IsAccessorPair()) {
+ return Map::Normalize(map, mode);
+ }
+
+ Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
+ if (current == *accessor) return map;
+
+ if (!current->IsTheHole()) {
+ return Map::Normalize(map, mode);
+ }
+
+ pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
+ } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
+ map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
+ return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
+ } else {
+ pair = isolate->factory()->NewAccessorPair();
+ }
+
+ pair->set(component, *accessor);
+ TransitionFlag flag = INSERT_TRANSITION;
+ CallbacksDescriptor new_desc(name, pair, attributes);
+ return Map::CopyInsertDescriptor(map, &new_desc, flag);
+}
+
+
Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag) {
« no previous file with comments | « src/objects.h ('k') | src/runtime.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698