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