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

Side by Side Diff: src/keys.cc

Issue 2038043002: [keys] keep track of first and last non-empty prototype (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: do not initialize handle with nullptr Created 4 years, 6 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
« no previous file with comments | « src/keys.h ('k') | no next file » | 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/keys.h" 5 #include "src/keys.h"
6 6
7 #include "src/api-arguments.h" 7 #include "src/api-arguments.h"
8 #include "src/elements.h" 8 #include "src/elements.h"
9 #include "src/factory.h" 9 #include "src/factory.h"
10 #include "src/identity-map.h" 10 #include "src/identity-map.h"
(...skipping 13 matching lines...) Expand all
24 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { 24 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
25 int len = array->length(); 25 int len = array->length();
26 for (int i = 0; i < len; i++) { 26 for (int i = 0; i < len; i++) {
27 Object* e = array->get(i); 27 Object* e = array->get(i);
28 if (!(e->IsName() || e->IsNumber())) return false; 28 if (!(e->IsName() || e->IsNumber())) return false;
29 } 29 }
30 return true; 30 return true;
31 } 31 }
32 32
33 } // namespace 33 } // namespace
34
35 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( 34 MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
36 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, 35 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
37 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { 36 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) {
38 USE(ContainsOnlyValidKeys);
39 Isolate* isolate = object->GetIsolate(); 37 Isolate* isolate = object->GetIsolate();
40 KeyAccumulator accumulator(isolate, mode, filter); 38 KeyAccumulator accumulator(isolate, mode, filter);
41 accumulator.set_filter_proxy_keys(filter_proxy_keys); 39 accumulator.set_filter_proxy_keys(filter_proxy_keys);
42 accumulator.set_is_for_in(is_for_in); 40 accumulator.set_is_for_in(is_for_in);
43 MAYBE_RETURN(accumulator.CollectKeys(object, object), 41 MAYBE_RETURN(accumulator.CollectKeys(object, object),
44 MaybeHandle<FixedArray>()); 42 MaybeHandle<FixedArray>());
45 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); 43 return accumulator.GetKeys(keys_conversion);
46 DCHECK(ContainsOnlyValidKeys(keys));
47 return keys;
48 } 44 }
49 45
50 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { 46 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
51 if (keys_.is_null()) { 47 if (keys_.is_null()) {
52 return isolate_->factory()->empty_fixed_array(); 48 return isolate_->factory()->empty_fixed_array();
53 } 49 }
54 if (mode_ == KeyCollectionMode::kOwnOnly && 50 if (mode_ == KeyCollectionMode::kOwnOnly &&
55 keys_->map() == isolate_->heap()->fixed_array_map()) { 51 keys_->map() == isolate_->heap()->fixed_array_map()) {
56 return Handle<FixedArray>::cast(keys_); 52 return Handle<FixedArray>::cast(keys_);
57 } 53 }
58 return OrderedHashSet::ConvertToKeysArray(keys(), convert); 54 USE(ContainsOnlyValidKeys);
55 Handle<FixedArray> result =
56 OrderedHashSet::ConvertToKeysArray(keys(), convert);
57 DCHECK(ContainsOnlyValidKeys(result));
58 return result;
59 } 59 }
60 60
61 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { 61 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) {
62 AddKey(handle(key, isolate_), convert); 62 AddKey(handle(key, isolate_), convert);
63 } 63 }
64 64
65 void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { 65 void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
66 if (key->IsSymbol()) { 66 if (key->IsSymbol()) {
67 if (filter_ & SKIP_SYMBOLS) return; 67 if (filter_ & SKIP_SYMBOLS) return;
68 if (Handle<Symbol>::cast(key)->is_private()) return; 68 if (Handle<Symbol>::cast(key)->is_private()) return;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 DCHECK(current->IsJSObject()); 169 DCHECK(current->IsJSObject());
170 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); 170 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
171 } 171 }
172 MAYBE_RETURN(result, Nothing<bool>()); 172 MAYBE_RETURN(result, Nothing<bool>());
173 if (!result.FromJust()) break; // |false| means "stop iterating". 173 if (!result.FromJust()) break; // |false| means "stop iterating".
174 // Iterate through proxies but ignore access checks for the ALL_CAN_READ 174 // Iterate through proxies but ignore access checks for the ALL_CAN_READ
175 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. 175 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys.
176 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { 176 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
177 return Nothing<bool>(); 177 return Nothing<bool>();
178 } 178 }
179 if (!last_non_empty_prototype_.is_null() &&
180 *last_non_empty_prototype_ == *current) {
181 break;
182 }
179 } 183 }
180 return Just(true); 184 return Just(true);
181 } 185 }
182 186
183 namespace { 187 namespace {
184 188
185 void TrySettingEmptyEnumCache(JSReceiver* object) { 189 void TrySettingEmptyEnumCache(JSReceiver* object) {
186 Map* map = object->map(); 190 Map* map = object->map();
187 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength()); 191 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
188 if (!map->OnlyHasSimpleProperties()) return; 192 if (!map->OnlyHasSimpleProperties()) return;
(...skipping 17 matching lines...) Expand all
206 } 210 }
207 } // namespace 211 } // namespace
208 212
209 void FastKeyAccumulator::Prepare() { 213 void FastKeyAccumulator::Prepare() {
210 DisallowHeapAllocation no_gc; 214 DisallowHeapAllocation no_gc;
211 // Directly go for the fast path for OWN_ONLY keys. 215 // Directly go for the fast path for OWN_ONLY keys.
212 if (mode_ == KeyCollectionMode::kOwnOnly) return; 216 if (mode_ == KeyCollectionMode::kOwnOnly) return;
213 // Fully walk the prototype chain and find the last prototype with keys. 217 // Fully walk the prototype chain and find the last prototype with keys.
214 is_receiver_simple_enum_ = false; 218 is_receiver_simple_enum_ = false;
215 has_empty_prototype_ = true; 219 has_empty_prototype_ = true;
216 JSReceiver* first_non_empty_prototype; 220 JSReceiver* last_prototype = nullptr;
217 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd(); 221 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
218 iter.Advance()) { 222 iter.Advance()) {
219 JSReceiver* current = iter.GetCurrent<JSReceiver>(); 223 JSReceiver* current = iter.GetCurrent<JSReceiver>();
220 if (CheckAndInitalizeSimpleEnumCache(current)) continue; 224 bool has_no_properties = CheckAndInitalizeSimpleEnumCache(current);
225 if (has_no_properties) continue;
226 last_prototype = current;
221 has_empty_prototype_ = false; 227 has_empty_prototype_ = false;
222 first_non_empty_prototype = current;
223 // TODO(cbruni): use the first non-empty prototype.
224 USE(first_non_empty_prototype);
225 return;
226 } 228 }
227 DCHECK(has_empty_prototype_); 229 if (has_empty_prototype_) {
228 is_receiver_simple_enum_ = 230 is_receiver_simple_enum_ =
229 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && 231 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
230 !JSObject::cast(*receiver_)->HasEnumerableElements(); 232 !JSObject::cast(*receiver_)->HasEnumerableElements();
233 } else if (last_prototype != nullptr) {
234 last_non_empty_prototype_ = handle(last_prototype, isolate_);
235 }
231 } 236 }
232 237
233 namespace { 238 namespace {
234 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate, 239 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
235 Handle<FixedArray> array, 240 Handle<FixedArray> array,
236 int length) { 241 int length) {
237 DCHECK_LE(length, array->length()); 242 DCHECK_LE(length, array->length());
238 if (array->length() == length) return array; 243 if (array->length() == length) return array;
239 return isolate->factory()->CopyFixedArrayUpTo(array, length); 244 return isolate->factory()->CopyFixedArrayUpTo(array, length);
240 } 245 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 // directly initialize the enum cache. 360 // directly initialize the enum cache.
356 return GetFastEnumPropertyKeys(isolate, object); 361 return GetFastEnumPropertyKeys(isolate, object);
357 } 362 }
358 363
359 bool OnlyHasSimpleProperties(Map* map) { 364 bool OnlyHasSimpleProperties(Map* map) {
360 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER; 365 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER;
361 } 366 }
362 367
363 } // namespace 368 } // namespace
364 369
365 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { 370 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
371 GetKeysConversion keys_conversion) {
366 Handle<FixedArray> keys; 372 Handle<FixedArray> keys;
367 if (GetKeysFast(convert).ToHandle(&keys)) { 373 if (filter_ == ENUMERABLE_STRINGS &&
374 GetKeysFast(keys_conversion).ToHandle(&keys)) {
368 return keys; 375 return keys;
369 } 376 }
370 return GetKeysSlow(convert); 377 return GetKeysSlow(keys_conversion);
371 } 378 }
372 379
373 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( 380 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
374 GetKeysConversion convert) { 381 GetKeysConversion keys_conversion) {
375 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly; 382 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
376 Map* map = receiver_->map(); 383 Map* map = receiver_->map();
377 if (!own_only || !OnlyHasSimpleProperties(map)) { 384 if (!own_only || !OnlyHasSimpleProperties(map)) {
378 return MaybeHandle<FixedArray>(); 385 return MaybeHandle<FixedArray>();
379 } 386 }
380 387
381 // From this point on we are certiain to only collect own keys. 388 // From this point on we are certiain to only collect own keys.
382 DCHECK(receiver_->IsJSObject()); 389 DCHECK(receiver_->IsJSObject());
383 Handle<JSObject> object = Handle<JSObject>::cast(receiver_); 390 Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
384 391
385 // Do not try to use the enum-cache for dict-mode objects. 392 // Do not try to use the enum-cache for dict-mode objects.
386 if (map->is_dictionary_map()) { 393 if (map->is_dictionary_map()) {
387 return GetOwnKeysWithElements<false>(isolate_, object, convert); 394 return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion);
388 } 395 }
389 int enum_length = receiver_->map()->EnumLength(); 396 int enum_length = receiver_->map()->EnumLength();
390 if (enum_length == kInvalidEnumCacheSentinel) { 397 if (enum_length == kInvalidEnumCacheSentinel) {
391 Handle<FixedArray> keys; 398 Handle<FixedArray> keys;
392 // Try initializing the enum cache and return own properties. 399 // Try initializing the enum cache and return own properties.
393 if (GetOwnKeysWithUninitializedEnumCache(isolate_, object) 400 if (GetOwnKeysWithUninitializedEnumCache(isolate_, object)
394 .ToHandle(&keys)) { 401 .ToHandle(&keys)) {
395 if (FLAG_trace_for_in_enumerate) { 402 if (FLAG_trace_for_in_enumerate) {
396 PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n", 403 PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
397 keys->length()); 404 keys->length());
398 } 405 }
399 is_receiver_simple_enum_ = 406 is_receiver_simple_enum_ =
400 object->map()->EnumLength() != kInvalidEnumCacheSentinel; 407 object->map()->EnumLength() != kInvalidEnumCacheSentinel;
401 return keys; 408 return keys;
402 } 409 }
403 } 410 }
404 // The properties-only case failed because there were probably elements on the 411 // The properties-only case failed because there were probably elements on the
405 // receiver. 412 // receiver.
406 return GetOwnKeysWithElements<true>(isolate_, object, convert); 413 return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion);
407 } 414 }
408 415
409 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( 416 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
410 GetKeysConversion convert) { 417 GetKeysConversion keys_conversion) {
411 return KeyAccumulator::GetKeys(receiver_, mode_, filter_, 418 KeyAccumulator accumulator(isolate_, mode_, filter_);
412 GetKeysConversion::kKeepNumbers, 419 accumulator.set_filter_proxy_keys(filter_proxy_keys_);
413 filter_proxy_keys_, is_for_in_); 420 accumulator.set_is_for_in(is_for_in_);
421 accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
422
423 MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
424 MaybeHandle<FixedArray>());
425 return accumulator.GetKeys(keys_conversion);
414 } 426 }
415 427
416 namespace { 428 namespace {
417 429
418 enum IndexedOrNamed { kIndexed, kNamed }; 430 enum IndexedOrNamed { kIndexed, kNamed };
419 431
420 // Returns |true| on success, |nothing| on exception. 432 // Returns |true| on success, |nothing| on exception.
421 template <class Callback, IndexedOrNamed type> 433 template <class Callback, IndexedOrNamed type>
422 Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver, 434 Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
423 Handle<JSObject> object, 435 Handle<JSObject> object,
424 KeyAccumulator* accumulator) { 436 KeyAccumulator* accumulator) {
425 Isolate* isolate = accumulator->isolate(); 437 Isolate* isolate = accumulator->isolate();
426 if (type == kIndexed) { 438 if (type == kIndexed) {
427 if (!object->HasIndexedInterceptor()) return Just(true); 439 if (!object->HasIndexedInterceptor()) return Just(true);
428 } else { 440 } else {
429 if (!object->HasNamedInterceptor()) return Just(true); 441 if (!object->HasNamedInterceptor()) return Just(true);
430 } 442 }
431 Handle<InterceptorInfo> interceptor(type == kIndexed 443 Handle<InterceptorInfo> interceptor(type == kIndexed
432 ? object->GetIndexedInterceptor() 444 ? object->GetIndexedInterceptor()
(...skipping 22 matching lines...) Expand all
455 467
456 } // namespace 468 } // namespace
457 469
458 Maybe<bool> KeyAccumulator::CollectOwnElementIndices( 470 Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
459 Handle<JSReceiver> receiver, Handle<JSObject> object) { 471 Handle<JSReceiver> receiver, Handle<JSObject> object) {
460 if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true); 472 if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
461 473
462 ElementsAccessor* accessor = object->GetElementsAccessor(); 474 ElementsAccessor* accessor = object->GetElementsAccessor();
463 accessor->CollectElementIndices(object, this); 475 accessor->CollectElementIndices(object, this);
464 476
465 return GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, 477 return CollectInterceptorKeys<v8::IndexedPropertyEnumeratorCallback,
466 kIndexed>(receiver, object, this); 478 kIndexed>(receiver, object, this);
467 } 479 }
468 480
469 namespace { 481 namespace {
470 482
471 template <bool skip_symbols> 483 template <bool skip_symbols>
472 int CollectOwnPropertyNamesInternal(Handle<JSObject> object, 484 int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
473 KeyAccumulator* keys, 485 KeyAccumulator* keys,
474 Handle<DescriptorArray> descs, 486 Handle<DescriptorArray> descs,
475 int start_index, int limit) { 487 int start_index, int limit) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 } 529 }
518 } else if (object->IsJSGlobalObject()) { 530 } else if (object->IsJSGlobalObject()) {
519 GlobalDictionary::CollectKeysTo( 531 GlobalDictionary::CollectKeysTo(
520 handle(object->global_dictionary(), isolate_), this, filter_); 532 handle(object->global_dictionary(), isolate_), this, filter_);
521 } else { 533 } else {
522 NameDictionary::CollectKeysTo( 534 NameDictionary::CollectKeysTo(
523 handle(object->property_dictionary(), isolate_), this, filter_); 535 handle(object->property_dictionary(), isolate_), this, filter_);
524 } 536 }
525 } 537 }
526 // Add the property keys from the interceptor. 538 // Add the property keys from the interceptor.
527 return GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, 539 return CollectInterceptorKeys<v8::GenericNamedPropertyEnumeratorCallback,
528 kNamed>(receiver, object, this); 540 kNamed>(receiver, object, this);
529 } 541 }
530 542
531 // Returns |true| on success, |false| if prototype walking should be stopped, 543 // Returns |true| on success, |false| if prototype walking should be stopped,
532 // |nothing| if an exception was thrown. 544 // |nothing| if an exception was thrown.
533 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, 545 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
534 Handle<JSObject> object) { 546 Handle<JSObject> object) {
535 // Check access rights if required. 547 // Check access rights if required.
536 if (object->IsAccessCheckNeeded() && 548 if (object->IsAccessCheckNeeded() &&
537 !isolate_->MayAccess(handle(isolate_->context()), object)) { 549 !isolate_->MayAccess(handle(isolate_->context()), object)) {
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
730 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); 742 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>());
731 bool prev_filter_proxy_keys_ = filter_proxy_keys_; 743 bool prev_filter_proxy_keys_ = filter_proxy_keys_;
732 filter_proxy_keys_ = false; 744 filter_proxy_keys_ = false;
733 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); 745 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
734 filter_proxy_keys_ = prev_filter_proxy_keys_; 746 filter_proxy_keys_ = prev_filter_proxy_keys_;
735 return result; 747 return result;
736 } 748 }
737 749
738 } // namespace internal 750 } // namespace internal
739 } // namespace v8 751 } // namespace v8
OLDNEW
« no previous file with comments | « src/keys.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698