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 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 return true; | 259 return true; |
260 } | 260 } |
261 | 261 |
262 // Returns |false| if not applicable. | 262 // Returns |false| if not applicable. |
263 MUST_USE_RESULT | 263 MUST_USE_RESULT |
264 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, | 264 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, |
265 Handle<Object> receiver, | 265 Handle<Object> receiver, |
266 Arguments* args, | 266 Arguments* args, |
267 int first_added_arg) { | 267 int first_added_arg) { |
268 if (!receiver->IsJSArray()) return false; | 268 if (!receiver->IsJSArray()) return false; |
| 269 |
269 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 270 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
270 ElementsKind origin_kind = array->GetElementsKind(); | 271 ElementsKind origin_kind = array->GetElementsKind(); |
271 if (IsDictionaryElementsKind(origin_kind)) return false; | 272 if (IsDictionaryElementsKind(origin_kind)) return false; |
272 if (array->map()->is_observed()) return false; | 273 if (array->map()->is_observed()) return false; |
273 if (!array->map()->is_extensible()) return false; | 274 if (!array->map()->is_extensible()) return false; |
274 if (args == nullptr) return true; | 275 if (args == nullptr) return true; |
275 | 276 |
276 // If there may be elements accessors in the prototype chain, the fast path | 277 // If there may be elements accessors in the prototype chain, the fast path |
277 // cannot be used if there arguments to add to the array. | 278 // cannot be used if there arguments to add to the array. |
278 if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false; | 279 if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false; |
(...skipping 1031 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1310 case FAST_STRING_WRAPPER_ELEMENTS: | 1311 case FAST_STRING_WRAPPER_ELEMENTS: |
1311 case SLOW_STRING_WRAPPER_ELEMENTS: | 1312 case SLOW_STRING_WRAPPER_ELEMENTS: |
1312 // |array| is guaranteed to be an array or typed array. | 1313 // |array| is guaranteed to be an array or typed array. |
1313 UNREACHABLE(); | 1314 UNREACHABLE(); |
1314 break; | 1315 break; |
1315 } | 1316 } |
1316 visitor->increase_index_offset(length); | 1317 visitor->increase_index_offset(length); |
1317 return true; | 1318 return true; |
1318 } | 1319 } |
1319 | 1320 |
1320 | |
1321 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | |
1322 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | |
1323 Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); | |
1324 return maybe.FromMaybe(false); | |
1325 } | |
1326 | |
1327 | |
1328 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { | 1321 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
1329 HandleScope handle_scope(isolate); | 1322 HandleScope handle_scope(isolate); |
1330 if (!obj->IsJSReceiver()) return Just(false); | 1323 if (!obj->IsJSReceiver()) return Just(false); |
1331 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | 1324 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
1332 Handle<Object> value; | 1325 Handle<Object> value; |
1333 MaybeHandle<Object> maybeValue = | 1326 MaybeHandle<Object> maybeValue = |
1334 i::Runtime::GetObjectProperty(isolate, obj, key); | 1327 i::Runtime::GetObjectProperty(isolate, obj, key); |
1335 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | 1328 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); |
1336 if (!value->IsUndefined()) return Just(value->BooleanValue()); | 1329 if (!value->IsUndefined()) return Just(value->BooleanValue()); |
1337 return Object::IsArray(obj); | 1330 return Object::IsArray(obj); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1512 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); | 1505 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); |
1513 } | 1506 } |
1514 | 1507 |
1515 if (is_array_species) { | 1508 if (is_array_species) { |
1516 return *visitor.ToArray(); | 1509 return *visitor.ToArray(); |
1517 } else { | 1510 } else { |
1518 return *visitor.storage_jsreceiver(); | 1511 return *visitor.storage_jsreceiver(); |
1519 } | 1512 } |
1520 } | 1513 } |
1521 | 1514 |
| 1515 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { |
| 1516 { |
| 1517 DisallowHeapAllocation no_gc; |
| 1518 Map* map = obj->map(); |
| 1519 if (map->prototype() == |
| 1520 isolate->native_context()->initial_array_prototype()) { |
| 1521 // If there is only the 'length' property we are fine. |
| 1522 if (map->NumberOfOwnDescriptors() == 1) return false; |
| 1523 } |
| 1524 } |
| 1525 // TODO(cbruni): slower lookup for array subclasses and support slow |
| 1526 // @@IsConcatSpreadable lookup. |
| 1527 return true; |
| 1528 } |
1522 | 1529 |
1523 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 1530 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
| 1531 if (!isolate->IsArrayIsConcatSpreadableLookupChainIntact()) { |
| 1532 return MaybeHandle<JSArray>(); |
| 1533 } |
1524 int n_arguments = args->length(); | 1534 int n_arguments = args->length(); |
1525 int result_len = 0; | 1535 int result_len = 0; |
1526 { | 1536 { |
1527 DisallowHeapAllocation no_gc; | 1537 DisallowHeapAllocation no_gc; |
1528 // Iterate through all the arguments performing checks | 1538 // Iterate through all the arguments performing checks |
1529 // and calculating total length. | 1539 // and calculating total length. |
1530 for (int i = 0; i < n_arguments; i++) { | 1540 for (int i = 0; i < n_arguments; i++) { |
1531 Object* arg = (*args)[i]; | 1541 Object* arg = (*args)[i]; |
1532 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); | 1542 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
1533 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { | 1543 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
1534 return MaybeHandle<JSArray>(); | 1544 return MaybeHandle<JSArray>(); |
1535 } | 1545 } |
1536 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. | 1546 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. |
1537 if (!JSObject::cast(arg)->HasFastElements()) { | 1547 if (!JSObject::cast(arg)->HasFastElements()) { |
1538 return MaybeHandle<JSArray>(); | 1548 return MaybeHandle<JSArray>(); |
1539 } | 1549 } |
1540 Handle<JSArray> array(JSArray::cast(arg), isolate); | 1550 Handle<JSArray> array(JSArray::cast(arg), isolate); |
1541 if (HasConcatSpreadableModifier(isolate, array)) { | 1551 if (IsSimpleArray(isolate, array)) { |
1542 return MaybeHandle<JSArray>(); | 1552 return MaybeHandle<JSArray>(); |
1543 } | 1553 } |
1544 int len = Smi::cast(array->length())->value(); | 1554 int len = Smi::cast(array->length())->value(); |
1545 | 1555 |
1546 // We shouldn't overflow when adding another len. | 1556 // We shouldn't overflow when adding another len. |
1547 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 1557 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
1548 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 1558 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
1549 USE(kHalfOfMaxInt); | 1559 USE(kHalfOfMaxInt); |
1550 result_len += len; | 1560 result_len += len; |
1551 DCHECK(result_len >= 0); | 1561 DCHECK_LE(0, result_len); |
1552 // Throw an Error if we overflow the FixedArray limits | 1562 // Throw an Error if we overflow the FixedArray limits |
1553 if (FixedArray::kMaxLength < result_len) { | 1563 if (FixedArray::kMaxLength < result_len) { |
1554 THROW_NEW_ERROR(isolate, | 1564 THROW_NEW_ERROR(isolate, |
1555 NewRangeError(MessageTemplate::kInvalidArrayLength), | 1565 NewRangeError(MessageTemplate::kInvalidArrayLength), |
1556 JSArray); | 1566 JSArray); |
1557 } | 1567 } |
1558 } | 1568 } |
1559 } | 1569 } |
1560 return ElementsAccessor::Concat(isolate, args, n_arguments); | 1570 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); |
1561 } | 1571 } |
1562 | 1572 |
1563 } // namespace | 1573 } // namespace |
1564 | 1574 |
1565 | 1575 |
1566 // ES6 22.1.3.1 Array.prototype.concat | 1576 // ES6 22.1.3.1 Array.prototype.concat |
1567 BUILTIN(ArrayConcat) { | 1577 BUILTIN(ArrayConcat) { |
1568 HandleScope scope(isolate); | 1578 HandleScope scope(isolate); |
1569 | 1579 |
1570 Handle<Object> receiver = args.receiver(); | 1580 Handle<Object> receiver = args.receiver(); |
(...skipping 3196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4767 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) | 4777 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) |
4768 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 4778 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
4769 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 4779 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
4770 #undef DEFINE_BUILTIN_ACCESSOR_C | 4780 #undef DEFINE_BUILTIN_ACCESSOR_C |
4771 #undef DEFINE_BUILTIN_ACCESSOR_A | 4781 #undef DEFINE_BUILTIN_ACCESSOR_A |
4772 #undef DEFINE_BUILTIN_ACCESSOR_T | 4782 #undef DEFINE_BUILTIN_ACCESSOR_T |
4773 #undef DEFINE_BUILTIN_ACCESSOR_H | 4783 #undef DEFINE_BUILTIN_ACCESSOR_H |
4774 | 4784 |
4775 } // namespace internal | 4785 } // namespace internal |
4776 } // namespace v8 | 4786 } // namespace v8 |
OLD | NEW |