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 1310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1321 case FAST_STRING_WRAPPER_ELEMENTS: | 1321 case FAST_STRING_WRAPPER_ELEMENTS: |
1322 case SLOW_STRING_WRAPPER_ELEMENTS: | 1322 case SLOW_STRING_WRAPPER_ELEMENTS: |
1323 // |array| is guaranteed to be an array or typed array. | 1323 // |array| is guaranteed to be an array or typed array. |
1324 UNREACHABLE(); | 1324 UNREACHABLE(); |
1325 break; | 1325 break; |
1326 } | 1326 } |
1327 visitor->increase_index_offset(length); | 1327 visitor->increase_index_offset(length); |
1328 return true; | 1328 return true; |
1329 } | 1329 } |
1330 | 1330 |
1331 | |
1332 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | |
1333 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | |
1334 Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); | |
1335 return maybe.FromMaybe(false); | |
1336 } | |
1337 | |
1338 | |
1339 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { | 1331 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
1340 HandleScope handle_scope(isolate); | 1332 HandleScope handle_scope(isolate); |
1341 if (!obj->IsJSReceiver()) return Just(false); | 1333 if (!obj->IsJSReceiver()) return Just(false); |
1342 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | 1334 if (!isolate->IsArrayIsConcatSpreadableLookupChainIntact()) { |
Toon Verwaest
2016/04/11 09:30:56
This only guarantees that Array.prototype and Obje
Camillo Bruni
2016/04/11 11:55:12
I think the naming for the protector is confusing.
| |
1343 Handle<Object> value; | 1335 // Slow path if @@isConcatSpreadable has been used. |
1344 MaybeHandle<Object> maybeValue = | 1336 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
1345 i::Runtime::GetObjectProperty(isolate, obj, key); | 1337 Handle<Object> value; |
1346 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | 1338 MaybeHandle<Object> maybeValue = |
1347 if (!value->IsUndefined()) return Just(value->BooleanValue()); | 1339 i::Runtime::GetObjectProperty(isolate, obj, key); |
1340 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | |
1341 if (!value->IsUndefined()) return Just(value->BooleanValue()); | |
1342 } | |
1348 return Object::IsArray(obj); | 1343 return Object::IsArray(obj); |
1349 } | 1344 } |
1350 | 1345 |
1351 | 1346 |
1352 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, | 1347 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
1353 Isolate* isolate) { | 1348 Isolate* isolate) { |
1354 int argument_count = args->length(); | 1349 int argument_count = args->length(); |
1355 | 1350 |
1356 bool is_array_species = *species == isolate->context()->array_function(); | 1351 bool is_array_species = *species == isolate->context()->array_function(); |
1357 | 1352 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1525 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); | 1520 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); |
1526 } | 1521 } |
1527 | 1522 |
1528 if (is_array_species) { | 1523 if (is_array_species) { |
1529 return *visitor.ToArray(); | 1524 return *visitor.ToArray(); |
1530 } else { | 1525 } else { |
1531 return *visitor.storage_jsreceiver(); | 1526 return *visitor.storage_jsreceiver(); |
1532 } | 1527 } |
1533 } | 1528 } |
1534 | 1529 |
1530 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { | |
1531 { | |
1532 DisallowHeapAllocation no_gc; | |
1533 Map* map = obj->map(); | |
1534 // If there is only the 'length' property we are fine. | |
1535 if (map->prototype() == | |
1536 isolate->native_context()->initial_array_prototype() && | |
1537 map->NumberOfOwnDescriptors() == 1) { | |
1538 return true; | |
1539 } | |
1540 } | |
1541 // TODO(cbruni): slower lookup for array subclasses and support slow | |
1542 // @@IsConcatSpreadable lookup. | |
1543 return false; | |
1544 } | |
1535 | 1545 |
1536 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 1546 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
1547 if (!isolate->IsArrayIsConcatSpreadableLookupChainIntact()) { | |
1548 return MaybeHandle<JSArray>(); | |
1549 } | |
1537 // We shouldn't overflow when adding another len. | 1550 // We shouldn't overflow when adding another len. |
1538 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 1551 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
1539 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 1552 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
1540 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); | 1553 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); |
1541 USE(kHalfOfMaxInt); | 1554 USE(kHalfOfMaxInt); |
1542 | 1555 |
1543 int n_arguments = args->length(); | 1556 int n_arguments = args->length(); |
1544 int result_len = 0; | 1557 int result_len = 0; |
1545 { | 1558 { |
1546 DisallowHeapAllocation no_gc; | 1559 DisallowHeapAllocation no_gc; |
1547 // Iterate through all the arguments performing checks | 1560 // Iterate through all the arguments performing checks |
1548 // and calculating total length. | 1561 // and calculating total length. |
1549 for (int i = 0; i < n_arguments; i++) { | 1562 for (int i = 0; i < n_arguments; i++) { |
1550 Object* arg = (*args)[i]; | 1563 Object* arg = (*args)[i]; |
1551 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); | 1564 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
1565 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { | |
1566 return MaybeHandle<JSArray>(); | |
1567 } | |
1568 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. | |
1552 if (!JSObject::cast(arg)->HasFastElements()) { | 1569 if (!JSObject::cast(arg)->HasFastElements()) { |
1553 return MaybeHandle<JSArray>(); | 1570 return MaybeHandle<JSArray>(); |
1554 } | 1571 } |
1555 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { | |
1556 return MaybeHandle<JSArray>(); | |
1557 } | |
1558 Handle<JSArray> array(JSArray::cast(arg), isolate); | 1572 Handle<JSArray> array(JSArray::cast(arg), isolate); |
1559 if (HasConcatSpreadableModifier(isolate, array)) { | 1573 if (!IsSimpleArray(isolate, array)) { |
1560 return MaybeHandle<JSArray>(); | 1574 return MaybeHandle<JSArray>(); |
1561 } | 1575 } |
1562 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't | 1576 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't |
1563 // overflow. | 1577 // overflow. |
1564 result_len += Smi::cast(array->length())->value(); | 1578 result_len += Smi::cast(array->length())->value(); |
1565 DCHECK(result_len >= 0); | 1579 DCHECK(result_len >= 0); |
1566 // Throw an Error if we overflow the FixedArray limits | 1580 // Throw an Error if we overflow the FixedArray limits |
1567 if (FixedDoubleArray::kMaxLength < result_len || | 1581 if (FixedArray::kMaxLength < result_len) { |
1568 FixedArray::kMaxLength < result_len) { | |
1569 AllowHeapAllocation allow_gc; | |
1570 THROW_NEW_ERROR(isolate, | 1582 THROW_NEW_ERROR(isolate, |
1571 NewRangeError(MessageTemplate::kInvalidArrayLength), | 1583 NewRangeError(MessageTemplate::kInvalidArrayLength), |
1572 JSArray); | 1584 JSArray); |
1573 } | 1585 } |
1574 } | 1586 } |
1575 } | 1587 } |
1576 return ElementsAccessor::Concat(isolate, args, n_arguments); | 1588 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); |
1577 } | 1589 } |
1578 | 1590 |
1579 } // namespace | 1591 } // namespace |
1580 | 1592 |
1581 | 1593 |
1582 // ES6 22.1.3.1 Array.prototype.concat | 1594 // ES6 22.1.3.1 Array.prototype.concat |
1583 BUILTIN(ArrayConcat) { | 1595 BUILTIN(ArrayConcat) { |
1584 HandleScope scope(isolate); | 1596 HandleScope scope(isolate); |
1585 | 1597 |
1586 Handle<Object> receiver = args.receiver(); | 1598 Handle<Object> receiver = args.receiver(); |
(...skipping 3361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4948 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) | 4960 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) |
4949 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 4961 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
4950 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 4962 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
4951 #undef DEFINE_BUILTIN_ACCESSOR_C | 4963 #undef DEFINE_BUILTIN_ACCESSOR_C |
4952 #undef DEFINE_BUILTIN_ACCESSOR_A | 4964 #undef DEFINE_BUILTIN_ACCESSOR_A |
4953 #undef DEFINE_BUILTIN_ACCESSOR_T | 4965 #undef DEFINE_BUILTIN_ACCESSOR_T |
4954 #undef DEFINE_BUILTIN_ACCESSOR_H | 4966 #undef DEFINE_BUILTIN_ACCESSOR_H |
4955 | 4967 |
4956 } // namespace internal | 4968 } // namespace internal |
4957 } // namespace v8 | 4969 } // namespace v8 |
OLD | NEW |