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-arguments.h" | 7 #include "src/api-arguments.h" |
8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1215 case FAST_STRING_WRAPPER_ELEMENTS: | 1215 case FAST_STRING_WRAPPER_ELEMENTS: |
1216 case SLOW_STRING_WRAPPER_ELEMENTS: | 1216 case SLOW_STRING_WRAPPER_ELEMENTS: |
1217 // |array| is guaranteed to be an array or typed array. | 1217 // |array| is guaranteed to be an array or typed array. |
1218 UNREACHABLE(); | 1218 UNREACHABLE(); |
1219 break; | 1219 break; |
1220 } | 1220 } |
1221 visitor->increase_index_offset(length); | 1221 visitor->increase_index_offset(length); |
1222 return true; | 1222 return true; |
1223 } | 1223 } |
1224 | 1224 |
1225 | |
1226 bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) { | |
1227 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | |
1228 Maybe<bool> maybe = JSReceiver::HasProperty(obj, key); | |
1229 return maybe.FromMaybe(false); | |
1230 } | |
1231 | |
1232 | |
1233 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { | 1225 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { |
1234 HandleScope handle_scope(isolate); | 1226 HandleScope handle_scope(isolate); |
1235 if (!obj->IsJSReceiver()) return Just(false); | 1227 if (!obj->IsJSReceiver()) return Just(false); |
1236 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); | 1228 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { |
1237 Handle<Object> value; | 1229 // Slow path if @@isConcatSpreadable has been used. |
1238 MaybeHandle<Object> maybeValue = | 1230 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); |
1239 i::Runtime::GetObjectProperty(isolate, obj, key); | 1231 Handle<Object> value; |
1240 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); | 1232 MaybeHandle<Object> maybeValue = |
1241 if (!value->IsUndefined()) return Just(value->BooleanValue()); | 1233 i::Runtime::GetObjectProperty(isolate, obj, key); |
| 1234 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); |
| 1235 if (!value->IsUndefined()) return Just(value->BooleanValue()); |
| 1236 } |
1242 return Object::IsArray(obj); | 1237 return Object::IsArray(obj); |
1243 } | 1238 } |
1244 | 1239 |
1245 | 1240 |
1246 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, | 1241 Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species, |
1247 Isolate* isolate) { | 1242 Isolate* isolate) { |
1248 int argument_count = args->length(); | 1243 int argument_count = args->length(); |
1249 | 1244 |
1250 bool is_array_species = *species == isolate->context()->array_function(); | 1245 bool is_array_species = *species == isolate->context()->array_function(); |
1251 | 1246 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1419 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); | 1414 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); |
1420 } | 1415 } |
1421 | 1416 |
1422 if (is_array_species) { | 1417 if (is_array_species) { |
1423 return *visitor.ToArray(); | 1418 return *visitor.ToArray(); |
1424 } else { | 1419 } else { |
1425 return *visitor.storage_jsreceiver(); | 1420 return *visitor.storage_jsreceiver(); |
1426 } | 1421 } |
1427 } | 1422 } |
1428 | 1423 |
| 1424 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { |
| 1425 DisallowHeapAllocation no_gc; |
| 1426 Map* map = obj->map(); |
| 1427 // If there is only the 'length' property we are fine. |
| 1428 if (map->prototype() == |
| 1429 isolate->native_context()->initial_array_prototype() && |
| 1430 map->NumberOfOwnDescriptors() == 1) { |
| 1431 return true; |
| 1432 } |
| 1433 // TODO(cbruni): slower lookup for array subclasses and support slow |
| 1434 // @@IsConcatSpreadable lookup. |
| 1435 return false; |
| 1436 } |
1429 | 1437 |
1430 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { | 1438 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) { |
| 1439 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { |
| 1440 return MaybeHandle<JSArray>(); |
| 1441 } |
1431 // We shouldn't overflow when adding another len. | 1442 // We shouldn't overflow when adding another len. |
1432 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); | 1443 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); |
1433 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); | 1444 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); |
1434 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); | 1445 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); |
1435 USE(kHalfOfMaxInt); | 1446 USE(kHalfOfMaxInt); |
1436 | 1447 |
1437 int n_arguments = args->length(); | 1448 int n_arguments = args->length(); |
1438 int result_len = 0; | 1449 int result_len = 0; |
1439 { | 1450 { |
1440 DisallowHeapAllocation no_gc; | 1451 DisallowHeapAllocation no_gc; |
1441 // Iterate through all the arguments performing checks | 1452 // Iterate through all the arguments performing checks |
1442 // and calculating total length. | 1453 // and calculating total length. |
1443 for (int i = 0; i < n_arguments; i++) { | 1454 for (int i = 0; i < n_arguments; i++) { |
1444 Object* arg = (*args)[i]; | 1455 Object* arg = (*args)[i]; |
1445 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); | 1456 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); |
| 1457 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { |
| 1458 return MaybeHandle<JSArray>(); |
| 1459 } |
| 1460 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. |
1446 if (!JSObject::cast(arg)->HasFastElements()) { | 1461 if (!JSObject::cast(arg)->HasFastElements()) { |
1447 return MaybeHandle<JSArray>(); | 1462 return MaybeHandle<JSArray>(); |
1448 } | 1463 } |
1449 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { | |
1450 return MaybeHandle<JSArray>(); | |
1451 } | |
1452 Handle<JSArray> array(JSArray::cast(arg), isolate); | 1464 Handle<JSArray> array(JSArray::cast(arg), isolate); |
1453 if (HasConcatSpreadableModifier(isolate, array)) { | 1465 if (!IsSimpleArray(isolate, array)) { |
1454 return MaybeHandle<JSArray>(); | 1466 return MaybeHandle<JSArray>(); |
1455 } | 1467 } |
1456 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't | 1468 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't |
1457 // overflow. | 1469 // overflow. |
1458 result_len += Smi::cast(array->length())->value(); | 1470 result_len += Smi::cast(array->length())->value(); |
1459 DCHECK(result_len >= 0); | 1471 DCHECK(result_len >= 0); |
1460 // Throw an Error if we overflow the FixedArray limits | 1472 // Throw an Error if we overflow the FixedArray limits |
1461 if (FixedDoubleArray::kMaxLength < result_len || | 1473 if (FixedArray::kMaxLength < result_len) { |
1462 FixedArray::kMaxLength < result_len) { | 1474 AllowHeapAllocation gc; |
1463 AllowHeapAllocation allow_gc; | |
1464 THROW_NEW_ERROR(isolate, | 1475 THROW_NEW_ERROR(isolate, |
1465 NewRangeError(MessageTemplate::kInvalidArrayLength), | 1476 NewRangeError(MessageTemplate::kInvalidArrayLength), |
1466 JSArray); | 1477 JSArray); |
1467 } | 1478 } |
1468 } | 1479 } |
1469 } | 1480 } |
1470 return ElementsAccessor::Concat(isolate, args, n_arguments); | 1481 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); |
1471 } | 1482 } |
1472 | 1483 |
1473 } // namespace | 1484 } // namespace |
1474 | 1485 |
1475 | 1486 |
1476 // ES6 22.1.3.1 Array.prototype.concat | 1487 // ES6 22.1.3.1 Array.prototype.concat |
1477 BUILTIN(ArrayConcat) { | 1488 BUILTIN(ArrayConcat) { |
1478 HandleScope scope(isolate); | 1489 HandleScope scope(isolate); |
1479 | 1490 |
1480 Handle<Object> receiver = args.receiver(); | 1491 Handle<Object> receiver = args.receiver(); |
(...skipping 3984 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5465 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) | 5476 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) |
5466 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 5477 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
5467 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 5478 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
5468 #undef DEFINE_BUILTIN_ACCESSOR_C | 5479 #undef DEFINE_BUILTIN_ACCESSOR_C |
5469 #undef DEFINE_BUILTIN_ACCESSOR_A | 5480 #undef DEFINE_BUILTIN_ACCESSOR_A |
5470 #undef DEFINE_BUILTIN_ACCESSOR_T | 5481 #undef DEFINE_BUILTIN_ACCESSOR_T |
5471 #undef DEFINE_BUILTIN_ACCESSOR_H | 5482 #undef DEFINE_BUILTIN_ACCESSOR_H |
5472 | 5483 |
5473 } // namespace internal | 5484 } // namespace internal |
5474 } // namespace v8 | 5485 } // namespace v8 |
OLD | NEW |