| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 1879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1890 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( | 1890 MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes( |
| 1891 uint32_t index, | 1891 uint32_t index, |
| 1892 Object* value, | 1892 Object* value, |
| 1893 bool* found, | 1893 bool* found, |
| 1894 StrictModeFlag strict_mode) { | 1894 StrictModeFlag strict_mode) { |
| 1895 Heap* heap = GetHeap(); | 1895 Heap* heap = GetHeap(); |
| 1896 for (Object* pt = GetPrototype(); | 1896 for (Object* pt = GetPrototype(); |
| 1897 pt != heap->null_value(); | 1897 pt != heap->null_value(); |
| 1898 pt = pt->GetPrototype()) { | 1898 pt = pt->GetPrototype()) { |
| 1899 if (!JSObject::cast(pt)->HasDictionaryElements()) { | 1899 if (!JSObject::cast(pt)->HasDictionaryElements()) { |
| 1900 continue; | 1900 continue; |
| 1901 } | 1901 } |
| 1902 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); | 1902 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); |
| 1903 int entry = dictionary->FindEntry(index); | 1903 int entry = dictionary->FindEntry(index); |
| 1904 if (entry != NumberDictionary::kNotFound) { | 1904 if (entry != NumberDictionary::kNotFound) { |
| 1905 PropertyDetails details = dictionary->DetailsAt(entry); | 1905 PropertyDetails details = dictionary->DetailsAt(entry); |
| 1906 if (details.type() == CALLBACKS) { | 1906 if (details.type() == CALLBACKS) { |
| 1907 *found = true; | 1907 *found = true; |
| 1908 return SetElementWithCallback(dictionary->ValueAt(entry), | 1908 return SetElementWithCallback(dictionary->ValueAt(entry), |
| 1909 index, | 1909 index, |
| 1910 value, | 1910 value, |
| (...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2797 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { | 2797 MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) { |
| 2798 if (HasFastProperties()) return this; | 2798 if (HasFastProperties()) return this; |
| 2799 ASSERT(!IsGlobalObject()); | 2799 ASSERT(!IsGlobalObject()); |
| 2800 return property_dictionary()-> | 2800 return property_dictionary()-> |
| 2801 TransformPropertiesToFastFor(this, unused_property_fields); | 2801 TransformPropertiesToFastFor(this, unused_property_fields); |
| 2802 } | 2802 } |
| 2803 | 2803 |
| 2804 | 2804 |
| 2805 MaybeObject* JSObject::NormalizeElements() { | 2805 MaybeObject* JSObject::NormalizeElements() { |
| 2806 ASSERT(!HasExternalArrayElements()); | 2806 ASSERT(!HasExternalArrayElements()); |
| 2807 if (HasDictionaryElements()) return this; |
| 2808 Map* old_map = map(); |
| 2809 ASSERT(old_map->has_fast_elements() || old_map->has_fast_double_elements()); |
| 2807 | 2810 |
| 2808 // Find the backing store. | 2811 Object* obj; |
| 2809 FixedArray* array = FixedArray::cast(elements()); | 2812 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); |
| 2810 Map* old_map = array->map(); | 2813 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2811 bool is_arguments = | |
| 2812 (old_map == old_map->heap()->non_strict_arguments_elements_map()); | |
| 2813 if (is_arguments) { | |
| 2814 array = FixedArray::cast(array->get(1)); | |
| 2815 } | 2814 } |
| 2816 if (array->IsDictionary()) return array; | 2815 Map* new_map = Map::cast(obj); |
| 2817 | 2816 |
| 2818 ASSERT(HasFastElements() || HasFastArgumentsElements()); | 2817 // Get number of entries. |
| 2819 // Compute the effective length and allocate a new backing store. | 2818 FixedArrayBase* array = FixedArrayBase::cast(elements()); |
| 2820 int length = IsJSArray() | 2819 |
| 2821 ? Smi::cast(JSArray::cast(this)->length())->value() | 2820 // Compute the effective length. |
| 2822 : array->length(); | 2821 int length = IsJSArray() ? |
| 2823 NumberDictionary* dictionary = NULL; | 2822 Smi::cast(JSArray::cast(this)->length())->value() : |
| 2824 { Object* object; | 2823 array->length(); |
| 2825 MaybeObject* maybe = NumberDictionary::Allocate(length); | 2824 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length); |
| 2826 if (!maybe->ToObject(&object)) return maybe; | 2825 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2827 dictionary = NumberDictionary::cast(object); | |
| 2828 } | 2826 } |
| 2829 | |
| 2830 // Copy the elements to the new backing store. | |
| 2831 bool has_double_elements = old_map->has_fast_double_elements(); | 2827 bool has_double_elements = old_map->has_fast_double_elements(); |
| 2828 NumberDictionary* dictionary = NumberDictionary::cast(obj); |
| 2829 // Copy entries. |
| 2832 for (int i = 0; i < length; i++) { | 2830 for (int i = 0; i < length; i++) { |
| 2833 Object* value = NULL; | 2831 Object* value = NULL; |
| 2834 if (has_double_elements) { | 2832 if (has_double_elements) { |
| 2835 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); | 2833 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); |
| 2836 if (double_array->is_the_hole(i)) { | 2834 if (double_array->is_the_hole(i)) { |
| 2837 value = GetIsolate()->heap()->the_hole_value(); | 2835 value = GetIsolate()->heap()->the_hole_value(); |
| 2838 } else { | 2836 } else { |
| 2839 // Objects must be allocated in the old object space, since the | 2837 // Objects must be allocated in the old object space, since the |
| 2840 // overall number of HeapNumbers needed for the conversion might | 2838 // overall number of HeapNumbers needed for the conversion might |
| 2841 // exceed the capacity of new space, and we would fail repeatedly | 2839 // exceed the capacity of new space, and we would fail repeatedly |
| 2842 // trying to convert the FixedDoubleArray. | 2840 // trying to convert the FixedDoubleArray. |
| 2843 MaybeObject* maybe_value_object = | 2841 MaybeObject* maybe_value_object = |
| 2844 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED); | 2842 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED); |
| 2845 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; | 2843 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; |
| 2846 } | 2844 } |
| 2847 } else { | 2845 } else { |
| 2848 ASSERT(old_map->has_fast_elements()); | 2846 ASSERT(old_map->has_fast_elements()); |
| 2849 value = array->get(i); | 2847 FixedArray* fixed_array = FixedArray::cast(array); |
| 2848 value = fixed_array->get(i); |
| 2850 } | 2849 } |
| 2851 PropertyDetails details = PropertyDetails(NONE, NORMAL); | 2850 PropertyDetails details = PropertyDetails(NONE, NORMAL); |
| 2852 if (!value->IsTheHole()) { | 2851 if (!value->IsTheHole()) { |
| 2853 Object* result; | 2852 Object* result; |
| 2854 MaybeObject* maybe_result = | 2853 MaybeObject* maybe_result = |
| 2855 dictionary->AddNumberEntry(i, value, details); | 2854 dictionary->AddNumberEntry(i, value, details); |
| 2856 if (!maybe_result->ToObject(&result)) return maybe_result; | 2855 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 2857 dictionary = NumberDictionary::cast(result); | 2856 dictionary = NumberDictionary::cast(result); |
| 2858 } | 2857 } |
| 2859 } | 2858 } |
| 2859 // Switch to using the dictionary as the backing storage for |
| 2860 // elements. Set the new map first to satify the elements type |
| 2861 // assert in set_elements(). |
| 2862 set_map(new_map); |
| 2863 set_elements(dictionary); |
| 2860 | 2864 |
| 2861 // Switch to using the dictionary as the backing storage for elements. | 2865 new_map->heap()->isolate()->counters()->elements_to_dictionary()-> |
| 2862 if (is_arguments) { | 2866 Increment(); |
| 2863 FixedArray::cast(elements())->set(1, dictionary); | |
| 2864 } else { | |
| 2865 // Set the new map first to satify the elements type assert in | |
| 2866 // set_elements(). | |
| 2867 Object* new_map; | |
| 2868 MaybeObject* maybe = map()->GetSlowElementsMap(); | |
| 2869 if (!maybe->ToObject(&new_map)) return maybe; | |
| 2870 set_map(Map::cast(new_map)); | |
| 2871 set_elements(dictionary); | |
| 2872 } | |
| 2873 | |
| 2874 old_map->isolate()->counters()->elements_to_dictionary()->Increment(); | |
| 2875 | 2867 |
| 2876 #ifdef DEBUG | 2868 #ifdef DEBUG |
| 2877 if (FLAG_trace_normalization) { | 2869 if (FLAG_trace_normalization) { |
| 2878 PrintF("Object elements have been normalized:\n"); | 2870 PrintF("Object elements have been normalized:\n"); |
| 2879 Print(); | 2871 Print(); |
| 2880 } | 2872 } |
| 2881 #endif | 2873 #endif |
| 2882 | 2874 |
| 2883 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 2875 return this; |
| 2884 return dictionary; | |
| 2885 } | 2876 } |
| 2886 | 2877 |
| 2887 | 2878 |
| 2888 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, | 2879 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, |
| 2889 DeleteMode mode) { | 2880 DeleteMode mode) { |
| 2890 // Check local property, ignore interceptor. | 2881 // Check local property, ignore interceptor. |
| 2891 LookupResult result; | 2882 LookupResult result; |
| 2892 LocalLookupRealNamedProperty(name, &result); | 2883 LocalLookupRealNamedProperty(name, &result); |
| 2893 if (!result.IsProperty()) return GetHeap()->true_value(); | 2884 if (!result.IsProperty()) return GetHeap()->true_value(); |
| 2894 | 2885 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2994 ASSERT(result->IsBoolean()); | 2985 ASSERT(result->IsBoolean()); |
| 2995 return *v8::Utils::OpenHandle(*result); | 2986 return *v8::Utils::OpenHandle(*result); |
| 2996 } | 2987 } |
| 2997 MaybeObject* raw_result = | 2988 MaybeObject* raw_result = |
| 2998 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); | 2989 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION); |
| 2999 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 2990 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| 3000 return raw_result; | 2991 return raw_result; |
| 3001 } | 2992 } |
| 3002 | 2993 |
| 3003 | 2994 |
| 3004 MaybeObject* JSObject::DeleteFastElement(uint32_t index) { | |
| 3005 ASSERT(HasFastElements() || HasFastArgumentsElements()); | |
| 3006 Heap* heap = GetHeap(); | |
| 3007 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 3008 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | |
| 3009 backing_store = FixedArray::cast(backing_store->get(1)); | |
| 3010 } else { | |
| 3011 Object* writable; | |
| 3012 MaybeObject* maybe = EnsureWritableFastElements(); | |
| 3013 if (!maybe->ToObject(&writable)) return maybe; | |
| 3014 backing_store = FixedArray::cast(writable); | |
| 3015 } | |
| 3016 int length = IsJSArray() | |
| 3017 ? Smi::cast(JSArray::cast(this)->length())->value() | |
| 3018 : backing_store->length(); | |
| 3019 if (index < static_cast<uint32_t>(length)) { | |
| 3020 backing_store->set_the_hole(index); | |
| 3021 } | |
| 3022 return heap->true_value(); | |
| 3023 } | |
| 3024 | |
| 3025 | |
| 3026 MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index, | |
| 3027 DeleteMode mode) { | |
| 3028 Isolate* isolate = GetIsolate(); | |
| 3029 Heap* heap = isolate->heap(); | |
| 3030 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 3031 if (backing_store->map() == heap->non_strict_arguments_elements_map()) { | |
| 3032 backing_store = FixedArray::cast(backing_store->get(1)); | |
| 3033 } | |
| 3034 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | |
| 3035 int entry = dictionary->FindEntry(index); | |
| 3036 if (entry != NumberDictionary::kNotFound) { | |
| 3037 Object* result = dictionary->DeleteProperty(entry, mode); | |
| 3038 if (mode == STRICT_DELETION && result == heap->false_value()) { | |
| 3039 // In strict mode, attempting to delete a non-configurable property | |
| 3040 // throws an exception. | |
| 3041 HandleScope scope(isolate); | |
| 3042 Handle<Object> name = isolate->factory()->NewNumberFromUint(index); | |
| 3043 Handle<Object> args[2] = { name, Handle<Object>(this) }; | |
| 3044 Handle<Object> error = | |
| 3045 isolate->factory()->NewTypeError("strict_delete_property", | |
| 3046 HandleVector(args, 2)); | |
| 3047 return isolate->Throw(*error); | |
| 3048 } | |
| 3049 } | |
| 3050 return heap->true_value(); | |
| 3051 } | |
| 3052 | |
| 3053 | |
| 3054 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { | 2995 MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { |
| 3055 Isolate* isolate = GetIsolate(); | 2996 Isolate* isolate = GetIsolate(); |
| 3056 // Check access rights if needed. | 2997 // Check access rights if needed. |
| 3057 if (IsAccessCheckNeeded() && | 2998 if (IsAccessCheckNeeded() && |
| 3058 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { | 2999 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) { |
| 3059 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); | 3000 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE); |
| 3060 return isolate->heap()->false_value(); | 3001 return isolate->heap()->false_value(); |
| 3061 } | 3002 } |
| 3062 | 3003 |
| 3063 if (IsJSGlobalProxy()) { | 3004 if (IsJSGlobalProxy()) { |
| 3064 Object* proto = GetPrototype(); | 3005 Object* proto = GetPrototype(); |
| 3065 if (proto->IsNull()) return isolate->heap()->false_value(); | 3006 if (proto->IsNull()) return isolate->heap()->false_value(); |
| 3066 ASSERT(proto->IsJSGlobalObject()); | 3007 ASSERT(proto->IsJSGlobalObject()); |
| 3067 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); | 3008 return JSGlobalObject::cast(proto)->DeleteElement(index, mode); |
| 3068 } | 3009 } |
| 3069 | 3010 |
| 3070 if (HasIndexedInterceptor()) { | 3011 if (HasIndexedInterceptor()) { |
| 3071 // Skip interceptor if forcing deletion. | 3012 // Skip interceptor if forcing deletion. |
| 3072 return (mode == FORCE_DELETION) | 3013 if (mode == FORCE_DELETION) { |
| 3073 ? DeleteElementPostInterceptor(index, FORCE_DELETION) | 3014 return DeleteElementPostInterceptor(index, mode); |
| 3074 : DeleteElementWithInterceptor(index); | 3015 } |
| 3016 return DeleteElementWithInterceptor(index); |
| 3075 } | 3017 } |
| 3076 | 3018 |
| 3077 switch (GetElementsKind()) { | 3019 switch (GetElementsKind()) { |
| 3078 case FAST_ELEMENTS: | 3020 case FAST_ELEMENTS: { |
| 3079 return DeleteFastElement(index); | 3021 Object* obj; |
| 3080 | 3022 { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
| 3081 case DICTIONARY_ELEMENTS: | 3023 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3082 return DeleteDictionaryElement(index, mode); | 3024 } |
| 3083 | 3025 int length = IsJSArray() |
| 3026 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 3027 : FixedArray::cast(elements())->length(); |
| 3028 if (index < static_cast<uint32_t>(length)) { |
| 3029 FixedArray::cast(elements())->set_the_hole(index); |
| 3030 } |
| 3031 break; |
| 3032 } |
| 3084 case FAST_DOUBLE_ELEMENTS: { | 3033 case FAST_DOUBLE_ELEMENTS: { |
| 3085 int length = IsJSArray() | 3034 int length = IsJSArray() |
| 3086 ? Smi::cast(JSArray::cast(this)->length())->value() | 3035 ? Smi::cast(JSArray::cast(this)->length())->value() |
| 3087 : FixedArray::cast(elements())->length(); | 3036 : FixedArray::cast(elements())->length(); |
| 3088 if (index < static_cast<uint32_t>(length)) { | 3037 if (index < static_cast<uint32_t>(length)) { |
| 3089 FixedDoubleArray::cast(elements())->set_the_hole(index); | 3038 FixedDoubleArray::cast(elements())->set_the_hole(index); |
| 3090 } | 3039 } |
| 3091 break; | 3040 break; |
| 3092 } | 3041 } |
| 3093 case EXTERNAL_PIXEL_ELEMENTS: | 3042 case EXTERNAL_PIXEL_ELEMENTS: |
| 3094 case EXTERNAL_BYTE_ELEMENTS: | 3043 case EXTERNAL_BYTE_ELEMENTS: |
| 3095 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3044 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3096 case EXTERNAL_SHORT_ELEMENTS: | 3045 case EXTERNAL_SHORT_ELEMENTS: |
| 3097 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3046 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3098 case EXTERNAL_INT_ELEMENTS: | 3047 case EXTERNAL_INT_ELEMENTS: |
| 3099 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3048 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3100 case EXTERNAL_FLOAT_ELEMENTS: | 3049 case EXTERNAL_FLOAT_ELEMENTS: |
| 3101 case EXTERNAL_DOUBLE_ELEMENTS: | 3050 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3102 // Pixel and external array elements cannot be deleted. Just | 3051 // Pixel and external array elements cannot be deleted. Just |
| 3103 // silently ignore here. | 3052 // silently ignore here. |
| 3104 break; | 3053 break; |
| 3105 | 3054 case DICTIONARY_ELEMENTS: { |
| 3106 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 3055 NumberDictionary* dictionary = element_dictionary(); |
| 3107 FixedArray* parameter_map = FixedArray::cast(elements()); | 3056 int entry = dictionary->FindEntry(index); |
| 3108 uint32_t length = parameter_map->length(); | 3057 if (entry != NumberDictionary::kNotFound) { |
| 3109 Object* probe = | 3058 Object* result = dictionary->DeleteProperty(entry, mode); |
| 3110 (index + 2) < length ? parameter_map->get(index + 2) : NULL; | 3059 if (mode == STRICT_DELETION && result == |
| 3111 if (probe != NULL && !probe->IsTheHole()) { | 3060 isolate->heap()->false_value()) { |
| 3112 // TODO(kmillikin): We could check if this was the last aliased | 3061 // In strict mode, deleting a non-configurable property throws |
| 3113 // parameter, and revert to normal elements in that case. That | 3062 // exception. dictionary->DeleteProperty will return false_value() |
| 3114 // would enable GC of the context. | 3063 // if a non-configurable property is being deleted. |
| 3115 parameter_map->set_the_hole(index + 2); | 3064 HandleScope scope; |
| 3116 } else { | 3065 Handle<Object> self(this); |
| 3117 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 3066 Handle<Object> i = isolate->factory()->NewNumberFromUint(index); |
| 3118 if (arguments->IsDictionary()) { | 3067 Handle<Object> args[2] = { i, self }; |
| 3119 return DeleteDictionaryElement(index, mode); | 3068 return isolate->Throw(*isolate->factory()->NewTypeError( |
| 3120 } else { | 3069 "strict_delete_property", HandleVector(args, 2))); |
| 3121 return DeleteFastElement(index); | |
| 3122 } | 3070 } |
| 3123 } | 3071 } |
| 3124 break; | 3072 break; |
| 3125 } | 3073 } |
| 3074 default: |
| 3075 UNREACHABLE(); |
| 3076 break; |
| 3126 } | 3077 } |
| 3127 return isolate->heap()->true_value(); | 3078 return isolate->heap()->true_value(); |
| 3128 } | 3079 } |
| 3129 | 3080 |
| 3130 | 3081 |
| 3131 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { | 3082 MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) { |
| 3132 Isolate* isolate = GetIsolate(); | 3083 Isolate* isolate = GetIsolate(); |
| 3133 // ECMA-262, 3rd, 8.6.2.5 | 3084 // ECMA-262, 3rd, 8.6.2.5 |
| 3134 ASSERT(name->IsString()); | 3085 ASSERT(name->IsString()); |
| 3135 | 3086 |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3178 { MaybeObject* maybe_obj = | 3129 { MaybeObject* maybe_obj = |
| 3179 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 3130 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 3180 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3131 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 3181 } | 3132 } |
| 3182 // Make sure the properties are normalized before removing the entry. | 3133 // Make sure the properties are normalized before removing the entry. |
| 3183 return DeleteNormalizedProperty(name, mode); | 3134 return DeleteNormalizedProperty(name, mode); |
| 3184 } | 3135 } |
| 3185 } | 3136 } |
| 3186 | 3137 |
| 3187 | 3138 |
| 3188 bool JSObject::ReferencesObjectFromElements(FixedArray* elements, | |
| 3189 ElementsKind kind, | |
| 3190 Object* object) { | |
| 3191 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); | |
| 3192 if (kind == FAST_ELEMENTS) { | |
| 3193 int length = IsJSArray() | |
| 3194 ? Smi::cast(JSArray::cast(this)->length())->value() | |
| 3195 : elements->length(); | |
| 3196 for (int i = 0; i < length; ++i) { | |
| 3197 Object* element = elements->get(i); | |
| 3198 if (!element->IsTheHole() && element == object) return true; | |
| 3199 } | |
| 3200 } else { | |
| 3201 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object); | |
| 3202 if (!key->IsUndefined()) return true; | |
| 3203 } | |
| 3204 return false; | |
| 3205 } | |
| 3206 | |
| 3207 | |
| 3208 // Check whether this object references another object. | 3139 // Check whether this object references another object. |
| 3209 bool JSObject::ReferencesObject(Object* obj) { | 3140 bool JSObject::ReferencesObject(Object* obj) { |
| 3210 Map* map_of_this = map(); | 3141 Map* map_of_this = map(); |
| 3211 Heap* heap = map_of_this->heap(); | 3142 Heap* heap = map_of_this->heap(); |
| 3212 AssertNoAllocation no_alloc; | 3143 AssertNoAllocation no_alloc; |
| 3213 | 3144 |
| 3214 // Is the object the constructor for this object? | 3145 // Is the object the constructor for this object? |
| 3215 if (map_of_this->constructor() == obj) { | 3146 if (map_of_this->constructor() == obj) { |
| 3216 return true; | 3147 return true; |
| 3217 } | 3148 } |
| 3218 | 3149 |
| 3219 // Is the object the prototype for this object? | 3150 // Is the object the prototype for this object? |
| 3220 if (map_of_this->prototype() == obj) { | 3151 if (map_of_this->prototype() == obj) { |
| 3221 return true; | 3152 return true; |
| 3222 } | 3153 } |
| 3223 | 3154 |
| 3224 // Check if the object is among the named properties. | 3155 // Check if the object is among the named properties. |
| 3225 Object* key = SlowReverseLookup(obj); | 3156 Object* key = SlowReverseLookup(obj); |
| 3226 if (!key->IsUndefined()) { | 3157 if (!key->IsUndefined()) { |
| 3227 return true; | 3158 return true; |
| 3228 } | 3159 } |
| 3229 | 3160 |
| 3230 // Check if the object is among the indexed properties. | 3161 // Check if the object is among the indexed properties. |
| 3231 ElementsKind kind = GetElementsKind(); | 3162 switch (GetElementsKind()) { |
| 3232 switch (kind) { | |
| 3233 case EXTERNAL_PIXEL_ELEMENTS: | 3163 case EXTERNAL_PIXEL_ELEMENTS: |
| 3234 case EXTERNAL_BYTE_ELEMENTS: | 3164 case EXTERNAL_BYTE_ELEMENTS: |
| 3235 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3165 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3236 case EXTERNAL_SHORT_ELEMENTS: | 3166 case EXTERNAL_SHORT_ELEMENTS: |
| 3237 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3167 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3238 case EXTERNAL_INT_ELEMENTS: | 3168 case EXTERNAL_INT_ELEMENTS: |
| 3239 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3169 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3240 case EXTERNAL_FLOAT_ELEMENTS: | 3170 case EXTERNAL_FLOAT_ELEMENTS: |
| 3241 case EXTERNAL_DOUBLE_ELEMENTS: | 3171 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3242 case FAST_DOUBLE_ELEMENTS: | |
| 3243 // Raw pixels and external arrays do not reference other | 3172 // Raw pixels and external arrays do not reference other |
| 3244 // objects. | 3173 // objects. |
| 3245 break; | 3174 break; |
| 3246 case FAST_ELEMENTS: | 3175 case FAST_ELEMENTS: { |
| 3247 case DICTIONARY_ELEMENTS: { | 3176 int length = IsJSArray() ? |
| 3248 FixedArray* elements = FixedArray::cast(this->elements()); | 3177 Smi::cast(JSArray::cast(this)->length())->value() : |
| 3249 if (ReferencesObjectFromElements(elements, kind, obj)) return true; | 3178 FixedArray::cast(elements())->length(); |
| 3179 for (int i = 0; i < length; i++) { |
| 3180 Object* element = FixedArray::cast(elements())->get(i); |
| 3181 if (!element->IsTheHole() && element == obj) { |
| 3182 return true; |
| 3183 } |
| 3184 } |
| 3250 break; | 3185 break; |
| 3251 } | 3186 } |
| 3252 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 3187 case DICTIONARY_ELEMENTS: { |
| 3253 FixedArray* parameter_map = FixedArray::cast(elements()); | 3188 key = element_dictionary()->SlowReverseLookup(obj); |
| 3254 // Check the mapped parameters. | 3189 if (!key->IsUndefined()) { |
| 3255 int length = parameter_map->length(); | 3190 return true; |
| 3256 for (int i = 2; i < length; ++i) { | |
| 3257 Object* value = parameter_map->get(i); | |
| 3258 if (!value->IsTheHole() && value == obj) return true; | |
| 3259 } | 3191 } |
| 3260 // Check the arguments. | |
| 3261 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 3262 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS; | |
| 3263 if (ReferencesObjectFromElements(arguments, kind, obj)) return true; | |
| 3264 break; | 3192 break; |
| 3265 } | 3193 } |
| 3194 default: |
| 3195 UNREACHABLE(); |
| 3196 break; |
| 3266 } | 3197 } |
| 3267 | 3198 |
| 3268 // For functions check the context. | 3199 // For functions check the context. |
| 3269 if (IsJSFunction()) { | 3200 if (IsJSFunction()) { |
| 3270 // Get the constructor function for arguments array. | 3201 // Get the constructor function for arguments array. |
| 3271 JSObject* arguments_boilerplate = | 3202 JSObject* arguments_boilerplate = |
| 3272 heap->isolate()->context()->global_context()-> | 3203 heap->isolate()->context()->global_context()-> |
| 3273 arguments_boilerplate(); | 3204 arguments_boilerplate(); |
| 3274 JSFunction* arguments_function = | 3205 JSFunction* arguments_function = |
| 3275 JSFunction::cast(arguments_boilerplate->map()->constructor()); | 3206 JSFunction::cast(arguments_boilerplate->map()->constructor()); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3290 if (ctxobj->map()->constructor() == arguments_function) { | 3221 if (ctxobj->map()->constructor() == arguments_function) { |
| 3291 if (ctxobj->ReferencesObject(obj)) { | 3222 if (ctxobj->ReferencesObject(obj)) { |
| 3292 return true; | 3223 return true; |
| 3293 } | 3224 } |
| 3294 } else if (ctxobj == obj) { | 3225 } else if (ctxobj == obj) { |
| 3295 return true; | 3226 return true; |
| 3296 } | 3227 } |
| 3297 } | 3228 } |
| 3298 } | 3229 } |
| 3299 | 3230 |
| 3300 // Check the context extension if any. | 3231 // Check the context extension (if any) if it can have references. |
| 3301 if (context->has_extension()) { | 3232 if (context->has_extension() && !context->IsCatchContext()) { |
| 3302 return context->extension()->ReferencesObject(obj); | 3233 return JSObject::cast(context->extension())->ReferencesObject(obj); |
| 3303 } | 3234 } |
| 3304 } | 3235 } |
| 3305 | 3236 |
| 3306 // No references to object. | 3237 // No references to object. |
| 3307 return false; | 3238 return false; |
| 3308 } | 3239 } |
| 3309 | 3240 |
| 3310 | 3241 |
| 3311 MaybeObject* JSObject::PreventExtensions() { | 3242 MaybeObject* JSObject::PreventExtensions() { |
| 3312 Isolate* isolate = GetIsolate(); | 3243 Isolate* isolate = GetIsolate(); |
| 3313 if (IsAccessCheckNeeded() && | 3244 if (IsAccessCheckNeeded() && |
| 3314 !isolate->MayNamedAccess(this, | 3245 !isolate->MayNamedAccess(this, |
| 3315 isolate->heap()->undefined_value(), | 3246 isolate->heap()->undefined_value(), |
| 3316 v8::ACCESS_KEYS)) { | 3247 v8::ACCESS_KEYS)) { |
| 3317 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); | 3248 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS); |
| 3318 return isolate->heap()->false_value(); | 3249 return isolate->heap()->false_value(); |
| 3319 } | 3250 } |
| 3320 | 3251 |
| 3321 if (IsJSGlobalProxy()) { | 3252 if (IsJSGlobalProxy()) { |
| 3322 Object* proto = GetPrototype(); | 3253 Object* proto = GetPrototype(); |
| 3323 if (proto->IsNull()) return this; | 3254 if (proto->IsNull()) return this; |
| 3324 ASSERT(proto->IsJSGlobalObject()); | 3255 ASSERT(proto->IsJSGlobalObject()); |
| 3325 return JSObject::cast(proto)->PreventExtensions(); | 3256 return JSObject::cast(proto)->PreventExtensions(); |
| 3326 } | 3257 } |
| 3327 | 3258 |
| 3328 // If there are fast elements we normalize. | 3259 // If there are fast elements we normalize. |
| 3329 if (HasFastElements()) { | 3260 if (HasFastElements()) { |
| 3330 MaybeObject* result = NormalizeElements(); | 3261 Object* ok; |
| 3331 if (result->IsFailure()) return result; | 3262 { MaybeObject* maybe_ok = NormalizeElements(); |
| 3263 if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| 3264 } |
| 3332 } | 3265 } |
| 3333 // TODO(kmillikin): Handle arguments object with dictionary elements. | |
| 3334 ASSERT(HasDictionaryElements()); | |
| 3335 // Make sure that we never go back to fast case. | 3266 // Make sure that we never go back to fast case. |
| 3336 element_dictionary()->set_requires_slow_elements(); | 3267 element_dictionary()->set_requires_slow_elements(); |
| 3337 | 3268 |
| 3338 // Do a map transition, other objects with this map may still | 3269 // Do a map transition, other objects with this map may still |
| 3339 // be extensible. | 3270 // be extensible. |
| 3340 Object* new_map; | 3271 Object* new_map; |
| 3341 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); | 3272 { MaybeObject* maybe_new_map = map()->CopyDropTransitions(); |
| 3342 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; | 3273 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
| 3343 } | 3274 } |
| 3344 Map::cast(new_map)->set_is_extensible(false); | 3275 Map::cast(new_map)->set_is_extensible(false); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3481 for (Object* current = this; | 3412 for (Object* current = this; |
| 3482 current != heap->null_value(); | 3413 current != heap->null_value(); |
| 3483 current = JSObject::cast(current)->GetPrototype()) { | 3414 current = JSObject::cast(current)->GetPrototype()) { |
| 3484 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); | 3415 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); |
| 3485 if (result->IsProperty() && result->type() == CALLBACKS) return; | 3416 if (result->IsProperty() && result->type() == CALLBACKS) return; |
| 3486 } | 3417 } |
| 3487 result->NotFound(); | 3418 result->NotFound(); |
| 3488 } | 3419 } |
| 3489 | 3420 |
| 3490 | 3421 |
| 3491 // Search for a getter or setter in an elements dictionary. Returns either | |
| 3492 // undefined if the element is read-only, or the getter/setter pair (fixed | |
| 3493 // array) if there is an existing one, or the hole value if the element does | |
| 3494 // not exist or is a normal non-getter/setter data element. | |
| 3495 static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary, | |
| 3496 uint32_t index, | |
| 3497 Heap* heap) { | |
| 3498 int entry = dictionary->FindEntry(index); | |
| 3499 if (entry != NumberDictionary::kNotFound) { | |
| 3500 Object* result = dictionary->ValueAt(entry); | |
| 3501 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 3502 if (details.IsReadOnly()) return heap->undefined_value(); | |
| 3503 if (details.type() == CALLBACKS && result->IsFixedArray()) return result; | |
| 3504 } | |
| 3505 return heap->the_hole_value(); | |
| 3506 } | |
| 3507 | |
| 3508 | |
| 3509 MaybeObject* JSObject::DefineGetterSetter(String* name, | 3422 MaybeObject* JSObject::DefineGetterSetter(String* name, |
| 3510 PropertyAttributes attributes) { | 3423 PropertyAttributes attributes) { |
| 3511 Heap* heap = GetHeap(); | 3424 Heap* heap = GetHeap(); |
| 3512 // Make sure that the top context does not change when doing callbacks or | 3425 // Make sure that the top context does not change when doing callbacks or |
| 3513 // interceptor calls. | 3426 // interceptor calls. |
| 3514 AssertNoContextChange ncc; | 3427 AssertNoContextChange ncc; |
| 3515 | 3428 |
| 3516 // Try to flatten before operating on the string. | 3429 // Try to flatten before operating on the string. |
| 3517 name->TryFlatten(); | 3430 name->TryFlatten(); |
| 3518 | 3431 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3529 break; | 3442 break; |
| 3530 case EXTERNAL_PIXEL_ELEMENTS: | 3443 case EXTERNAL_PIXEL_ELEMENTS: |
| 3531 case EXTERNAL_BYTE_ELEMENTS: | 3444 case EXTERNAL_BYTE_ELEMENTS: |
| 3532 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3445 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3533 case EXTERNAL_SHORT_ELEMENTS: | 3446 case EXTERNAL_SHORT_ELEMENTS: |
| 3534 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3447 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3535 case EXTERNAL_INT_ELEMENTS: | 3448 case EXTERNAL_INT_ELEMENTS: |
| 3536 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3449 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3537 case EXTERNAL_FLOAT_ELEMENTS: | 3450 case EXTERNAL_FLOAT_ELEMENTS: |
| 3538 case EXTERNAL_DOUBLE_ELEMENTS: | 3451 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3539 case FAST_DOUBLE_ELEMENTS: | |
| 3540 // Ignore getters and setters on pixel and external array | 3452 // Ignore getters and setters on pixel and external array |
| 3541 // elements. | 3453 // elements. |
| 3542 return heap->undefined_value(); | 3454 return heap->undefined_value(); |
| 3543 case DICTIONARY_ELEMENTS: { | 3455 case DICTIONARY_ELEMENTS: { |
| 3544 Object* probe = | 3456 // Lookup the index. |
| 3545 FindGetterSetterInDictionary(element_dictionary(), index, heap); | 3457 NumberDictionary* dictionary = element_dictionary(); |
| 3546 if (!probe->IsTheHole()) return probe; | 3458 int entry = dictionary->FindEntry(index); |
| 3547 // Otherwise allow to override it. | 3459 if (entry != NumberDictionary::kNotFound) { |
| 3548 break; | 3460 Object* result = dictionary->ValueAt(entry); |
| 3549 } | 3461 PropertyDetails details = dictionary->DetailsAt(entry); |
| 3550 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 3462 if (details.IsReadOnly()) return heap->undefined_value(); |
| 3551 // Ascertain whether we have read-only properties or an existing | 3463 if (details.type() == CALLBACKS) { |
| 3552 // getter/setter pair in an arguments elements dictionary backing | 3464 if (result->IsFixedArray()) { |
| 3553 // store. | 3465 return result; |
| 3554 FixedArray* parameter_map = FixedArray::cast(elements()); | 3466 } |
| 3555 uint32_t length = parameter_map->length(); | 3467 // Otherwise allow to override it. |
| 3556 Object* probe = | |
| 3557 (index + 2) < length ? parameter_map->get(index + 2) : NULL; | |
| 3558 if (probe == NULL || probe->IsTheHole()) { | |
| 3559 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 3560 if (arguments->IsDictionary()) { | |
| 3561 NumberDictionary* dictionary = NumberDictionary::cast(arguments); | |
| 3562 probe = FindGetterSetterInDictionary(dictionary, index, heap); | |
| 3563 if (!probe->IsTheHole()) return probe; | |
| 3564 } | 3468 } |
| 3565 } | 3469 } |
| 3566 break; | 3470 break; |
| 3567 } | 3471 } |
| 3472 default: |
| 3473 UNREACHABLE(); |
| 3474 break; |
| 3568 } | 3475 } |
| 3569 } else { | 3476 } else { |
| 3570 // Lookup the name. | 3477 // Lookup the name. |
| 3571 LookupResult result; | 3478 LookupResult result; |
| 3572 LocalLookup(name, &result); | 3479 LocalLookup(name, &result); |
| 3573 if (result.IsProperty()) { | 3480 if (result.IsProperty()) { |
| 3574 if (result.IsReadOnly()) return heap->undefined_value(); | 3481 if (result.IsReadOnly()) return heap->undefined_value(); |
| 3575 if (result.type() == CALLBACKS) { | 3482 if (result.type() == CALLBACKS) { |
| 3576 Object* obj = result.GetCallbackObject(); | 3483 Object* obj = result.GetCallbackObject(); |
| 3577 // Need to preserve old getters/setters. | 3484 // Need to preserve old getters/setters. |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3620 return true; | 3527 return true; |
| 3621 } | 3528 } |
| 3622 | 3529 |
| 3623 | 3530 |
| 3624 MaybeObject* JSObject::SetElementCallback(uint32_t index, | 3531 MaybeObject* JSObject::SetElementCallback(uint32_t index, |
| 3625 Object* structure, | 3532 Object* structure, |
| 3626 PropertyAttributes attributes) { | 3533 PropertyAttributes attributes) { |
| 3627 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 3534 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 3628 | 3535 |
| 3629 // Normalize elements to make this operation simple. | 3536 // Normalize elements to make this operation simple. |
| 3630 NumberDictionary* dictionary = NULL; | 3537 Object* ok; |
| 3631 { Object* result; | 3538 { MaybeObject* maybe_ok = NormalizeElements(); |
| 3632 MaybeObject* maybe = NormalizeElements(); | 3539 if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| 3633 if (!maybe->ToObject(&result)) return maybe; | |
| 3634 dictionary = NumberDictionary::cast(result); | |
| 3635 } | 3540 } |
| 3636 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | |
| 3637 | 3541 |
| 3638 // Update the dictionary with the new CALLBACKS property. | 3542 // Update the dictionary with the new CALLBACKS property. |
| 3639 { Object* result; | 3543 Object* dict; |
| 3640 MaybeObject* maybe = dictionary->Set(index, structure, details); | 3544 { MaybeObject* maybe_dict = |
| 3641 if (!maybe->ToObject(&result)) return maybe; | 3545 element_dictionary()->Set(index, structure, details); |
| 3642 dictionary = NumberDictionary::cast(result); | 3546 if (!maybe_dict->ToObject(&dict)) return maybe_dict; |
| 3643 } | 3547 } |
| 3644 | 3548 |
| 3645 dictionary->set_requires_slow_elements(); | 3549 NumberDictionary* elements = NumberDictionary::cast(dict); |
| 3646 // Update the dictionary backing store on the object. | 3550 elements->set_requires_slow_elements(); |
| 3647 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { | 3551 // Set the potential new dictionary on the object. |
| 3648 // Also delete any parameter alias. | 3552 set_elements(elements); |
| 3649 // | |
| 3650 // TODO(kmillikin): when deleting the last parameter alias we could | |
| 3651 // switch to a direct backing store without the parameter map. This | |
| 3652 // would allow GC of the context. | |
| 3653 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 3654 uint32_t length = parameter_map->length(); | |
| 3655 if (index + 2 < length) { | |
| 3656 parameter_map->set(index + 2, GetHeap()->the_hole_value()); | |
| 3657 } | |
| 3658 parameter_map->set(1, dictionary); | |
| 3659 } else { | |
| 3660 set_elements(dictionary); | |
| 3661 } | |
| 3662 | 3553 |
| 3663 return structure; | 3554 return structure; |
| 3664 } | 3555 } |
| 3665 | 3556 |
| 3666 | 3557 |
| 3667 MaybeObject* JSObject::SetPropertyCallback(String* name, | 3558 MaybeObject* JSObject::SetPropertyCallback(String* name, |
| 3668 Object* structure, | 3559 Object* structure, |
| 3669 PropertyAttributes attributes) { | 3560 PropertyAttributes attributes) { |
| 3670 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 3561 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
| 3671 | 3562 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3778 break; | 3669 break; |
| 3779 case EXTERNAL_PIXEL_ELEMENTS: | 3670 case EXTERNAL_PIXEL_ELEMENTS: |
| 3780 case EXTERNAL_BYTE_ELEMENTS: | 3671 case EXTERNAL_BYTE_ELEMENTS: |
| 3781 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3672 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 3782 case EXTERNAL_SHORT_ELEMENTS: | 3673 case EXTERNAL_SHORT_ELEMENTS: |
| 3783 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3674 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 3784 case EXTERNAL_INT_ELEMENTS: | 3675 case EXTERNAL_INT_ELEMENTS: |
| 3785 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3676 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 3786 case EXTERNAL_FLOAT_ELEMENTS: | 3677 case EXTERNAL_FLOAT_ELEMENTS: |
| 3787 case EXTERNAL_DOUBLE_ELEMENTS: | 3678 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3788 case FAST_DOUBLE_ELEMENTS: | |
| 3789 // Ignore getters and setters on pixel and external array | 3679 // Ignore getters and setters on pixel and external array |
| 3790 // elements. | 3680 // elements. |
| 3791 return isolate->heap()->undefined_value(); | 3681 return isolate->heap()->undefined_value(); |
| 3792 case DICTIONARY_ELEMENTS: | 3682 case DICTIONARY_ELEMENTS: |
| 3793 break; | 3683 break; |
| 3794 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3684 default: |
| 3795 UNIMPLEMENTED(); | 3685 UNREACHABLE(); |
| 3796 break; | 3686 break; |
| 3797 } | 3687 } |
| 3798 | 3688 |
| 3799 Object* ok; | 3689 Object* ok; |
| 3800 { MaybeObject* maybe_ok = | 3690 { MaybeObject* maybe_ok = |
| 3801 SetElementCallback(index, info, info->property_attributes()); | 3691 SetElementCallback(index, info, info->property_attributes()); |
| 3802 if (!maybe_ok->ToObject(&ok)) return maybe_ok; | 3692 if (!maybe_ok->ToObject(&ok)) return maybe_ok; |
| 3803 } | 3693 } |
| 3804 } else { | 3694 } else { |
| 3805 // Lookup the name. | 3695 // Lookup the name. |
| (...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4572 int pos = 0; | 4462 int pos = 0; |
| 4573 // Copy the elements from the JSArray to the temporary fixed array. | 4463 // Copy the elements from the JSArray to the temporary fixed array. |
| 4574 for (int i = 0; i < capacity; i++) { | 4464 for (int i = 0; i < capacity; i++) { |
| 4575 if (dict->IsKey(dict->KeyAt(i))) { | 4465 if (dict->IsKey(dict->KeyAt(i))) { |
| 4576 key_array->set(pos++, dict->ValueAt(i)); | 4466 key_array->set(pos++, dict->ValueAt(i)); |
| 4577 } | 4467 } |
| 4578 } | 4468 } |
| 4579 // Compute the union of this and the temporary fixed array. | 4469 // Compute the union of this and the temporary fixed array. |
| 4580 return UnionOfKeys(key_array); | 4470 return UnionOfKeys(key_array); |
| 4581 } | 4471 } |
| 4582 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS: | 4472 default: |
| 4583 UNIMPLEMENTED(); | 4473 UNREACHABLE(); |
| 4584 break; | |
| 4585 case JSObject::EXTERNAL_BYTE_ELEMENTS: | |
| 4586 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 4587 case JSObject::EXTERNAL_SHORT_ELEMENTS: | |
| 4588 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 4589 case JSObject::EXTERNAL_INT_ELEMENTS: | |
| 4590 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 4591 case JSObject::EXTERNAL_FLOAT_ELEMENTS: | |
| 4592 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: | |
| 4593 case JSObject::EXTERNAL_PIXEL_ELEMENTS: | |
| 4594 case JSObject::FAST_DOUBLE_ELEMENTS: | |
| 4595 break; | |
| 4596 } | 4474 } |
| 4597 UNREACHABLE(); | 4475 UNREACHABLE(); |
| 4598 return GetHeap()->null_value(); // Failure case needs to "return" a value. | 4476 return GetHeap()->null_value(); // Failure case needs to "return" a value. |
| 4599 } | 4477 } |
| 4600 | 4478 |
| 4601 | 4479 |
| 4602 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { | 4480 MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) { |
| 4603 int len0 = length(); | 4481 int len0 = length(); |
| 4604 #ifdef DEBUG | 4482 #ifdef DEBUG |
| 4605 if (FLAG_enable_slow_asserts) { | 4483 if (FLAG_enable_slow_asserts) { |
| (...skipping 2565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7171 PrintF(out, "name = %s\n", name); | 7049 PrintF(out, "name = %s\n", name); |
| 7172 } | 7050 } |
| 7173 if (kind() == OPTIMIZED_FUNCTION) { | 7051 if (kind() == OPTIMIZED_FUNCTION) { |
| 7174 PrintF(out, "stack_slots = %d\n", stack_slots()); | 7052 PrintF(out, "stack_slots = %d\n", stack_slots()); |
| 7175 } | 7053 } |
| 7176 | 7054 |
| 7177 PrintF(out, "Instructions (size = %d)\n", instruction_size()); | 7055 PrintF(out, "Instructions (size = %d)\n", instruction_size()); |
| 7178 Disassembler::Decode(out, this); | 7056 Disassembler::Decode(out, this); |
| 7179 PrintF(out, "\n"); | 7057 PrintF(out, "\n"); |
| 7180 | 7058 |
| 7181 #ifdef DEBUG | |
| 7182 if (kind() == FUNCTION) { | 7059 if (kind() == FUNCTION) { |
| 7183 DeoptimizationOutputData* data = | 7060 DeoptimizationOutputData* data = |
| 7184 DeoptimizationOutputData::cast(this->deoptimization_data()); | 7061 DeoptimizationOutputData::cast(this->deoptimization_data()); |
| 7185 data->DeoptimizationOutputDataPrint(out); | 7062 data->DeoptimizationOutputDataPrint(out); |
| 7186 } else if (kind() == OPTIMIZED_FUNCTION) { | 7063 } else if (kind() == OPTIMIZED_FUNCTION) { |
| 7187 DeoptimizationInputData* data = | 7064 DeoptimizationInputData* data = |
| 7188 DeoptimizationInputData::cast(this->deoptimization_data()); | 7065 DeoptimizationInputData::cast(this->deoptimization_data()); |
| 7189 data->DeoptimizationInputDataPrint(out); | 7066 data->DeoptimizationInputDataPrint(out); |
| 7190 } | 7067 } |
| 7191 PrintF("\n"); | 7068 PrintF("\n"); |
| 7192 #endif | |
| 7193 | 7069 |
| 7194 if (kind() == OPTIMIZED_FUNCTION) { | 7070 if (kind() == OPTIMIZED_FUNCTION) { |
| 7195 SafepointTable table(this); | 7071 SafepointTable table(this); |
| 7196 PrintF(out, "Safepoints (size = %u)\n", table.size()); | 7072 PrintF(out, "Safepoints (size = %u)\n", table.size()); |
| 7197 for (unsigned i = 0; i < table.length(); i++) { | 7073 for (unsigned i = 0; i < table.length(); i++) { |
| 7198 unsigned pc_offset = table.GetPcOffset(i); | 7074 unsigned pc_offset = table.GetPcOffset(i); |
| 7199 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); | 7075 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset); |
| 7200 table.PrintEntry(i); | 7076 table.PrintEntry(i); |
| 7201 PrintF(out, " (sp -> fp)"); | 7077 PrintF(out, " (sp -> fp)"); |
| 7202 SafepointEntry entry = table.GetEntry(i); | 7078 SafepointEntry entry = table.GetEntry(i); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 7229 } | 7105 } |
| 7230 } | 7106 } |
| 7231 | 7107 |
| 7232 PrintF("RelocInfo (size = %d)\n", relocation_size()); | 7108 PrintF("RelocInfo (size = %d)\n", relocation_size()); |
| 7233 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); | 7109 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out); |
| 7234 PrintF(out, "\n"); | 7110 PrintF(out, "\n"); |
| 7235 } | 7111 } |
| 7236 #endif // ENABLE_DISASSEMBLER | 7112 #endif // ENABLE_DISASSEMBLER |
| 7237 | 7113 |
| 7238 | 7114 |
| 7239 static void CopyFastElementsToFast(FixedArray* source, | |
| 7240 FixedArray* destination, | |
| 7241 WriteBarrierMode mode) { | |
| 7242 uint32_t count = static_cast<uint32_t>(source->length()); | |
| 7243 for (uint32_t i = 0; i < count; ++i) { | |
| 7244 destination->set(i, source->get(i), mode); | |
| 7245 } | |
| 7246 } | |
| 7247 | |
| 7248 | |
| 7249 static void CopySlowElementsToFast(NumberDictionary* source, | |
| 7250 FixedArray* destination, | |
| 7251 WriteBarrierMode mode) { | |
| 7252 for (int i = 0; i < source->Capacity(); ++i) { | |
| 7253 Object* key = source->KeyAt(i); | |
| 7254 if (key->IsNumber()) { | |
| 7255 uint32_t entry = static_cast<uint32_t>(key->Number()); | |
| 7256 destination->set(entry, source->ValueAt(i), mode); | |
| 7257 } | |
| 7258 } | |
| 7259 } | |
| 7260 | |
| 7261 | |
| 7262 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, | 7115 MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity, |
| 7263 int length) { | 7116 int length) { |
| 7264 Heap* heap = GetHeap(); | 7117 Heap* heap = GetHeap(); |
| 7265 // We should never end in here with a pixel or external array. | 7118 // We should never end in here with a pixel or external array. |
| 7266 ASSERT(!HasExternalArrayElements()); | 7119 ASSERT(!HasExternalArrayElements()); |
| 7267 | 7120 |
| 7268 // Allocate a new fast elements backing store. | 7121 Object* obj; |
| 7269 FixedArray* new_elements = NULL; | 7122 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); |
| 7270 { Object* object; | 7123 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7271 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity); | |
| 7272 if (!maybe->ToObject(&object)) return maybe; | |
| 7273 new_elements = FixedArray::cast(object); | |
| 7274 } | 7124 } |
| 7125 FixedArray* elems = FixedArray::cast(obj); |
| 7275 | 7126 |
| 7276 // Find the new map to use for this object if there is a map change. | 7127 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); |
| 7277 Map* new_map = NULL; | 7128 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7278 if (elements()->map() != heap->non_strict_arguments_elements_map()) { | |
| 7279 Object* object; | |
| 7280 MaybeObject* maybe = map()->GetFastElementsMap(); | |
| 7281 if (!maybe->ToObject(&object)) return maybe; | |
| 7282 new_map = Map::cast(object); | |
| 7283 } | 7129 } |
| 7130 Map* new_map = Map::cast(obj); |
| 7284 | 7131 |
| 7285 AssertNoAllocation no_gc; | |
| 7286 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc); | |
| 7287 switch (GetElementsKind()) { | 7132 switch (GetElementsKind()) { |
| 7288 case FAST_ELEMENTS: | 7133 case FAST_ELEMENTS: { |
| 7289 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode); | 7134 AssertNoAllocation no_gc; |
| 7290 set_map(new_map); | 7135 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| 7291 set_elements(new_elements); | 7136 FixedArray* old_elements = FixedArray::cast(elements()); |
| 7292 break; | 7137 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| 7293 case DICTIONARY_ELEMENTS: | 7138 // Fill out the new array with this content and array holes. |
| 7294 CopySlowElementsToFast(NumberDictionary::cast(elements()), | 7139 for (uint32_t i = 0; i < old_length; i++) { |
| 7295 new_elements, | 7140 elems->set(i, old_elements->get(i), mode); |
| 7296 mode); | |
| 7297 set_map(new_map); | |
| 7298 set_elements(new_elements); | |
| 7299 break; | |
| 7300 case NON_STRICT_ARGUMENTS_ELEMENTS: { | |
| 7301 // The object's map and the parameter map are unchanged, the unaliased | |
| 7302 // arguments are copied to the new backing store. | |
| 7303 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 7304 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 7305 if (arguments->IsDictionary()) { | |
| 7306 CopySlowElementsToFast(NumberDictionary::cast(arguments), | |
| 7307 new_elements, | |
| 7308 mode); | |
| 7309 } else { | |
| 7310 CopyFastElementsToFast(arguments, new_elements, mode); | |
| 7311 } | 7141 } |
| 7312 parameter_map->set(1, new_elements); | |
| 7313 break; | 7142 break; |
| 7314 } | 7143 } |
| 7315 case FAST_DOUBLE_ELEMENTS: { | 7144 case FAST_DOUBLE_ELEMENTS: { |
| 7316 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); | 7145 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); |
| 7317 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 7146 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
| 7318 // Fill out the new array with this content and array holes. | 7147 // Fill out the new array with this content and array holes. |
| 7319 for (uint32_t i = 0; i < old_length; i++) { | 7148 for (uint32_t i = 0; i < old_length; i++) { |
| 7320 if (!old_elements->is_the_hole(i)) { | 7149 if (!old_elements->is_the_hole(i)) { |
| 7321 Object* obj; | 7150 Object* obj; |
| 7322 // Objects must be allocated in the old object space, since the | 7151 // Objects must be allocated in the old object space, since the |
| 7323 // overall number of HeapNumbers needed for the conversion might | 7152 // overall number of HeapNumbers needed for the conversion might |
| 7324 // exceed the capacity of new space, and we would fail repeatedly | 7153 // exceed the capacity of new space, and we would fail repeatedly |
| 7325 // trying to convert the FixedDoubleArray. | 7154 // trying to convert the FixedDoubleArray. |
| 7326 MaybeObject* maybe_value_object = | 7155 MaybeObject* maybe_value_object = |
| 7327 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); | 7156 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); |
| 7328 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; | 7157 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; |
| 7329 // Force write barrier. It's not worth trying to exploit | 7158 // Force write barrier. It's not worth trying to exploit |
| 7330 // elems->GetWriteBarrierMode(), since it requires an | 7159 // elems->GetWriteBarrierMode(), since it requires an |
| 7331 // AssertNoAllocation stack object that would have to be positioned | 7160 // AssertNoAllocation stack object that would have to be positioned |
| 7332 // after the HeapNumber allocation anyway. | 7161 // after the HeapNumber allocation anyway. |
| 7333 new_elements->set(i, obj, UPDATE_WRITE_BARRIER); | 7162 elems->set(i, obj, UPDATE_WRITE_BARRIER); |
| 7334 } | 7163 } |
| 7335 } | 7164 } |
| 7336 break; | 7165 break; |
| 7337 } | 7166 } |
| 7338 case EXTERNAL_BYTE_ELEMENTS: | 7167 case DICTIONARY_ELEMENTS: { |
| 7339 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 7168 AssertNoAllocation no_gc; |
| 7340 case EXTERNAL_SHORT_ELEMENTS: | 7169 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); |
| 7341 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 7170 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| 7342 case EXTERNAL_INT_ELEMENTS: | 7171 for (int i = 0; i < dictionary->Capacity(); i++) { |
| 7343 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7172 Object* key = dictionary->KeyAt(i); |
| 7344 case EXTERNAL_FLOAT_ELEMENTS: | 7173 if (key->IsNumber()) { |
| 7345 case EXTERNAL_DOUBLE_ELEMENTS: | 7174 uint32_t entry = static_cast<uint32_t>(key->Number()); |
| 7346 case EXTERNAL_PIXEL_ELEMENTS: | 7175 elems->set(entry, dictionary->ValueAt(i), mode); |
| 7176 } |
| 7177 } |
| 7178 break; |
| 7179 } |
| 7180 default: |
| 7347 UNREACHABLE(); | 7181 UNREACHABLE(); |
| 7348 break; | 7182 break; |
| 7349 } | 7183 } |
| 7350 | 7184 |
| 7351 // Update the length if necessary. | 7185 set_map(new_map); |
| 7186 set_elements(elems); |
| 7187 |
| 7352 if (IsJSArray()) { | 7188 if (IsJSArray()) { |
| 7353 JSArray::cast(this)->set_length(Smi::FromInt(length)); | 7189 JSArray::cast(this)->set_length(Smi::FromInt(length)); |
| 7354 } | 7190 } |
| 7355 | 7191 |
| 7356 return new_elements; | 7192 return this; |
| 7357 } | 7193 } |
| 7358 | 7194 |
| 7359 | 7195 |
| 7360 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( | 7196 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( |
| 7361 int capacity, | 7197 int capacity, |
| 7362 int length) { | 7198 int length) { |
| 7363 Heap* heap = GetHeap(); | 7199 Heap* heap = GetHeap(); |
| 7364 // We should never end in here with a pixel or external array. | 7200 // We should never end in here with a pixel or external array. |
| 7365 ASSERT(!HasExternalArrayElements()); | 7201 ASSERT(!HasExternalArrayElements()); |
| 7366 | 7202 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7410 // We should never end in here with a pixel or external array. | 7246 // We should never end in here with a pixel or external array. |
| 7411 ASSERT(!HasExternalArrayElements()); | 7247 ASSERT(!HasExternalArrayElements()); |
| 7412 | 7248 |
| 7413 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 7249 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
| 7414 | 7250 |
| 7415 switch (GetElementsKind()) { | 7251 switch (GetElementsKind()) { |
| 7416 case FAST_ELEMENTS: { | 7252 case FAST_ELEMENTS: { |
| 7417 // Make sure we never try to shrink dense arrays into sparse arrays. | 7253 // Make sure we never try to shrink dense arrays into sparse arrays. |
| 7418 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= | 7254 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= |
| 7419 new_length); | 7255 new_length); |
| 7420 MaybeObject* result = NormalizeElements(); | 7256 Object* obj; |
| 7421 if (result->IsFailure()) return result; | 7257 { MaybeObject* maybe_obj = NormalizeElements(); |
| 7258 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7259 } |
| 7422 | 7260 |
| 7423 // Update length for JSArrays. | 7261 // Update length for JSArrays. |
| 7424 if (IsJSArray()) JSArray::cast(this)->set_length(len); | 7262 if (IsJSArray()) JSArray::cast(this)->set_length(len); |
| 7425 break; | 7263 break; |
| 7426 } | 7264 } |
| 7427 case DICTIONARY_ELEMENTS: { | 7265 case DICTIONARY_ELEMENTS: { |
| 7428 if (IsJSArray()) { | 7266 if (IsJSArray()) { |
| 7429 uint32_t old_length = | 7267 uint32_t old_length = |
| 7430 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 7268 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 7431 element_dictionary()->RemoveNumberEntries(new_length, old_length), | 7269 element_dictionary()->RemoveNumberEntries(new_length, old_length), |
| 7432 JSArray::cast(this)->set_length(len); | 7270 JSArray::cast(this)->set_length(len); |
| 7433 } | 7271 } |
| 7434 break; | 7272 break; |
| 7435 } | 7273 } |
| 7436 case NON_STRICT_ARGUMENTS_ELEMENTS: | 7274 default: |
| 7437 UNIMPLEMENTED(); | |
| 7438 break; | |
| 7439 case EXTERNAL_BYTE_ELEMENTS: | |
| 7440 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 7441 case EXTERNAL_SHORT_ELEMENTS: | |
| 7442 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 7443 case EXTERNAL_INT_ELEMENTS: | |
| 7444 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 7445 case EXTERNAL_FLOAT_ELEMENTS: | |
| 7446 case EXTERNAL_DOUBLE_ELEMENTS: | |
| 7447 case EXTERNAL_PIXEL_ELEMENTS: | |
| 7448 case FAST_DOUBLE_ELEMENTS: | |
| 7449 UNREACHABLE(); | 7275 UNREACHABLE(); |
| 7450 break; | 7276 break; |
| 7451 } | 7277 } |
| 7452 return this; | 7278 return this; |
| 7453 } | 7279 } |
| 7454 | 7280 |
| 7455 | 7281 |
| 7456 MaybeObject* JSArray::Initialize(int capacity) { | 7282 MaybeObject* JSArray::Initialize(int capacity) { |
| 7457 Heap* heap = GetHeap(); | 7283 Heap* heap = GetHeap(); |
| 7458 ASSERT(capacity >= 0); | 7284 ASSERT(capacity >= 0); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7518 FixedArray::cast(elements())->set_the_hole(i); | 7344 FixedArray::cast(elements())->set_the_hole(i); |
| 7519 } | 7345 } |
| 7520 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 7346 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 7521 } | 7347 } |
| 7522 return this; | 7348 return this; |
| 7523 } | 7349 } |
| 7524 int min = NewElementsCapacity(old_capacity); | 7350 int min = NewElementsCapacity(old_capacity); |
| 7525 int new_capacity = value > min ? value : min; | 7351 int new_capacity = value > min ? value : min; |
| 7526 if (new_capacity <= kMaxFastElementsLength || | 7352 if (new_capacity <= kMaxFastElementsLength || |
| 7527 !ShouldConvertToSlowElements(new_capacity)) { | 7353 !ShouldConvertToSlowElements(new_capacity)) { |
| 7528 MaybeObject* result = | 7354 Object* obj; |
| 7529 SetFastElementsCapacityAndLength(new_capacity, value); | 7355 { MaybeObject* maybe_obj = |
| 7530 if (result->IsFailure()) return result; | 7356 SetFastElementsCapacityAndLength(new_capacity, value); |
| 7357 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7358 } |
| 7531 return this; | 7359 return this; |
| 7532 } | 7360 } |
| 7533 break; | 7361 break; |
| 7534 } | 7362 } |
| 7535 case DICTIONARY_ELEMENTS: { | 7363 case DICTIONARY_ELEMENTS: { |
| 7536 if (IsJSArray()) { | 7364 if (IsJSArray()) { |
| 7537 if (value == 0) { | 7365 if (value == 0) { |
| 7538 // If the length of a slow array is reset to zero, we clear | 7366 // If the length of a slow array is reset to zero, we clear |
| 7539 // the array and flush backing storage. This has the added | 7367 // the array and flush backing storage. This has the added |
| 7540 // benefit that the array returns to fast mode. | 7368 // benefit that the array returns to fast mode. |
| 7541 Object* obj; | 7369 Object* obj; |
| 7542 { MaybeObject* maybe_obj = ResetElements(); | 7370 { MaybeObject* maybe_obj = ResetElements(); |
| 7543 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7371 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 7544 } | 7372 } |
| 7545 } else { | 7373 } else { |
| 7546 // Remove deleted elements. | 7374 // Remove deleted elements. |
| 7547 uint32_t old_length = | 7375 uint32_t old_length = |
| 7548 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); | 7376 static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); |
| 7549 element_dictionary()->RemoveNumberEntries(value, old_length); | 7377 element_dictionary()->RemoveNumberEntries(value, old_length); |
| 7550 } | 7378 } |
| 7551 JSArray::cast(this)->set_length(Smi::cast(smi_length)); | 7379 JSArray::cast(this)->set_length(Smi::cast(smi_length)); |
| 7552 } | 7380 } |
| 7553 return this; | 7381 return this; |
| 7554 } | 7382 } |
| 7555 case NON_STRICT_ARGUMENTS_ELEMENTS: | 7383 default: |
| 7556 case EXTERNAL_BYTE_ELEMENTS: | |
| 7557 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | |
| 7558 case EXTERNAL_SHORT_ELEMENTS: | |
| 7559 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | |
| 7560 case EXTERNAL_INT_ELEMENTS: | |
| 7561 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | |
| 7562 case EXTERNAL_FLOAT_ELEMENTS: | |
| 7563 case EXTERNAL_DOUBLE_ELEMENTS: | |
| 7564 case EXTERNAL_PIXEL_ELEMENTS: | |
| 7565 case FAST_DOUBLE_ELEMENTS: | |
| 7566 UNREACHABLE(); | 7384 UNREACHABLE(); |
| 7567 break; | 7385 break; |
| 7568 } | 7386 } |
| 7569 } | 7387 } |
| 7570 | 7388 |
| 7571 // General slow case. | 7389 // General slow case. |
| 7572 if (len->IsNumber()) { | 7390 if (len->IsNumber()) { |
| 7573 uint32_t length; | 7391 uint32_t length; |
| 7574 if (len->ToArrayIndex(&length)) { | 7392 if (len->ToArrayIndex(&length)) { |
| 7575 return SetSlowElements(len); | 7393 return SetSlowElements(len); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7752 } | 7570 } |
| 7753 break; | 7571 break; |
| 7754 } | 7572 } |
| 7755 case EXTERNAL_BYTE_ELEMENTS: | 7573 case EXTERNAL_BYTE_ELEMENTS: |
| 7756 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 7574 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 7757 case EXTERNAL_SHORT_ELEMENTS: | 7575 case EXTERNAL_SHORT_ELEMENTS: |
| 7758 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 7576 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7759 case EXTERNAL_INT_ELEMENTS: | 7577 case EXTERNAL_INT_ELEMENTS: |
| 7760 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7578 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7761 case EXTERNAL_FLOAT_ELEMENTS: | 7579 case EXTERNAL_FLOAT_ELEMENTS: |
| 7762 case EXTERNAL_DOUBLE_ELEMENTS: | 7580 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7763 case FAST_DOUBLE_ELEMENTS: { | |
| 7764 ExternalArray* array = ExternalArray::cast(elements()); | 7581 ExternalArray* array = ExternalArray::cast(elements()); |
| 7765 if (index < static_cast<uint32_t>(array->length())) { | 7582 if (index < static_cast<uint32_t>(array->length())) { |
| 7766 return true; | 7583 return true; |
| 7767 } | 7584 } |
| 7768 break; | 7585 break; |
| 7769 } | 7586 } |
| 7770 case DICTIONARY_ELEMENTS: { | 7587 case DICTIONARY_ELEMENTS: { |
| 7771 if (element_dictionary()->FindEntry(index) | 7588 if (element_dictionary()->FindEntry(index) |
| 7772 != NumberDictionary::kNotFound) { | 7589 != NumberDictionary::kNotFound) { |
| 7773 return true; | 7590 return true; |
| 7774 } | 7591 } |
| 7775 break; | 7592 break; |
| 7776 } | 7593 } |
| 7777 case NON_STRICT_ARGUMENTS_ELEMENTS: | 7594 default: |
| 7778 UNREACHABLE(); | 7595 UNREACHABLE(); |
| 7779 break; | 7596 break; |
| 7780 } | 7597 } |
| 7781 | 7598 |
| 7782 // Handle [] on String objects. | 7599 // Handle [] on String objects. |
| 7783 if (this->IsStringObjectWithCharacterAt(index)) return true; | 7600 if (this->IsStringObjectWithCharacterAt(index)) return true; |
| 7784 | 7601 |
| 7785 Object* pt = GetPrototype(); | 7602 Object* pt = GetPrototype(); |
| 7786 if (pt->IsNull()) return false; | 7603 if (pt->IsNull()) return false; |
| 7787 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 7604 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7881 case EXTERNAL_SHORT_ELEMENTS: | 7698 case EXTERNAL_SHORT_ELEMENTS: |
| 7882 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 7699 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 7883 case EXTERNAL_INT_ELEMENTS: | 7700 case EXTERNAL_INT_ELEMENTS: |
| 7884 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7701 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7885 case EXTERNAL_FLOAT_ELEMENTS: | 7702 case EXTERNAL_FLOAT_ELEMENTS: |
| 7886 case EXTERNAL_DOUBLE_ELEMENTS: { | 7703 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7887 ExternalArray* array = ExternalArray::cast(elements()); | 7704 ExternalArray* array = ExternalArray::cast(elements()); |
| 7888 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; | 7705 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT; |
| 7889 break; | 7706 break; |
| 7890 } | 7707 } |
| 7891 case FAST_DOUBLE_ELEMENTS: | |
| 7892 UNREACHABLE(); | |
| 7893 break; | |
| 7894 case DICTIONARY_ELEMENTS: { | 7708 case DICTIONARY_ELEMENTS: { |
| 7895 if (element_dictionary()->FindEntry(index) != | 7709 if (element_dictionary()->FindEntry(index) != |
| 7896 NumberDictionary::kNotFound) { | 7710 NumberDictionary::kNotFound) { |
| 7897 return DICTIONARY_ELEMENT; | 7711 return DICTIONARY_ELEMENT; |
| 7898 } | 7712 } |
| 7899 break; | 7713 break; |
| 7900 } | 7714 } |
| 7901 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 7715 default: |
| 7902 // Aliased parameters and non-aliased elements in a fast backing store | 7716 UNREACHABLE(); |
| 7903 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary | |
| 7904 // backing store behave as DICTIONARY_ELEMENT. | |
| 7905 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 7906 uint32_t length = parameter_map->length(); | |
| 7907 Object* probe = | |
| 7908 (index + 2) < length ? parameter_map->get(index + 2) : NULL; | |
| 7909 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; | |
| 7910 // If not aliased, check the arguments. | |
| 7911 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 7912 if (arguments->IsDictionary()) { | |
| 7913 NumberDictionary* dictionary = NumberDictionary::cast(arguments); | |
| 7914 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) { | |
| 7915 return DICTIONARY_ELEMENT; | |
| 7916 } | |
| 7917 } else { | |
| 7918 length = arguments->length(); | |
| 7919 probe = (index < length) ? arguments->get(index) : NULL; | |
| 7920 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT; | |
| 7921 } | |
| 7922 break; | 7717 break; |
| 7923 } | |
| 7924 } | 7718 } |
| 7925 | 7719 |
| 7926 return UNDEFINED_ELEMENT; | 7720 return UNDEFINED_ELEMENT; |
| 7927 } | 7721 } |
| 7928 | 7722 |
| 7929 | 7723 |
| 7930 bool JSObject::HasElementInElements(FixedArray* elements, | |
| 7931 ElementsKind kind, | |
| 7932 uint32_t index) { | |
| 7933 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS); | |
| 7934 if (kind == FAST_ELEMENTS) { | |
| 7935 int length = IsJSArray() | |
| 7936 ? Smi::cast(JSArray::cast(this)->length())->value() | |
| 7937 : elements->length(); | |
| 7938 if (index < static_cast<uint32_t>(length) && | |
| 7939 !elements->get(index)->IsTheHole()) { | |
| 7940 return true; | |
| 7941 } | |
| 7942 } else { | |
| 7943 if (NumberDictionary::cast(elements)->FindEntry(index) != | |
| 7944 NumberDictionary::kNotFound) { | |
| 7945 return true; | |
| 7946 } | |
| 7947 } | |
| 7948 return false; | |
| 7949 } | |
| 7950 | |
| 7951 | |
| 7952 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { | 7724 bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) { |
| 7953 // Check access rights if needed. | 7725 // Check access rights if needed. |
| 7954 if (IsAccessCheckNeeded()) { | 7726 if (IsAccessCheckNeeded()) { |
| 7955 Heap* heap = GetHeap(); | 7727 Heap* heap = GetHeap(); |
| 7956 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { | 7728 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) { |
| 7957 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 7729 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
| 7958 return false; | 7730 return false; |
| 7959 } | 7731 } |
| 7960 } | 7732 } |
| 7961 | 7733 |
| 7962 // Check for lookup interceptor | 7734 // Check for lookup interceptor |
| 7963 if (HasIndexedInterceptor()) { | 7735 if (HasIndexedInterceptor()) { |
| 7964 return HasElementWithInterceptor(receiver, index); | 7736 return HasElementWithInterceptor(receiver, index); |
| 7965 } | 7737 } |
| 7966 | 7738 |
| 7967 ElementsKind kind = GetElementsKind(); | 7739 switch (GetElementsKind()) { |
| 7968 switch (kind) { | |
| 7969 case FAST_ELEMENTS: { | 7740 case FAST_ELEMENTS: { |
| 7970 uint32_t length = IsJSArray() ? | 7741 uint32_t length = IsJSArray() ? |
| 7971 static_cast<uint32_t> | 7742 static_cast<uint32_t> |
| 7972 (Smi::cast(JSArray::cast(this)->length())->value()) : | 7743 (Smi::cast(JSArray::cast(this)->length())->value()) : |
| 7973 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 7744 static_cast<uint32_t>(FixedArray::cast(elements())->length()); |
| 7974 if ((index < length) && | 7745 if ((index < length) && |
| 7975 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; | 7746 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; |
| 7976 break; | 7747 break; |
| 7977 } | 7748 } |
| 7978 case EXTERNAL_PIXEL_ELEMENTS: { | 7749 case EXTERNAL_PIXEL_ELEMENTS: { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 7989 case EXTERNAL_INT_ELEMENTS: | 7760 case EXTERNAL_INT_ELEMENTS: |
| 7990 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 7761 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 7991 case EXTERNAL_FLOAT_ELEMENTS: | 7762 case EXTERNAL_FLOAT_ELEMENTS: |
| 7992 case EXTERNAL_DOUBLE_ELEMENTS: { | 7763 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 7993 ExternalArray* array = ExternalArray::cast(elements()); | 7764 ExternalArray* array = ExternalArray::cast(elements()); |
| 7994 if (index < static_cast<uint32_t>(array->length())) { | 7765 if (index < static_cast<uint32_t>(array->length())) { |
| 7995 return true; | 7766 return true; |
| 7996 } | 7767 } |
| 7997 break; | 7768 break; |
| 7998 } | 7769 } |
| 7999 case FAST_DOUBLE_ELEMENTS: | |
| 8000 UNREACHABLE(); | |
| 8001 break; | |
| 8002 case DICTIONARY_ELEMENTS: { | 7770 case DICTIONARY_ELEMENTS: { |
| 8003 if (element_dictionary()->FindEntry(index) | 7771 if (element_dictionary()->FindEntry(index) |
| 8004 != NumberDictionary::kNotFound) { | 7772 != NumberDictionary::kNotFound) { |
| 8005 return true; | 7773 return true; |
| 8006 } | 7774 } |
| 8007 break; | 7775 break; |
| 8008 } | 7776 } |
| 8009 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 7777 default: |
| 8010 FixedArray* parameter_map = FixedArray::cast(elements()); | 7778 UNREACHABLE(); |
| 8011 uint32_t length = parameter_map->length(); | |
| 8012 Object* probe = | |
| 8013 (index + 2 < length) ? parameter_map->get(index + 2) : NULL; | |
| 8014 if (probe != NULL && !probe->IsTheHole()) return true; | |
| 8015 | |
| 8016 // Not a mapped parameter, check the arguments. | |
| 8017 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 8018 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS; | |
| 8019 if (HasElementInElements(arguments, kind, index)) return true; | |
| 8020 break; | 7779 break; |
| 8021 } | |
| 8022 } | 7780 } |
| 8023 | 7781 |
| 8024 // Handle [] on String objects. | 7782 // Handle [] on String objects. |
| 8025 if (this->IsStringObjectWithCharacterAt(index)) return true; | 7783 if (this->IsStringObjectWithCharacterAt(index)) return true; |
| 8026 | 7784 |
| 8027 Object* pt = GetPrototype(); | 7785 Object* pt = GetPrototype(); |
| 8028 if (pt->IsNull()) return false; | 7786 if (pt->IsNull()) return false; |
| 8029 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); | 7787 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index); |
| 8030 } | 7788 } |
| 8031 | 7789 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8077 | 7835 |
| 8078 // api style callbacks. | 7836 // api style callbacks. |
| 8079 if (structure->IsAccessorInfo()) { | 7837 if (structure->IsAccessorInfo()) { |
| 8080 Handle<AccessorInfo> data(AccessorInfo::cast(structure)); | 7838 Handle<AccessorInfo> data(AccessorInfo::cast(structure)); |
| 8081 Object* fun_obj = data->getter(); | 7839 Object* fun_obj = data->getter(); |
| 8082 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); | 7840 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj); |
| 8083 HandleScope scope(isolate); | 7841 HandleScope scope(isolate); |
| 8084 Handle<JSObject> self(JSObject::cast(receiver)); | 7842 Handle<JSObject> self(JSObject::cast(receiver)); |
| 8085 Handle<JSObject> holder_handle(JSObject::cast(holder)); | 7843 Handle<JSObject> holder_handle(JSObject::cast(holder)); |
| 8086 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | 7844 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); |
| 8087 Handle<String> key = isolate->factory()->NumberToString(number); | 7845 Handle<String> key(isolate->factory()->NumberToString(number)); |
| 8088 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); | 7846 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key)); |
| 8089 CustomArguments args(isolate, data->data(), *self, *holder_handle); | 7847 CustomArguments args(isolate, data->data(), *self, *holder_handle); |
| 8090 v8::AccessorInfo info(args.end()); | 7848 v8::AccessorInfo info(args.end()); |
| 8091 v8::Handle<v8::Value> result; | 7849 v8::Handle<v8::Value> result; |
| 8092 { | 7850 { |
| 8093 // Leaving JavaScript. | 7851 // Leaving JavaScript. |
| 8094 VMState state(isolate, EXTERNAL); | 7852 VMState state(isolate, EXTERNAL); |
| 8095 result = call_fun(v8::Utils::ToLocal(key), info); | 7853 result = call_fun(v8::Utils::ToLocal(key), info); |
| 8096 } | 7854 } |
| 8097 RETURN_IF_SCHEDULED_EXCEPTION(isolate); | 7855 RETURN_IF_SCHEDULED_EXCEPTION(isolate); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8172 *isolate->factory()->NewTypeError("no_setter_in_callback", | 7930 *isolate->factory()->NewTypeError("no_setter_in_callback", |
| 8173 HandleVector(args, 2))); | 7931 HandleVector(args, 2))); |
| 8174 } | 7932 } |
| 8175 } | 7933 } |
| 8176 | 7934 |
| 8177 UNREACHABLE(); | 7935 UNREACHABLE(); |
| 8178 return NULL; | 7936 return NULL; |
| 8179 } | 7937 } |
| 8180 | 7938 |
| 8181 | 7939 |
| 8182 bool JSObject::HasFastArgumentsElements() { | |
| 8183 Heap* heap = GetHeap(); | |
| 8184 if (!elements()->IsFixedArray()) return false; | |
| 8185 FixedArray* elements = FixedArray::cast(this->elements()); | |
| 8186 if (elements->map() != heap->non_strict_arguments_elements_map()) { | |
| 8187 return false; | |
| 8188 } | |
| 8189 FixedArray* arguments = FixedArray::cast(elements->get(1)); | |
| 8190 return !arguments->IsDictionary(); | |
| 8191 } | |
| 8192 | |
| 8193 | |
| 8194 bool JSObject::HasDictionaryArgumentsElements() { | |
| 8195 Heap* heap = GetHeap(); | |
| 8196 if (!elements()->IsFixedArray()) return false; | |
| 8197 FixedArray* elements = FixedArray::cast(this->elements()); | |
| 8198 if (elements->map() != heap->non_strict_arguments_elements_map()) { | |
| 8199 return false; | |
| 8200 } | |
| 8201 FixedArray* arguments = FixedArray::cast(elements->get(1)); | |
| 8202 return arguments->IsDictionary(); | |
| 8203 } | |
| 8204 | |
| 8205 | |
| 8206 // Adding n elements in fast case is O(n*n). | 7940 // Adding n elements in fast case is O(n*n). |
| 8207 // Note: revisit design to have dual undefined values to capture absent | 7941 // Note: revisit design to have dual undefined values to capture absent |
| 8208 // elements. | 7942 // elements. |
| 8209 MaybeObject* JSObject::SetFastElement(uint32_t index, | 7943 MaybeObject* JSObject::SetFastElement(uint32_t index, |
| 8210 Object* value, | 7944 Object* value, |
| 8211 StrictModeFlag strict_mode, | 7945 StrictModeFlag strict_mode, |
| 8212 bool check_prototype) { | 7946 bool check_prototype) { |
| 8213 ASSERT(HasFastElements() || HasFastArgumentsElements()); | 7947 ASSERT(HasFastElements()); |
| 8214 | 7948 |
| 8215 FixedArray* backing_store = FixedArray::cast(elements()); | 7949 Object* elms_obj; |
| 8216 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) { | 7950 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements(); |
| 8217 backing_store = FixedArray::cast(backing_store->get(1)); | 7951 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj; |
| 8218 } else { | |
| 8219 Object* writable; | |
| 8220 MaybeObject* maybe = EnsureWritableFastElements(); | |
| 8221 if (!maybe->ToObject(&writable)) return maybe; | |
| 8222 backing_store = FixedArray::cast(writable); | |
| 8223 } | 7952 } |
| 8224 uint32_t length = static_cast<uint32_t>(backing_store->length()); | 7953 FixedArray* elms = FixedArray::cast(elms_obj); |
| 7954 uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
| 8225 | 7955 |
| 8226 if (check_prototype && | 7956 if (check_prototype && |
| 8227 (index >= length || backing_store->get(index)->IsTheHole())) { | 7957 (index >= elms_length || elms->get(index)->IsTheHole())) { |
| 8228 bool found; | 7958 bool found; |
| 8229 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | 7959 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
| 8230 value, | 7960 value, |
| 8231 &found, | 7961 &found, |
| 8232 strict_mode); | 7962 strict_mode); |
| 8233 if (found) return result; | 7963 if (found) return result; |
| 8234 } | 7964 } |
| 8235 | 7965 |
| 8236 // Check whether there is extra space in fixed array.. | 7966 // Check whether there is extra space in fixed array.. |
| 8237 if (index < length) { | 7967 if (index < elms_length) { |
| 8238 backing_store->set(index, value); | 7968 elms->set(index, value); |
| 8239 if (IsJSArray()) { | 7969 if (IsJSArray()) { |
| 8240 // Update the length of the array if needed. | 7970 // Update the length of the array if needed. |
| 8241 uint32_t array_length = 0; | 7971 uint32_t array_length = 0; |
| 8242 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 7972 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
| 8243 if (index >= array_length) { | 7973 if (index >= array_length) { |
| 8244 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 7974 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
| 8245 } | 7975 } |
| 8246 } | 7976 } |
| 8247 return value; | 7977 return value; |
| 8248 } | 7978 } |
| 8249 | 7979 |
| 8250 // Allow gap in fast case. | 7980 // Allow gap in fast case. |
| 8251 if ((index - length) < kMaxGap) { | 7981 if ((index - elms_length) < kMaxGap) { |
| 8252 // Try allocating extra space. | 7982 // Try allocating extra space. |
| 8253 int new_capacity = NewElementsCapacity(index + 1); | 7983 int new_capacity = NewElementsCapacity(index+1); |
| 8254 if (new_capacity <= kMaxFastElementsLength || | 7984 if (new_capacity <= kMaxFastElementsLength || |
| 8255 !ShouldConvertToSlowElements(new_capacity)) { | 7985 !ShouldConvertToSlowElements(new_capacity)) { |
| 8256 ASSERT(static_cast<uint32_t>(new_capacity) > index); | 7986 ASSERT(static_cast<uint32_t>(new_capacity) > index); |
| 8257 Object* new_elements; | 7987 Object* obj; |
| 8258 MaybeObject* maybe = | 7988 { MaybeObject* maybe_obj = |
| 8259 SetFastElementsCapacityAndLength(new_capacity, index + 1); | 7989 SetFastElementsCapacityAndLength(new_capacity, index + 1); |
| 8260 if (!maybe->ToObject(&new_elements)) return maybe; | 7990 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 8261 FixedArray::cast(new_elements)->set(index, value); | 7991 } |
| 7992 FixedArray::cast(elements())->set(index, value); |
| 8262 return value; | 7993 return value; |
| 8263 } | 7994 } |
| 8264 } | 7995 } |
| 8265 | 7996 |
| 8266 // Otherwise default to slow case. | 7997 // Otherwise default to slow case. |
| 8267 MaybeObject* result = NormalizeElements(); | 7998 Object* obj; |
| 8268 if (result->IsFailure()) return result; | 7999 { MaybeObject* maybe_obj = NormalizeElements(); |
| 8269 return SetDictionaryElement(index, value, strict_mode, check_prototype); | 8000 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 8001 } |
| 8002 ASSERT(HasDictionaryElements()); |
| 8003 return SetElement(index, value, strict_mode, check_prototype); |
| 8270 } | 8004 } |
| 8271 | 8005 |
| 8272 | 8006 |
| 8273 MaybeObject* JSObject::SetDictionaryElement(uint32_t index, | |
| 8274 Object* value, | |
| 8275 StrictModeFlag strict_mode, | |
| 8276 bool check_prototype) { | |
| 8277 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | |
| 8278 Isolate* isolate = GetIsolate(); | |
| 8279 Heap* heap = isolate->heap(); | |
| 8280 | |
| 8281 // Insert element in the dictionary. | |
| 8282 FixedArray* elements = FixedArray::cast(this->elements()); | |
| 8283 bool is_arguments = | |
| 8284 (elements->map() == heap->non_strict_arguments_elements_map()); | |
| 8285 NumberDictionary* dictionary = NULL; | |
| 8286 if (is_arguments) { | |
| 8287 dictionary = NumberDictionary::cast(elements->get(1)); | |
| 8288 } else { | |
| 8289 dictionary = NumberDictionary::cast(elements); | |
| 8290 } | |
| 8291 | |
| 8292 int entry = dictionary->FindEntry(index); | |
| 8293 if (entry != NumberDictionary::kNotFound) { | |
| 8294 Object* element = dictionary->ValueAt(entry); | |
| 8295 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 8296 if (details.type() == CALLBACKS) { | |
| 8297 return SetElementWithCallback(element, index, value, this, strict_mode); | |
| 8298 } else { | |
| 8299 dictionary->UpdateMaxNumberKey(index); | |
| 8300 // If put fails in strict mode, throw an exception. | |
| 8301 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) { | |
| 8302 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | |
| 8303 Handle<Object> holder(this); | |
| 8304 Handle<Object> args[2] = { number, holder }; | |
| 8305 Handle<Object> error = | |
| 8306 isolate->factory()->NewTypeError("strict_read_only_property", | |
| 8307 HandleVector(args, 2)); | |
| 8308 return isolate->Throw(*error); | |
| 8309 } | |
| 8310 } | |
| 8311 } else { | |
| 8312 // Index not already used. Look for an accessor in the prototype chain. | |
| 8313 if (check_prototype) { | |
| 8314 bool found; | |
| 8315 MaybeObject* result = | |
| 8316 SetElementWithCallbackSetterInPrototypes( | |
| 8317 index, value, &found, strict_mode); | |
| 8318 if (found) return result; | |
| 8319 } | |
| 8320 // When we set the is_extensible flag to false we always force the | |
| 8321 // element into dictionary mode (and force them to stay there). | |
| 8322 if (!map()->is_extensible()) { | |
| 8323 if (strict_mode == kNonStrictMode) { | |
| 8324 return isolate->heap()->undefined_value(); | |
| 8325 } else { | |
| 8326 Handle<Object> number = isolate->factory()->NewNumberFromUint(index); | |
| 8327 Handle<String> name = isolate->factory()->NumberToString(number); | |
| 8328 Handle<Object> args[1] = { name }; | |
| 8329 Handle<Object> error = | |
| 8330 isolate->factory()->NewTypeError("object_not_extensible", | |
| 8331 HandleVector(args, 1)); | |
| 8332 return isolate->Throw(*error); | |
| 8333 } | |
| 8334 } | |
| 8335 Object* new_dictionary; | |
| 8336 MaybeObject* maybe = dictionary->AtNumberPut(index, value); | |
| 8337 if (!maybe->ToObject(&new_dictionary)) return maybe; | |
| 8338 if (dictionary != NumberDictionary::cast(new_dictionary)) { | |
| 8339 if (is_arguments) { | |
| 8340 elements->set(1, new_dictionary); | |
| 8341 } else { | |
| 8342 set_elements(HeapObject::cast(new_dictionary)); | |
| 8343 } | |
| 8344 dictionary = NumberDictionary::cast(new_dictionary); | |
| 8345 } | |
| 8346 } | |
| 8347 | |
| 8348 // Update the array length if this JSObject is an array. | |
| 8349 if (IsJSArray()) { | |
| 8350 MaybeObject* result = | |
| 8351 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value); | |
| 8352 if (result->IsFailure()) return result; | |
| 8353 } | |
| 8354 | |
| 8355 // Attempt to put this object back in fast case. | |
| 8356 if (ShouldConvertToFastElements()) { | |
| 8357 uint32_t new_length = 0; | |
| 8358 if (IsJSArray()) { | |
| 8359 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | |
| 8360 } else { | |
| 8361 new_length = dictionary->max_number_key() + 1; | |
| 8362 } | |
| 8363 MaybeObject* result = | |
| 8364 SetFastElementsCapacityAndLength(new_length, new_length); | |
| 8365 if (result->IsFailure()) return result; | |
| 8366 #ifdef DEBUG | |
| 8367 if (FLAG_trace_normalization) { | |
| 8368 PrintF("Object elements are fast case again:\n"); | |
| 8369 Print(); | |
| 8370 } | |
| 8371 #endif | |
| 8372 } | |
| 8373 return value; | |
| 8374 } | |
| 8375 | |
| 8376 | |
| 8377 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( | 8007 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( |
| 8378 uint32_t index, | 8008 uint32_t index, |
| 8379 Object* value, | 8009 Object* value, |
| 8380 StrictModeFlag strict_mode, | 8010 StrictModeFlag strict_mode, |
| 8381 bool check_prototype) { | 8011 bool check_prototype) { |
| 8382 ASSERT(HasFastDoubleElements()); | 8012 ASSERT(HasFastDoubleElements()); |
| 8383 | 8013 |
| 8384 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | 8014 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8385 uint32_t elms_length = static_cast<uint32_t>(elms->length()); | 8015 uint32_t elms_length = static_cast<uint32_t>(elms->length()); |
| 8386 | 8016 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8497 } | 8127 } |
| 8498 | 8128 |
| 8499 | 8129 |
| 8500 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, | 8130 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
| 8501 Object* value, | 8131 Object* value, |
| 8502 StrictModeFlag strict_mode, | 8132 StrictModeFlag strict_mode, |
| 8503 bool check_prototype) { | 8133 bool check_prototype) { |
| 8504 Isolate* isolate = GetIsolate(); | 8134 Isolate* isolate = GetIsolate(); |
| 8505 switch (GetElementsKind()) { | 8135 switch (GetElementsKind()) { |
| 8506 case FAST_ELEMENTS: | 8136 case FAST_ELEMENTS: |
| 8137 // Fast case. |
| 8507 return SetFastElement(index, value, strict_mode, check_prototype); | 8138 return SetFastElement(index, value, strict_mode, check_prototype); |
| 8508 case FAST_DOUBLE_ELEMENTS: | 8139 case FAST_DOUBLE_ELEMENTS: |
| 8509 return SetFastDoubleElement(index, value, strict_mode, check_prototype); | 8140 return SetFastDoubleElement(index, value, strict_mode, check_prototype); |
| 8510 case EXTERNAL_PIXEL_ELEMENTS: { | 8141 case EXTERNAL_PIXEL_ELEMENTS: { |
| 8511 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | 8142 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
| 8512 return pixels->SetValue(index, value); | 8143 return pixels->SetValue(index, value); |
| 8513 } | 8144 } |
| 8514 case EXTERNAL_BYTE_ELEMENTS: { | 8145 case EXTERNAL_BYTE_ELEMENTS: { |
| 8515 ExternalByteArray* array = ExternalByteArray::cast(elements()); | 8146 ExternalByteArray* array = ExternalByteArray::cast(elements()); |
| 8516 return array->SetValue(index, value); | 8147 return array->SetValue(index, value); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 8539 return array->SetValue(index, value); | 8170 return array->SetValue(index, value); |
| 8540 } | 8171 } |
| 8541 case EXTERNAL_FLOAT_ELEMENTS: { | 8172 case EXTERNAL_FLOAT_ELEMENTS: { |
| 8542 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); | 8173 ExternalFloatArray* array = ExternalFloatArray::cast(elements()); |
| 8543 return array->SetValue(index, value); | 8174 return array->SetValue(index, value); |
| 8544 } | 8175 } |
| 8545 case EXTERNAL_DOUBLE_ELEMENTS: { | 8176 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 8546 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); | 8177 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); |
| 8547 return array->SetValue(index, value); | 8178 return array->SetValue(index, value); |
| 8548 } | 8179 } |
| 8549 case DICTIONARY_ELEMENTS: | 8180 case DICTIONARY_ELEMENTS: { |
| 8550 return SetDictionaryElement(index, value, strict_mode, check_prototype); | 8181 // Insert element in the dictionary. |
| 8551 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 8182 FixedArray* elms = FixedArray::cast(elements()); |
| 8552 FixedArray* parameter_map = FixedArray::cast(elements()); | 8183 NumberDictionary* dictionary = NumberDictionary::cast(elms); |
| 8553 uint32_t length = parameter_map->length(); | 8184 |
| 8554 Object* probe = | 8185 int entry = dictionary->FindEntry(index); |
| 8555 (index + 2 < length) ? parameter_map->get(index + 2) : NULL; | 8186 if (entry != NumberDictionary::kNotFound) { |
| 8556 if (probe != NULL && !probe->IsTheHole()) { | 8187 Object* element = dictionary->ValueAt(entry); |
| 8557 Context* context = Context::cast(parameter_map->get(0)); | 8188 PropertyDetails details = dictionary->DetailsAt(entry); |
| 8558 int context_index = Smi::cast(probe)->value(); | 8189 if (details.type() == CALLBACKS) { |
| 8559 ASSERT(!context->get(context_index)->IsTheHole()); | 8190 return SetElementWithCallback(element, |
| 8560 context->set(context_index, value); | 8191 index, |
| 8561 return value; | 8192 value, |
| 8193 this, |
| 8194 strict_mode); |
| 8195 } else { |
| 8196 dictionary->UpdateMaxNumberKey(index); |
| 8197 // If put fails instrict mode, throw exception. |
| 8198 if (!dictionary->ValueAtPut(entry, value) && |
| 8199 strict_mode == kStrictMode) { |
| 8200 Handle<Object> holder(this); |
| 8201 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); |
| 8202 Handle<Object> args[2] = { number, holder }; |
| 8203 return isolate->Throw( |
| 8204 *isolate->factory()->NewTypeError("strict_read_only_property", |
| 8205 HandleVector(args, 2))); |
| 8206 } |
| 8207 } |
| 8562 } else { | 8208 } else { |
| 8563 // Object is not mapped, defer to the arguments. | 8209 // Index not already used. Look for an accessor in the prototype chain. |
| 8564 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | 8210 if (check_prototype) { |
| 8565 if (arguments->IsDictionary()) { | 8211 bool found; |
| 8566 return SetDictionaryElement(index, value, strict_mode, | 8212 MaybeObject* result = |
| 8567 check_prototype); | 8213 // Strict mode not needed. No-setter case already handled. |
| 8568 } else { | 8214 SetElementWithCallbackSetterInPrototypes(index, |
| 8569 return SetFastElement(index, value, strict_mode, check_prototype); | 8215 value, |
| 8216 &found, |
| 8217 strict_mode); |
| 8218 if (found) return result; |
| 8219 } |
| 8220 // When we set the is_extensible flag to false we always force |
| 8221 // the element into dictionary mode (and force them to stay there). |
| 8222 if (!map()->is_extensible()) { |
| 8223 if (strict_mode == kNonStrictMode) { |
| 8224 return isolate->heap()->undefined_value(); |
| 8225 } else { |
| 8226 Handle<Object> number(isolate->factory()->NewNumberFromUint(index)); |
| 8227 Handle<String> index_string( |
| 8228 isolate->factory()->NumberToString(number)); |
| 8229 Handle<Object> args[1] = { index_string }; |
| 8230 return isolate->Throw( |
| 8231 *isolate->factory()->NewTypeError("object_not_extensible", |
| 8232 HandleVector(args, 1))); |
| 8233 } |
| 8234 } |
| 8235 Object* result; |
| 8236 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value); |
| 8237 if (!maybe_result->ToObject(&result)) return maybe_result; |
| 8238 } |
| 8239 if (elms != FixedArray::cast(result)) { |
| 8240 set_elements(FixedArray::cast(result)); |
| 8570 } | 8241 } |
| 8571 } | 8242 } |
| 8243 |
| 8244 // Update the array length if this JSObject is an array. |
| 8245 if (IsJSArray()) { |
| 8246 JSArray* array = JSArray::cast(this); |
| 8247 Object* return_value; |
| 8248 { MaybeObject* maybe_return_value = |
| 8249 array->JSArrayUpdateLengthFromIndex(index, value); |
| 8250 if (!maybe_return_value->ToObject(&return_value)) { |
| 8251 return maybe_return_value; |
| 8252 } |
| 8253 } |
| 8254 } |
| 8255 |
| 8256 // Attempt to put this object back in fast case. |
| 8257 if (ShouldConvertToFastElements()) { |
| 8258 uint32_t new_length = 0; |
| 8259 if (IsJSArray()) { |
| 8260 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
| 8261 } else { |
| 8262 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
| 8263 } |
| 8264 if (ShouldConvertToFastDoubleElements()) { |
| 8265 Object* obj; |
| 8266 { MaybeObject* maybe_obj = |
| 8267 SetFastDoubleElementsCapacityAndLength(new_length, new_length); |
| 8268 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 8269 } |
| 8270 #ifdef DEBUG |
| 8271 if (FLAG_trace_normalization) { |
| 8272 PrintF("Object elements are fast double case again:\n"); |
| 8273 Print(); |
| 8274 } |
| 8275 #endif |
| 8276 } else { |
| 8277 Object* obj; |
| 8278 { MaybeObject* maybe_obj = |
| 8279 SetFastElementsCapacityAndLength(new_length, new_length); |
| 8280 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 8281 } |
| 8282 #ifdef DEBUG |
| 8283 if (FLAG_trace_normalization) { |
| 8284 PrintF("Object elements are fast case again:\n"); |
| 8285 Print(); |
| 8286 } |
| 8287 #endif |
| 8288 } |
| 8289 } |
| 8290 |
| 8291 return value; |
| 8572 } | 8292 } |
| 8573 } | 8293 } |
| 8574 // All possible cases have been handled above. Add a return to avoid the | 8294 // All possible cases have been handled above. Add a return to avoid the |
| 8575 // complaints from the compiler. | 8295 // complaints from the compiler. |
| 8576 UNREACHABLE(); | 8296 UNREACHABLE(); |
| 8577 return isolate->heap()->null_value(); | 8297 return isolate->heap()->null_value(); |
| 8578 } | 8298 } |
| 8579 | 8299 |
| 8580 | 8300 |
| 8581 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, | 8301 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8642 if (details.type() == CALLBACKS) { | 8362 if (details.type() == CALLBACKS) { |
| 8643 return GetElementWithCallback(receiver, | 8363 return GetElementWithCallback(receiver, |
| 8644 element, | 8364 element, |
| 8645 index, | 8365 index, |
| 8646 this); | 8366 this); |
| 8647 } | 8367 } |
| 8648 return element; | 8368 return element; |
| 8649 } | 8369 } |
| 8650 break; | 8370 break; |
| 8651 } | 8371 } |
| 8652 case NON_STRICT_ARGUMENTS_ELEMENTS: | 8372 default: |
| 8653 UNIMPLEMENTED(); | 8373 UNREACHABLE(); |
| 8654 break; | 8374 break; |
| 8655 } | 8375 } |
| 8656 | 8376 |
| 8657 // Continue searching via the prototype chain. | 8377 // Continue searching via the prototype chain. |
| 8658 Object* pt = GetPrototype(); | 8378 Object* pt = GetPrototype(); |
| 8659 if (pt->IsNull()) return GetHeap()->undefined_value(); | 8379 if (pt->IsNull()) return GetHeap()->undefined_value(); |
| 8660 return pt->GetElementWithReceiver(receiver, index); | 8380 return pt->GetElementWithReceiver(receiver, index); |
| 8661 } | 8381 } |
| 8662 | 8382 |
| 8663 | 8383 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8755 if (details.type() == CALLBACKS) { | 8475 if (details.type() == CALLBACKS) { |
| 8756 return GetElementWithCallback(receiver, | 8476 return GetElementWithCallback(receiver, |
| 8757 element, | 8477 element, |
| 8758 index, | 8478 index, |
| 8759 this); | 8479 this); |
| 8760 } | 8480 } |
| 8761 return element; | 8481 return element; |
| 8762 } | 8482 } |
| 8763 break; | 8483 break; |
| 8764 } | 8484 } |
| 8765 case NON_STRICT_ARGUMENTS_ELEMENTS: { | |
| 8766 FixedArray* parameter_map = FixedArray::cast(elements()); | |
| 8767 uint32_t length = parameter_map->length(); | |
| 8768 Object* probe = | |
| 8769 (index + 2 < length) ? parameter_map->get(index + 2) : NULL; | |
| 8770 if (probe != NULL && !probe->IsTheHole()) { | |
| 8771 Context* context = Context::cast(parameter_map->get(0)); | |
| 8772 int context_index = Smi::cast(probe)->value(); | |
| 8773 ASSERT(!context->get(context_index)->IsTheHole()); | |
| 8774 return context->get(context_index); | |
| 8775 } else { | |
| 8776 // Object is not mapped, defer to the arguments. | |
| 8777 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 8778 if (arguments->IsDictionary()) { | |
| 8779 NumberDictionary* dictionary = NumberDictionary::cast(arguments); | |
| 8780 int entry = dictionary->FindEntry(index); | |
| 8781 if (entry != NumberDictionary::kNotFound) { | |
| 8782 Object* element = dictionary->ValueAt(entry); | |
| 8783 PropertyDetails details = dictionary->DetailsAt(entry); | |
| 8784 if (details.type() == CALLBACKS) { | |
| 8785 return GetElementWithCallback(receiver, | |
| 8786 element, | |
| 8787 index, | |
| 8788 this); | |
| 8789 } | |
| 8790 return element; | |
| 8791 } | |
| 8792 } else if (index < static_cast<uint32_t>(arguments->length())) { | |
| 8793 Object* value = arguments->get(index); | |
| 8794 if (!value->IsTheHole()) return value; | |
| 8795 } | |
| 8796 } | |
| 8797 break; | |
| 8798 } | |
| 8799 } | 8485 } |
| 8800 | 8486 |
| 8801 Object* pt = GetPrototype(); | 8487 Object* pt = GetPrototype(); |
| 8802 Heap* heap = GetHeap(); | 8488 Heap* heap = GetHeap(); |
| 8803 if (pt == heap->null_value()) return heap->undefined_value(); | 8489 if (pt == heap->null_value()) return heap->undefined_value(); |
| 8804 return pt->GetElementWithReceiver(receiver, index); | 8490 return pt->GetElementWithReceiver(receiver, index); |
| 8805 } | 8491 } |
| 8806 | 8492 |
| 8807 | 8493 |
| 8808 MaybeObject* JSObject::GetExternalElement(uint32_t index) { | 8494 MaybeObject* JSObject::GetExternalElement(uint32_t index) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8882 double value = array->get(index); | 8568 double value = array->get(index); |
| 8883 return GetHeap()->AllocateHeapNumber(value); | 8569 return GetHeap()->AllocateHeapNumber(value); |
| 8884 } | 8570 } |
| 8885 break; | 8571 break; |
| 8886 } | 8572 } |
| 8887 case FAST_DOUBLE_ELEMENTS: | 8573 case FAST_DOUBLE_ELEMENTS: |
| 8888 case FAST_ELEMENTS: | 8574 case FAST_ELEMENTS: |
| 8889 case DICTIONARY_ELEMENTS: | 8575 case DICTIONARY_ELEMENTS: |
| 8890 UNREACHABLE(); | 8576 UNREACHABLE(); |
| 8891 break; | 8577 break; |
| 8892 case NON_STRICT_ARGUMENTS_ELEMENTS: | |
| 8893 UNIMPLEMENTED(); | |
| 8894 break; | |
| 8895 } | 8578 } |
| 8896 return GetHeap()->undefined_value(); | 8579 return GetHeap()->undefined_value(); |
| 8897 } | 8580 } |
| 8898 | 8581 |
| 8899 | 8582 |
| 8900 bool JSObject::HasDenseElements() { | 8583 bool JSObject::HasDenseElements() { |
| 8901 int capacity = 0; | 8584 int capacity = 0; |
| 8902 int number_of_elements = 0; | 8585 int number_of_elements = 0; |
| 8903 | 8586 |
| 8904 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 8905 switch (GetElementsKind()) { | 8587 switch (GetElementsKind()) { |
| 8906 case NON_STRICT_ARGUMENTS_ELEMENTS: | 8588 case FAST_ELEMENTS: { |
| 8907 backing_store = FixedArray::cast(backing_store->get(1)); | 8589 FixedArray* elms = FixedArray::cast(elements()); |
| 8908 if (backing_store->IsDictionary()) { | 8590 capacity = elms->length(); |
| 8909 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | 8591 for (int i = 0; i < capacity; i++) { |
| 8910 capacity = dictionary->Capacity(); | 8592 if (!elms->get(i)->IsTheHole()) number_of_elements++; |
| 8911 number_of_elements = dictionary->NumberOfElements(); | |
| 8912 break; | |
| 8913 } | 8593 } |
| 8914 // Fall through. | |
| 8915 case FAST_ELEMENTS: | |
| 8916 capacity = backing_store->length(); | |
| 8917 for (int i = 0; i < capacity; ++i) { | |
| 8918 if (!backing_store->get(i)->IsTheHole()) ++number_of_elements; | |
| 8919 } | |
| 8920 break; | |
| 8921 case DICTIONARY_ELEMENTS: { | |
| 8922 NumberDictionary* dictionary = NumberDictionary::cast(backing_store); | |
| 8923 capacity = dictionary->Capacity(); | |
| 8924 number_of_elements = dictionary->NumberOfElements(); | |
| 8925 break; | 8594 break; |
| 8926 } | 8595 } |
| 8927 case FAST_DOUBLE_ELEMENTS: { | 8596 case FAST_DOUBLE_ELEMENTS: { |
| 8928 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | 8597 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); |
| 8929 capacity = elms->length(); | 8598 capacity = elms->length(); |
| 8930 for (int i = 0; i < capacity; i++) { | 8599 for (int i = 0; i < capacity; i++) { |
| 8931 if (!elms->is_the_hole(i)) number_of_elements++; | 8600 if (!elms->is_the_hole(i)) number_of_elements++; |
| 8932 } | 8601 } |
| 8933 break; | 8602 break; |
| 8934 } | 8603 } |
| 8935 case EXTERNAL_PIXEL_ELEMENTS: | 8604 case EXTERNAL_PIXEL_ELEMENTS: |
| 8936 case EXTERNAL_BYTE_ELEMENTS: | 8605 case EXTERNAL_BYTE_ELEMENTS: |
| 8937 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8606 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 8938 case EXTERNAL_SHORT_ELEMENTS: | 8607 case EXTERNAL_SHORT_ELEMENTS: |
| 8939 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8608 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 8940 case EXTERNAL_INT_ELEMENTS: | 8609 case EXTERNAL_INT_ELEMENTS: |
| 8941 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8610 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 8942 case EXTERNAL_FLOAT_ELEMENTS: | 8611 case EXTERNAL_FLOAT_ELEMENTS: |
| 8943 case EXTERNAL_DOUBLE_ELEMENTS: { | 8612 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 8944 return true; | 8613 return true; |
| 8945 } | 8614 } |
| 8615 case DICTIONARY_ELEMENTS: { |
| 8616 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| 8617 capacity = dictionary->Capacity(); |
| 8618 number_of_elements = dictionary->NumberOfElements(); |
| 8619 break; |
| 8620 } |
| 8621 default: |
| 8622 UNREACHABLE(); |
| 8623 break; |
| 8946 } | 8624 } |
| 8947 return (capacity == 0) || (number_of_elements > (capacity / 2)); | 8625 |
| 8626 if (capacity == 0) return true; |
| 8627 return (number_of_elements > (capacity / 2)); |
| 8948 } | 8628 } |
| 8949 | 8629 |
| 8950 | 8630 |
| 8951 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 8631 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { |
| 8952 // Keep the array in fast case if the current backing storage is | 8632 // Keep the array in fast case if the current backing storage is |
| 8953 // almost filled and if the new capacity is no more than twice the | 8633 // almost filled and if the new capacity is no more than twice the |
| 8954 // old capacity. | 8634 // old capacity. |
| 8955 int elements_length = 0; | 8635 int elements_length = 0; |
| 8956 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) { | 8636 if (HasFastElements()) { |
| 8957 FixedArray* backing_store = FixedArray::cast(elements()); | |
| 8958 elements_length = FixedArray::cast(backing_store->get(1))->length(); | |
| 8959 } else if (HasFastElements()) { | |
| 8960 elements_length = FixedArray::cast(elements())->length(); | 8637 elements_length = FixedArray::cast(elements())->length(); |
| 8961 } else if (HasFastDoubleElements()) { | 8638 } else if (HasFastDoubleElements()) { |
| 8962 elements_length = FixedDoubleArray::cast(elements())->length(); | 8639 elements_length = FixedDoubleArray::cast(elements())->length(); |
| 8963 } else { | 8640 } else { |
| 8964 UNREACHABLE(); | 8641 UNREACHABLE(); |
| 8965 } | 8642 } |
| 8966 return !HasDenseElements() || ((new_capacity / 2) > elements_length); | 8643 return !HasDenseElements() || ((new_capacity / 2) > elements_length); |
| 8967 } | 8644 } |
| 8968 | 8645 |
| 8969 | 8646 |
| 8970 bool JSObject::ShouldConvertToFastElements() { | 8647 bool JSObject::ShouldConvertToFastElements() { |
| 8971 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 8648 ASSERT(HasDictionaryElements()); |
| 8649 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
| 8972 // If the elements are sparse, we should not go back to fast case. | 8650 // If the elements are sparse, we should not go back to fast case. |
| 8973 if (!HasDenseElements()) return false; | 8651 if (!HasDenseElements()) return false; |
| 8652 // If an element has been added at a very high index in the elements |
| 8653 // dictionary, we cannot go back to fast case. |
| 8654 if (dictionary->requires_slow_elements()) return false; |
| 8974 // An object requiring access checks is never allowed to have fast | 8655 // An object requiring access checks is never allowed to have fast |
| 8975 // elements. If it had fast elements we would skip security checks. | 8656 // elements. If it had fast elements we would skip security checks. |
| 8976 if (IsAccessCheckNeeded()) return false; | 8657 if (IsAccessCheckNeeded()) return false; |
| 8977 | |
| 8978 FixedArray* elements = FixedArray::cast(this->elements()); | |
| 8979 NumberDictionary* dictionary = NULL; | |
| 8980 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) { | |
| 8981 dictionary = NumberDictionary::cast(elements->get(1)); | |
| 8982 } else { | |
| 8983 dictionary = NumberDictionary::cast(elements); | |
| 8984 } | |
| 8985 // If an element has been added at a very high index in the elements | |
| 8986 // dictionary, we cannot go back to fast case. | |
| 8987 if (dictionary->requires_slow_elements()) return false; | |
| 8988 // If the dictionary backing storage takes up roughly half as much | 8658 // If the dictionary backing storage takes up roughly half as much |
| 8989 // space as a fast-case backing storage would the array should have | 8659 // space as a fast-case backing storage would the array should have |
| 8990 // fast elements. | 8660 // fast elements. |
| 8991 uint32_t length = 0; | 8661 uint32_t length = 0; |
| 8992 if (IsJSArray()) { | 8662 if (IsJSArray()) { |
| 8993 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | 8663 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
| 8994 } else { | 8664 } else { |
| 8995 length = dictionary->max_number_key(); | 8665 length = dictionary->max_number_key(); |
| 8996 } | 8666 } |
| 8997 return static_cast<uint32_t>(dictionary->Capacity()) >= | 8667 return static_cast<uint32_t>(dictionary->Capacity()) >= |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9197 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8867 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 9198 case EXTERNAL_SHORT_ELEMENTS: | 8868 case EXTERNAL_SHORT_ELEMENTS: |
| 9199 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8869 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 9200 case EXTERNAL_INT_ELEMENTS: | 8870 case EXTERNAL_INT_ELEMENTS: |
| 9201 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8871 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 9202 case EXTERNAL_FLOAT_ELEMENTS: | 8872 case EXTERNAL_FLOAT_ELEMENTS: |
| 9203 case EXTERNAL_DOUBLE_ELEMENTS: { | 8873 case EXTERNAL_DOUBLE_ELEMENTS: { |
| 9204 ExternalArray* array = ExternalArray::cast(elements()); | 8874 ExternalArray* array = ExternalArray::cast(elements()); |
| 9205 return index < static_cast<uint32_t>(array->length()); | 8875 return index < static_cast<uint32_t>(array->length()); |
| 9206 } | 8876 } |
| 9207 case FAST_DOUBLE_ELEMENTS: | |
| 9208 UNREACHABLE(); | |
| 9209 break; | |
| 9210 case DICTIONARY_ELEMENTS: { | 8877 case DICTIONARY_ELEMENTS: { |
| 9211 return element_dictionary()->FindEntry(index) | 8878 return element_dictionary()->FindEntry(index) |
| 9212 != NumberDictionary::kNotFound; | 8879 != NumberDictionary::kNotFound; |
| 9213 } | 8880 } |
| 9214 case NON_STRICT_ARGUMENTS_ELEMENTS: | 8881 default: |
| 9215 UNIMPLEMENTED(); | 8882 UNREACHABLE(); |
| 9216 break; | 8883 break; |
| 9217 } | 8884 } |
| 9218 // All possibilities have been handled above already. | 8885 // All possibilities have been handled above already. |
| 9219 UNREACHABLE(); | 8886 UNREACHABLE(); |
| 9220 return GetHeap()->null_value(); | 8887 return GetHeap()->null_value(); |
| 9221 } | 8888 } |
| 9222 | 8889 |
| 9223 | 8890 |
| 9224 bool JSObject::HasRealNamedCallbackProperty(String* key) { | 8891 bool JSObject::HasRealNamedCallbackProperty(String* key) { |
| 9225 // Check access rights if needed. | 8892 // Check access rights if needed. |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9449 int length = ExternalArray::cast(elements())->length(); | 9116 int length = ExternalArray::cast(elements())->length(); |
| 9450 while (counter < length) { | 9117 while (counter < length) { |
| 9451 if (storage != NULL) { | 9118 if (storage != NULL) { |
| 9452 storage->set(counter, Smi::FromInt(counter)); | 9119 storage->set(counter, Smi::FromInt(counter)); |
| 9453 } | 9120 } |
| 9454 counter++; | 9121 counter++; |
| 9455 } | 9122 } |
| 9456 ASSERT(!storage || storage->length() >= counter); | 9123 ASSERT(!storage || storage->length() >= counter); |
| 9457 break; | 9124 break; |
| 9458 } | 9125 } |
| 9459 case FAST_DOUBLE_ELEMENTS: | |
| 9460 UNREACHABLE(); | |
| 9461 break; | |
| 9462 case DICTIONARY_ELEMENTS: { | 9126 case DICTIONARY_ELEMENTS: { |
| 9463 if (storage != NULL) { | 9127 if (storage != NULL) { |
| 9464 element_dictionary()->CopyKeysTo(storage, filter); | 9128 element_dictionary()->CopyKeysTo(storage, filter); |
| 9465 } | 9129 } |
| 9466 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter); | 9130 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); |
| 9467 break; | 9131 break; |
| 9468 } | 9132 } |
| 9469 case NON_STRICT_ARGUMENTS_ELEMENTS: { | 9133 default: |
| 9470 FixedArray* parameter_map = FixedArray::cast(elements()); | 9134 UNREACHABLE(); |
| 9471 int length = parameter_map->length(); | |
| 9472 for (int i = 2; i < length; ++i) { | |
| 9473 if (!parameter_map->get(i)->IsTheHole()) { | |
| 9474 if (storage != NULL) storage->set(i - 2, Smi::FromInt(i - 2)); | |
| 9475 ++counter; | |
| 9476 } | |
| 9477 } | |
| 9478 FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); | |
| 9479 if (arguments->IsDictionary()) { | |
| 9480 NumberDictionary* dictionary = NumberDictionary::cast(arguments); | |
| 9481 if (storage != NULL) dictionary->CopyKeysTo(storage, filter); | |
| 9482 counter += dictionary->NumberOfElementsFilterAttributes(filter); | |
| 9483 } else { | |
| 9484 int length = arguments->length(); | |
| 9485 for (int i = 0; i < length; ++i) { | |
| 9486 if (!arguments->get(i)->IsTheHole()) { | |
| 9487 if (storage != NULL) storage->set(i, Smi::FromInt(i)); | |
| 9488 ++counter; | |
| 9489 } | |
| 9490 } | |
| 9491 } | |
| 9492 break; | 9135 break; |
| 9493 } | |
| 9494 } | 9136 } |
| 9495 | 9137 |
| 9496 if (this->IsJSValue()) { | 9138 if (this->IsJSValue()) { |
| 9497 Object* val = JSValue::cast(this)->value(); | 9139 Object* val = JSValue::cast(this)->value(); |
| 9498 if (val->IsString()) { | 9140 if (val->IsString()) { |
| 9499 String* str = String::cast(val); | 9141 String* str = String::cast(val); |
| 9500 if (storage) { | 9142 if (storage) { |
| 9501 for (int i = 0; i < str->length(); i++) { | 9143 for (int i = 0; i < str->length(); i++) { |
| 9502 storage->set(counter + i, Smi::FromInt(i)); | 9144 storage->set(counter + i, Smi::FromInt(i)); |
| 9503 } | 9145 } |
| (...skipping 2060 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11564 if (break_point_objects()->IsUndefined()) return 0; | 11206 if (break_point_objects()->IsUndefined()) return 0; |
| 11565 // Single beak point. | 11207 // Single beak point. |
| 11566 if (!break_point_objects()->IsFixedArray()) return 1; | 11208 if (!break_point_objects()->IsFixedArray()) return 1; |
| 11567 // Multiple break points. | 11209 // Multiple break points. |
| 11568 return FixedArray::cast(break_point_objects())->length(); | 11210 return FixedArray::cast(break_point_objects())->length(); |
| 11569 } | 11211 } |
| 11570 #endif | 11212 #endif |
| 11571 | 11213 |
| 11572 | 11214 |
| 11573 } } // namespace v8::internal | 11215 } } // namespace v8::internal |
| OLD | NEW |