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

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: 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 16 matching lines...) Expand all
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 34
35 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( 35 MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
36 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, 36 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter,
37 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { 37 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in,
38 JSReceiver* first_non_empty_prototype,
39 JSReceiver* last_non_empty_prototype) {
38 USE(ContainsOnlyValidKeys); 40 USE(ContainsOnlyValidKeys);
39 Isolate* isolate = object->GetIsolate(); 41 Isolate* isolate = object->GetIsolate();
40 KeyAccumulator accumulator(isolate, mode, filter); 42 KeyAccumulator accumulator(isolate, mode, filter);
41 accumulator.set_filter_proxy_keys(filter_proxy_keys); 43 accumulator.set_filter_proxy_keys(filter_proxy_keys);
42 accumulator.set_is_for_in(is_for_in); 44 accumulator.set_is_for_in(is_for_in);
45 if (first_non_empty_prototype != nullptr) {
46 accumulator.set_first_non_empty_prototype(first_non_empty_prototype);
47 }
48 if (first_non_empty_prototype != nullptr) {
49 accumulator.set_last_non_empty_prototype(last_non_empty_prototype);
50 }
43 MAYBE_RETURN(accumulator.CollectKeys(object, object), 51 MAYBE_RETURN(accumulator.CollectKeys(object, object),
44 MaybeHandle<FixedArray>()); 52 MaybeHandle<FixedArray>());
45 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); 53 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion);
46 DCHECK(ContainsOnlyValidKeys(keys)); 54 DCHECK(ContainsOnlyValidKeys(keys));
47 return keys; 55 return keys;
48 } 56 }
49 57
50 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { 58 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
51 if (keys_.is_null()) { 59 if (keys_.is_null()) {
52 return isolate_->factory()->empty_fixed_array(); 60 return isolate_->factory()->empty_fixed_array();
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 // AdvanceFollowingProxies. 158 // AdvanceFollowingProxies.
151 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) { 159 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
152 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), 160 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)),
153 Nothing<bool>()); 161 Nothing<bool>());
154 return Just(true); 162 return Just(true);
155 } 163 }
156 164
157 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly 165 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
158 ? PrototypeIterator::END_AT_NON_HIDDEN 166 ? PrototypeIterator::END_AT_NON_HIDDEN
159 : PrototypeIterator::END_AT_NULL; 167 : PrototypeIterator::END_AT_NULL;
168 if (!first_non_empty_prototype_.is_null()) {
169 object = first_non_empty_prototype_;
170 }
160 for (PrototypeIterator iter(isolate_, object, 171 for (PrototypeIterator iter(isolate_, object,
161 PrototypeIterator::START_AT_RECEIVER, end); 172 PrototypeIterator::START_AT_RECEIVER, end);
162 !iter.IsAtEnd();) { 173 !iter.IsAtEnd();) {
163 Handle<JSReceiver> current = 174 Handle<JSReceiver> current =
164 PrototypeIterator::GetCurrent<JSReceiver>(iter); 175 PrototypeIterator::GetCurrent<JSReceiver>(iter);
165 Maybe<bool> result = Just(false); // Dummy initialization. 176 Maybe<bool> result = Just(false); // Dummy initialization.
166 if (current->IsJSProxy()) { 177 if (current->IsJSProxy()) {
167 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); 178 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
168 } else { 179 } else {
169 DCHECK(current->IsJSObject()); 180 DCHECK(current->IsJSObject());
170 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); 181 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
171 } 182 }
172 MAYBE_RETURN(result, Nothing<bool>()); 183 MAYBE_RETURN(result, Nothing<bool>());
173 if (!result.FromJust()) break; // |false| means "stop iterating". 184 if (!result.FromJust()) break; // |false| means "stop iterating".
174 // Iterate through proxies but ignore access checks for the ALL_CAN_READ 185 // Iterate through proxies but ignore access checks for the ALL_CAN_READ
175 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. 186 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys.
176 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { 187 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
177 return Nothing<bool>(); 188 return Nothing<bool>();
178 } 189 }
190 if (!last_non_empty_prototype_.is_null() &&
191 *last_non_empty_prototype_ == *current) {
192 break;
193 }
179 } 194 }
180 return Just(true); 195 return Just(true);
181 } 196 }
182 197
183 namespace { 198 namespace {
184 199
185 void TrySettingEmptyEnumCache(JSReceiver* object) { 200 void TrySettingEmptyEnumCache(JSReceiver* object) {
186 Map* map = object->map(); 201 Map* map = object->map();
187 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength()); 202 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
188 if (!map->OnlyHasSimpleProperties()) return; 203 if (!map->OnlyHasSimpleProperties()) return;
(...skipping 17 matching lines...) Expand all
206 } 221 }
207 } // namespace 222 } // namespace
208 223
209 void FastKeyAccumulator::Prepare() { 224 void FastKeyAccumulator::Prepare() {
210 DisallowHeapAllocation no_gc; 225 DisallowHeapAllocation no_gc;
211 // Directly go for the fast path for OWN_ONLY keys. 226 // Directly go for the fast path for OWN_ONLY keys.
212 if (mode_ == KeyCollectionMode::kOwnOnly) return; 227 if (mode_ == KeyCollectionMode::kOwnOnly) return;
213 // Fully walk the prototype chain and find the last prototype with keys. 228 // Fully walk the prototype chain and find the last prototype with keys.
214 is_receiver_simple_enum_ = false; 229 is_receiver_simple_enum_ = false;
215 has_empty_prototype_ = true; 230 has_empty_prototype_ = true;
216 JSReceiver* first_non_empty_prototype; 231 JSReceiver* first_prototype;
232 JSReceiver* last_prototype;
217 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd(); 233 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
218 iter.Advance()) { 234 iter.Advance()) {
219 JSReceiver* current = iter.GetCurrent<JSReceiver>(); 235 JSReceiver* current = iter.GetCurrent<JSReceiver>();
220 if (CheckAndInitalizeSimpleEnumCache(current)) continue; 236 bool has_no_properties = CheckAndInitalizeSimpleEnumCache(current);
221 has_empty_prototype_ = false; 237 if (has_no_properties) continue;
222 first_non_empty_prototype = current; 238 last_prototype = current;
223 // TODO(cbruni): use the first non-empty prototype. 239 if (has_empty_prototype_) {
224 USE(first_non_empty_prototype); 240 has_empty_prototype_ = false;
225 return; 241 first_prototype = current;
242 }
226 } 243 }
227 DCHECK(has_empty_prototype_); 244 if (has_empty_prototype_) {
228 is_receiver_simple_enum_ = 245 is_receiver_simple_enum_ =
229 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel && 246 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
230 !JSObject::cast(*receiver_)->HasEnumerableElements(); 247 !JSObject::cast(*receiver_)->HasEnumerableElements();
248 } else {
249 first_non_empty_prototype_ = handle(first_prototype, isolate_);
250 last_non_empty_prototype_ = handle(last_prototype, isolate_);
251 }
231 } 252 }
232 253
233 namespace { 254 namespace {
234 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate, 255 static Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
235 Handle<FixedArray> array, 256 Handle<FixedArray> array,
236 int length) { 257 int length) {
237 DCHECK_LE(length, array->length()); 258 DCHECK_LE(length, array->length());
238 if (array->length() == length) return array; 259 if (array->length() == length) return array;
239 return isolate->factory()->CopyFixedArrayUpTo(array, length); 260 return isolate->factory()->CopyFixedArrayUpTo(array, length);
240 } 261 }
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 } 378 }
358 379
359 bool OnlyHasSimpleProperties(Map* map) { 380 bool OnlyHasSimpleProperties(Map* map) {
360 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER; 381 return map->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER;
361 } 382 }
362 383
363 } // namespace 384 } // namespace
364 385
365 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { 386 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) {
366 Handle<FixedArray> keys; 387 Handle<FixedArray> keys;
367 if (GetKeysFast(convert).ToHandle(&keys)) { 388 if (filter_ == ENUMERABLE_STRINGS && GetKeysFast(convert).ToHandle(&keys)) {
368 return keys; 389 return keys;
369 } 390 }
370 return GetKeysSlow(convert); 391 return GetKeysSlow(convert);
371 } 392 }
372 393
373 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( 394 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
374 GetKeysConversion convert) { 395 GetKeysConversion convert) {
375 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly; 396 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
376 Map* map = receiver_->map(); 397 Map* map = receiver_->map();
377 if (!own_only || !OnlyHasSimpleProperties(map)) { 398 if (!own_only || !OnlyHasSimpleProperties(map)) {
(...skipping 23 matching lines...) Expand all
401 return keys; 422 return keys;
402 } 423 }
403 } 424 }
404 // The properties-only case failed because there were probably elements on the 425 // The properties-only case failed because there were probably elements on the
405 // receiver. 426 // receiver.
406 return GetOwnKeysWithElements<true>(isolate_, object, convert); 427 return GetOwnKeysWithElements<true>(isolate_, object, convert);
407 } 428 }
408 429
409 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( 430 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
410 GetKeysConversion convert) { 431 GetKeysConversion convert) {
411 return KeyAccumulator::GetKeys(receiver_, mode_, filter_, 432 return KeyAccumulator::GetKeys(
412 GetKeysConversion::kKeepNumbers, 433 receiver_, mode_, filter_, GetKeysConversion::kKeepNumbers,
413 filter_proxy_keys_, is_for_in_); 434 filter_proxy_keys_, is_for_in_, *first_non_empty_prototype_,
Jakob Kummerow 2016/06/06 12:54:40 any particular reason for the deref/rehandlify dan
435 *last_non_empty_prototype_);
414 } 436 }
415 437
416 namespace { 438 namespace {
417 439
418 enum IndexedOrNamed { kIndexed, kNamed }; 440 enum IndexedOrNamed { kIndexed, kNamed };
419 441
420 // Returns |true| on success, |nothing| on exception. 442 // Returns |true| on success, |nothing| on exception.
421 template <class Callback, IndexedOrNamed type> 443 template <class Callback, IndexedOrNamed type>
422 Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver, 444 Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
423 Handle<JSObject> object, 445 Handle<JSObject> object,
424 KeyAccumulator* accumulator) { 446 KeyAccumulator* accumulator) {
425 Isolate* isolate = accumulator->isolate(); 447 Isolate* isolate = accumulator->isolate();
426 if (type == kIndexed) { 448 if (type == kIndexed) {
427 if (!object->HasIndexedInterceptor()) return Just(true); 449 if (!object->HasIndexedInterceptor()) return Just(true);
428 } else { 450 } else {
429 if (!object->HasNamedInterceptor()) return Just(true); 451 if (!object->HasNamedInterceptor()) return Just(true);
430 } 452 }
431 Handle<InterceptorInfo> interceptor(type == kIndexed 453 Handle<InterceptorInfo> interceptor(type == kIndexed
432 ? object->GetIndexedInterceptor() 454 ? object->GetIndexedInterceptor()
(...skipping 22 matching lines...) Expand all
455 477
456 } // namespace 478 } // namespace
457 479
458 Maybe<bool> KeyAccumulator::CollectOwnElementIndices( 480 Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
459 Handle<JSReceiver> receiver, Handle<JSObject> object) { 481 Handle<JSReceiver> receiver, Handle<JSObject> object) {
460 if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true); 482 if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
461 483
462 ElementsAccessor* accessor = object->GetElementsAccessor(); 484 ElementsAccessor* accessor = object->GetElementsAccessor();
463 accessor->CollectElementIndices(object, this); 485 accessor->CollectElementIndices(object, this);
464 486
465 return GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, 487 return CollectInterceptorKeys<v8::IndexedPropertyEnumeratorCallback,
466 kIndexed>(receiver, object, this); 488 kIndexed>(receiver, object, this);
467 } 489 }
468 490
469 namespace { 491 namespace {
470 492
471 template <bool skip_symbols> 493 template <bool skip_symbols>
472 int CollectOwnPropertyNamesInternal(Handle<JSObject> object, 494 int CollectOwnPropertyNamesInternal(Handle<JSObject> object,
473 KeyAccumulator* keys, 495 KeyAccumulator* keys,
474 Handle<DescriptorArray> descs, 496 Handle<DescriptorArray> descs,
475 int start_index, int limit) { 497 int start_index, int limit) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 } 539 }
518 } else if (object->IsJSGlobalObject()) { 540 } else if (object->IsJSGlobalObject()) {
519 GlobalDictionary::CollectKeysTo( 541 GlobalDictionary::CollectKeysTo(
520 handle(object->global_dictionary(), isolate_), this, filter_); 542 handle(object->global_dictionary(), isolate_), this, filter_);
521 } else { 543 } else {
522 NameDictionary::CollectKeysTo( 544 NameDictionary::CollectKeysTo(
523 handle(object->property_dictionary(), isolate_), this, filter_); 545 handle(object->property_dictionary(), isolate_), this, filter_);
524 } 546 }
525 } 547 }
526 // Add the property keys from the interceptor. 548 // Add the property keys from the interceptor.
527 return GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, 549 return CollectInterceptorKeys<v8::GenericNamedPropertyEnumeratorCallback,
528 kNamed>(receiver, object, this); 550 kNamed>(receiver, object, this);
529 } 551 }
530 552
531 // Returns |true| on success, |false| if prototype walking should be stopped, 553 // Returns |true| on success, |false| if prototype walking should be stopped,
532 // |nothing| if an exception was thrown. 554 // |nothing| if an exception was thrown.
533 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, 555 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
534 Handle<JSObject> object) { 556 Handle<JSObject> object) {
535 // Check access rights if required. 557 // Check access rights if required.
536 if (object->IsAccessCheckNeeded() && 558 if (object->IsAccessCheckNeeded() &&
537 !isolate_->MayAccess(handle(isolate_->context()), object)) { 559 !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>()); 752 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>());
731 bool prev_filter_proxy_keys_ = filter_proxy_keys_; 753 bool prev_filter_proxy_keys_ = filter_proxy_keys_;
732 filter_proxy_keys_ = false; 754 filter_proxy_keys_ = false;
733 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); 755 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
734 filter_proxy_keys_ = prev_filter_proxy_keys_; 756 filter_proxy_keys_ = prev_filter_proxy_keys_;
735 return result; 757 return result;
736 } 758 }
737 759
738 } // namespace internal 760 } // namespace internal
739 } // namespace v8 761 } // 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