| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/arguments.h" | 7 #include "src/arguments.h" |
| 8 #include "src/runtime/runtime-utils.h" | 8 #include "src/runtime/runtime-utils.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 * length overflows 32-bit non-negative integer. | 97 * length overflows 32-bit non-negative integer. |
| 98 */ | 98 */ |
| 99 class ArrayConcatVisitor { | 99 class ArrayConcatVisitor { |
| 100 public: | 100 public: |
| 101 ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage, | 101 ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage, |
| 102 bool fast_elements) | 102 bool fast_elements) |
| 103 : isolate_(isolate), | 103 : isolate_(isolate), |
| 104 storage_(Handle<FixedArray>::cast( | 104 storage_(Handle<FixedArray>::cast( |
| 105 isolate->global_handles()->Create(*storage))), | 105 isolate->global_handles()->Create(*storage))), |
| 106 index_offset_(0u), | 106 index_offset_(0u), |
| 107 fast_elements_(fast_elements), | 107 bit_field_(FastElementsField::encode(fast_elements) | |
| 108 exceeds_array_limit_(false) {} | 108 ExceedsLimitField::encode(false)) {} |
| 109 | 109 |
| 110 ~ArrayConcatVisitor() { clear_storage(); } | 110 ~ArrayConcatVisitor() { clear_storage(); } |
| 111 | 111 |
| 112 void visit(uint32_t i, Handle<Object> elm) { | 112 void visit(uint32_t i, Handle<Object> elm) { |
| 113 if (i > JSObject::kMaxElementCount - index_offset_) { | 113 if (i > JSObject::kMaxElementCount - index_offset_) { |
| 114 exceeds_array_limit_ = true; | 114 set_exceeds_array_limit(true); |
| 115 return; | 115 return; |
| 116 } | 116 } |
| 117 uint32_t index = index_offset_ + i; | 117 uint32_t index = index_offset_ + i; |
| 118 | 118 |
| 119 if (fast_elements_) { | 119 if (fast_elements()) { |
| 120 if (index < static_cast<uint32_t>(storage_->length())) { | 120 if (index < static_cast<uint32_t>(storage_->length())) { |
| 121 storage_->set(index, *elm); | 121 storage_->set(index, *elm); |
| 122 return; | 122 return; |
| 123 } | 123 } |
| 124 // Our initial estimate of length was foiled, possibly by | 124 // Our initial estimate of length was foiled, possibly by |
| 125 // getters on the arrays increasing the length of later arrays | 125 // getters on the arrays increasing the length of later arrays |
| 126 // during iteration. | 126 // during iteration. |
| 127 // This shouldn't happen in anything but pathological cases. | 127 // This shouldn't happen in anything but pathological cases. |
| 128 SetDictionaryMode(); | 128 SetDictionaryMode(); |
| 129 // Fall-through to dictionary mode. | 129 // Fall-through to dictionary mode. |
| 130 } | 130 } |
| 131 DCHECK(!fast_elements_); | 131 DCHECK(!fast_elements()); |
| 132 Handle<SeededNumberDictionary> dict( | 132 Handle<SeededNumberDictionary> dict( |
| 133 SeededNumberDictionary::cast(*storage_)); | 133 SeededNumberDictionary::cast(*storage_)); |
| 134 Handle<SeededNumberDictionary> result = | 134 Handle<SeededNumberDictionary> result = |
| 135 SeededNumberDictionary::AtNumberPut(dict, index, elm); | 135 SeededNumberDictionary::AtNumberPut(dict, index, elm); |
| 136 if (!result.is_identical_to(dict)) { | 136 if (!result.is_identical_to(dict)) { |
| 137 // Dictionary needed to grow. | 137 // Dictionary needed to grow. |
| 138 clear_storage(); | 138 clear_storage(); |
| 139 set_storage(*result); | 139 set_storage(*result); |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 | 142 |
| 143 void increase_index_offset(uint32_t delta) { | 143 void increase_index_offset(uint32_t delta) { |
| 144 if (JSObject::kMaxElementCount - index_offset_ < delta) { | 144 if (JSObject::kMaxElementCount - index_offset_ < delta) { |
| 145 index_offset_ = JSObject::kMaxElementCount; | 145 index_offset_ = JSObject::kMaxElementCount; |
| 146 } else { | 146 } else { |
| 147 index_offset_ += delta; | 147 index_offset_ += delta; |
| 148 } | 148 } |
| 149 // If the initial length estimate was off (see special case in visit()), | 149 // If the initial length estimate was off (see special case in visit()), |
| 150 // but the array blowing the limit didn't contain elements beyond the | 150 // but the array blowing the limit didn't contain elements beyond the |
| 151 // provided-for index range, go to dictionary mode now. | 151 // provided-for index range, go to dictionary mode now. |
| 152 if (fast_elements_ && | 152 if (fast_elements() && |
| 153 index_offset_ > | 153 index_offset_ > |
| 154 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { | 154 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { |
| 155 SetDictionaryMode(); | 155 SetDictionaryMode(); |
| 156 } | 156 } |
| 157 } | 157 } |
| 158 | 158 |
| 159 bool exceeds_array_limit() { return exceeds_array_limit_; } | 159 bool exceeds_array_limit() const { |
| 160 return ExceedsLimitField::decode(bit_field_); |
| 161 } |
| 160 | 162 |
| 161 Handle<JSArray> ToArray() { | 163 Handle<JSArray> ToArray() { |
| 162 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | 164 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); |
| 163 Handle<Object> length = | 165 Handle<Object> length = |
| 164 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); | 166 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); |
| 165 Handle<Map> map = JSObject::GetElementsTransitionMap( | 167 Handle<Map> map = JSObject::GetElementsTransitionMap( |
| 166 array, fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); | 168 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); |
| 167 array->set_map(*map); | 169 array->set_map(*map); |
| 168 array->set_length(*length); | 170 array->set_length(*length); |
| 169 array->set_elements(*storage_); | 171 array->set_elements(*storage_); |
| 170 return array; | 172 return array; |
| 171 } | 173 } |
| 172 | 174 |
| 173 private: | 175 private: |
| 174 // Convert storage to dictionary mode. | 176 // Convert storage to dictionary mode. |
| 175 void SetDictionaryMode() { | 177 void SetDictionaryMode() { |
| 176 DCHECK(fast_elements_); | 178 DCHECK(fast_elements()); |
| 177 Handle<FixedArray> current_storage(*storage_); | 179 Handle<FixedArray> current_storage(*storage_); |
| 178 Handle<SeededNumberDictionary> slow_storage( | 180 Handle<SeededNumberDictionary> slow_storage( |
| 179 SeededNumberDictionary::New(isolate_, current_storage->length())); | 181 SeededNumberDictionary::New(isolate_, current_storage->length())); |
| 180 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); | 182 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); |
| 181 for (uint32_t i = 0; i < current_length; i++) { | 183 for (uint32_t i = 0; i < current_length; i++) { |
| 182 HandleScope loop_scope(isolate_); | 184 HandleScope loop_scope(isolate_); |
| 183 Handle<Object> element(current_storage->get(i), isolate_); | 185 Handle<Object> element(current_storage->get(i), isolate_); |
| 184 if (!element->IsTheHole()) { | 186 if (!element->IsTheHole()) { |
| 185 Handle<SeededNumberDictionary> new_storage = | 187 Handle<SeededNumberDictionary> new_storage = |
| 186 SeededNumberDictionary::AtNumberPut(slow_storage, i, element); | 188 SeededNumberDictionary::AtNumberPut(slow_storage, i, element); |
| 187 if (!new_storage.is_identical_to(slow_storage)) { | 189 if (!new_storage.is_identical_to(slow_storage)) { |
| 188 slow_storage = loop_scope.CloseAndEscape(new_storage); | 190 slow_storage = loop_scope.CloseAndEscape(new_storage); |
| 189 } | 191 } |
| 190 } | 192 } |
| 191 } | 193 } |
| 192 clear_storage(); | 194 clear_storage(); |
| 193 set_storage(*slow_storage); | 195 set_storage(*slow_storage); |
| 194 fast_elements_ = false; | 196 set_fast_elements(false); |
| 195 } | 197 } |
| 196 | 198 |
| 197 inline void clear_storage() { | 199 inline void clear_storage() { |
| 198 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); | 200 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location()); |
| 199 } | 201 } |
| 200 | 202 |
| 201 inline void set_storage(FixedArray* storage) { | 203 inline void set_storage(FixedArray* storage) { |
| 202 storage_ = | 204 storage_ = |
| 203 Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage)); | 205 Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage)); |
| 204 } | 206 } |
| 205 | 207 |
| 208 class FastElementsField : public BitField<bool, 0, 1> {}; |
| 209 class ExceedsLimitField : public BitField<bool, 1, 1> {}; |
| 210 |
| 211 bool fast_elements() const { return FastElementsField::decode(bit_field_); } |
| 212 void set_fast_elements(bool fast) { |
| 213 bit_field_ = FastElementsField::update(bit_field_, fast); |
| 214 } |
| 215 void set_exceeds_array_limit(bool exceeds) { |
| 216 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); |
| 217 } |
| 218 |
| 206 Isolate* isolate_; | 219 Isolate* isolate_; |
| 207 Handle<FixedArray> storage_; // Always a global handle. | 220 Handle<FixedArray> storage_; // Always a global handle. |
| 208 // Index after last seen index. Always less than or equal to | 221 // Index after last seen index. Always less than or equal to |
| 209 // JSObject::kMaxElementCount. | 222 // JSObject::kMaxElementCount. |
| 210 uint32_t index_offset_; | 223 uint32_t index_offset_; |
| 211 bool fast_elements_ : 1; | 224 uint32_t bit_field_; |
| 212 bool exceeds_array_limit_ : 1; | |
| 213 }; | 225 }; |
| 214 | 226 |
| 215 | 227 |
| 216 static uint32_t EstimateElementCount(Handle<JSArray> array) { | 228 static uint32_t EstimateElementCount(Handle<JSArray> array) { |
| 217 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | 229 uint32_t length = static_cast<uint32_t>(array->length()->Number()); |
| 218 int element_count = 0; | 230 int element_count = 0; |
| 219 switch (array->GetElementsKind()) { | 231 switch (array->GetElementsKind()) { |
| 220 case FAST_SMI_ELEMENTS: | 232 case FAST_SMI_ELEMENTS: |
| 221 case FAST_HOLEY_SMI_ELEMENTS: | 233 case FAST_HOLEY_SMI_ELEMENTS: |
| 222 case FAST_ELEMENTS: | 234 case FAST_ELEMENTS: |
| (...skipping 952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1175 } | 1187 } |
| 1176 | 1188 |
| 1177 | 1189 |
| 1178 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { | 1190 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) { |
| 1179 SealHandleScope shs(isolate); | 1191 SealHandleScope shs(isolate); |
| 1180 DCHECK(args.length() == 2); | 1192 DCHECK(args.length() == 2); |
| 1181 return isolate->heap()->undefined_value(); | 1193 return isolate->heap()->undefined_value(); |
| 1182 } | 1194 } |
| 1183 } | 1195 } |
| 1184 } // namespace v8::internal | 1196 } // namespace v8::internal |
| OLD | NEW |