OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
| 7 |
| 8 #include "src/code-factory.h" |
7 #include "src/elements.h" | 9 #include "src/elements.h" |
8 | 10 |
9 namespace v8 { | 11 namespace v8 { |
10 namespace internal { | 12 namespace internal { |
11 | 13 |
12 namespace { | 14 namespace { |
13 | 15 |
14 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { | 16 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { |
15 // This is an extended version of ECMA-262 7.1.11 handling signed values | 17 // This is an extended version of ECMA-262 7.1.11 handling signed values |
16 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] | 18 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 map != context->fast_aliased_arguments_map()) { | 50 map != context->fast_aliased_arguments_map()) { |
49 return false; | 51 return false; |
50 } | 52 } |
51 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements()); | 53 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements()); |
52 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); | 54 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); |
53 if (!len_obj->IsSmi()) return false; | 55 if (!len_obj->IsSmi()) return false; |
54 *out = Max(0, Smi::cast(len_obj)->value()); | 56 *out = Max(0, Smi::cast(len_obj)->value()); |
55 return *out <= object->elements()->length(); | 57 return *out <= object->elements()->length(); |
56 } | 58 } |
57 | 59 |
58 inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object) { | |
59 DisallowHeapAllocation no_gc; | |
60 HeapObject* prototype = HeapObject::cast(object->map()->prototype()); | |
61 HeapObject* null = isolate->heap()->null_value(); | |
62 HeapObject* empty = isolate->heap()->empty_fixed_array(); | |
63 while (prototype != null) { | |
64 Map* map = prototype->map(); | |
65 if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false; | |
66 if (JSObject::cast(prototype)->elements() != empty) return false; | |
67 prototype = HeapObject::cast(map->prototype()); | |
68 } | |
69 return true; | |
70 } | |
71 | |
72 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, | 60 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
73 JSArray* receiver) { | 61 JSArray* receiver) { |
74 return PrototypeHasNoElements(isolate, receiver); | 62 return JSObject::PrototypeHasNoElements(isolate, receiver); |
75 } | 63 } |
76 | 64 |
77 inline bool HasSimpleElements(JSObject* current) { | 65 inline bool HasSimpleElements(JSObject* current) { |
78 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && | 66 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
79 !current->GetElementsAccessor()->HasAccessors(current); | 67 !current->GetElementsAccessor()->HasAccessors(current); |
80 } | 68 } |
81 | 69 |
82 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, | 70 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, |
83 JSObject* receiver) { | 71 JSObject* receiver) { |
84 // Check that we have no accessors on the receiver's elements. | 72 // Check that we have no accessors on the receiver's elements. |
85 if (!HasSimpleElements(receiver)) return false; | 73 if (!HasSimpleElements(receiver)) return false; |
86 return PrototypeHasNoElements(isolate, receiver); | 74 return JSObject::PrototypeHasNoElements(isolate, receiver); |
87 } | 75 } |
88 | 76 |
89 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { | 77 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { |
90 DisallowHeapAllocation no_gc; | 78 DisallowHeapAllocation no_gc; |
91 PrototypeIterator iter(isolate, receiver, kStartAtReceiver); | 79 PrototypeIterator iter(isolate, receiver, kStartAtReceiver); |
92 for (; !iter.IsAtEnd(); iter.Advance()) { | 80 for (; !iter.IsAtEnd(); iter.Advance()) { |
93 if (iter.GetCurrent()->IsJSProxy()) return false; | 81 if (iter.GetCurrent()->IsJSProxy()) return false; |
94 JSObject* current = iter.GetCurrent<JSObject>(); | 82 JSObject* current = iter.GetCurrent<JSObject>(); |
95 if (!HasSimpleElements(current)) return false; | 83 if (!HasSimpleElements(current)) return false; |
96 } | 84 } |
(...skipping 1167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1264 assembler->Return(assembler->BooleanConstant(true)); | 1252 assembler->Return(assembler->BooleanConstant(true)); |
1265 | 1253 |
1266 assembler->Bind(&return_false); | 1254 assembler->Bind(&return_false); |
1267 assembler->Return(assembler->BooleanConstant(false)); | 1255 assembler->Return(assembler->BooleanConstant(false)); |
1268 | 1256 |
1269 assembler->Bind(&call_runtime); | 1257 assembler->Bind(&call_runtime); |
1270 assembler->Return( | 1258 assembler->Return( |
1271 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); | 1259 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); |
1272 } | 1260 } |
1273 | 1261 |
| 1262 void Builtins::Generate_ArrayIncludes(CodeStubAssembler* assembler) { |
| 1263 typedef compiler::Node Node; |
| 1264 typedef CodeStubAssembler::Label Label; |
| 1265 typedef CodeStubAssembler::Variable Variable; |
| 1266 |
| 1267 Node* array = assembler->Parameter(0); |
| 1268 Node* search_element = assembler->Parameter(1); |
| 1269 Node* start_from = assembler->Parameter(2); |
| 1270 Node* context = assembler->Parameter(3 + 2); |
| 1271 |
| 1272 Node* int32_zero = assembler->Int32Constant(0); |
| 1273 Node* int32_one = assembler->Int32Constant(1); |
| 1274 |
| 1275 Node* the_hole = assembler->TheHoleConstant(); |
| 1276 Node* undefined = assembler->UndefinedConstant(); |
| 1277 Node* heap_number_map = assembler->HeapNumberMapConstant(); |
| 1278 |
| 1279 Variable len_var(assembler, MachineRepresentation::kWord32), |
| 1280 index_var(assembler, MachineRepresentation::kWord32), |
| 1281 start_from_var(assembler, MachineRepresentation::kWord32); |
| 1282 |
| 1283 Label init_k(assembler), return_true(assembler), return_false(assembler), |
| 1284 call_runtime(assembler); |
| 1285 |
| 1286 Label init_len(assembler); |
| 1287 |
| 1288 index_var.Bind(int32_zero); |
| 1289 len_var.Bind(int32_zero); |
| 1290 |
| 1291 // Take slow path if not a JSArray, if retrieving elements requires |
| 1292 // traversing prototype, or if access checks are required. |
| 1293 assembler->BranchIfFastJSArray(array, context, &init_len, &call_runtime); |
| 1294 |
| 1295 assembler->Bind(&init_len); |
| 1296 { |
| 1297 // Handle case where JSArray length is not an Smi in the runtime |
| 1298 Node* len = assembler->LoadObjectField(array, JSArray::kLengthOffset); |
| 1299 assembler->GotoUnless(assembler->WordIsSmi(len), &call_runtime); |
| 1300 |
| 1301 len_var.Bind(assembler->SmiToWord(len)); |
| 1302 assembler->Branch(assembler->Word32Equal(len_var.value(), int32_zero), |
| 1303 &return_false, &init_k); |
| 1304 } |
| 1305 |
| 1306 assembler->Bind(&init_k); |
| 1307 { |
| 1308 Label done(assembler), init_k_smi(assembler), init_k_heap_num(assembler), |
| 1309 init_k_zero(assembler), init_k_n(assembler); |
| 1310 Callable call_to_integer = CodeFactory::ToInteger(assembler->isolate()); |
| 1311 Node* tagged_n = assembler->CallStub(call_to_integer, context, start_from); |
| 1312 |
| 1313 assembler->Branch(assembler->WordIsSmi(tagged_n), &init_k_smi, |
| 1314 &init_k_heap_num); |
| 1315 |
| 1316 assembler->Bind(&init_k_smi); |
| 1317 { |
| 1318 start_from_var.Bind(assembler->SmiToWord32(tagged_n)); |
| 1319 assembler->Goto(&init_k_n); |
| 1320 } |
| 1321 |
| 1322 assembler->Bind(&init_k_heap_num); |
| 1323 { |
| 1324 Label do_return_false(assembler); |
| 1325 Node* fp_len = assembler->ChangeInt32ToFloat64(len_var.value()); |
| 1326 Node* fp_n = assembler->LoadHeapNumberValue(tagged_n); |
| 1327 assembler->GotoIf(assembler->Float64GreaterThanOrEqual(fp_n, fp_len), |
| 1328 &do_return_false); |
| 1329 start_from_var.Bind(assembler->TruncateFloat64ToWord32(fp_n)); |
| 1330 assembler->Goto(&init_k_n); |
| 1331 |
| 1332 assembler->Bind(&do_return_false); |
| 1333 { |
| 1334 index_var.Bind(int32_zero); |
| 1335 assembler->Goto(&return_false); |
| 1336 } |
| 1337 } |
| 1338 |
| 1339 assembler->Bind(&init_k_n); |
| 1340 { |
| 1341 Label if_positive(assembler), if_negative(assembler), done(assembler); |
| 1342 assembler->Branch( |
| 1343 assembler->Int32LessThan(start_from_var.value(), int32_zero), |
| 1344 &if_negative, &if_positive); |
| 1345 |
| 1346 assembler->Bind(&if_positive); |
| 1347 { |
| 1348 index_var.Bind(start_from_var.value()); |
| 1349 assembler->Goto(&done); |
| 1350 } |
| 1351 |
| 1352 assembler->Bind(&if_negative); |
| 1353 { |
| 1354 index_var.Bind( |
| 1355 assembler->Int32Add(len_var.value(), start_from_var.value())); |
| 1356 assembler->Branch( |
| 1357 assembler->Int32LessThan(index_var.value(), int32_zero), |
| 1358 &init_k_zero, &done); |
| 1359 } |
| 1360 |
| 1361 assembler->Bind(&init_k_zero); |
| 1362 { |
| 1363 index_var.Bind(int32_zero); |
| 1364 assembler->Goto(&done); |
| 1365 } |
| 1366 |
| 1367 assembler->Bind(&done); |
| 1368 } |
| 1369 } |
| 1370 |
| 1371 static int32_t kElementsKind[] = { |
| 1372 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, |
| 1373 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, |
| 1374 }; |
| 1375 |
| 1376 Label if_smiorobjects(assembler), if_packed_doubles(assembler), |
| 1377 if_holey_doubles(assembler); |
| 1378 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, |
| 1379 &if_smiorobjects, &if_smiorobjects, |
| 1380 &if_packed_doubles, &if_holey_doubles}; |
| 1381 |
| 1382 Node* map = assembler->LoadMap(array); |
| 1383 Node* bit_field2 = assembler->LoadMapBitField2(map); |
| 1384 Node* elements_kind = |
| 1385 assembler->BitFieldDecode<Map::ElementsKindBits>(bit_field2); |
| 1386 Node* elements = assembler->LoadElements(array); |
| 1387 assembler->Switch(elements_kind, &return_false, kElementsKind, |
| 1388 element_kind_handlers, arraysize(kElementsKind)); |
| 1389 |
| 1390 assembler->Bind(&if_smiorobjects); |
| 1391 { |
| 1392 Variable search_num(assembler, MachineRepresentation::kFloat64); |
| 1393 Label ident_loop(assembler, &index_var), |
| 1394 heap_num_loop(assembler, &search_num), |
| 1395 string_loop(assembler, &index_var), simd_loop(assembler), |
| 1396 undef_loop(assembler, &index_var), not_smi(assembler), |
| 1397 not_heap_num(assembler); |
| 1398 |
| 1399 assembler->GotoUnless(assembler->WordIsSmi(search_element), ¬_smi); |
| 1400 search_num.Bind(assembler->SmiToFloat64(search_element)); |
| 1401 assembler->Goto(&heap_num_loop); |
| 1402 |
| 1403 assembler->Bind(¬_smi); |
| 1404 assembler->GotoIf(assembler->WordEqual(search_element, undefined), |
| 1405 &undef_loop); |
| 1406 Node* map = assembler->LoadMap(search_element); |
| 1407 assembler->GotoIf(assembler->WordNotEqual(map, heap_number_map), |
| 1408 ¬_heap_num); |
| 1409 search_num.Bind(assembler->LoadHeapNumberValue(search_element)); |
| 1410 assembler->Goto(&heap_num_loop); |
| 1411 |
| 1412 assembler->Bind(¬_heap_num); |
| 1413 Node* search_type = assembler->LoadMapInstanceType(map); |
| 1414 assembler->GotoIf( |
| 1415 assembler->Int32LessThan( |
| 1416 search_type, assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
| 1417 &string_loop); |
| 1418 assembler->GotoIf( |
| 1419 assembler->WordEqual(search_type, |
| 1420 assembler->Int32Constant(SIMD128_VALUE_TYPE)), |
| 1421 &simd_loop); |
| 1422 assembler->Goto(&ident_loop); |
| 1423 |
| 1424 assembler->Bind(&ident_loop); |
| 1425 { |
| 1426 assembler->GotoUnless( |
| 1427 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1428 &return_false); |
| 1429 Node* element_k = |
| 1430 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1431 assembler->GotoIf(assembler->WordEqual(element_k, search_element), |
| 1432 &return_true); |
| 1433 |
| 1434 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1435 assembler->Goto(&ident_loop); |
| 1436 } |
| 1437 |
| 1438 assembler->Bind(&undef_loop); |
| 1439 { |
| 1440 assembler->GotoUnless( |
| 1441 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1442 &return_false); |
| 1443 Node* element_k = |
| 1444 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1445 assembler->GotoIf(assembler->WordEqual(element_k, undefined), |
| 1446 &return_true); |
| 1447 assembler->GotoIf(assembler->WordEqual(element_k, the_hole), |
| 1448 &return_true); |
| 1449 |
| 1450 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1451 assembler->Goto(&undef_loop); |
| 1452 } |
| 1453 |
| 1454 assembler->Bind(&heap_num_loop); |
| 1455 { |
| 1456 Label nan_loop(assembler, &index_var), |
| 1457 not_nan_loop(assembler, &index_var); |
| 1458 assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, |
| 1459 ¬_nan_loop); |
| 1460 |
| 1461 assembler->Bind(¬_nan_loop); |
| 1462 { |
| 1463 Label continue_loop(assembler), not_smi(assembler); |
| 1464 assembler->GotoUnless( |
| 1465 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1466 &return_false); |
| 1467 Node* element_k = |
| 1468 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1469 assembler->GotoUnless(assembler->WordIsSmi(element_k), ¬_smi); |
| 1470 assembler->Branch( |
| 1471 assembler->Float64Equal(search_num.value(), |
| 1472 assembler->SmiToFloat64(element_k)), |
| 1473 &return_true, &continue_loop); |
| 1474 |
| 1475 assembler->Bind(¬_smi); |
| 1476 assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), |
| 1477 heap_number_map), |
| 1478 &continue_loop); |
| 1479 assembler->BranchIfFloat64Equal( |
| 1480 search_num.value(), assembler->LoadHeapNumberValue(element_k), |
| 1481 &return_true, &continue_loop); |
| 1482 |
| 1483 assembler->Bind(&continue_loop); |
| 1484 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1485 assembler->Goto(¬_nan_loop); |
| 1486 } |
| 1487 |
| 1488 assembler->Bind(&nan_loop); |
| 1489 { |
| 1490 Label continue_loop(assembler); |
| 1491 assembler->GotoUnless( |
| 1492 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1493 &return_false); |
| 1494 Node* element_k = |
| 1495 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1496 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); |
| 1497 assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), |
| 1498 heap_number_map), |
| 1499 &continue_loop); |
| 1500 assembler->BranchIfFloat64IsNaN( |
| 1501 assembler->LoadHeapNumberValue(element_k), &return_true, |
| 1502 &continue_loop); |
| 1503 |
| 1504 assembler->Bind(&continue_loop); |
| 1505 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1506 assembler->Goto(&nan_loop); |
| 1507 } |
| 1508 } |
| 1509 |
| 1510 assembler->Bind(&string_loop); |
| 1511 { |
| 1512 Label continue_loop(assembler); |
| 1513 assembler->GotoUnless( |
| 1514 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1515 &return_false); |
| 1516 Node* element_k = |
| 1517 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1518 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); |
| 1519 assembler->GotoUnless(assembler->Int32LessThan( |
| 1520 assembler->LoadMapInstanceType(element_k), |
| 1521 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
| 1522 &continue_loop); |
| 1523 |
| 1524 // TODO(bmeurer): Consider inlining the StringEqual logic here. |
| 1525 Callable callable = CodeFactory::StringEqual(assembler->isolate()); |
| 1526 Node* result = |
| 1527 assembler->CallStub(callable, context, search_element, element_k); |
| 1528 assembler->Branch( |
| 1529 assembler->WordEqual(assembler->BooleanConstant(true), result), |
| 1530 &return_true, &continue_loop); |
| 1531 |
| 1532 assembler->Bind(&continue_loop); |
| 1533 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1534 assembler->Goto(&string_loop); |
| 1535 } |
| 1536 |
| 1537 assembler->Bind(&simd_loop); |
| 1538 { |
| 1539 Label continue_loop(assembler, &index_var), |
| 1540 loop_body(assembler, &index_var); |
| 1541 Node* map = assembler->LoadMap(search_element); |
| 1542 |
| 1543 assembler->Goto(&loop_body); |
| 1544 assembler->Bind(&loop_body); |
| 1545 assembler->GotoUnless( |
| 1546 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1547 &return_false); |
| 1548 |
| 1549 Node* element_k = |
| 1550 assembler->LoadFixedArrayElement(elements, index_var.value()); |
| 1551 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); |
| 1552 |
| 1553 Node* map_k = assembler->LoadMap(element_k); |
| 1554 assembler->BranchIfSimd128Equal(search_element, map, element_k, map_k, |
| 1555 &return_true, &continue_loop); |
| 1556 |
| 1557 assembler->Bind(&continue_loop); |
| 1558 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1559 assembler->Goto(&loop_body); |
| 1560 } |
| 1561 } |
| 1562 |
| 1563 assembler->Bind(&if_packed_doubles); |
| 1564 { |
| 1565 Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var), |
| 1566 hole_loop(assembler, &index_var), search_notnan(assembler); |
| 1567 Variable search_num(assembler, MachineRepresentation::kFloat64); |
| 1568 |
| 1569 assembler->GotoUnless(assembler->WordIsSmi(search_element), &search_notnan); |
| 1570 search_num.Bind(assembler->SmiToFloat64(search_element)); |
| 1571 assembler->Goto(¬_nan_loop); |
| 1572 |
| 1573 assembler->Bind(&search_notnan); |
| 1574 assembler->GotoIf(assembler->WordNotEqual( |
| 1575 assembler->LoadMap(search_element), heap_number_map), |
| 1576 &return_false); |
| 1577 |
| 1578 search_num.Bind(assembler->LoadHeapNumberValue(search_element)); |
| 1579 |
| 1580 assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, |
| 1581 ¬_nan_loop); |
| 1582 |
| 1583 // Search for HeapNumber |
| 1584 assembler->Bind(¬_nan_loop); |
| 1585 { |
| 1586 Label continue_loop(assembler); |
| 1587 assembler->GotoUnless( |
| 1588 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1589 &return_false); |
| 1590 Node* element_k = assembler->LoadFixedDoubleArrayElement( |
| 1591 elements, index_var.value(), MachineType::Float64()); |
| 1592 assembler->BranchIfFloat64Equal(element_k, search_num.value(), |
| 1593 &return_true, &continue_loop); |
| 1594 assembler->Bind(&continue_loop); |
| 1595 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1596 assembler->Goto(¬_nan_loop); |
| 1597 } |
| 1598 |
| 1599 // Search for NaN |
| 1600 assembler->Bind(&nan_loop); |
| 1601 { |
| 1602 Label continue_loop(assembler); |
| 1603 assembler->GotoUnless( |
| 1604 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1605 &return_false); |
| 1606 Node* element_k = assembler->LoadFixedDoubleArrayElement( |
| 1607 elements, index_var.value(), MachineType::Float64()); |
| 1608 assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); |
| 1609 assembler->Bind(&continue_loop); |
| 1610 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1611 assembler->Goto(&nan_loop); |
| 1612 } |
| 1613 } |
| 1614 |
| 1615 assembler->Bind(&if_holey_doubles); |
| 1616 { |
| 1617 Label nan_loop(assembler, &index_var), not_nan_loop(assembler, &index_var), |
| 1618 hole_loop(assembler, &index_var), search_notnan(assembler); |
| 1619 Variable search_num(assembler, MachineRepresentation::kFloat64); |
| 1620 |
| 1621 assembler->GotoUnless(assembler->WordIsSmi(search_element), &search_notnan); |
| 1622 search_num.Bind(assembler->SmiToFloat64(search_element)); |
| 1623 assembler->Goto(¬_nan_loop); |
| 1624 |
| 1625 assembler->Bind(&search_notnan); |
| 1626 assembler->GotoIf(assembler->WordEqual(search_element, undefined), |
| 1627 &hole_loop); |
| 1628 assembler->GotoIf(assembler->WordNotEqual( |
| 1629 assembler->LoadMap(search_element), heap_number_map), |
| 1630 &return_false); |
| 1631 |
| 1632 search_num.Bind(assembler->LoadHeapNumberValue(search_element)); |
| 1633 |
| 1634 assembler->BranchIfFloat64IsNaN(search_num.value(), &nan_loop, |
| 1635 ¬_nan_loop); |
| 1636 |
| 1637 // Search for HeapNumber |
| 1638 assembler->Bind(¬_nan_loop); |
| 1639 { |
| 1640 Label continue_loop(assembler); |
| 1641 assembler->GotoUnless( |
| 1642 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1643 &return_false); |
| 1644 |
| 1645 if (kPointerSize == kDoubleSize) { |
| 1646 Node* element = assembler->LoadFixedDoubleArrayElement( |
| 1647 elements, index_var.value(), MachineType::Uint64()); |
| 1648 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); |
| 1649 assembler->GotoIf(assembler->Word64Equal(element, the_hole), |
| 1650 &continue_loop); |
| 1651 } else { |
| 1652 Node* element_upper = assembler->LoadFixedDoubleArrayElement( |
| 1653 elements, index_var.value(), MachineType::Uint32(), |
| 1654 kIeeeDoubleExponentWordOffset); |
| 1655 assembler->GotoIf( |
| 1656 assembler->Word32Equal(element_upper, |
| 1657 assembler->Int32Constant(kHoleNanUpper32)), |
| 1658 &continue_loop); |
| 1659 } |
| 1660 |
| 1661 Node* element_k = assembler->LoadFixedDoubleArrayElement( |
| 1662 elements, index_var.value(), MachineType::Float64()); |
| 1663 assembler->BranchIfFloat64Equal(element_k, search_num.value(), |
| 1664 &return_true, &continue_loop); |
| 1665 assembler->Bind(&continue_loop); |
| 1666 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1667 assembler->Goto(¬_nan_loop); |
| 1668 } |
| 1669 |
| 1670 // Search for NaN |
| 1671 assembler->Bind(&nan_loop); |
| 1672 { |
| 1673 Label continue_loop(assembler); |
| 1674 assembler->GotoUnless( |
| 1675 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1676 &return_false); |
| 1677 |
| 1678 if (kPointerSize == kDoubleSize) { |
| 1679 Node* element = assembler->LoadFixedDoubleArrayElement( |
| 1680 elements, index_var.value(), MachineType::Uint64()); |
| 1681 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); |
| 1682 assembler->GotoIf(assembler->Word64Equal(element, the_hole), |
| 1683 &continue_loop); |
| 1684 } else { |
| 1685 Node* element_upper = assembler->LoadFixedDoubleArrayElement( |
| 1686 elements, index_var.value(), MachineType::Uint32(), |
| 1687 kIeeeDoubleExponentWordOffset); |
| 1688 assembler->GotoIf( |
| 1689 assembler->Word32Equal(element_upper, |
| 1690 assembler->Int32Constant(kHoleNanUpper32)), |
| 1691 &continue_loop); |
| 1692 } |
| 1693 |
| 1694 Node* element_k = assembler->LoadFixedDoubleArrayElement( |
| 1695 elements, index_var.value(), MachineType::Float64()); |
| 1696 assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); |
| 1697 assembler->Bind(&continue_loop); |
| 1698 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1699 assembler->Goto(&nan_loop); |
| 1700 } |
| 1701 |
| 1702 // Search for the Hole |
| 1703 assembler->Bind(&hole_loop); |
| 1704 { |
| 1705 assembler->GotoUnless( |
| 1706 assembler->Int32LessThan(index_var.value(), len_var.value()), |
| 1707 &return_false); |
| 1708 |
| 1709 if (kPointerSize == kDoubleSize) { |
| 1710 Node* element = assembler->LoadFixedDoubleArrayElement( |
| 1711 elements, index_var.value(), MachineType::Uint64()); |
| 1712 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); |
| 1713 assembler->GotoIf(assembler->Word64Equal(element, the_hole), |
| 1714 &return_true); |
| 1715 } else { |
| 1716 Node* element_upper = assembler->LoadFixedDoubleArrayElement( |
| 1717 elements, index_var.value(), MachineType::Uint32(), |
| 1718 kIeeeDoubleExponentWordOffset); |
| 1719 assembler->GotoIf( |
| 1720 assembler->Word32Equal(element_upper, |
| 1721 assembler->Int32Constant(kHoleNanUpper32)), |
| 1722 &return_true); |
| 1723 } |
| 1724 |
| 1725 index_var.Bind(assembler->Int32Add(index_var.value(), int32_one)); |
| 1726 assembler->Goto(&hole_loop); |
| 1727 } |
| 1728 } |
| 1729 |
| 1730 assembler->Bind(&return_true); |
| 1731 assembler->Return(assembler->BooleanConstant(true)); |
| 1732 |
| 1733 assembler->Bind(&return_false); |
| 1734 assembler->Return(assembler->BooleanConstant(false)); |
| 1735 |
| 1736 assembler->Bind(&call_runtime); |
| 1737 assembler->Return(assembler->CallRuntime(Runtime::kArrayIncludes_Slow, |
| 1738 context, array, search_element, |
| 1739 start_from)); |
| 1740 } |
| 1741 |
1274 } // namespace internal | 1742 } // namespace internal |
1275 } // namespace v8 | 1743 } // namespace v8 |
OLD | NEW |