OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 result = enum_fun(info); | 541 result = enum_fun(info); |
542 } | 542 } |
543 } | 543 } |
544 return result; | 544 return result; |
545 } | 545 } |
546 | 546 |
547 | 547 |
548 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, | 548 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, |
549 KeyCollectionType type) { | 549 KeyCollectionType type) { |
550 Handle<FixedArray> content = Factory::empty_fixed_array(); | 550 Handle<FixedArray> content = Factory::empty_fixed_array(); |
| 551 Handle<JSObject> arguments_boilerplate = |
| 552 Handle<JSObject>( |
| 553 Top::context()->global_context()->arguments_boilerplate()); |
| 554 Handle<JSFunction> arguments_function = |
| 555 Handle<JSFunction>( |
| 556 JSFunction::cast(arguments_boilerplate->map()->constructor())); |
551 | 557 |
552 // Only collect keys if access is permitted. | 558 // Only collect keys if access is permitted. |
553 for (Handle<Object> p = object; | 559 for (Handle<Object> p = object; |
554 *p != Heap::null_value(); | 560 *p != Heap::null_value(); |
555 p = Handle<Object>(p->GetPrototype())) { | 561 p = Handle<Object>(p->GetPrototype())) { |
556 Handle<JSObject> current(JSObject::cast(*p)); | 562 Handle<JSObject> current(JSObject::cast(*p)); |
557 | 563 |
558 // Check access rights if required. | 564 // Check access rights if required. |
559 if (current->IsAccessCheckNeeded() && | 565 if (current->IsAccessCheckNeeded() && |
560 !Top::MayNamedAccess(*current, Heap::undefined_value(), | 566 !Top::MayNamedAccess(*current, Heap::undefined_value(), |
561 v8::ACCESS_KEYS)) { | 567 v8::ACCESS_KEYS)) { |
562 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); | 568 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); |
563 break; | 569 break; |
564 } | 570 } |
565 | 571 |
566 // Compute the element keys. | 572 // Compute the element keys. |
567 Handle<FixedArray> element_keys = | 573 Handle<FixedArray> element_keys = |
568 Factory::NewFixedArray(current->NumberOfEnumElements()); | 574 Factory::NewFixedArray(current->NumberOfEnumElements()); |
569 current->GetEnumElementKeys(*element_keys); | 575 current->GetEnumElementKeys(*element_keys); |
570 content = UnionOfKeys(content, element_keys); | 576 content = UnionOfKeys(content, element_keys); |
571 | 577 |
572 // Add the element keys from the interceptor. | 578 // Add the element keys from the interceptor. |
573 if (current->HasIndexedInterceptor()) { | 579 if (current->HasIndexedInterceptor()) { |
574 v8::Handle<v8::Array> result = | 580 v8::Handle<v8::Array> result = |
575 GetKeysForIndexedInterceptor(object, current); | 581 GetKeysForIndexedInterceptor(object, current); |
576 if (!result.IsEmpty()) | 582 if (!result.IsEmpty()) |
577 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); | 583 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); |
578 } | 584 } |
579 | 585 |
580 // Compute the property keys. | 586 // We can cache the computed property keys if access checks are |
581 content = UnionOfKeys(content, GetEnumPropertyKeys(current)); | 587 // not needed and no interceptors are involved. |
| 588 // |
| 589 // We do not use the cache if the object has elements and |
| 590 // therefore it does not make sense to cache the property names |
| 591 // for arguments objects. Arguments objects will always have |
| 592 // elements. |
| 593 bool cache_enum_keys = |
| 594 ((current->map()->constructor() != *arguments_function) && |
| 595 !current->IsAccessCheckNeeded() && |
| 596 !current->HasNamedInterceptor() && |
| 597 !current->HasIndexedInterceptor()); |
| 598 // Compute the property keys and cache them if possible. |
| 599 content = |
| 600 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); |
582 | 601 |
583 // Add the property keys from the interceptor. | 602 // Add the property keys from the interceptor. |
584 if (current->HasNamedInterceptor()) { | 603 if (current->HasNamedInterceptor()) { |
585 v8::Handle<v8::Array> result = | 604 v8::Handle<v8::Array> result = |
586 GetKeysForNamedInterceptor(object, current); | 605 GetKeysForNamedInterceptor(object, current); |
587 if (!result.IsEmpty()) | 606 if (!result.IsEmpty()) |
588 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); | 607 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); |
589 } | 608 } |
590 | 609 |
591 // If we only want local properties we bail out after the first | 610 // If we only want local properties we bail out after the first |
592 // iteration. | 611 // iteration. |
593 if (type == LOCAL_ONLY) | 612 if (type == LOCAL_ONLY) |
594 break; | 613 break; |
595 } | 614 } |
596 return content; | 615 return content; |
597 } | 616 } |
598 | 617 |
599 | 618 |
600 Handle<JSArray> GetKeysFor(Handle<JSObject> object) { | 619 Handle<JSArray> GetKeysFor(Handle<JSObject> object) { |
601 Counters::for_in.Increment(); | 620 Counters::for_in.Increment(); |
602 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object, | 621 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object, |
603 INCLUDE_PROTOS); | 622 INCLUDE_PROTOS); |
604 return Factory::NewJSArrayWithElements(elements); | 623 return Factory::NewJSArrayWithElements(elements); |
605 } | 624 } |
606 | 625 |
607 | 626 |
608 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) { | 627 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, |
| 628 bool cache_result) { |
609 int index = 0; | 629 int index = 0; |
610 if (object->HasFastProperties()) { | 630 if (object->HasFastProperties()) { |
611 if (object->map()->instance_descriptors()->HasEnumCache()) { | 631 if (object->map()->instance_descriptors()->HasEnumCache()) { |
612 Counters::enum_cache_hits.Increment(); | 632 Counters::enum_cache_hits.Increment(); |
613 DescriptorArray* desc = object->map()->instance_descriptors(); | 633 DescriptorArray* desc = object->map()->instance_descriptors(); |
614 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache())); | 634 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache())); |
615 } | 635 } |
616 Counters::enum_cache_misses.Increment(); | 636 Counters::enum_cache_misses.Increment(); |
617 int num_enum = object->NumberOfEnumProperties(); | 637 int num_enum = object->NumberOfEnumProperties(); |
618 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); | 638 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); |
619 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); | 639 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); |
620 Handle<DescriptorArray> descs = | 640 Handle<DescriptorArray> descs = |
621 Handle<DescriptorArray>(object->map()->instance_descriptors()); | 641 Handle<DescriptorArray>(object->map()->instance_descriptors()); |
622 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 642 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
623 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { | 643 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { |
624 (*storage)->set(index, descs->GetKey(i)); | 644 (*storage)->set(index, descs->GetKey(i)); |
625 PropertyDetails details(descs->GetDetails(i)); | 645 PropertyDetails details(descs->GetDetails(i)); |
626 (*sort_array)->set(index, Smi::FromInt(details.index())); | 646 (*sort_array)->set(index, Smi::FromInt(details.index())); |
627 index++; | 647 index++; |
628 } | 648 } |
629 } | 649 } |
630 (*storage)->SortPairs(*sort_array, sort_array->length()); | 650 (*storage)->SortPairs(*sort_array, sort_array->length()); |
631 Handle<FixedArray> bridge_storage = | 651 if (cache_result) { |
632 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); | 652 Handle<FixedArray> bridge_storage = |
633 DescriptorArray* desc = object->map()->instance_descriptors(); | 653 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); |
634 desc->SetEnumCache(*bridge_storage, *storage); | 654 DescriptorArray* desc = object->map()->instance_descriptors(); |
| 655 desc->SetEnumCache(*bridge_storage, *storage); |
| 656 } |
635 ASSERT(storage->length() == index); | 657 ASSERT(storage->length() == index); |
636 return storage; | 658 return storage; |
637 } else { | 659 } else { |
638 int num_enum = object->NumberOfEnumProperties(); | 660 int num_enum = object->NumberOfEnumProperties(); |
639 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); | 661 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); |
640 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); | 662 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); |
641 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array); | 663 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array); |
642 return storage; | 664 return storage; |
643 } | 665 } |
644 } | 666 } |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 Handle<Map> new_map = Factory::CopyMapDropTransitions(old_map); | 802 Handle<Map> new_map = Factory::CopyMapDropTransitions(old_map); |
781 obj->set_map(*new_map); | 803 obj->set_map(*new_map); |
782 new_map->set_needs_loading(true); | 804 new_map->set_needs_loading(true); |
783 // Store the lazy loading info in the constructor field. We'll | 805 // Store the lazy loading info in the constructor field. We'll |
784 // reestablish the constructor from the fixed array after loading. | 806 // reestablish the constructor from the fixed array after loading. |
785 new_map->set_constructor(*arr); | 807 new_map->set_constructor(*arr); |
786 ASSERT(!obj->IsLoaded()); | 808 ASSERT(!obj->IsLoaded()); |
787 } | 809 } |
788 | 810 |
789 } } // namespace v8::internal | 811 } } // namespace v8::internal |
OLD | NEW |