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

Side by Side Diff: src/objects.cc

Issue 2123012: Allow to define accessors on objects. (Closed)
Patch Set: Last round of comments Created 10 years, 7 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/objects.h ('k') | test/cctest/test-api.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 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-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 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 Object* getter = FixedArray::cast(structure)->get(kGetterIndex); 182 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
183 if (getter->IsJSFunction()) { 183 if (getter->IsJSFunction()) {
184 return Object::GetPropertyWithDefinedGetter(receiver, 184 return Object::GetPropertyWithDefinedGetter(receiver,
185 JSFunction::cast(getter)); 185 JSFunction::cast(getter));
186 } 186 }
187 // Getter is not a function. 187 // Getter is not a function.
188 return Heap::undefined_value(); 188 return Heap::undefined_value();
189 } 189 }
190 190
191 UNREACHABLE(); 191 UNREACHABLE();
192 return 0; 192 return NULL;
193 } 193 }
194 194
195 195
196 Object* Object::GetPropertyWithDefinedGetter(Object* receiver, 196 Object* Object::GetPropertyWithDefinedGetter(Object* receiver,
197 JSFunction* getter) { 197 JSFunction* getter) {
198 HandleScope scope; 198 HandleScope scope;
199 Handle<JSFunction> fun(JSFunction::cast(getter)); 199 Handle<JSFunction> fun(JSFunction::cast(getter));
200 Handle<Object> self(receiver); 200 Handle<Object> self(receiver);
201 #ifdef ENABLE_DEBUGGER_SUPPORT 201 #ifdef ENABLE_DEBUGGER_SUPPORT
202 // Handle stepping into a getter if step into is active. 202 // Handle stepping into a getter if step into is active.
(...skipping 1403 matching lines...) Expand 10 before | Expand all | Expand 10 after
1606 } else { 1606 } else {
1607 Handle<String> key(name); 1607 Handle<String> key(name);
1608 Handle<Object> holder_handle(holder); 1608 Handle<Object> holder_handle(holder);
1609 Handle<Object> args[2] = { key, holder_handle }; 1609 Handle<Object> args[2] = { key, holder_handle };
1610 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", 1610 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
1611 HandleVector(args, 2))); 1611 HandleVector(args, 2)));
1612 } 1612 }
1613 } 1613 }
1614 1614
1615 UNREACHABLE(); 1615 UNREACHABLE();
1616 return 0; 1616 return NULL;
1617 } 1617 }
1618 1618
1619 1619
1620 Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter, 1620 Object* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1621 Object* value) { 1621 Object* value) {
1622 Handle<Object> value_handle(value); 1622 Handle<Object> value_handle(value);
1623 Handle<JSFunction> fun(JSFunction::cast(setter)); 1623 Handle<JSFunction> fun(JSFunction::cast(setter));
1624 Handle<JSObject> self(this); 1624 Handle<JSObject> self(this);
1625 #ifdef ENABLE_DEBUGGER_SUPPORT 1625 #ifdef ENABLE_DEBUGGER_SUPPORT
1626 // Handle stepping into a setter if step into is active. 1626 // Handle stepping into a setter if step into is active.
(...skipping 23 matching lines...) Expand all
1650 } 1650 }
1651 if (result->type() == CALLBACKS) { 1651 if (result->type() == CALLBACKS) {
1652 return; 1652 return;
1653 } 1653 }
1654 } 1654 }
1655 } 1655 }
1656 result->NotFound(); 1656 result->NotFound();
1657 } 1657 }
1658 1658
1659 1659
1660 Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { 1660 bool JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
1661 Object* value) {
1661 for (Object* pt = GetPrototype(); 1662 for (Object* pt = GetPrototype();
1662 pt != Heap::null_value(); 1663 pt != Heap::null_value();
1663 pt = pt->GetPrototype()) { 1664 pt = pt->GetPrototype()) {
1664 if (!JSObject::cast(pt)->HasDictionaryElements()) { 1665 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1665 continue; 1666 continue;
1666 } 1667 }
1667 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); 1668 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1668 int entry = dictionary->FindEntry(index); 1669 int entry = dictionary->FindEntry(index);
1669 if (entry != NumberDictionary::kNotFound) { 1670 if (entry != NumberDictionary::kNotFound) {
1670 Object* element = dictionary->ValueAt(entry); 1671 Object* element = dictionary->ValueAt(entry);
1671 PropertyDetails details = dictionary->DetailsAt(entry); 1672 PropertyDetails details = dictionary->DetailsAt(entry);
1672 if (details.type() == CALLBACKS) { 1673 if (details.type() == CALLBACKS) {
1673 // Only accessors allowed as elements. 1674 SetElementWithCallback(element, index, value, JSObject::cast(pt));
1674 return FixedArray::cast(element)->get(kSetterIndex); 1675 return true;
1675 } 1676 }
1676 } 1677 }
1677 } 1678 }
1678 return Heap::undefined_value(); 1679 return false;
1679 } 1680 }
1680 1681
1681 1682
1682 void JSObject::LookupInDescriptor(String* name, LookupResult* result) { 1683 void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1683 DescriptorArray* descriptors = map()->instance_descriptors(); 1684 DescriptorArray* descriptors = map()->instance_descriptors();
1684 int number = DescriptorLookupCache::Lookup(descriptors, name); 1685 int number = DescriptorLookupCache::Lookup(descriptors, name);
1685 if (number == DescriptorLookupCache::kAbsent) { 1686 if (number == DescriptorLookupCache::kAbsent) {
1686 number = descriptors->Search(name); 1687 number = descriptors->Search(name);
1687 DescriptorLookupCache::Update(descriptors, name, number); 1688 DescriptorLookupCache::Update(descriptors, name, number);
1688 } 1689 }
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after
2685 result->NotFound(); 2686 result->NotFound();
2686 } 2687 }
2687 2688
2688 2689
2689 Object* JSObject::DefineGetterSetter(String* name, 2690 Object* JSObject::DefineGetterSetter(String* name,
2690 PropertyAttributes attributes) { 2691 PropertyAttributes attributes) {
2691 // Make sure that the top context does not change when doing callbacks or 2692 // Make sure that the top context does not change when doing callbacks or
2692 // interceptor calls. 2693 // interceptor calls.
2693 AssertNoContextChange ncc; 2694 AssertNoContextChange ncc;
2694 2695
2695 // Check access rights if needed.
2696 if (IsAccessCheckNeeded() &&
2697 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
2698 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
2699 return Heap::undefined_value();
2700 }
2701
2702 // Try to flatten before operating on the string. 2696 // Try to flatten before operating on the string.
2703 name->TryFlatten(); 2697 name->TryFlatten();
2704 2698
2705 // Check if there is an API defined callback object which prohibits 2699 if (!CanSetCallback(name)) {
2706 // callback overwriting in this object or it's prototype chain. 2700 return Heap::undefined_value();
2707 // This mechanism is needed for instance in a browser setting, where
2708 // certain accessors such as window.location should not be allowed
2709 // to be overwritten because allowing overwriting could potentially
2710 // cause security problems.
2711 LookupResult callback_result;
2712 LookupCallback(name, &callback_result);
2713 if (callback_result.IsFound()) {
2714 Object* obj = callback_result.GetCallbackObject();
2715 if (obj->IsAccessorInfo() &&
2716 AccessorInfo::cast(obj)->prohibits_overwriting()) {
2717 return Heap::undefined_value();
2718 }
2719 } 2701 }
2720 2702
2721 uint32_t index; 2703 uint32_t index;
2722 bool is_element = name->AsArrayIndex(&index); 2704 bool is_element = name->AsArrayIndex(&index);
2723 if (is_element && IsJSArray()) return Heap::undefined_value(); 2705 if (is_element && IsJSArray()) return Heap::undefined_value();
2724 2706
2725 if (is_element) { 2707 if (is_element) {
2726 switch (GetElementsKind()) { 2708 switch (GetElementsKind()) {
2727 case FAST_ELEMENTS: 2709 case FAST_ELEMENTS:
2728 break; 2710 break;
(...skipping 10 matching lines...) Expand all
2739 return Heap::undefined_value(); 2721 return Heap::undefined_value();
2740 case DICTIONARY_ELEMENTS: { 2722 case DICTIONARY_ELEMENTS: {
2741 // Lookup the index. 2723 // Lookup the index.
2742 NumberDictionary* dictionary = element_dictionary(); 2724 NumberDictionary* dictionary = element_dictionary();
2743 int entry = dictionary->FindEntry(index); 2725 int entry = dictionary->FindEntry(index);
2744 if (entry != NumberDictionary::kNotFound) { 2726 if (entry != NumberDictionary::kNotFound) {
2745 Object* result = dictionary->ValueAt(entry); 2727 Object* result = dictionary->ValueAt(entry);
2746 PropertyDetails details = dictionary->DetailsAt(entry); 2728 PropertyDetails details = dictionary->DetailsAt(entry);
2747 if (details.IsReadOnly()) return Heap::undefined_value(); 2729 if (details.IsReadOnly()) return Heap::undefined_value();
2748 if (details.type() == CALLBACKS) { 2730 if (details.type() == CALLBACKS) {
2749 // Only accessors allowed as elements. 2731 if (result->IsFixedArray()) {
2750 ASSERT(result->IsFixedArray()); 2732 return result;
2751 return result; 2733 }
2734 // Otherwise allow to override it.
2752 } 2735 }
2753 } 2736 }
2754 break; 2737 break;
2755 } 2738 }
2756 default: 2739 default:
2757 UNREACHABLE(); 2740 UNREACHABLE();
2758 break; 2741 break;
2759 } 2742 }
2760 } else { 2743 } else {
2761 // Lookup the name. 2744 // Lookup the name.
2762 LookupResult result; 2745 LookupResult result;
2763 LocalLookup(name, &result); 2746 LocalLookup(name, &result);
2764 if (result.IsProperty()) { 2747 if (result.IsProperty()) {
2765 if (result.IsReadOnly()) return Heap::undefined_value(); 2748 if (result.IsReadOnly()) return Heap::undefined_value();
2766 if (result.type() == CALLBACKS) { 2749 if (result.type() == CALLBACKS) {
2767 Object* obj = result.GetCallbackObject(); 2750 Object* obj = result.GetCallbackObject();
2751 // Need to preserve old getters/setters.
2768 if (obj->IsFixedArray()) { 2752 if (obj->IsFixedArray()) {
2769 // The object might be in fast mode even though it has 2753 // Use set to update attributes.
2770 // a getter/setter. 2754 return SetPropertyCallback(name, obj, attributes);
2771 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2772 if (ok->IsFailure()) return ok;
2773
2774 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
2775 SetNormalizedProperty(name, obj, details);
2776 return obj;
2777 } 2755 }
2778 } 2756 }
2779 } 2757 }
2780 } 2758 }
2781 2759
2782 // Allocate the fixed array to hold getter and setter. 2760 // Allocate the fixed array to hold getter and setter.
2783 Object* structure = Heap::AllocateFixedArray(2, TENURED); 2761 Object* structure = Heap::AllocateFixedArray(2, TENURED);
2784 if (structure->IsFailure()) return structure; 2762 if (structure->IsFailure()) return structure;
2763
2764 if (is_element) {
2765 return SetElementCallback(index, structure, attributes);
2766 } else {
2767 return SetPropertyCallback(name, structure, attributes);
2768 }
2769 }
2770
2771
2772 bool JSObject::CanSetCallback(String* name) {
2773 ASSERT(!IsAccessCheckNeeded()
2774 || Top::MayNamedAccess(this, name, v8::ACCESS_SET));
2775
2776 // Check if there is an API defined callback object which prohibits
2777 // callback overwriting in this object or it's prototype chain.
2778 // This mechanism is needed for instance in a browser setting, where
2779 // certain accessors such as window.location should not be allowed
2780 // to be overwritten because allowing overwriting could potentially
2781 // cause security problems.
2782 LookupResult callback_result;
2783 LookupCallback(name, &callback_result);
2784 if (callback_result.IsProperty()) {
2785 Object* obj = callback_result.GetCallbackObject();
2786 if (obj->IsAccessorInfo() &&
2787 AccessorInfo::cast(obj)->prohibits_overwriting()) {
2788 return false;
2789 }
2790 }
2791
2792 return true;
2793 }
2794
2795
2796 Object* JSObject::SetElementCallback(uint32_t index,
2797 Object* structure,
2798 PropertyAttributes attributes) {
2785 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); 2799 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
2786 2800
2787 if (is_element) { 2801 // Normalize elements to make this operation simple.
2788 // Normalize object to make this operation simple. 2802 Object* ok = NormalizeElements();
2789 Object* ok = NormalizeElements(); 2803 if (ok->IsFailure()) return ok;
2790 if (ok->IsFailure()) return ok;
2791 2804
2792 // Update the dictionary with the new CALLBACKS property. 2805 // Update the dictionary with the new CALLBACKS property.
2793 Object* dict = 2806 Object* dict =
2794 element_dictionary()->Set(index, structure, details); 2807 element_dictionary()->Set(index, structure, details);
2795 if (dict->IsFailure()) return dict; 2808 if (dict->IsFailure()) return dict;
2796 2809
2797 // If name is an index we need to stay in slow case. 2810 NumberDictionary* elements = NumberDictionary::cast(dict);
2798 NumberDictionary* elements = NumberDictionary::cast(dict); 2811 elements->set_requires_slow_elements();
2799 elements->set_requires_slow_elements(); 2812 // Set the potential new dictionary on the object.
2800 // Set the potential new dictionary on the object. 2813 set_elements(elements);
2801 set_elements(NumberDictionary::cast(dict));
2802 } else {
2803 // Normalize object to make this operation simple.
2804 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2805 if (ok->IsFailure()) return ok;
2806
2807 // For the global object allocate a new map to invalidate the global inline
2808 // caches which have a global property cell reference directly in the code.
2809 if (IsGlobalObject()) {
2810 Object* new_map = map()->CopyDropDescriptors();
2811 if (new_map->IsFailure()) return new_map;
2812 set_map(Map::cast(new_map));
2813 }
2814
2815 // Update the dictionary with the new CALLBACKS property.
2816 return SetNormalizedProperty(name, structure, details);
2817 }
2818 2814
2819 return structure; 2815 return structure;
2820 } 2816 }
2821 2817
2822 2818
2819 Object* JSObject::SetPropertyCallback(String* name,
2820 Object* structure,
2821 PropertyAttributes attributes) {
2822 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
2823
2824 bool convert_back_to_fast = HasFastProperties() &&
2825 (map()->instance_descriptors()->number_of_descriptors()
2826 < DescriptorArray::kMaxNumberOfDescriptors);
2827
2828 // Normalize object to make this operation simple.
2829 Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2830 if (ok->IsFailure()) return ok;
2831
2832 // For the global object allocate a new map to invalidate the global inline
2833 // caches which have a global property cell reference directly in the code.
2834 if (IsGlobalObject()) {
2835 Object* new_map = map()->CopyDropDescriptors();
2836 if (new_map->IsFailure()) return new_map;
2837 set_map(Map::cast(new_map));
2838 }
2839
2840 // Update the dictionary with the new CALLBACKS property.
2841 Object* result = SetNormalizedProperty(name, structure, details);
2842 if (result->IsFailure()) return result;
2843
2844 if (convert_back_to_fast) {
2845 ok = TransformToFastProperties(0);
2846 if (ok->IsFailure()) return ok;
2847 }
2848 return result;
2849 }
2850
2823 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun, 2851 Object* JSObject::DefineAccessor(String* name, bool is_getter, JSFunction* fun,
2824 PropertyAttributes attributes) { 2852 PropertyAttributes attributes) {
2825 // Check access rights if needed. 2853 // Check access rights if needed.
2826 if (IsAccessCheckNeeded() && 2854 if (IsAccessCheckNeeded() &&
2827 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2855 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
2828 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); 2856 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
2829 return Heap::undefined_value(); 2857 return Heap::undefined_value();
2830 } 2858 }
2831 2859
2832 if (IsJSGlobalProxy()) { 2860 if (IsJSGlobalProxy()) {
2833 Object* proto = GetPrototype(); 2861 Object* proto = GetPrototype();
2834 if (proto->IsNull()) return this; 2862 if (proto->IsNull()) return this;
2835 ASSERT(proto->IsJSGlobalObject()); 2863 ASSERT(proto->IsJSGlobalObject());
2836 return JSObject::cast(proto)->DefineAccessor(name, is_getter, 2864 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
2837 fun, attributes); 2865 fun, attributes);
2838 } 2866 }
2839 2867
2840 Object* array = DefineGetterSetter(name, attributes); 2868 Object* array = DefineGetterSetter(name, attributes);
2841 if (array->IsFailure() || array->IsUndefined()) return array; 2869 if (array->IsFailure() || array->IsUndefined()) return array;
2842 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun); 2870 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
2843 return this; 2871 return this;
2844 } 2872 }
2845 2873
2846 2874
2875 Object* JSObject::DefineAccessor(AccessorInfo* info) {
2876 String* name = String::cast(info->name());
2877 // Check access rights if needed.
2878 if (IsAccessCheckNeeded() &&
2879 !Top::MayNamedAccess(this, name, v8::ACCESS_SET)) {
2880 Top::ReportFailedAccessCheck(this, v8::ACCESS_SET);
2881 return Heap::undefined_value();
2882 }
2883
2884 if (IsJSGlobalProxy()) {
2885 Object* proto = GetPrototype();
2886 if (proto->IsNull()) return this;
2887 ASSERT(proto->IsJSGlobalObject());
2888 return JSObject::cast(proto)->DefineAccessor(info);
2889 }
2890
2891 // Make sure that the top context does not change when doing callbacks or
2892 // interceptor calls.
2893 AssertNoContextChange ncc;
2894
2895 // Try to flatten before operating on the string.
2896 name->TryFlatten();
2897
2898 if (!CanSetCallback(name)) {
2899 return Heap::undefined_value();
2900 }
2901
2902 uint32_t index = 0;
2903 bool is_element = name->AsArrayIndex(&index);
2904
2905 if (is_element) {
2906 if (IsJSArray()) return Heap::undefined_value();
2907
2908 // Accessors overwrite previous callbacks (cf. with getters/setters).
2909 switch (GetElementsKind()) {
2910 case FAST_ELEMENTS:
2911 break;
2912 case PIXEL_ELEMENTS:
2913 case EXTERNAL_BYTE_ELEMENTS:
2914 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2915 case EXTERNAL_SHORT_ELEMENTS:
2916 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2917 case EXTERNAL_INT_ELEMENTS:
2918 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2919 case EXTERNAL_FLOAT_ELEMENTS:
2920 // Ignore getters and setters on pixel and external array
2921 // elements.
2922 return Heap::undefined_value();
2923 case DICTIONARY_ELEMENTS:
2924 break;
2925 default:
2926 UNREACHABLE();
2927 break;
2928 }
2929
2930 SetElementCallback(index, info, info->property_attributes());
2931 } else {
2932 // Lookup the name.
2933 LookupResult result;
2934 LocalLookup(name, &result);
2935 // ES5 forbids turning a property into an accessor if it's not
2936 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
2937 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
2938 return Heap::undefined_value();
2939 }
2940 SetPropertyCallback(name, info, info->property_attributes());
2941 }
2942
2943 return this;
2944 }
2945
2946
2847 Object* JSObject::LookupAccessor(String* name, bool is_getter) { 2947 Object* JSObject::LookupAccessor(String* name, bool is_getter) {
2848 // Make sure that the top context does not change when doing callbacks or 2948 // Make sure that the top context does not change when doing callbacks or
2849 // interceptor calls. 2949 // interceptor calls.
2850 AssertNoContextChange ncc; 2950 AssertNoContextChange ncc;
2851 2951
2852 // Check access rights if needed. 2952 // Check access rights if needed.
2853 if (IsAccessCheckNeeded() && 2953 if (IsAccessCheckNeeded() &&
2854 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) { 2954 !Top::MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2855 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS); 2955 Top::ReportFailedAccessCheck(this, v8::ACCESS_HAS);
2856 return Heap::undefined_value(); 2956 return Heap::undefined_value();
2857 } 2957 }
2858 2958
2859 // Make the lookup and include prototypes. 2959 // Make the lookup and include prototypes.
2860 int accessor_index = is_getter ? kGetterIndex : kSetterIndex; 2960 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
2861 uint32_t index; 2961 uint32_t index;
2862 if (name->AsArrayIndex(&index)) { 2962 if (name->AsArrayIndex(&index)) {
2863 for (Object* obj = this; 2963 for (Object* obj = this;
2864 obj != Heap::null_value(); 2964 obj != Heap::null_value();
2865 obj = JSObject::cast(obj)->GetPrototype()) { 2965 obj = JSObject::cast(obj)->GetPrototype()) {
2866 JSObject* js_object = JSObject::cast(obj); 2966 JSObject* js_object = JSObject::cast(obj);
2867 if (js_object->HasDictionaryElements()) { 2967 if (js_object->HasDictionaryElements()) {
2868 NumberDictionary* dictionary = js_object->element_dictionary(); 2968 NumberDictionary* dictionary = js_object->element_dictionary();
2869 int entry = dictionary->FindEntry(index); 2969 int entry = dictionary->FindEntry(index);
2870 if (entry != NumberDictionary::kNotFound) { 2970 if (entry != NumberDictionary::kNotFound) {
2871 Object* element = dictionary->ValueAt(entry); 2971 Object* element = dictionary->ValueAt(entry);
2872 PropertyDetails details = dictionary->DetailsAt(entry); 2972 PropertyDetails details = dictionary->DetailsAt(entry);
2873 if (details.type() == CALLBACKS) { 2973 if (details.type() == CALLBACKS) {
2874 // Only accessors allowed as elements. 2974 if (element->IsFixedArray()) {
2875 return FixedArray::cast(element)->get(accessor_index); 2975 return FixedArray::cast(element)->get(accessor_index);
2976 }
2876 } 2977 }
2877 } 2978 }
2878 } 2979 }
2879 } 2980 }
2880 } else { 2981 } else {
2881 for (Object* obj = this; 2982 for (Object* obj = this;
2882 obj != Heap::null_value(); 2983 obj != Heap::null_value();
2883 obj = JSObject::cast(obj)->GetPrototype()) { 2984 obj = JSObject::cast(obj)->GetPrototype()) {
2884 LookupResult result; 2985 LookupResult result;
2885 JSObject::cast(obj)->LocalLookup(name, &result); 2986 JSObject::cast(obj)->LocalLookup(name, &result);
(...skipping 2954 matching lines...) Expand 10 before | Expand all | Expand 10 after
5840 RETURN_IF_SCHEDULED_EXCEPTION(); 5941 RETURN_IF_SCHEDULED_EXCEPTION();
5841 if (!result.IsEmpty()) return *value_handle; 5942 if (!result.IsEmpty()) return *value_handle;
5842 } 5943 }
5843 Object* raw_result = 5944 Object* raw_result =
5844 this_handle->SetElementWithoutInterceptor(index, *value_handle); 5945 this_handle->SetElementWithoutInterceptor(index, *value_handle);
5845 RETURN_IF_SCHEDULED_EXCEPTION(); 5946 RETURN_IF_SCHEDULED_EXCEPTION();
5846 return raw_result; 5947 return raw_result;
5847 } 5948 }
5848 5949
5849 5950
5951 Object* JSObject::GetElementWithCallback(Object* receiver,
5952 Object* structure,
5953 uint32_t index,
5954 Object* holder) {
5955 ASSERT(!structure->IsProxy());
5956
5957 // api style callbacks.
5958 if (structure->IsAccessorInfo()) {
5959 AccessorInfo* data = AccessorInfo::cast(structure);
5960 Object* fun_obj = data->getter();
5961 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
5962 HandleScope scope;
5963 Handle<JSObject> self(JSObject::cast(receiver));
5964 Handle<JSObject> holder_handle(JSObject::cast(holder));
5965 Handle<Object> number = Factory::NewNumberFromUint(index);
5966 Handle<String> key(Factory::NumberToString(number));
5967 LOG(ApiNamedPropertyAccess("load", *self, *key));
5968 CustomArguments args(data->data(), *self, *holder_handle);
5969 v8::AccessorInfo info(args.end());
5970 v8::Handle<v8::Value> result;
5971 {
5972 // Leaving JavaScript.
5973 VMState state(EXTERNAL);
5974 result = call_fun(v8::Utils::ToLocal(key), info);
5975 }
5976 RETURN_IF_SCHEDULED_EXCEPTION();
5977 if (result.IsEmpty()) return Heap::undefined_value();
5978 return *v8::Utils::OpenHandle(*result);
5979 }
5980
5981 // __defineGetter__ callback
5982 if (structure->IsFixedArray()) {
5983 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
5984 if (getter->IsJSFunction()) {
5985 return Object::GetPropertyWithDefinedGetter(receiver,
5986 JSFunction::cast(getter));
5987 }
5988 // Getter is not a function.
5989 return Heap::undefined_value();
5990 }
5991
5992 UNREACHABLE();
5993 return NULL;
5994 }
5995
5996
5997 Object* JSObject::SetElementWithCallback(Object* structure,
5998 uint32_t index,
5999 Object* value,
6000 JSObject* holder) {
6001 HandleScope scope;
6002
6003 // We should never get here to initialize a const with the hole
6004 // value since a const declaration would conflict with the setter.
6005 ASSERT(!value->IsTheHole());
6006 Handle<Object> value_handle(value);
6007
6008 // To accommodate both the old and the new api we switch on the
6009 // data structure used to store the callbacks. Eventually proxy
6010 // callbacks should be phased out.
6011 ASSERT(!structure->IsProxy());
6012
6013 if (structure->IsAccessorInfo()) {
6014 // api style callbacks
6015 AccessorInfo* data = AccessorInfo::cast(structure);
6016 Object* call_obj = data->setter();
6017 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
6018 if (call_fun == NULL) return value;
6019 Handle<Object> number = Factory::NewNumberFromUint(index);
6020 Handle<String> key(Factory::NumberToString(number));
6021 LOG(ApiNamedPropertyAccess("store", this, *key));
6022 CustomArguments args(data->data(), this, JSObject::cast(holder));
6023 v8::AccessorInfo info(args.end());
6024 {
6025 // Leaving JavaScript.
6026 VMState state(EXTERNAL);
6027 call_fun(v8::Utils::ToLocal(key),
6028 v8::Utils::ToLocal(value_handle),
6029 info);
6030 }
6031 RETURN_IF_SCHEDULED_EXCEPTION();
6032 return *value_handle;
6033 }
6034
6035 if (structure->IsFixedArray()) {
6036 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
6037 if (setter->IsJSFunction()) {
6038 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
6039 } else {
6040 Handle<Object> holder_handle(holder);
6041 Handle<Object> key(Factory::NewNumberFromUint(index));
6042 Handle<Object> args[2] = { key, holder_handle };
6043 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
6044 HandleVector(args, 2)));
6045 }
6046 }
6047
6048 UNREACHABLE();
6049 return NULL;
6050 }
6051
6052
5850 // Adding n elements in fast case is O(n*n). 6053 // Adding n elements in fast case is O(n*n).
5851 // Note: revisit design to have dual undefined values to capture absent 6054 // Note: revisit design to have dual undefined values to capture absent
5852 // elements. 6055 // elements.
5853 Object* JSObject::SetFastElement(uint32_t index, Object* value) { 6056 Object* JSObject::SetFastElement(uint32_t index, Object* value) {
5854 ASSERT(HasFastElements()); 6057 ASSERT(HasFastElements());
5855 6058
5856 FixedArray* elms = FixedArray::cast(elements()); 6059 FixedArray* elms = FixedArray::cast(elements());
5857 uint32_t elms_length = static_cast<uint32_t>(elms->length()); 6060 uint32_t elms_length = static_cast<uint32_t>(elms->length());
5858 6061
5859 if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) { 6062 if (!IsJSArray() && (index >= elms_length || elms->get(index)->IsTheHole())) {
5860 Object* setter = LookupCallbackSetterInPrototypes(index); 6063 if (SetElementWithCallbackSetterInPrototypes(index, value)) {
5861 if (setter->IsJSFunction()) { 6064 return value;
5862 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
5863 } 6065 }
5864 } 6066 }
5865 6067
5866 // Check whether there is extra space in fixed array.. 6068 // Check whether there is extra space in fixed array..
5867 if (index < elms_length) { 6069 if (index < elms_length) {
5868 elms->set(index, value); 6070 elms->set(index, value);
5869 if (IsJSArray()) { 6071 if (IsJSArray()) {
5870 // Update the length of the array if needed. 6072 // Update the length of the array if needed.
5871 uint32_t array_length = 0; 6073 uint32_t array_length = 0;
5872 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), 6074 CHECK(Array::IndexFromObject(JSArray::cast(this)->length(),
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
5970 case DICTIONARY_ELEMENTS: { 6172 case DICTIONARY_ELEMENTS: {
5971 // Insert element in the dictionary. 6173 // Insert element in the dictionary.
5972 FixedArray* elms = FixedArray::cast(elements()); 6174 FixedArray* elms = FixedArray::cast(elements());
5973 NumberDictionary* dictionary = NumberDictionary::cast(elms); 6175 NumberDictionary* dictionary = NumberDictionary::cast(elms);
5974 6176
5975 int entry = dictionary->FindEntry(index); 6177 int entry = dictionary->FindEntry(index);
5976 if (entry != NumberDictionary::kNotFound) { 6178 if (entry != NumberDictionary::kNotFound) {
5977 Object* element = dictionary->ValueAt(entry); 6179 Object* element = dictionary->ValueAt(entry);
5978 PropertyDetails details = dictionary->DetailsAt(entry); 6180 PropertyDetails details = dictionary->DetailsAt(entry);
5979 if (details.type() == CALLBACKS) { 6181 if (details.type() == CALLBACKS) {
5980 // Only accessors allowed as elements. 6182 return SetElementWithCallback(element, index, value, this);
5981 FixedArray* structure = FixedArray::cast(element);
5982 if (structure->get(kSetterIndex)->IsJSFunction()) {
5983 JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex));
5984 return SetPropertyWithDefinedSetter(setter, value);
5985 } else {
5986 Handle<Object> self(this);
5987 Handle<Object> key(Factory::NewNumberFromUint(index));
5988 Handle<Object> args[2] = { key, self };
5989 return Top::Throw(*Factory::NewTypeError("no_setter_in_callback",
5990 HandleVector(args, 2)));
5991 }
5992 } else { 6183 } else {
5993 dictionary->UpdateMaxNumberKey(index); 6184 dictionary->UpdateMaxNumberKey(index);
5994 dictionary->ValueAtPut(entry, value); 6185 dictionary->ValueAtPut(entry, value);
5995 } 6186 }
5996 } else { 6187 } else {
5997 // Index not already used. Look for an accessor in the prototype chain. 6188 // Index not already used. Look for an accessor in the prototype chain.
5998 if (!IsJSArray()) { 6189 if (!IsJSArray()) {
5999 Object* setter = LookupCallbackSetterInPrototypes(index); 6190 if (SetElementWithCallbackSetterInPrototypes(index, value)) {
6000 if (setter->IsJSFunction()) { 6191 return value;
6001 return SetPropertyWithDefinedSetter(JSFunction::cast(setter),
6002 value);
6003 } 6192 }
6004 } 6193 }
6005 Object* result = dictionary->AtNumberPut(index, value); 6194 Object* result = dictionary->AtNumberPut(index, value);
6006 if (result->IsFailure()) return result; 6195 if (result->IsFailure()) return result;
6007 if (elms != FixedArray::cast(result)) { 6196 if (elms != FixedArray::cast(result)) {
6008 set_elements(FixedArray::cast(result)); 6197 set_elements(FixedArray::cast(result));
6009 } 6198 }
6010 } 6199 }
6011 6200
6012 // Update the array length if this JSObject is an array. 6201 // Update the array length if this JSObject is an array.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
6095 UNIMPLEMENTED(); 6284 UNIMPLEMENTED();
6096 break; 6285 break;
6097 } 6286 }
6098 case DICTIONARY_ELEMENTS: { 6287 case DICTIONARY_ELEMENTS: {
6099 NumberDictionary* dictionary = element_dictionary(); 6288 NumberDictionary* dictionary = element_dictionary();
6100 int entry = dictionary->FindEntry(index); 6289 int entry = dictionary->FindEntry(index);
6101 if (entry != NumberDictionary::kNotFound) { 6290 if (entry != NumberDictionary::kNotFound) {
6102 Object* element = dictionary->ValueAt(entry); 6291 Object* element = dictionary->ValueAt(entry);
6103 PropertyDetails details = dictionary->DetailsAt(entry); 6292 PropertyDetails details = dictionary->DetailsAt(entry);
6104 if (details.type() == CALLBACKS) { 6293 if (details.type() == CALLBACKS) {
6105 // Only accessors allowed as elements. 6294 return GetElementWithCallback(receiver,
6106 FixedArray* structure = FixedArray::cast(element); 6295 element,
6107 Object* getter = structure->get(kGetterIndex); 6296 index,
6108 if (getter->IsJSFunction()) { 6297 this);
6109 return GetPropertyWithDefinedGetter(receiver,
6110 JSFunction::cast(getter));
6111 } else {
6112 // Getter is not a function.
6113 return Heap::undefined_value();
6114 }
6115 } 6298 }
6116 return element; 6299 return element;
6117 } 6300 }
6118 break; 6301 break;
6119 } 6302 }
6120 default: 6303 default:
6121 UNREACHABLE(); 6304 UNREACHABLE();
6122 break; 6305 break;
6123 } 6306 }
6124 6307
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
6252 } 6435 }
6253 break; 6436 break;
6254 } 6437 }
6255 case DICTIONARY_ELEMENTS: { 6438 case DICTIONARY_ELEMENTS: {
6256 NumberDictionary* dictionary = element_dictionary(); 6439 NumberDictionary* dictionary = element_dictionary();
6257 int entry = dictionary->FindEntry(index); 6440 int entry = dictionary->FindEntry(index);
6258 if (entry != NumberDictionary::kNotFound) { 6441 if (entry != NumberDictionary::kNotFound) {
6259 Object* element = dictionary->ValueAt(entry); 6442 Object* element = dictionary->ValueAt(entry);
6260 PropertyDetails details = dictionary->DetailsAt(entry); 6443 PropertyDetails details = dictionary->DetailsAt(entry);
6261 if (details.type() == CALLBACKS) { 6444 if (details.type() == CALLBACKS) {
6262 // Only accessors allowed as elements. 6445 return GetElementWithCallback(receiver,
6263 FixedArray* structure = FixedArray::cast(element); 6446 element,
6264 Object* getter = structure->get(kGetterIndex); 6447 index,
6265 if (getter->IsJSFunction()) { 6448 this);
6266 return GetPropertyWithDefinedGetter(receiver,
6267 JSFunction::cast(getter));
6268 } else {
6269 // Getter is not a function.
6270 return Heap::undefined_value();
6271 }
6272 } 6449 }
6273 return element; 6450 return element;
6274 } 6451 }
6275 break; 6452 break;
6276 } 6453 }
6277 } 6454 }
6278 6455
6279 Object* pt = GetPrototype(); 6456 Object* pt = GetPrototype();
6280 if (pt == Heap::null_value()) return Heap::undefined_value(); 6457 if (pt == Heap::null_value()) return Heap::undefined_value();
6281 return pt->GetElementWithReceiver(receiver, index); 6458 return pt->GetElementWithReceiver(receiver, index);
(...skipping 2266 matching lines...) Expand 10 before | Expand all | Expand 10 after
8548 if (break_point_objects()->IsUndefined()) return 0; 8725 if (break_point_objects()->IsUndefined()) return 0;
8549 // Single beak point. 8726 // Single beak point.
8550 if (!break_point_objects()->IsFixedArray()) return 1; 8727 if (!break_point_objects()->IsFixedArray()) return 1;
8551 // Multiple break points. 8728 // Multiple break points.
8552 return FixedArray::cast(break_point_objects())->length(); 8729 return FixedArray::cast(break_point_objects())->length();
8553 } 8730 }
8554 #endif 8731 #endif
8555 8732
8556 8733
8557 } } // namespace v8::internal 8734 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | test/cctest/test-api.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698