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" | |
9 #include "src/elements.h" | 7 #include "src/elements.h" |
10 | 8 |
11 namespace v8 { | 9 namespace v8 { |
12 namespace internal { | 10 namespace internal { |
13 | 11 |
14 namespace { | 12 namespace { |
15 | 13 |
16 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { | 14 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { |
17 // This is an extended version of ECMA-262 7.1.11 handling signed values | 15 // This is an extended version of ECMA-262 7.1.11 handling signed values |
18 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] | 16 // 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... |
50 map != context->fast_aliased_arguments_map()) { | 48 map != context->fast_aliased_arguments_map()) { |
51 return false; | 49 return false; |
52 } | 50 } |
53 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements()); | 51 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements()); |
54 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); | 52 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); |
55 if (!len_obj->IsSmi()) return false; | 53 if (!len_obj->IsSmi()) return false; |
56 *out = Max(0, Smi::cast(len_obj)->value()); | 54 *out = Max(0, Smi::cast(len_obj)->value()); |
57 return *out <= object->elements()->length(); | 55 return *out <= object->elements()->length(); |
58 } | 56 } |
59 | 57 |
| 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 |
60 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, | 72 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
61 JSArray* receiver) { | 73 JSArray* receiver) { |
62 return JSObject::PrototypeHasNoElements(isolate, receiver); | 74 return PrototypeHasNoElements(isolate, receiver); |
63 } | 75 } |
64 | 76 |
65 inline bool HasSimpleElements(JSObject* current) { | 77 inline bool HasSimpleElements(JSObject* current) { |
66 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && | 78 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
67 !current->GetElementsAccessor()->HasAccessors(current); | 79 !current->GetElementsAccessor()->HasAccessors(current); |
68 } | 80 } |
69 | 81 |
70 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, | 82 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, |
71 JSObject* receiver) { | 83 JSObject* receiver) { |
72 // Check that we have no accessors on the receiver's elements. | 84 // Check that we have no accessors on the receiver's elements. |
73 if (!HasSimpleElements(receiver)) return false; | 85 if (!HasSimpleElements(receiver)) return false; |
74 return JSObject::PrototypeHasNoElements(isolate, receiver); | 86 return PrototypeHasNoElements(isolate, receiver); |
75 } | 87 } |
76 | 88 |
77 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { | 89 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { |
78 DisallowHeapAllocation no_gc; | 90 DisallowHeapAllocation no_gc; |
79 PrototypeIterator iter(isolate, receiver, kStartAtReceiver); | 91 PrototypeIterator iter(isolate, receiver, kStartAtReceiver); |
80 for (; !iter.IsAtEnd(); iter.Advance()) { | 92 for (; !iter.IsAtEnd(); iter.Advance()) { |
81 if (iter.GetCurrent()->IsJSProxy()) return false; | 93 if (iter.GetCurrent()->IsJSProxy()) return false; |
82 JSObject* current = iter.GetCurrent<JSObject>(); | 94 JSObject* current = iter.GetCurrent<JSObject>(); |
83 if (!HasSimpleElements(current)) return false; | 95 if (!HasSimpleElements(current)) return false; |
84 } | 96 } |
(...skipping 1167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 assembler->Return(assembler->BooleanConstant(true)); | 1264 assembler->Return(assembler->BooleanConstant(true)); |
1253 | 1265 |
1254 assembler->Bind(&return_false); | 1266 assembler->Bind(&return_false); |
1255 assembler->Return(assembler->BooleanConstant(false)); | 1267 assembler->Return(assembler->BooleanConstant(false)); |
1256 | 1268 |
1257 assembler->Bind(&call_runtime); | 1269 assembler->Bind(&call_runtime); |
1258 assembler->Return( | 1270 assembler->Return( |
1259 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); | 1271 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); |
1260 } | 1272 } |
1261 | 1273 |
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 | |
1742 } // namespace internal | 1274 } // namespace internal |
1743 } // namespace v8 | 1275 } // namespace v8 |
OLD | NEW |