| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/builtins.h" | 5 #include "src/builtins.h" |
| 6 | 6 |
| 7 #include "src/api.h" | 7 #include "src/api.h" |
| 8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
| 9 #include "src/api-natives.h" | 9 #include "src/api-natives.h" |
| 10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 215 } | 215 } |
| 216 | 216 |
| 217 | 217 |
| 218 inline bool PrototypeHasNoElements(PrototypeIterator* iter) { | 218 inline bool PrototypeHasNoElements(PrototypeIterator* iter) { |
| 219 DisallowHeapAllocation no_gc; | 219 DisallowHeapAllocation no_gc; |
| 220 for (; !iter->IsAtEnd(); iter->Advance()) { | 220 for (; !iter->IsAtEnd(); iter->Advance()) { |
| 221 if (iter->GetCurrent()->IsJSProxy()) return false; | 221 if (iter->GetCurrent()->IsJSProxy()) return false; |
| 222 JSObject* current = iter->GetCurrent<JSObject>(); | 222 JSObject* current = iter->GetCurrent<JSObject>(); |
| 223 if (current->IsAccessCheckNeeded()) return false; | 223 if (current->IsAccessCheckNeeded()) return false; |
| 224 if (current->HasIndexedInterceptor()) return false; | 224 if (current->HasIndexedInterceptor()) return false; |
| 225 if (current->HasStringWrapperElements()) return false; |
| 225 if (current->elements()->length() != 0) return false; | 226 if (current->elements()->length() != 0) return false; |
| 226 } | 227 } |
| 227 return true; | 228 return true; |
| 228 } | 229 } |
| 229 | 230 |
| 230 | |
| 231 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, | 231 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
| 232 JSArray* receiver) { | 232 JSArray* receiver) { |
| 233 DisallowHeapAllocation no_gc; | 233 DisallowHeapAllocation no_gc; |
| 234 // If the array prototype chain is intact (and free of elements), and if the | 234 // If the array prototype chain is intact (and free of elements), and if the |
| 235 // receiver's prototype is the array prototype, then we are done. | 235 // receiver's prototype is the array prototype, then we are done. |
| 236 Object* prototype = receiver->map()->prototype(); | 236 Object* prototype = receiver->map()->prototype(); |
| 237 if (prototype->IsJSArray() && | 237 if (prototype->IsJSArray() && |
| 238 isolate->is_initial_array_prototype(JSArray::cast(prototype)) && | 238 isolate->is_initial_array_prototype(JSArray::cast(prototype)) && |
| 239 isolate->IsFastArrayConstructorPrototypeChainIntact()) { | 239 isolate->IsFastArrayConstructorPrototypeChainIntact()) { |
| 240 return true; | 240 return true; |
| 241 } | 241 } |
| 242 | |
| 243 // Slow case. | 242 // Slow case. |
| 244 PrototypeIterator iter(isolate, receiver); | 243 PrototypeIterator iter(isolate, receiver); |
| 245 return PrototypeHasNoElements(&iter); | 244 return PrototypeHasNoElements(&iter); |
| 246 } | 245 } |
| 247 | 246 |
| 247 inline bool HasSimpleElements(JSObject* current) { |
| 248 if (current->IsAccessCheckNeeded()) return false; |
| 249 if (current->HasIndexedInterceptor()) return false; |
| 250 if (current->HasStringWrapperElements()) return false; |
| 251 if (current->GetElementsAccessor()->HasAccessors(current)) return false; |
| 252 return true; |
| 253 } |
| 254 |
| 255 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, |
| 256 JSReceiver* receiver) { |
| 257 // Check that we have no accessors on the receiver's elements. |
| 258 JSObject* object = JSObject::cast(receiver); |
| 259 if (!HasSimpleElements(object)) return false; |
| 260 // Check that ther are not elements on the prototype. |
| 261 DisallowHeapAllocation no_gc; |
| 262 PrototypeIterator iter(isolate, receiver); |
| 263 return PrototypeHasNoElements(&iter); |
| 264 } |
| 265 |
| 266 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { |
| 267 // Check that ther are not elements on the prototype. |
| 268 DisallowHeapAllocation no_gc; |
| 269 PrototypeIterator iter(isolate, receiver, |
| 270 PrototypeIterator::START_AT_RECEIVER); |
| 271 for (; !iter.IsAtEnd(); iter.Advance()) { |
| 272 if (iter.GetCurrent()->IsJSProxy()) return false; |
| 273 JSObject* current = iter.GetCurrent<JSObject>(); |
| 274 if (!HasSimpleElements(current)) return false; |
| 275 } |
| 276 return true; |
| 277 } |
| 278 |
| 248 // Returns |false| if not applicable. | 279 // Returns |false| if not applicable. |
| 249 MUST_USE_RESULT | 280 MUST_USE_RESULT |
| 250 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, | 281 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, |
| 251 Handle<Object> receiver, | 282 Handle<Object> receiver, |
| 252 Arguments* args, | 283 Arguments* args, |
| 253 int first_added_arg) { | 284 int first_added_arg) { |
| 254 if (!receiver->IsJSArray()) return false; | 285 if (!receiver->IsJSArray()) return false; |
| 255 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 286 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
| 256 // If there may be elements accessors in the prototype chain, the fast path | 287 // If there may be elements accessors in the prototype chain, the fast path |
| 257 // cannot be used if there arguments to add to the array. | 288 // cannot be used if there arguments to add to the array. |
| 258 if (args != nullptr && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { | 289 if (args != nullptr && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { |
| 259 return false; | 290 return false; |
| 260 } | 291 } |
| 261 ElementsKind origin_kind = array->map()->elements_kind(); | 292 ElementsKind origin_kind = array->GetElementsKind(); |
| 262 if (IsDictionaryElementsKind(origin_kind)) return false; | 293 if (IsDictionaryElementsKind(origin_kind)) return false; |
| 263 if (array->map()->is_observed()) return false; | 294 if (array->map()->is_observed()) return false; |
| 264 if (!array->map()->is_extensible()) return false; | 295 if (!array->map()->is_extensible()) return false; |
| 265 if (args == nullptr) return true; | 296 if (args == nullptr) return true; |
| 266 | 297 |
| 267 // Adding elements to the array prototype would break code that makes sure | 298 // Adding elements to the array prototype would break code that makes sure |
| 268 // it has no elements. Handle that elsewhere. | 299 // it has no elements. Handle that elsewhere. |
| 269 if (isolate->IsAnyInitialArrayPrototype(array)) return false; | 300 if (isolate->IsAnyInitialArrayPrototype(array)) return false; |
| 270 | 301 |
| 271 // Need to ensure that the arguments passed in args can be contained in | 302 // Need to ensure that the arguments passed in args can be contained in |
| (...skipping 784 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1056 Handle<Object> key = isolate->factory()->length_string(); | 1087 Handle<Object> key = isolate->factory()->length_string(); |
| 1057 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 1088 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 1058 isolate, val, Runtime::GetObjectProperty(isolate, receiver, key), | 1089 isolate, val, Runtime::GetObjectProperty(isolate, receiver, key), |
| 1059 false); | 1090 false); |
| 1060 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val, | 1091 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val, |
| 1061 Object::ToLength(isolate, val), false); | 1092 Object::ToLength(isolate, val), false); |
| 1062 // TODO(caitp): Support larger element indexes (up to 2^53-1). | 1093 // TODO(caitp): Support larger element indexes (up to 2^53-1). |
| 1063 if (!val->ToUint32(&length)) { | 1094 if (!val->ToUint32(&length)) { |
| 1064 length = 0; | 1095 length = 0; |
| 1065 } | 1096 } |
| 1097 // TODO(cbruni): handle other element kind as well |
| 1098 return IterateElementsSlow(isolate, receiver, length, visitor); |
| 1066 } | 1099 } |
| 1067 | 1100 |
| 1068 if (!receiver->IsJSArray()) { | 1101 if (!HasOnlySimpleElements(isolate, *receiver)) { |
| 1069 // For classes which are not known to be safe to access via elements alone, | |
| 1070 // use the slow case. | |
| 1071 return IterateElementsSlow(isolate, receiver, length, visitor); | 1102 return IterateElementsSlow(isolate, receiver, length, visitor); |
| 1072 } | 1103 } |
| 1073 Handle<JSObject> array = Handle<JSObject>::cast(receiver); | 1104 Handle<JSObject> array = Handle<JSObject>::cast(receiver); |
| 1074 | 1105 |
| 1075 switch (array->GetElementsKind()) { | 1106 switch (array->GetElementsKind()) { |
| 1076 case FAST_SMI_ELEMENTS: | 1107 case FAST_SMI_ELEMENTS: |
| 1077 case FAST_ELEMENTS: | 1108 case FAST_ELEMENTS: |
| 1078 case FAST_HOLEY_SMI_ELEMENTS: | 1109 case FAST_HOLEY_SMI_ELEMENTS: |
| 1079 case FAST_HOLEY_ELEMENTS: { | 1110 case FAST_HOLEY_ELEMENTS: { |
| 1080 // Run through the elements FixedArray and use HasElement and GetElement | 1111 // Run through the elements FixedArray and use HasElement and GetElement |
| 1081 // to check the prototype for missing elements. | 1112 // to check the prototype for missing elements. |
| 1082 Handle<FixedArray> elements(FixedArray::cast(array->elements())); | 1113 Handle<FixedArray> elements(FixedArray::cast(array->elements())); |
| 1083 int fast_length = static_cast<int>(length); | 1114 int fast_length = static_cast<int>(length); |
| 1084 DCHECK(fast_length <= elements->length()); | 1115 DCHECK_LE(fast_length, elements->length()); |
| 1085 for (int j = 0; j < fast_length; j++) { | 1116 for (int j = 0; j < fast_length; j++) { |
| 1086 HandleScope loop_scope(isolate); | 1117 HandleScope loop_scope(isolate); |
| 1087 Handle<Object> element_value(elements->get(j), isolate); | 1118 Handle<Object> element_value(elements->get(j), isolate); |
| 1088 if (!element_value->IsTheHole()) { | 1119 if (!element_value->IsTheHole()) { |
| 1089 if (!visitor->visit(j, element_value)) return false; | 1120 if (!visitor->visit(j, element_value)) return false; |
| 1090 } else { | 1121 } else { |
| 1091 Maybe<bool> maybe = JSReceiver::HasElement(array, j); | 1122 Maybe<bool> maybe = JSReceiver::HasElement(array, j); |
| 1092 if (!maybe.IsJust()) return false; | 1123 if (!maybe.IsJust()) return false; |
| 1093 if (maybe.FromJust()) { | 1124 if (maybe.FromJust()) { |
| 1094 // Call GetElement on array, not its prototype, or getters won't | 1125 // Call GetElement on array, not its prototype, or getters won't |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1134 isolate, element_value, | 1165 isolate, element_value, |
| 1135 JSReceiver::GetElement(isolate, array, j), false); | 1166 JSReceiver::GetElement(isolate, array, j), false); |
| 1136 if (!visitor->visit(j, element_value)) return false; | 1167 if (!visitor->visit(j, element_value)) return false; |
| 1137 } | 1168 } |
| 1138 } | 1169 } |
| 1139 } | 1170 } |
| 1140 break; | 1171 break; |
| 1141 } | 1172 } |
| 1142 | 1173 |
| 1143 case DICTIONARY_ELEMENTS: { | 1174 case DICTIONARY_ELEMENTS: { |
| 1144 // CollectElementIndices() can't be called when there's a JSProxy | |
| 1145 // on the prototype chain. | |
| 1146 for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd(); | |
| 1147 iter.Advance()) { | |
| 1148 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) { | |
| 1149 return IterateElementsSlow(isolate, array, length, visitor); | |
| 1150 } | |
| 1151 } | |
| 1152 Handle<SeededNumberDictionary> dict(array->element_dictionary()); | 1175 Handle<SeededNumberDictionary> dict(array->element_dictionary()); |
| 1153 List<uint32_t> indices(dict->Capacity() / 2); | 1176 List<uint32_t> indices(dict->Capacity() / 2); |
| 1154 // Collect all indices in the object and the prototypes less | 1177 // Collect all indices in the object and the prototypes less |
| 1155 // than length. This might introduce duplicates in the indices list. | 1178 // than length. This might introduce duplicates in the indices list. |
| 1156 CollectElementIndices(array, length, &indices); | 1179 CollectElementIndices(array, length, &indices); |
| 1157 indices.Sort(&compareUInt32); | 1180 indices.Sort(&compareUInt32); |
| 1158 int j = 0; | 1181 int j = 0; |
| 1159 int n = indices.length(); | 1182 int n = indices.length(); |
| 1160 while (j < n) { | 1183 while (j < n) { |
| 1161 HandleScope loop_scope(isolate); | 1184 HandleScope loop_scope(isolate); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1182 false); | 1205 false); |
| 1183 if (!visitor->visit(index, element)) return false; | 1206 if (!visitor->visit(index, element)) return false; |
| 1184 } | 1207 } |
| 1185 break; | 1208 break; |
| 1186 } | 1209 } |
| 1187 case NO_ELEMENTS: | 1210 case NO_ELEMENTS: |
| 1188 break; | 1211 break; |
| 1189 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: | 1212 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: |
| 1190 TYPED_ARRAYS(TYPED_ARRAY_CASE) | 1213 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 1191 #undef TYPED_ARRAY_CASE | 1214 #undef TYPED_ARRAY_CASE |
| 1215 return IterateElementsSlow(isolate, receiver, length, visitor); |
| 1192 case FAST_STRING_WRAPPER_ELEMENTS: | 1216 case FAST_STRING_WRAPPER_ELEMENTS: |
| 1193 case SLOW_STRING_WRAPPER_ELEMENTS: | 1217 case SLOW_STRING_WRAPPER_ELEMENTS: |
| 1194 // |array| is guaranteed to be an array or typed array. | 1218 // |array| is guaranteed to be an array or typed array. |
| 1195 UNREACHABLE(); | 1219 UNREACHABLE(); |
| 1196 break; | 1220 break; |
| 1197 } | 1221 } |
| 1198 visitor->increase_index_offset(length); | 1222 visitor->increase_index_offset(length); |
| 1199 return true; | 1223 return true; |
| 1200 } | 1224 } |
| 1201 | 1225 |
| 1202 | 1226 |
| 1203 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | 1227 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { |
| 1204 DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact()); | |
| 1205 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | 1228 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
| 1206 Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); | 1229 Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); |
| 1207 return maybe.FromMaybe(false); | 1230 return maybe.FromMaybe(false); |
| 1208 } | 1231 } |
| 1209 | 1232 |
| 1210 | 1233 |
| 1211 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { | 1234 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
| 1212 HandleScope handle_scope(isolate); | 1235 HandleScope handle_scope(isolate); |
| 1213 if (!obj->IsJSReceiver()) return Just(false); | 1236 if (!obj->IsJSReceiver()) return Just(false); |
| 1214 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | 1237 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1239 for (int i = 0; i < argument_count; i++) { | 1262 for (int i = 0; i < argument_count; i++) { |
| 1240 HandleScope loop_scope(isolate); | 1263 HandleScope loop_scope(isolate); |
| 1241 Handle<Object> obj((*args)[i], isolate); | 1264 Handle<Object> obj((*args)[i], isolate); |
| 1242 uint32_t length_estimate; | 1265 uint32_t length_estimate; |
| 1243 uint32_t element_estimate; | 1266 uint32_t element_estimate; |
| 1244 if (obj->IsJSArray()) { | 1267 if (obj->IsJSArray()) { |
| 1245 Handle<JSArray> array(Handle<JSArray>::cast(obj)); | 1268 Handle<JSArray> array(Handle<JSArray>::cast(obj)); |
| 1246 length_estimate = static_cast<uint32_t>(array->length()->Number()); | 1269 length_estimate = static_cast<uint32_t>(array->length()->Number()); |
| 1247 if (length_estimate != 0) { | 1270 if (length_estimate != 0) { |
| 1248 ElementsKind array_kind = | 1271 ElementsKind array_kind = |
| 1249 GetPackedElementsKind(array->map()->elements_kind()); | 1272 GetPackedElementsKind(array->GetElementsKind()); |
| 1250 kind = GetMoreGeneralElementsKind(kind, array_kind); | 1273 kind = GetMoreGeneralElementsKind(kind, array_kind); |
| 1251 } | 1274 } |
| 1252 element_estimate = EstimateElementCount(array); | 1275 element_estimate = EstimateElementCount(array); |
| 1253 } else { | 1276 } else { |
| 1254 if (obj->IsHeapObject()) { | 1277 if (obj->IsHeapObject()) { |
| 1255 if (obj->IsNumber()) { | 1278 kind = GetMoreGeneralElementsKind( |
| 1256 kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS); | 1279 kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS); |
| 1257 } else { | |
| 1258 kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS); | |
| 1259 } | |
| 1260 } | 1280 } |
| 1261 length_estimate = 1; | 1281 length_estimate = 1; |
| 1262 element_estimate = 1; | 1282 element_estimate = 1; |
| 1263 } | 1283 } |
| 1264 // Avoid overflows by capping at kMaxElementCount. | 1284 // Avoid overflows by capping at kMaxElementCount. |
| 1265 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) { | 1285 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) { |
| 1266 estimate_result_length = JSObject::kMaxElementCount; | 1286 estimate_result_length = JSObject::kMaxElementCount; |
| 1267 } else { | 1287 } else { |
| 1268 estimate_result_length += length_estimate; | 1288 estimate_result_length += length_estimate; |
| 1269 } | 1289 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1292 Handle<Object> obj((*args)[i], isolate); | 1312 Handle<Object> obj((*args)[i], isolate); |
| 1293 if (obj->IsSmi()) { | 1313 if (obj->IsSmi()) { |
| 1294 double_storage->set(j, Smi::cast(*obj)->value()); | 1314 double_storage->set(j, Smi::cast(*obj)->value()); |
| 1295 j++; | 1315 j++; |
| 1296 } else if (obj->IsNumber()) { | 1316 } else if (obj->IsNumber()) { |
| 1297 double_storage->set(j, obj->Number()); | 1317 double_storage->set(j, obj->Number()); |
| 1298 j++; | 1318 j++; |
| 1299 } else { | 1319 } else { |
| 1300 JSArray* array = JSArray::cast(*obj); | 1320 JSArray* array = JSArray::cast(*obj); |
| 1301 uint32_t length = static_cast<uint32_t>(array->length()->Number()); | 1321 uint32_t length = static_cast<uint32_t>(array->length()->Number()); |
| 1302 switch (array->map()->elements_kind()) { | 1322 switch (array->GetElementsKind()) { |
| 1303 case FAST_HOLEY_DOUBLE_ELEMENTS: | 1323 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 1304 case FAST_DOUBLE_ELEMENTS: { | 1324 case FAST_DOUBLE_ELEMENTS: { |
| 1305 // Empty array is FixedArray but not FixedDoubleArray. | 1325 // Empty array is FixedArray but not FixedDoubleArray. |
| 1306 if (length == 0) break; | 1326 if (length == 0) break; |
| 1307 FixedDoubleArray* elements = | 1327 FixedDoubleArray* elements = |
| 1308 FixedDoubleArray::cast(array->elements()); | 1328 FixedDoubleArray::cast(array->elements()); |
| 1309 for (uint32_t i = 0; i < length; i++) { | 1329 for (uint32_t i = 0; i < length; i++) { |
| 1310 if (elements->is_the_hole(i)) { | 1330 if (elements->is_the_hole(i)) { |
| 1311 // TODO(jkummerow/verwaest): We could be a bit more clever | 1331 // TODO(jkummerow/verwaest): We could be a bit more clever |
| 1312 // here: Check if there are no elements/getters on the | 1332 // here: Check if there are no elements/getters on the |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1344 DCHECK_EQ(0u, length); | 1364 DCHECK_EQ(0u, length); |
| 1345 break; | 1365 break; |
| 1346 default: | 1366 default: |
| 1347 UNREACHABLE(); | 1367 UNREACHABLE(); |
| 1348 } | 1368 } |
| 1349 } | 1369 } |
| 1350 if (failure) break; | 1370 if (failure) break; |
| 1351 } | 1371 } |
| 1352 } | 1372 } |
| 1353 if (!failure) { | 1373 if (!failure) { |
| 1354 Handle<JSArray> array = isolate->factory()->NewJSArray(0); | 1374 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); |
| 1355 Smi* length = Smi::FromInt(j); | |
| 1356 Handle<Map> map; | |
| 1357 map = JSObject::GetElementsTransitionMap(array, kind); | |
| 1358 array->set_map(*map); | |
| 1359 array->set_length(length); | |
| 1360 array->set_elements(*storage); | |
| 1361 return *array; | |
| 1362 } | 1375 } |
| 1363 // In case of failure, fall through. | 1376 // In case of failure, fall through. |
| 1364 } | 1377 } |
| 1365 | 1378 |
| 1366 Handle<Object> storage; | 1379 Handle<Object> storage; |
| 1367 if (fast_case) { | 1380 if (fast_case) { |
| 1368 // The backing storage array must have non-existing elements to preserve | 1381 // The backing storage array must have non-existing elements to preserve |
| 1369 // holes across concat operations. | 1382 // holes across concat operations. |
| 1370 storage = | 1383 storage = |
| 1371 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); | 1384 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 | 1421 |
| 1409 if (is_array_species) { | 1422 if (is_array_species) { |
| 1410 return *visitor.ToArray(); | 1423 return *visitor.ToArray(); |
| 1411 } else { | 1424 } else { |
| 1412 return *visitor.storage_jsreceiver(); | 1425 return *visitor.storage_jsreceiver(); |
| 1413 } | 1426 } |
| 1414 } | 1427 } |
| 1415 | 1428 |
| 1416 | 1429 |
| 1417 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 1430 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
| 1418 if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) { | |
| 1419 return MaybeHandle<JSArray>(); | |
| 1420 } | |
| 1421 int n_arguments = args->length(); | 1431 int n_arguments = args->length(); |
| 1422 int result_len = 0; | 1432 int result_len = 0; |
| 1423 { | 1433 { |
| 1424 DisallowHeapAllocation no_gc; | 1434 DisallowHeapAllocation no_gc; |
| 1425 Object* array_proto = isolate->array_function()->prototype(); | |
| 1426 // Iterate through all the arguments performing checks | 1435 // Iterate through all the arguments performing checks |
| 1427 // and calculating total length. | 1436 // and calculating total length. |
| 1428 for (int i = 0; i < n_arguments; i++) { | 1437 for (int i = 0; i < n_arguments; i++) { |
| 1429 Object* arg = (*args)[i]; | 1438 Object* arg = (*args)[i]; |
| 1430 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); | 1439 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
| 1440 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
| 1441 return MaybeHandle<JSArray>(); |
| 1442 } |
| 1443 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. |
| 1444 if (!JSObject::cast(arg)->HasFastElements()) { |
| 1445 return MaybeHandle<JSArray>(); |
| 1446 } |
| 1431 Handle<JSArray> array(JSArray::cast(arg), isolate); | 1447 Handle<JSArray> array(JSArray::cast(arg), isolate); |
| 1432 if (!array->HasFastElements()) return MaybeHandle<JSArray>(); | |
| 1433 PrototypeIterator iter(isolate, *array); | |
| 1434 if (iter.GetCurrent() != array_proto) return MaybeHandle<JSArray>(); | |
| 1435 if (HasConcatSpreadableModifier(isolate, array)) { | 1448 if (HasConcatSpreadableModifier(isolate, array)) { |
| 1436 return MaybeHandle<JSArray>(); | 1449 return MaybeHandle<JSArray>(); |
| 1437 } | 1450 } |
| 1438 int len = Smi::cast(array->length())->value(); | 1451 int len = Smi::cast(array->length())->value(); |
| 1439 | 1452 |
| 1440 // We shouldn't overflow when adding another len. | 1453 // We shouldn't overflow when adding another len. |
| 1441 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 1454 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
| 1442 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 1455 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
| 1443 USE(kHalfOfMaxInt); | 1456 USE(kHalfOfMaxInt); |
| 1444 result_len += len; | 1457 result_len += len; |
| (...skipping 3088 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4533 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 4546 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
| 4534 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 4547 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 4535 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 4548 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
| 4536 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 4549 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
| 4537 #undef DEFINE_BUILTIN_ACCESSOR_C | 4550 #undef DEFINE_BUILTIN_ACCESSOR_C |
| 4538 #undef DEFINE_BUILTIN_ACCESSOR_A | 4551 #undef DEFINE_BUILTIN_ACCESSOR_A |
| 4539 | 4552 |
| 4540 | 4553 |
| 4541 } // namespace internal | 4554 } // namespace internal |
| 4542 } // namespace v8 | 4555 } // namespace v8 |
| OLD | NEW |