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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/runtime.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/accessors.h" 7 #include "src/accessors.h"
8 #include "src/allocation-site-scopes.h" 8 #include "src/allocation-site-scopes.h"
9 #include "src/api.h" 9 #include "src/api.h"
10 #include "src/arguments.h" 10 #include "src/arguments.h"
(...skipping 6084 matching lines...) Expand 10 before | Expand all | Expand 10 after
6095 } 6095 }
6096 6096
6097 Isolate* isolate = object->GetIsolate(); 6097 Isolate* isolate = object->GetIsolate();
6098 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair(); 6098 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
6099 accessors->SetComponents(*getter, *setter); 6099 accessors->SetComponents(*getter, *setter);
6100 6100
6101 SetElementCallback(object, index, accessors, attributes); 6101 SetElementCallback(object, index, accessors, attributes);
6102 } 6102 }
6103 6103
6104 6104
6105 Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
6106 Handle<Name> name) {
6107 Isolate* isolate = object->GetIsolate();
6108 LookupResult result(isolate);
6109 object->LookupOwnRealNamedProperty(name, &result);
6110 if (result.IsPropertyCallbacks()) {
6111 // Note that the result can actually have IsDontDelete() == true when we
6112 // e.g. have to fall back to the slow case while adding a setter after
6113 // successfully reusing a map transition for a getter. Nevertheless, this is
6114 // OK, because the assertion only holds for the whole addition of both
6115 // accessors, not for the addition of each part. See first comment in
6116 // DefinePropertyAccessor below.
6117 Object* obj = result.GetCallbackObject();
6118 if (obj->IsAccessorPair()) {
6119 return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
6120 }
6121 }
6122 return isolate->factory()->NewAccessorPair();
6123 }
6124
6125
6126 void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
6127 Handle<Name> name,
6128 Handle<Object> getter,
6129 Handle<Object> setter,
6130 PropertyAttributes attributes) {
6131 // We could assert that the property is configurable here, but we would need
6132 // to do a lookup, which seems to be a bit of overkill.
6133 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
6134 if (object->HasFastProperties() && !only_attribute_changes &&
6135 (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors)) {
6136 bool getterOk = getter->IsNull() ||
6137 DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
6138 bool setterOk = !getterOk || setter->IsNull() ||
6139 DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
6140 if (getterOk && setterOk) return;
6141 }
6142
6143 Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
6144 accessors->SetComponents(*getter, *setter);
6145
6146 SetPropertyCallback(object, name, accessors, attributes);
6147 }
6148
6149
6150 bool Map::DictionaryElementsInPrototypeChainOnly() { 6105 bool Map::DictionaryElementsInPrototypeChainOnly() {
6151 if (IsDictionaryElementsKind(elements_kind())) { 6106 if (IsDictionaryElementsKind(elements_kind())) {
6152 return false; 6107 return false;
6153 } 6108 }
6154 6109
6155 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) { 6110 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
6156 if (iter.GetCurrent()->IsJSProxy()) { 6111 if (iter.GetCurrent()->IsJSProxy()) {
6157 // Be conservative, don't walk into proxies. 6112 // Be conservative, don't walk into proxies.
6158 return true; 6113 return true;
6159 } 6114 }
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
6298 if (preexists && (it.property_kind() == LookupIterator::DATA || 6253 if (preexists && (it.property_kind() == LookupIterator::DATA ||
6299 it.GetAccessors()->IsAccessorInfo())) { 6254 it.GetAccessors()->IsAccessorInfo())) {
6300 old_value = GetProperty(&it).ToHandleChecked(); 6255 old_value = GetProperty(&it).ToHandleChecked();
6301 } 6256 }
6302 } 6257 }
6303 } 6258 }
6304 6259
6305 if (is_element) { 6260 if (is_element) {
6306 DefineElementAccessor(object, index, getter, setter, attributes); 6261 DefineElementAccessor(object, index, getter, setter, attributes);
6307 } else { 6262 } else {
6308 DefinePropertyAccessor(object, name, getter, setter, attributes); 6263 DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
6264 getter->IsNull());
6265 DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
6266 setter->IsNull());
6267 // At least one of the accessors needs to be a new value.
6268 DCHECK(!getter->IsNull() || !setter->IsNull());
6269 LookupIterator it(object, name, LookupIterator::CHECK_PROPERTY);
6270 if (!getter->IsNull()) {
6271 it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
6272 }
6273 if (!setter->IsNull()) {
6274 it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
6275 }
6309 } 6276 }
6310 6277
6311 if (is_observed) { 6278 if (is_observed) {
6312 const char* type = preexists ? "reconfigure" : "add"; 6279 const char* type = preexists ? "reconfigure" : "add";
6313 EnqueueChangeRecord(object, type, name, old_value); 6280 EnqueueChangeRecord(object, type, name, old_value);
6314 } 6281 }
6315 6282
6316 return isolate->factory()->undefined_value(); 6283 return isolate->factory()->undefined_value();
6317 } 6284 }
6318 6285
6319 6286
6320 static bool TryAccessorTransition(Handle<JSObject> self,
6321 Handle<Map> transitioned_map,
6322 int target_descriptor,
6323 AccessorComponent component,
6324 Handle<Object> accessor,
6325 PropertyAttributes attributes) {
6326 DescriptorArray* descs = transitioned_map->instance_descriptors();
6327 PropertyDetails details = descs->GetDetails(target_descriptor);
6328
6329 // If the transition target was not callbacks, fall back to the slow case.
6330 if (details.type() != CALLBACKS) return false;
6331 Object* descriptor = descs->GetCallbacksObject(target_descriptor);
6332 if (!descriptor->IsAccessorPair()) return false;
6333
6334 Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
6335 PropertyAttributes target_attributes = details.attributes();
6336
6337 // Reuse transition if adding same accessor with same attributes.
6338 if (target_accessor == *accessor && target_attributes == attributes) {
6339 JSObject::MigrateToMap(self, transitioned_map);
6340 return true;
6341 }
6342
6343 // If either not the same accessor, or not the same attributes, fall back to
6344 // the slow case.
6345 return false;
6346 }
6347
6348
6349 bool JSObject::DefineFastAccessor(Handle<JSObject> object,
6350 Handle<Name> name,
6351 AccessorComponent component,
6352 Handle<Object> accessor,
6353 PropertyAttributes attributes) {
6354 DCHECK(accessor->IsSpecFunction() || accessor->IsUndefined());
6355 Isolate* isolate = object->GetIsolate();
6356 LookupResult result(isolate);
6357 object->LookupOwn(name, &result);
6358
6359 if (result.IsFound() && !result.IsPropertyCallbacks()) {
6360 return false;
6361 }
6362
6363 // Return success if the same accessor with the same attributes already exist.
6364 AccessorPair* source_accessors = NULL;
6365 if (result.IsPropertyCallbacks()) {
6366 Object* callback_value = result.GetCallbackObject();
6367 if (callback_value->IsAccessorPair()) {
6368 source_accessors = AccessorPair::cast(callback_value);
6369 Object* entry = source_accessors->get(component);
6370 if (entry == *accessor && result.GetAttributes() == attributes) {
6371 return true;
6372 }
6373 } else {
6374 return false;
6375 }
6376
6377 int descriptor_number = result.GetDescriptorIndex();
6378
6379 object->map()->LookupTransition(*object, *name, &result);
6380
6381 if (result.IsFound()) {
6382 Handle<Map> target(result.GetTransitionTarget());
6383 DCHECK(target->NumberOfOwnDescriptors() ==
6384 object->map()->NumberOfOwnDescriptors());
6385 // This works since descriptors are sorted in order of addition.
6386 DCHECK(Name::Equals(
6387 handle(object->map()->instance_descriptors()->GetKey(
6388 descriptor_number)),
6389 name));
6390 return TryAccessorTransition(object, target, descriptor_number,
6391 component, accessor, attributes);
6392 }
6393 } else {
6394 // If not, lookup a transition.
6395 object->map()->LookupTransition(*object, *name, &result);
6396
6397 // If there is a transition, try to follow it.
6398 if (result.IsFound()) {
6399 Handle<Map> target(result.GetTransitionTarget());
6400 int descriptor_number = target->LastAdded();
6401 DCHECK(Name::Equals(name,
6402 handle(target->instance_descriptors()->GetKey(descriptor_number))));
6403 return TryAccessorTransition(object, target, descriptor_number,
6404 component, accessor, attributes);
6405 }
6406 }
6407
6408 // If there is no transition yet, add a transition to the a new accessor pair
6409 // containing the accessor. Allocate a new pair if there were no source
6410 // accessors. Otherwise, copy the pair and modify the accessor.
6411 Handle<AccessorPair> accessors = source_accessors != NULL
6412 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
6413 : isolate->factory()->NewAccessorPair();
6414 accessors->set(component, *accessor);
6415
6416 CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
6417 Handle<Map> new_map = Map::CopyInsertDescriptor(
6418 handle(object->map()), &new_accessors_desc, INSERT_TRANSITION);
6419
6420 JSObject::MigrateToMap(object, new_map);
6421 return true;
6422 }
6423
6424
6425 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, 6287 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6426 Handle<AccessorInfo> info) { 6288 Handle<AccessorInfo> info) {
6427 Isolate* isolate = object->GetIsolate(); 6289 Isolate* isolate = object->GetIsolate();
6428 Factory* factory = isolate->factory(); 6290 Factory* factory = isolate->factory();
6429 Handle<Name> name(Name::cast(info->name())); 6291 Handle<Name> name(Name::cast(info->name()));
6430 6292
6431 // Check access rights if needed. 6293 // Check access rights if needed.
6432 if (object->IsAccessCheckNeeded() && 6294 if (object->IsAccessCheckNeeded() &&
6433 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) { 6295 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6434 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET); 6296 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after
7055 // Dictionaries have to be reconfigured in-place. 6917 // Dictionaries have to be reconfigured in-place.
7056 DCHECK(!map->is_dictionary_map()); 6918 DCHECK(!map->is_dictionary_map());
7057 6919
7058 // For now, give up on transitioning and just create a unique map. 6920 // For now, give up on transitioning and just create a unique map.
7059 // TODO(verwaest/ishell): Cache transitions with different attributes. 6921 // TODO(verwaest/ishell): Cache transitions with different attributes.
7060 return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD, 6922 return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
7061 attributes, "attributes mismatch"); 6923 attributes, "attributes mismatch");
7062 } 6924 }
7063 6925
7064 6926
6927 Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
6928 Handle<Name> name,
6929 AccessorComponent component,
6930 Handle<Object> accessor,
6931 PropertyAttributes attributes) {
6932 Isolate* isolate = name->GetIsolate();
6933
6934 // Dictionary maps can always have additional data properties.
6935 if (map->is_dictionary_map()) {
6936 // For global objects, property cells are inlined. We need to change the
6937 // map.
6938 if (map->IsGlobalObjectMap()) return Copy(map);
6939 return map;
6940 }
6941
6942 // Migrate to the newest map before transitioning to the new property.
6943 if (map->is_deprecated()) map = Update(map);
6944
6945 PropertyNormalizationMode mode = map->is_prototype_map()
6946 ? KEEP_INOBJECT_PROPERTIES
6947 : CLEAR_INOBJECT_PROPERTIES;
6948
6949 int index = map->SearchTransition(*name);
6950 if (index != TransitionArray::kNotFound) {
6951 Handle<Map> transition(map->GetTransition(index));
6952 DescriptorArray* descriptors = transition->instance_descriptors();
6953 // Fast path, assume that we're modifying the last added descriptor.
6954 int descriptor = transition->LastAdded();
6955 if (descriptors->GetKey(descriptor) != *name) {
6956 // If not, search for the descriptor.
6957 descriptor = descriptors->SearchWithCache(*name, *transition);
6958 }
6959
6960 if (descriptors->GetDetails(descriptor).type() != CALLBACKS) {
6961 return Map::Normalize(map, mode);
6962 }
6963
6964 // TODO(verwaest): Handle attributes better.
6965 if (descriptors->GetDetails(descriptor).attributes() != attributes) {
6966 return Map::Normalize(map, mode);
6967 }
6968
6969 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
6970 if (!maybe_pair->IsAccessorPair()) {
6971 return Map::Normalize(map, mode);
6972 }
6973
6974 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
6975 if (pair->get(component) != *accessor) {
6976 return Map::Normalize(map, mode);
6977 }
6978
6979 return transition;
6980 }
6981
6982 Handle<AccessorPair> pair;
6983 DescriptorArray* old_descriptors = map->instance_descriptors();
6984 int descriptor = old_descriptors->SearchWithCache(*name, *map);
6985 if (descriptor != DescriptorArray::kNotFound) {
6986 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
6987 if (old_details.type() != CALLBACKS) {
6988 return Map::Normalize(map, mode);
6989 }
6990
6991 if (old_details.attributes() != attributes) {
6992 return Map::Normalize(map, mode);
6993 }
6994
6995 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
6996 if (!maybe_pair->IsAccessorPair()) {
6997 return Map::Normalize(map, mode);
6998 }
6999
7000 Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
7001 if (current == *accessor) return map;
7002
7003 if (!current->IsTheHole()) {
7004 return Map::Normalize(map, mode);
7005 }
7006
7007 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
7008 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
7009 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
7010 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
7011 } else {
7012 pair = isolate->factory()->NewAccessorPair();
7013 }
7014
7015 pair->set(component, *accessor);
7016 TransitionFlag flag = INSERT_TRANSITION;
7017 CallbacksDescriptor new_desc(name, pair, attributes);
7018 return Map::CopyInsertDescriptor(map, &new_desc, flag);
7019 }
7020
7021
7065 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map, 7022 Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
7066 Descriptor* descriptor, 7023 Descriptor* descriptor,
7067 TransitionFlag flag) { 7024 TransitionFlag flag) {
7068 Handle<DescriptorArray> descriptors(map->instance_descriptors()); 7025 Handle<DescriptorArray> descriptors(map->instance_descriptors());
7069 7026
7070 // Ensure the key is unique. 7027 // Ensure the key is unique.
7071 descriptor->KeyToUniqueName(); 7028 descriptor->KeyToUniqueName();
7072 7029
7073 if (flag == INSERT_TRANSITION && 7030 if (flag == INSERT_TRANSITION &&
7074 map->owns_descriptors() && 7031 map->owns_descriptors() &&
(...skipping 9530 matching lines...) Expand 10 before | Expand all | Expand 10 after
16605 #define ERROR_MESSAGES_TEXTS(C, T) T, 16562 #define ERROR_MESSAGES_TEXTS(C, T) T,
16606 static const char* error_messages_[] = { 16563 static const char* error_messages_[] = {
16607 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) 16564 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16608 }; 16565 };
16609 #undef ERROR_MESSAGES_TEXTS 16566 #undef ERROR_MESSAGES_TEXTS
16610 return error_messages_[reason]; 16567 return error_messages_[reason];
16611 } 16568 }
16612 16569
16613 16570
16614 } } // namespace v8::internal 16571 } } // namespace v8::internal
OLDNEW
« 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