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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 #endif | 51 #endif |
52 | 52 |
53 namespace v8 { | 53 namespace v8 { |
54 namespace internal { | 54 namespace internal { |
55 | 55 |
56 // Getters and setters are stored in a fixed array property. These are | 56 // Getters and setters are stored in a fixed array property. These are |
57 // constants for their indices. | 57 // constants for their indices. |
58 const int kGetterIndex = 0; | 58 const int kGetterIndex = 0; |
59 const int kSetterIndex = 1; | 59 const int kSetterIndex = 1; |
60 | 60 |
61 uint64_t FixedDoubleArray::kHoleNanInt64 = -1; | |
62 uint64_t FixedDoubleArray::kCanonicalNonHoleNanLower32 = 0x7FF00000; | |
63 uint64_t FixedDoubleArray::kCanonicalNonHoleNanInt64 = | |
64 kCanonicalNonHoleNanLower32 << 32; | |
61 | 65 |
62 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, | 66 MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor, |
63 Object* value) { | 67 Object* value) { |
64 Object* result; | 68 Object* result; |
65 { MaybeObject* maybe_result = | 69 { MaybeObject* maybe_result = |
66 constructor->GetHeap()->AllocateJSObject(constructor); | 70 constructor->GetHeap()->AllocateJSObject(constructor); |
67 if (!maybe_result->ToObject(&result)) return maybe_result; | 71 if (!maybe_result->ToObject(&result)) return maybe_result; |
68 } | 72 } |
69 JSValue::cast(result)->set_value(value); | 73 JSValue::cast(result)->set_value(value); |
70 return result; | 74 return result; |
(...skipping 1100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1171 } | 1175 } |
1172 break; | 1176 break; |
1173 } | 1177 } |
1174 return; | 1178 return; |
1175 } | 1179 } |
1176 | 1180 |
1177 switch (type) { | 1181 switch (type) { |
1178 case FIXED_ARRAY_TYPE: | 1182 case FIXED_ARRAY_TYPE: |
1179 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); | 1183 FixedArray::BodyDescriptor::IterateBody(this, object_size, v); |
1180 break; | 1184 break; |
1185 case FIXED_DOUBLE_ARRAY_TYPE: | |
1186 break; | |
1181 case JS_OBJECT_TYPE: | 1187 case JS_OBJECT_TYPE: |
1182 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: | 1188 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: |
1183 case JS_VALUE_TYPE: | 1189 case JS_VALUE_TYPE: |
1184 case JS_ARRAY_TYPE: | 1190 case JS_ARRAY_TYPE: |
1185 case JS_REGEXP_TYPE: | 1191 case JS_REGEXP_TYPE: |
1186 case JS_GLOBAL_PROXY_TYPE: | 1192 case JS_GLOBAL_PROXY_TYPE: |
1187 case JS_GLOBAL_OBJECT_TYPE: | 1193 case JS_GLOBAL_OBJECT_TYPE: |
1188 case JS_BUILTINS_OBJECT_TYPE: | 1194 case JS_BUILTINS_OBJECT_TYPE: |
1189 case JS_MESSAGE_OBJECT_TYPE: | 1195 case JS_MESSAGE_OBJECT_TYPE: |
1190 JSObject::BodyDescriptor::IterateBody(this, object_size, v); | 1196 JSObject::BodyDescriptor::IterateBody(this, object_size, v); |
(...skipping 1602 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2793 ASSERT(!IsGlobalObject()); | 2799 ASSERT(!IsGlobalObject()); |
2794 return property_dictionary()-> | 2800 return property_dictionary()-> |
2795 TransformPropertiesToFastFor(this, unused_property_fields); | 2801 TransformPropertiesToFastFor(this, unused_property_fields); |
2796 } | 2802 } |
2797 | 2803 |
2798 | 2804 |
2799 MaybeObject* JSObject::NormalizeElements() { | 2805 MaybeObject* JSObject::NormalizeElements() { |
2800 ASSERT(!HasExternalArrayElements()); | 2806 ASSERT(!HasExternalArrayElements()); |
2801 if (HasDictionaryElements()) return this; | 2807 if (HasDictionaryElements()) return this; |
2802 Map* old_map = map(); | 2808 Map* old_map = map(); |
2803 ASSERT(old_map->has_fast_elements()); | 2809 ASSERT(old_map->has_fast_elements() || old_map->has_fast_double_elements()); |
2804 | 2810 |
2805 Object* obj; | 2811 Object* obj; |
2806 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); | 2812 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap(); |
2807 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2813 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
2808 } | 2814 } |
2809 Map* new_map = Map::cast(obj); | 2815 Map* new_map = Map::cast(obj); |
2810 | 2816 |
2811 // Get number of entries. | 2817 // Get number of entries. |
2812 FixedArray* array = FixedArray::cast(elements()); | 2818 FixedArrayBase* array = FixedArrayBase::cast(elements()); |
2813 | 2819 |
2814 // Compute the effective length. | 2820 // Compute the effective length. |
2815 int length = IsJSArray() ? | 2821 int length = IsJSArray() ? |
2816 Smi::cast(JSArray::cast(this)->length())->value() : | 2822 Smi::cast(JSArray::cast(this)->length())->value() : |
2817 array->length(); | 2823 array->length(); |
2818 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length); | 2824 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length); |
2819 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2825 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
2820 } | 2826 } |
2827 bool has_double_elements = old_map->has_fast_double_elements(); | |
2821 NumberDictionary* dictionary = NumberDictionary::cast(obj); | 2828 NumberDictionary* dictionary = NumberDictionary::cast(obj); |
2822 // Copy entries. | 2829 // Copy entries. |
2823 for (int i = 0; i < length; i++) { | 2830 for (int i = 0; i < length; i++) { |
2824 Object* value = array->get(i); | 2831 Object* value = NULL; |
2832 if (has_double_elements) { | |
2833 FixedDoubleArray* double_array = FixedDoubleArray::cast(array); | |
2834 if (double_array->is_the_hole(i)) { | |
2835 value = GetIsolate()->heap()->the_hole_value(); | |
2836 } else { | |
2837 // Objects must be allocated in the old object space, since the | |
2838 // overall number of HeapNumbers needed for the conversion might | |
2839 // exceed the capacity of new space, and we would fail repeatedly | |
2840 // trying to convert the FixedDoubleArray. | |
2841 MaybeObject* maybe_value_object = | |
2842 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED); | |
2843 if (!maybe_value_object->ToObject(&value)) return maybe_value_object; | |
2844 } | |
2845 } else { | |
2846 ASSERT(old_map->has_fast_elements()); | |
2847 FixedArray* fixed_array = FixedArray::cast(array); | |
2848 value = fixed_array->get(i); | |
2849 } | |
2850 PropertyDetails details = PropertyDetails(NONE, NORMAL); | |
2851 ASSERT(value != NULL); | |
2825 if (!value->IsTheHole()) { | 2852 if (!value->IsTheHole()) { |
2826 PropertyDetails details = PropertyDetails(NONE, NORMAL); | |
2827 Object* result; | 2853 Object* result; |
2828 { MaybeObject* maybe_result = | 2854 MaybeObject* maybe_result = |
2829 dictionary->AddNumberEntry(i, array->get(i), details); | 2855 dictionary->AddNumberEntry(i, value, details); |
2830 if (!maybe_result->ToObject(&result)) return maybe_result; | 2856 if (!maybe_result->ToObject(&result)) return maybe_result; |
2831 } | |
2832 dictionary = NumberDictionary::cast(result); | 2857 dictionary = NumberDictionary::cast(result); |
2833 } | 2858 } |
2834 } | 2859 } |
2835 // Switch to using the dictionary as the backing storage for | 2860 // Switch to using the dictionary as the backing storage for |
2836 // elements. Set the new map first to satify the elements type | 2861 // elements. Set the new map first to satify the elements type |
2837 // assert in set_elements(). | 2862 // assert in set_elements(). |
2838 set_map(new_map); | 2863 set_map(new_map); |
2839 set_elements(dictionary); | 2864 set_elements(dictionary); |
2840 | 2865 |
2841 new_map->heap()->isolate()->counters()->elements_to_dictionary()-> | 2866 new_map->heap()->isolate()->counters()->elements_to_dictionary()-> |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2991 } | 3016 } |
2992 return DeleteElementWithInterceptor(index); | 3017 return DeleteElementWithInterceptor(index); |
2993 } | 3018 } |
2994 | 3019 |
2995 switch (GetElementsKind()) { | 3020 switch (GetElementsKind()) { |
2996 case FAST_ELEMENTS: { | 3021 case FAST_ELEMENTS: { |
2997 Object* obj; | 3022 Object* obj; |
2998 { MaybeObject* maybe_obj = EnsureWritableFastElements(); | 3023 { MaybeObject* maybe_obj = EnsureWritableFastElements(); |
2999 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 3024 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
3000 } | 3025 } |
3001 uint32_t length = IsJSArray() ? | 3026 int length = IsJSArray() |
3002 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : | 3027 ? Smi::cast(JSArray::cast(this)->length())->value() |
3003 static_cast<uint32_t>(FixedArray::cast(elements())->length()); | 3028 : FixedArray::cast(elements())->length(); |
3004 if (index < length) { | 3029 if (index < static_cast<uint32_t>(length)) { |
3005 FixedArray::cast(elements())->set_the_hole(index); | 3030 FixedArray::cast(elements())->set_the_hole(index); |
3006 } | 3031 } |
3007 break; | 3032 break; |
3008 } | 3033 } |
3034 case FAST_DOUBLE_ELEMENTS: { | |
3035 int length = IsJSArray() | |
3036 ? Smi::cast(JSArray::cast(this)->length())->value() | |
3037 : FixedArray::cast(elements())->length(); | |
3038 if (index < static_cast<uint32_t>(length)) { | |
3039 FixedDoubleArray::cast(elements())->set_the_hole(index); | |
3040 } | |
3041 break; | |
3042 } | |
3009 case EXTERNAL_PIXEL_ELEMENTS: | 3043 case EXTERNAL_PIXEL_ELEMENTS: |
3010 case EXTERNAL_BYTE_ELEMENTS: | 3044 case EXTERNAL_BYTE_ELEMENTS: |
3011 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 3045 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
3012 case EXTERNAL_SHORT_ELEMENTS: | 3046 case EXTERNAL_SHORT_ELEMENTS: |
3013 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 3047 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
3014 case EXTERNAL_INT_ELEMENTS: | 3048 case EXTERNAL_INT_ELEMENTS: |
3015 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 3049 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
3016 case EXTERNAL_FLOAT_ELEMENTS: | 3050 case EXTERNAL_FLOAT_ELEMENTS: |
3017 case EXTERNAL_DOUBLE_ELEMENTS: | 3051 case EXTERNAL_DOUBLE_ELEMENTS: |
3018 // Pixel and external array elements cannot be deleted. Just | 3052 // Pixel and external array elements cannot be deleted. Just |
(...skipping 4072 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7091 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); | 7125 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity); |
7092 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7126 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7093 } | 7127 } |
7094 FixedArray* elems = FixedArray::cast(obj); | 7128 FixedArray* elems = FixedArray::cast(obj); |
7095 | 7129 |
7096 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); | 7130 { MaybeObject* maybe_obj = map()->GetFastElementsMap(); |
7097 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 7131 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7098 } | 7132 } |
7099 Map* new_map = Map::cast(obj); | 7133 Map* new_map = Map::cast(obj); |
7100 | 7134 |
7101 AssertNoAllocation no_gc; | |
7102 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | |
7103 switch (GetElementsKind()) { | 7135 switch (GetElementsKind()) { |
7104 case FAST_ELEMENTS: { | 7136 case FAST_ELEMENTS: { |
7137 AssertNoAllocation no_gc; | |
7138 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | |
7105 FixedArray* old_elements = FixedArray::cast(elements()); | 7139 FixedArray* old_elements = FixedArray::cast(elements()); |
7106 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | 7140 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); |
7107 // Fill out the new array with this content and array holes. | 7141 // Fill out the new array with this content and array holes. |
7108 for (uint32_t i = 0; i < old_length; i++) { | 7142 for (uint32_t i = 0; i < old_length; i++) { |
7109 elems->set(i, old_elements->get(i), mode); | 7143 elems->set(i, old_elements->get(i), mode); |
7110 } | 7144 } |
7111 break; | 7145 break; |
7112 } | 7146 } |
7147 case FAST_DOUBLE_ELEMENTS: { | |
7148 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements()); | |
7149 uint32_t old_length = static_cast<uint32_t>(old_elements->length()); | |
7150 // Fill out the new array with this content and array holes. | |
7151 for (uint32_t i = 0; i < old_length; i++) { | |
7152 if (!old_elements->is_the_hole(i)) { | |
7153 Object* obj; | |
7154 // Objects must be allocated in the old object space, since the | |
7155 // overall number of HeapNumbers needed for the conversion might | |
7156 // exceed the capacity of new space, and we would fail repeatedly | |
7157 // trying to convert the FixedDoubleArray. | |
7158 MaybeObject* maybe_value_object = | |
7159 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED); | |
7160 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object; | |
7161 // Force write barrier. It's not worth trying to exploit | |
7162 // elems->GetWriteBarrierMode(), since it requires an | |
7163 // AssertNoAllocation stack object that would have to be positioned | |
7164 // after the HeapNumber allocation anyway. | |
7165 elems->set(i, obj, UPDATE_WRITE_BARRIER); | |
7166 } | |
7167 } | |
7168 break; | |
7169 } | |
7113 case DICTIONARY_ELEMENTS: { | 7170 case DICTIONARY_ELEMENTS: { |
7171 AssertNoAllocation no_gc; | |
7172 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc); | |
7114 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 7173 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
7115 for (int i = 0; i < dictionary->Capacity(); i++) { | 7174 for (int i = 0; i < dictionary->Capacity(); i++) { |
7116 Object* key = dictionary->KeyAt(i); | 7175 Object* key = dictionary->KeyAt(i); |
7117 if (key->IsNumber()) { | 7176 if (key->IsNumber()) { |
7118 uint32_t entry = static_cast<uint32_t>(key->Number()); | 7177 uint32_t entry = static_cast<uint32_t>(key->Number()); |
7119 elems->set(entry, dictionary->ValueAt(i), mode); | 7178 elems->set(entry, dictionary->ValueAt(i), mode); |
7120 } | 7179 } |
7121 } | 7180 } |
7122 break; | 7181 break; |
7123 } | 7182 } |
7124 default: | 7183 default: |
7125 UNREACHABLE(); | 7184 UNREACHABLE(); |
7126 break; | 7185 break; |
7127 } | 7186 } |
7128 | 7187 |
7129 set_map(new_map); | 7188 set_map(new_map); |
7130 set_elements(elems); | 7189 set_elements(elems); |
7131 | 7190 |
7132 if (IsJSArray()) { | 7191 if (IsJSArray()) { |
7133 JSArray::cast(this)->set_length(Smi::FromInt(length)); | 7192 JSArray::cast(this)->set_length(Smi::FromInt(length)); |
7134 } | 7193 } |
7135 | 7194 |
7136 return this; | 7195 return this; |
7137 } | 7196 } |
7138 | 7197 |
7139 | 7198 |
7199 MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength( | |
7200 int capacity, | |
7201 int length) { | |
7202 Heap* heap = GetHeap(); | |
7203 // We should never end in here with a pixel or external array. | |
7204 ASSERT(!HasExternalArrayElements()); | |
7205 | |
7206 Object* obj; | |
7207 { MaybeObject* maybe_obj = | |
7208 heap->AllocateUninitializedFixedDoubleArray(capacity); | |
7209 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
7210 } | |
7211 FixedDoubleArray* elems = FixedDoubleArray::cast(obj); | |
7212 | |
7213 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap(); | |
7214 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
7215 } | |
7216 Map* new_map = Map::cast(obj); | |
7217 | |
7218 AssertNoAllocation no_gc; | |
7219 switch (GetElementsKind()) { | |
7220 case FAST_ELEMENTS: { | |
7221 elems->Initialize(FixedArray::cast(elements())); | |
7222 break; | |
7223 } | |
7224 case FAST_DOUBLE_ELEMENTS: { | |
7225 elems->Initialize(FixedDoubleArray::cast(elements())); | |
7226 break; | |
7227 } | |
7228 case DICTIONARY_ELEMENTS: { | |
7229 elems->Initialize(NumberDictionary::cast(elements())); | |
7230 break; | |
7231 } | |
7232 default: | |
7233 UNREACHABLE(); | |
7234 break; | |
7235 } | |
7236 | |
7237 set_map(new_map); | |
7238 set_elements(elems); | |
7239 | |
7240 if (IsJSArray()) { | |
7241 JSArray::cast(this)->set_length(Smi::FromInt(length)); | |
7242 } | |
7243 | |
7244 return this; | |
7245 } | |
7246 | |
7247 | |
7140 MaybeObject* JSObject::SetSlowElements(Object* len) { | 7248 MaybeObject* JSObject::SetSlowElements(Object* len) { |
7141 // We should never end in here with a pixel or external array. | 7249 // We should never end in here with a pixel or external array. |
7142 ASSERT(!HasExternalArrayElements()); | 7250 ASSERT(!HasExternalArrayElements()); |
7143 | 7251 |
7144 uint32_t new_length = static_cast<uint32_t>(len->Number()); | 7252 uint32_t new_length = static_cast<uint32_t>(len->Number()); |
7145 | 7253 |
7146 switch (GetElementsKind()) { | 7254 switch (GetElementsKind()) { |
7147 case FAST_ELEMENTS: { | 7255 case FAST_ELEMENTS: { |
7148 // Make sure we never try to shrink dense arrays into sparse arrays. | 7256 // Make sure we never try to shrink dense arrays into sparse arrays. |
7149 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= | 7257 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= |
(...skipping 701 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7851 if (check_prototype && | 7959 if (check_prototype && |
7852 (index >= elms_length || elms->get(index)->IsTheHole())) { | 7960 (index >= elms_length || elms->get(index)->IsTheHole())) { |
7853 bool found; | 7961 bool found; |
7854 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | 7962 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, |
7855 value, | 7963 value, |
7856 &found, | 7964 &found, |
7857 strict_mode); | 7965 strict_mode); |
7858 if (found) return result; | 7966 if (found) return result; |
7859 } | 7967 } |
7860 | 7968 |
7861 | |
7862 // Check whether there is extra space in fixed array.. | 7969 // Check whether there is extra space in fixed array.. |
7863 if (index < elms_length) { | 7970 if (index < elms_length) { |
7864 elms->set(index, value); | 7971 elms->set(index, value); |
7865 if (IsJSArray()) { | 7972 if (IsJSArray()) { |
7866 // Update the length of the array if needed. | 7973 // Update the length of the array if needed. |
7867 uint32_t array_length = 0; | 7974 uint32_t array_length = 0; |
7868 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | 7975 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); |
7869 if (index >= array_length) { | 7976 if (index >= array_length) { |
7870 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | 7977 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); |
7871 } | 7978 } |
(...skipping 21 matching lines...) Expand all Loading... | |
7893 // Otherwise default to slow case. | 8000 // Otherwise default to slow case. |
7894 Object* obj; | 8001 Object* obj; |
7895 { MaybeObject* maybe_obj = NormalizeElements(); | 8002 { MaybeObject* maybe_obj = NormalizeElements(); |
7896 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8003 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
7897 } | 8004 } |
7898 ASSERT(HasDictionaryElements()); | 8005 ASSERT(HasDictionaryElements()); |
7899 return SetElement(index, value, strict_mode, check_prototype); | 8006 return SetElement(index, value, strict_mode, check_prototype); |
7900 } | 8007 } |
7901 | 8008 |
7902 | 8009 |
8010 MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement( | |
8011 uint32_t index, | |
8012 Object* value, | |
8013 StrictModeFlag strict_mode, | |
8014 bool check_prototype) { | |
8015 ASSERT(HasFastDoubleElements()); | |
8016 | |
8017 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | |
8018 uint32_t elms_length = static_cast<uint32_t>(elms->length()); | |
8019 | |
8020 // If storing to an element that isn't in the array, pass the store request | |
8021 // up the prototype chain before storing in the receiver's elements. | |
8022 if (check_prototype && | |
8023 (index >= elms_length || elms->is_the_hole(index))) { | |
8024 bool found; | |
8025 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index, | |
8026 value, | |
8027 &found, | |
8028 strict_mode); | |
8029 if (found) return result; | |
8030 } | |
8031 | |
8032 // If the value object is not a heap number, switch to fast elements and try | |
8033 // again. | |
8034 bool value_is_smi = value->IsSmi(); | |
8035 if (!value->IsNumber()) { | |
8036 Object* obj; | |
8037 uint32_t length = elms_length; | |
8038 if (IsJSArray()) { | |
8039 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | |
8040 } | |
8041 MaybeObject* maybe_obj = | |
8042 SetFastElementsCapacityAndLength(elms_length, length); | |
8043 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
8044 return SetFastElement(index, value, strict_mode, check_prototype); | |
8045 } | |
8046 | |
8047 double double_value = value_is_smi | |
8048 ? static_cast<double>(Smi::cast(value)->value()) | |
8049 : HeapNumber::cast(value)->value(); | |
8050 | |
8051 // Check whether there is extra space in the fixed array.. | |
Mads Ager (chromium)
2011/06/08 13:13:13
.. -> .
danno
2011/06/09 09:45:40
Done.
| |
8052 if (index < elms_length) { | |
8053 elms->set(index, double_value); | |
8054 if (IsJSArray()) { | |
8055 // Update the length of the array if needed. | |
8056 uint32_t array_length = 0; | |
8057 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length)); | |
8058 if (index >= array_length) { | |
8059 JSArray::cast(this)->set_length(Smi::FromInt(index + 1)); | |
8060 } | |
8061 } | |
8062 return value; | |
8063 } | |
8064 | |
8065 // Allow gap in fast case. | |
8066 if ((index - elms_length) < kMaxGap) { | |
8067 // Try allocating extra space. | |
8068 int new_capacity = NewElementsCapacity(index+1); | |
8069 if (new_capacity <= kMaxFastElementsLength || | |
8070 !ShouldConvertToSlowElements(new_capacity)) { | |
8071 ASSERT(static_cast<uint32_t>(new_capacity) > index); | |
8072 Object* obj; | |
8073 { MaybeObject* maybe_obj = | |
8074 SetFastDoubleElementsCapacityAndLength(new_capacity, | |
8075 index + 1); | |
8076 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
8077 } | |
8078 FixedDoubleArray::cast(elements())->set(index, double_value); | |
8079 return value; | |
8080 } | |
8081 } | |
8082 | |
8083 // Otherwise default to slow case. | |
8084 Object* obj; | |
8085 { MaybeObject* maybe_obj = NormalizeElements(); | |
8086 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
8087 } | |
8088 ASSERT(HasDictionaryElements()); | |
8089 return SetElement(index, value, strict_mode, check_prototype); | |
8090 } | |
8091 | |
8092 | |
7903 MaybeObject* JSObject::SetElement(uint32_t index, | 8093 MaybeObject* JSObject::SetElement(uint32_t index, |
7904 Object* value, | 8094 Object* value, |
7905 StrictModeFlag strict_mode, | 8095 StrictModeFlag strict_mode, |
7906 bool check_prototype) { | 8096 bool check_prototype) { |
7907 // Check access rights if needed. | 8097 // Check access rights if needed. |
7908 if (IsAccessCheckNeeded()) { | 8098 if (IsAccessCheckNeeded()) { |
7909 Heap* heap = GetHeap(); | 8099 Heap* heap = GetHeap(); |
7910 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { | 8100 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) { |
7911 HandleScope scope; | 8101 HandleScope scope; |
7912 Handle<Object> value_handle(value); | 8102 Handle<Object> value_handle(value); |
(...skipping 29 matching lines...) Expand all Loading... | |
7942 | 8132 |
7943 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, | 8133 MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index, |
7944 Object* value, | 8134 Object* value, |
7945 StrictModeFlag strict_mode, | 8135 StrictModeFlag strict_mode, |
7946 bool check_prototype) { | 8136 bool check_prototype) { |
7947 Isolate* isolate = GetIsolate(); | 8137 Isolate* isolate = GetIsolate(); |
7948 switch (GetElementsKind()) { | 8138 switch (GetElementsKind()) { |
7949 case FAST_ELEMENTS: | 8139 case FAST_ELEMENTS: |
7950 // Fast case. | 8140 // Fast case. |
7951 return SetFastElement(index, value, strict_mode, check_prototype); | 8141 return SetFastElement(index, value, strict_mode, check_prototype); |
8142 case FAST_DOUBLE_ELEMENTS: | |
8143 return SetFastDoubleElement(index, value, strict_mode, check_prototype); | |
7952 case EXTERNAL_PIXEL_ELEMENTS: { | 8144 case EXTERNAL_PIXEL_ELEMENTS: { |
7953 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); | 8145 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements()); |
7954 return pixels->SetValue(index, value); | 8146 return pixels->SetValue(index, value); |
7955 } | 8147 } |
7956 case EXTERNAL_BYTE_ELEMENTS: { | 8148 case EXTERNAL_BYTE_ELEMENTS: { |
7957 ExternalByteArray* array = ExternalByteArray::cast(elements()); | 8149 ExternalByteArray* array = ExternalByteArray::cast(elements()); |
7958 return array->SetValue(index, value); | 8150 return array->SetValue(index, value); |
7959 } | 8151 } |
7960 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { | 8152 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: { |
7961 ExternalUnsignedByteArray* array = | 8153 ExternalUnsignedByteArray* array = |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8065 } | 8257 } |
8066 | 8258 |
8067 // Attempt to put this object back in fast case. | 8259 // Attempt to put this object back in fast case. |
8068 if (ShouldConvertToFastElements()) { | 8260 if (ShouldConvertToFastElements()) { |
8069 uint32_t new_length = 0; | 8261 uint32_t new_length = 0; |
8070 if (IsJSArray()) { | 8262 if (IsJSArray()) { |
8071 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); | 8263 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length)); |
8072 } else { | 8264 } else { |
8073 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; | 8265 new_length = NumberDictionary::cast(elements())->max_number_key() + 1; |
8074 } | 8266 } |
8075 Object* obj; | 8267 if (ShouldConvertToFastDoubleElements()) { |
8076 { MaybeObject* maybe_obj = | 8268 Object* obj; |
8077 SetFastElementsCapacityAndLength(new_length, new_length); | 8269 { MaybeObject* maybe_obj = |
8078 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 8270 SetFastDoubleElementsCapacityAndLength(new_length, new_length); |
8271 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
8272 } | |
8273 #ifdef DEBUG | |
8274 if (FLAG_trace_normalization) { | |
8275 PrintF("Object elements are fast double case again:\n"); | |
8276 Print(); | |
8277 } | |
8278 #endif | |
8279 } else { | |
8280 Object* obj; | |
8281 { MaybeObject* maybe_obj = | |
8282 SetFastElementsCapacityAndLength(new_length, new_length); | |
8283 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
8284 } | |
8285 #ifdef DEBUG | |
8286 if (FLAG_trace_normalization) { | |
8287 PrintF("Object elements are fast case again:\n"); | |
8288 Print(); | |
8289 } | |
8290 #endif | |
8079 } | 8291 } |
8080 #ifdef DEBUG | |
8081 if (FLAG_trace_normalization) { | |
8082 PrintF("Object elements are fast case again:\n"); | |
8083 Print(); | |
8084 } | |
8085 #endif | |
8086 } | 8292 } |
8087 | 8293 |
8088 return value; | 8294 return value; |
8089 } | 8295 } |
8090 default: | |
8091 UNREACHABLE(); | |
8092 break; | |
8093 } | 8296 } |
8094 // All possible cases have been handled above. Add a return to avoid the | 8297 // All possible cases have been handled above. Add a return to avoid the |
8095 // complaints from the compiler. | 8298 // complaints from the compiler. |
8096 UNREACHABLE(); | 8299 UNREACHABLE(); |
8097 return isolate->heap()->null_value(); | 8300 return isolate->heap()->null_value(); |
8098 } | 8301 } |
8099 | 8302 |
8100 | 8303 |
8101 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, | 8304 MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index, |
8102 Object* value) { | 8305 Object* value) { |
(...skipping 19 matching lines...) Expand all Loading... | |
8122 // JSArray::length cannot change. | 8325 // JSArray::length cannot change. |
8123 switch (GetElementsKind()) { | 8326 switch (GetElementsKind()) { |
8124 case FAST_ELEMENTS: { | 8327 case FAST_ELEMENTS: { |
8125 FixedArray* elms = FixedArray::cast(elements()); | 8328 FixedArray* elms = FixedArray::cast(elements()); |
8126 if (index < static_cast<uint32_t>(elms->length())) { | 8329 if (index < static_cast<uint32_t>(elms->length())) { |
8127 Object* value = elms->get(index); | 8330 Object* value = elms->get(index); |
8128 if (!value->IsTheHole()) return value; | 8331 if (!value->IsTheHole()) return value; |
8129 } | 8332 } |
8130 break; | 8333 break; |
8131 } | 8334 } |
8335 case FAST_DOUBLE_ELEMENTS: { | |
8336 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | |
8337 if (index < static_cast<uint32_t>(elms->length())) { | |
8338 if (!elms->is_the_hole(index)) { | |
8339 return GetHeap()->NumberFromDouble(elms->get(index)); | |
8340 } | |
8341 } | |
8342 break; | |
8343 } | |
8132 case EXTERNAL_PIXEL_ELEMENTS: | 8344 case EXTERNAL_PIXEL_ELEMENTS: |
8133 case EXTERNAL_BYTE_ELEMENTS: | 8345 case EXTERNAL_BYTE_ELEMENTS: |
8134 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8346 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
8135 case EXTERNAL_SHORT_ELEMENTS: | 8347 case EXTERNAL_SHORT_ELEMENTS: |
8136 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8348 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
8137 case EXTERNAL_INT_ELEMENTS: | 8349 case EXTERNAL_INT_ELEMENTS: |
8138 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8350 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
8139 case EXTERNAL_FLOAT_ELEMENTS: | 8351 case EXTERNAL_FLOAT_ELEMENTS: |
8140 case EXTERNAL_DOUBLE_ELEMENTS: { | 8352 case EXTERNAL_DOUBLE_ELEMENTS: { |
8141 MaybeObject* maybe_value = GetExternalElement(index); | 8353 MaybeObject* maybe_value = GetExternalElement(index); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8225 // JSArray::length cannot change. | 8437 // JSArray::length cannot change. |
8226 switch (GetElementsKind()) { | 8438 switch (GetElementsKind()) { |
8227 case FAST_ELEMENTS: { | 8439 case FAST_ELEMENTS: { |
8228 FixedArray* elms = FixedArray::cast(elements()); | 8440 FixedArray* elms = FixedArray::cast(elements()); |
8229 if (index < static_cast<uint32_t>(elms->length())) { | 8441 if (index < static_cast<uint32_t>(elms->length())) { |
8230 Object* value = elms->get(index); | 8442 Object* value = elms->get(index); |
8231 if (!value->IsTheHole()) return value; | 8443 if (!value->IsTheHole()) return value; |
8232 } | 8444 } |
8233 break; | 8445 break; |
8234 } | 8446 } |
8447 case FAST_DOUBLE_ELEMENTS: { | |
8448 FixedDoubleArray* elms = FixedDoubleArray::cast(elements()); | |
8449 if (index < static_cast<uint32_t>(elms->length())) { | |
8450 if (!elms->is_the_hole(index)) { | |
8451 double double_value = elms->get(index); | |
8452 return GetHeap()->AllocateHeapNumber(double_value); | |
Mads Ager (chromium)
2011/06/08 13:13:13
Use NumberFromDouble?
danno
2011/06/09 09:45:40
Done.
| |
8453 } | |
8454 } | |
8455 break; | |
8456 } | |
8235 case EXTERNAL_PIXEL_ELEMENTS: | 8457 case EXTERNAL_PIXEL_ELEMENTS: |
8236 case EXTERNAL_BYTE_ELEMENTS: | 8458 case EXTERNAL_BYTE_ELEMENTS: |
8237 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 8459 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
8238 case EXTERNAL_SHORT_ELEMENTS: | 8460 case EXTERNAL_SHORT_ELEMENTS: |
8239 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 8461 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
8240 case EXTERNAL_INT_ELEMENTS: | 8462 case EXTERNAL_INT_ELEMENTS: |
8241 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 8463 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
8242 case EXTERNAL_FLOAT_ELEMENTS: | 8464 case EXTERNAL_FLOAT_ELEMENTS: |
8243 case EXTERNAL_DOUBLE_ELEMENTS: { | 8465 case EXTERNAL_DOUBLE_ELEMENTS: { |
8244 MaybeObject* maybe_value = GetExternalElement(index); | 8466 MaybeObject* maybe_value = GetExternalElement(index); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8344 break; | 8566 break; |
8345 } | 8567 } |
8346 case EXTERNAL_DOUBLE_ELEMENTS: { | 8568 case EXTERNAL_DOUBLE_ELEMENTS: { |
8347 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); | 8569 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements()); |
8348 if (index < static_cast<uint32_t>(array->length())) { | 8570 if (index < static_cast<uint32_t>(array->length())) { |
8349 double value = array->get(index); | 8571 double value = array->get(index); |
8350 return GetHeap()->AllocateHeapNumber(value); | 8572 return GetHeap()->AllocateHeapNumber(value); |
8351 } | 8573 } |
8352 break; | 8574 break; |
8353 } | 8575 } |
8576 case FAST_DOUBLE_ELEMENTS: | |
8354 case FAST_ELEMENTS: | 8577 case FAST_ELEMENTS: |
8355 case DICTIONARY_ELEMENTS: | 8578 case DICTIONARY_ELEMENTS: |
8356 UNREACHABLE(); | 8579 UNREACHABLE(); |
8357 break; | 8580 break; |
8358 } | 8581 } |
8359 return GetHeap()->undefined_value(); | 8582 return GetHeap()->undefined_value(); |
8360 } | 8583 } |
8361 | 8584 |
8362 | 8585 |
8363 bool JSObject::HasDenseElements() { | 8586 bool JSObject::HasDenseElements() { |
(...skipping 30 matching lines...) Expand all Loading... | |
8394 UNREACHABLE(); | 8617 UNREACHABLE(); |
8395 break; | 8618 break; |
8396 } | 8619 } |
8397 | 8620 |
8398 if (capacity == 0) return true; | 8621 if (capacity == 0) return true; |
8399 return (number_of_elements > (capacity / 2)); | 8622 return (number_of_elements > (capacity / 2)); |
8400 } | 8623 } |
8401 | 8624 |
8402 | 8625 |
8403 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { | 8626 bool JSObject::ShouldConvertToSlowElements(int new_capacity) { |
8404 ASSERT(HasFastElements()); | |
8405 // Keep the array in fast case if the current backing storage is | 8627 // Keep the array in fast case if the current backing storage is |
8406 // almost filled and if the new capacity is no more than twice the | 8628 // almost filled and if the new capacity is no more than twice the |
8407 // old capacity. | 8629 // old capacity. |
8408 int elements_length = FixedArray::cast(elements())->length(); | 8630 int elements_length = 0; |
8631 if (HasFastElements()) { | |
8632 elements_length = FixedArray::cast(elements())->length(); | |
8633 } else if (HasFastDoubleElements()) { | |
8634 elements_length = FixedDoubleArray::cast(elements())->length(); | |
8635 } else { | |
8636 UNREACHABLE(); | |
8637 } | |
8409 return !HasDenseElements() || ((new_capacity / 2) > elements_length); | 8638 return !HasDenseElements() || ((new_capacity / 2) > elements_length); |
8410 } | 8639 } |
8411 | 8640 |
8412 | 8641 |
8413 bool JSObject::ShouldConvertToFastElements() { | 8642 bool JSObject::ShouldConvertToFastElements() { |
8414 ASSERT(HasDictionaryElements()); | 8643 ASSERT(HasDictionaryElements()); |
8415 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | 8644 NumberDictionary* dictionary = NumberDictionary::cast(elements()); |
8416 // If the elements are sparse, we should not go back to fast case. | 8645 // If the elements are sparse, we should not go back to fast case. |
8417 if (!HasDenseElements()) return false; | 8646 if (!HasDenseElements()) return false; |
8418 // If an element has been added at a very high index in the elements | 8647 // If an element has been added at a very high index in the elements |
8419 // dictionary, we cannot go back to fast case. | 8648 // dictionary, we cannot go back to fast case. |
8420 if (dictionary->requires_slow_elements()) return false; | 8649 if (dictionary->requires_slow_elements()) return false; |
8421 // An object requiring access checks is never allowed to have fast | 8650 // An object requiring access checks is never allowed to have fast |
8422 // elements. If it had fast elements we would skip security checks. | 8651 // elements. If it had fast elements we would skip security checks. |
8423 if (IsAccessCheckNeeded()) return false; | 8652 if (IsAccessCheckNeeded()) return false; |
8424 // If the dictionary backing storage takes up roughly half as much | 8653 // If the dictionary backing storage takes up roughly half as much |
8425 // space as a fast-case backing storage would the array should have | 8654 // space as a fast-case backing storage would the array should have |
8426 // fast elements. | 8655 // fast elements. |
8427 uint32_t length = 0; | 8656 uint32_t length = 0; |
8428 if (IsJSArray()) { | 8657 if (IsJSArray()) { |
8429 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); | 8658 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length)); |
8430 } else { | 8659 } else { |
8431 length = dictionary->max_number_key(); | 8660 length = dictionary->max_number_key(); |
8432 } | 8661 } |
8433 return static_cast<uint32_t>(dictionary->Capacity()) >= | 8662 return static_cast<uint32_t>(dictionary->Capacity()) >= |
8434 (length / (2 * NumberDictionary::kEntrySize)); | 8663 (length / (2 * NumberDictionary::kEntrySize)); |
8435 } | 8664 } |
8436 | 8665 |
8437 | 8666 |
8667 bool JSObject::ShouldConvertToFastDoubleElements() { | |
8668 if (FLAG_unbox_double_arrays) { | |
8669 ASSERT(HasDictionaryElements()); | |
8670 NumberDictionary* dictionary = NumberDictionary::cast(elements()); | |
8671 for (int i = 0; i < dictionary->Capacity(); i++) { | |
8672 Object* key = dictionary->KeyAt(i); | |
8673 if (key->IsNumber()) { | |
8674 if (!dictionary->ValueAt(i)->IsNumber()) return false; | |
8675 } | |
8676 } | |
8677 return true; | |
8678 } else { | |
8679 return false; | |
8680 } | |
8681 } | |
8682 | |
8683 | |
8438 // Certain compilers request function template instantiation when they | 8684 // Certain compilers request function template instantiation when they |
8439 // see the definition of the other template functions in the | 8685 // see the definition of the other template functions in the |
8440 // class. This requires us to have the template functions put | 8686 // class. This requires us to have the template functions put |
8441 // together, so even though this function belongs in objects-debug.cc, | 8687 // together, so even though this function belongs in objects-debug.cc, |
8442 // we keep it here instead to satisfy certain compilers. | 8688 // we keep it here instead to satisfy certain compilers. |
8443 #ifdef OBJECT_PRINT | 8689 #ifdef OBJECT_PRINT |
8444 template<typename Shape, typename Key> | 8690 template<typename Shape, typename Key> |
8445 void Dictionary<Shape, Key>::Print(FILE* out) { | 8691 void Dictionary<Shape, Key>::Print(FILE* out) { |
8446 int capacity = HashTable<Shape, Key>::Capacity(); | 8692 int capacity = HashTable<Shape, Key>::Capacity(); |
8447 for (int i = 0; i < capacity; i++) { | 8693 for (int i = 0; i < capacity; i++) { |
(...skipping 2507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10955 if (break_point_objects()->IsUndefined()) return 0; | 11201 if (break_point_objects()->IsUndefined()) return 0; |
10956 // Single beak point. | 11202 // Single beak point. |
10957 if (!break_point_objects()->IsFixedArray()) return 1; | 11203 if (!break_point_objects()->IsFixedArray()) return 1; |
10958 // Multiple break points. | 11204 // Multiple break points. |
10959 return FixedArray::cast(break_point_objects())->length(); | 11205 return FixedArray::cast(break_point_objects())->length(); |
10960 } | 11206 } |
10961 #endif | 11207 #endif |
10962 | 11208 |
10963 | 11209 |
10964 } } // namespace v8::internal | 11210 } } // namespace v8::internal |
OLD | NEW |