| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 614 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { | 625 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { |
| 626 int len = array->length(); | 626 int len = array->length(); |
| 627 for (int i = 0; i < len; i++) { | 627 for (int i = 0; i < len; i++) { |
| 628 Object* e = array->get(i); | 628 Object* e = array->get(i); |
| 629 if (!(e->IsString() || e->IsNumber())) return false; | 629 if (!(e->IsString() || e->IsNumber())) return false; |
| 630 } | 630 } |
| 631 return true; | 631 return true; |
| 632 } | 632 } |
| 633 | 633 |
| 634 | 634 |
| 635 |
| 636 template |
| 637 Handle<FixedArray> GetKeysInFixedArrayFor<true>(Handle<JSReceiver> object, |
| 638 KeyCollectionType type, |
| 639 bool* threw); |
| 640 template |
| 641 Handle<FixedArray> GetKeysInFixedArrayFor<false>(Handle<JSReceiver> object, |
| 642 KeyCollectionType type, |
| 643 bool* threw); |
| 644 |
| 645 template<bool allow_side_effect> |
| 635 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object, | 646 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object, |
| 636 KeyCollectionType type, | 647 KeyCollectionType type, |
| 637 bool* threw) { | 648 bool* threw) { |
| 638 USE(ContainsOnlyValidKeys); | 649 USE(ContainsOnlyValidKeys); |
| 639 Isolate* isolate = object->GetIsolate(); | 650 Isolate* isolate = object->GetIsolate(); |
| 640 Handle<FixedArray> content = isolate->factory()->empty_fixed_array(); | 651 Handle<FixedArray> content = isolate->factory()->empty_fixed_array(); |
| 641 Handle<JSObject> arguments_boilerplate = Handle<JSObject>( | 652 Handle<JSObject> arguments_boilerplate = Handle<JSObject>( |
| 642 isolate->context()->native_context()->arguments_boilerplate(), | 653 isolate->context()->native_context()->arguments_boilerplate(), |
| 643 isolate); | 654 isolate); |
| 644 Handle<JSFunction> arguments_function = Handle<JSFunction>( | 655 Handle<JSFunction> arguments_function = Handle<JSFunction>( |
| 645 JSFunction::cast(arguments_boilerplate->map()->constructor()), | 656 JSFunction::cast(arguments_boilerplate->map()->constructor()), |
| 646 isolate); | 657 isolate); |
| 647 | 658 |
| 648 // Only collect keys if access is permitted. | 659 // Only collect keys if access is permitted. |
| 649 for (Handle<Object> p = object; | 660 for (Handle<Object> p = object; |
| 650 *p != isolate->heap()->null_value(); | 661 *p != isolate->heap()->null_value(); |
| 651 p = Handle<Object>(p->GetPrototype(), isolate)) { | 662 p = Handle<Object>(p->GetPrototype(), isolate)) { |
| 652 if (p->IsJSProxy()) { | 663 if (p->IsJSProxy()) { |
| 653 Handle<JSProxy> proxy(JSProxy::cast(*p), isolate); | 664 if (allow_side_effect) { |
| 654 Handle<Object> args[] = { proxy }; | 665 Handle<JSProxy> proxy(JSProxy::cast(*p), isolate); |
| 655 Handle<Object> names = Execution::Call( | 666 Handle<Object> args[] = { proxy }; |
| 656 isolate->proxy_enumerate(), object, ARRAY_SIZE(args), args, threw); | 667 Handle<Object> names = Execution::Call( |
| 657 if (*threw) return content; | 668 isolate->proxy_enumerate(), object, ARRAY_SIZE(args), args, threw); |
| 658 content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names)); | 669 if (*threw) return content; |
| 670 content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names)); |
| 671 } |
| 659 break; | 672 break; |
| 660 } | 673 } |
| 661 | 674 |
| 662 Handle<JSObject> current(JSObject::cast(*p), isolate); | 675 Handle<JSObject> current(JSObject::cast(*p), isolate); |
| 663 | 676 |
| 664 // Check access rights if required. | 677 // Check access rights if required. |
| 665 if (current->IsAccessCheckNeeded() && | 678 if (current->IsAccessCheckNeeded()) { |
| 666 !isolate->MayNamedAccess(*current, | 679 if (!allow_side_effect) { |
| 667 isolate->heap()->undefined_value(), | 680 break; |
| 668 v8::ACCESS_KEYS)) { | 681 } else if (!isolate->MayNamedAccess( |
| 669 isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); | 682 *current, isolate->heap()->undefined_value(), v8::ACCESS_KEYS)) { |
| 670 break; | 683 isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); |
| 684 break; |
| 685 } |
| 671 } | 686 } |
| 672 | 687 |
| 673 // Compute the element keys. | 688 // Compute the element keys. |
| 674 Handle<FixedArray> element_keys = | 689 Handle<FixedArray> element_keys = |
| 675 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); | 690 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); |
| 676 current->GetEnumElementKeys(*element_keys); | 691 current->GetEnumElementKeys(*element_keys); |
| 677 content = UnionOfKeys(content, element_keys); | 692 content = UnionOfKeys(content, element_keys); |
| 678 ASSERT(ContainsOnlyValidKeys(content)); | 693 ASSERT(ContainsOnlyValidKeys(content)); |
| 679 | 694 |
| 680 // Add the element keys from the interceptor. | 695 // Add the element keys from the interceptor. |
| 681 if (current->HasIndexedInterceptor()) { | 696 if (allow_side_effect && current->HasIndexedInterceptor()) { |
| 682 v8::Handle<v8::Array> result = | 697 v8::Handle<v8::Array> result = |
| 683 GetKeysForIndexedInterceptor(object, current); | 698 GetKeysForIndexedInterceptor(object, current); |
| 684 if (!result.IsEmpty()) | 699 if (!result.IsEmpty()) |
| 685 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); | 700 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); |
| 686 ASSERT(ContainsOnlyValidKeys(content)); | 701 ASSERT(ContainsOnlyValidKeys(content)); |
| 687 } | 702 } |
| 688 | 703 |
| 689 // We can cache the computed property keys if access checks are | 704 // We can cache the computed property keys if access checks are |
| 690 // not needed and no interceptors are involved. | 705 // not needed and no interceptors are involved. |
| 691 // | 706 // |
| 692 // We do not use the cache if the object has elements and | 707 // We do not use the cache if the object has elements and |
| 693 // therefore it does not make sense to cache the property names | 708 // therefore it does not make sense to cache the property names |
| 694 // for arguments objects. Arguments objects will always have | 709 // for arguments objects. Arguments objects will always have |
| 695 // elements. | 710 // elements. |
| 696 // Wrapped strings have elements, but don't have an elements | 711 // Wrapped strings have elements, but don't have an elements |
| 697 // array or dictionary. So the fast inline test for whether to | 712 // array or dictionary. So the fast inline test for whether to |
| 698 // use the cache says yes, so we should not create a cache. | 713 // use the cache says yes, so we should not create a cache. |
| 699 bool cache_enum_keys = | 714 bool cache_enum_keys = |
| 700 ((current->map()->constructor() != *arguments_function) && | 715 ((current->map()->constructor() != *arguments_function) && |
| 701 !current->IsJSValue() && | 716 !current->IsJSValue() && |
| 702 !current->IsAccessCheckNeeded() && | 717 !current->IsAccessCheckNeeded() && |
| 703 !current->HasNamedInterceptor() && | 718 !current->HasNamedInterceptor() && |
| 704 !current->HasIndexedInterceptor()); | 719 !current->HasIndexedInterceptor()); |
| 705 // Compute the property keys and cache them if possible. | 720 // Compute the property keys and cache them if possible. |
| 706 content = | 721 content = |
| 707 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); | 722 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); |
| 708 ASSERT(ContainsOnlyValidKeys(content)); | 723 ASSERT(ContainsOnlyValidKeys(content)); |
| 709 | 724 |
| 710 // Add the property keys from the interceptor. | 725 // Add the property keys from the interceptor. |
| 711 if (current->HasNamedInterceptor()) { | 726 if (allow_side_effect && current->HasNamedInterceptor()) { |
| 712 v8::Handle<v8::Array> result = | 727 v8::Handle<v8::Array> result = |
| 713 GetKeysForNamedInterceptor(object, current); | 728 GetKeysForNamedInterceptor(object, current); |
| 714 if (!result.IsEmpty()) | 729 if (!result.IsEmpty()) |
| 715 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); | 730 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); |
| 716 ASSERT(ContainsOnlyValidKeys(content)); | 731 ASSERT(ContainsOnlyValidKeys(content)); |
| 717 } | 732 } |
| 718 | 733 |
| 719 // If we only want local properties we bail out after the first | 734 // If we only want local properties we bail out after the first |
| 720 // iteration. | 735 // iteration. |
| 721 if (type == LOCAL_ONLY) | 736 if (type == LOCAL_ONLY) break; |
| 722 break; | |
| 723 } | 737 } |
| 724 return content; | 738 return content; |
| 725 } | 739 } |
| 726 | 740 |
| 727 | 741 |
| 728 Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) { | |
| 729 Isolate* isolate = object->GetIsolate(); | |
| 730 isolate->counters()->for_in()->Increment(); | |
| 731 Handle<FixedArray> elements = | |
| 732 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw); | |
| 733 return isolate->factory()->NewJSArrayWithElements(elements); | |
| 734 } | |
| 735 | |
| 736 | |
| 737 Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { | 742 Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { |
| 738 ASSERT(array->length() >= length); | 743 ASSERT(array->length() >= length); |
| 739 if (array->length() == length) return array; | 744 if (array->length() == length) return array; |
| 740 | 745 |
| 741 Handle<FixedArray> new_array = | 746 Handle<FixedArray> new_array = |
| 742 array->GetIsolate()->factory()->NewFixedArray(length); | 747 array->GetIsolate()->factory()->NewFixedArray(length); |
| 743 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); | 748 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); |
| 744 return new_array; | 749 return new_array; |
| 745 } | 750 } |
| 746 | 751 |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 928 data->next = prev_next_; | 933 data->next = prev_next_; |
| 929 data->limit = prev_limit_; | 934 data->limit = prev_limit_; |
| 930 #ifdef DEBUG | 935 #ifdef DEBUG |
| 931 handles_detached_ = true; | 936 handles_detached_ = true; |
| 932 #endif | 937 #endif |
| 933 return deferred; | 938 return deferred; |
| 934 } | 939 } |
| 935 | 940 |
| 936 | 941 |
| 937 } } // namespace v8::internal | 942 } } // namespace v8::internal |
| OLD | NEW |