OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |