OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/hydrogen.h" | 5 #include "src/hydrogen.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 #include "src/allocation-site-scopes.h" | 10 #include "src/allocation-site-scopes.h" |
(...skipping 1212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1223 | 1223 |
1224 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 1224 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
1225 HBasicBlock* header = graph()->CreateBasicBlock(); | 1225 HBasicBlock* header = graph()->CreateBasicBlock(); |
1226 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 1226 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
1227 header->SetInitialEnvironment(entry_env); | 1227 header->SetInitialEnvironment(entry_env); |
1228 header->AttachLoopInformation(); | 1228 header->AttachLoopInformation(); |
1229 return header; | 1229 return header; |
1230 } | 1230 } |
1231 | 1231 |
1232 | 1232 |
| 1233 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) { |
| 1234 HValue* map = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), |
| 1235 HObjectAccess::ForMap()); |
| 1236 |
| 1237 HValue* bit_field2 = Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), |
| 1238 HObjectAccess::ForMapBitField2()); |
| 1239 return BuildDecodeField<Map::ElementsKindBits>(bit_field2); |
| 1240 } |
| 1241 |
| 1242 |
1233 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { | 1243 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
1234 if (obj->type().IsHeapObject()) return obj; | 1244 if (obj->type().IsHeapObject()) return obj; |
1235 return Add<HCheckHeapObject>(obj); | 1245 return Add<HCheckHeapObject>(obj); |
1236 } | 1246 } |
1237 | 1247 |
1238 | 1248 |
1239 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { | 1249 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { |
1240 Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 1250 Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
1241 FinishExitCurrentBlock(New<HAbnormalExit>()); | 1251 FinishExitCurrentBlock(New<HAbnormalExit>()); |
1242 } | 1252 } |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1392 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1402 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
1393 array_length, elements_length); | 1403 array_length, elements_length); |
1394 | 1404 |
1395 if_builder.End(); | 1405 if_builder.End(); |
1396 } | 1406 } |
1397 | 1407 |
1398 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1408 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
1399 } | 1409 } |
1400 | 1410 |
1401 | 1411 |
| 1412 void HGraphBuilder::BuildJSObjectCheck(HValue* receiver, |
| 1413 int bit_field_mask) { |
| 1414 // Check that the object isn't a smi. |
| 1415 Add<HCheckHeapObject>(receiver); |
| 1416 |
| 1417 // Get the map of the receiver. |
| 1418 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), |
| 1419 HObjectAccess::ForMap()); |
| 1420 |
| 1421 // Check the instance type and if an access check is needed, this can be |
| 1422 // done with a single load, since both bytes are adjacent in the map. |
| 1423 HObjectAccess access(HObjectAccess::ForMapInstanceTypeAndBitField()); |
| 1424 HValue* instance_type_and_bit_field = |
| 1425 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), access); |
| 1426 |
| 1427 HValue* mask = Add<HConstant>(0x00FF | (bit_field_mask << 8)); |
| 1428 HValue* and_result = AddUncasted<HBitwise>(Token::BIT_AND, |
| 1429 instance_type_and_bit_field, |
| 1430 mask); |
| 1431 HValue* sub_result = AddUncasted<HSub>(and_result, |
| 1432 Add<HConstant>(JS_OBJECT_TYPE)); |
| 1433 Add<HBoundsCheck>(sub_result, Add<HConstant>(0x100 - JS_OBJECT_TYPE)); |
| 1434 } |
| 1435 |
| 1436 |
| 1437 void HGraphBuilder::BuildKeyedIndexCheck(HValue* key, |
| 1438 HIfContinuation* join_continuation) { |
| 1439 // The sometimes unintuitively backward ordering of the ifs below is |
| 1440 // convoluted, but necessary. All of the paths must guarantee that the |
| 1441 // if-true of the continuation returns a smi element index and the if-false of |
| 1442 // the continuation returns either a symbol or a unique string key. All other |
| 1443 // object types cause a deopt to fall back to the runtime. |
| 1444 |
| 1445 IfBuilder key_smi_if(this); |
| 1446 key_smi_if.If<HIsSmiAndBranch>(key); |
| 1447 key_smi_if.Then(); |
| 1448 { |
| 1449 Push(key); // Nothing to do, just continue to true of continuation. |
| 1450 } |
| 1451 key_smi_if.Else(); |
| 1452 { |
| 1453 HValue* map = Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), |
| 1454 HObjectAccess::ForMap()); |
| 1455 HValue* instance_type = |
| 1456 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), |
| 1457 HObjectAccess::ForMapInstanceType()); |
| 1458 |
| 1459 // Non-unique string, check for a string with a hash code that is actually |
| 1460 // an index. |
| 1461 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); |
| 1462 IfBuilder not_string_or_name_if(this); |
| 1463 not_string_or_name_if.If<HCompareNumericAndBranch>( |
| 1464 instance_type, |
| 1465 Add<HConstant>(LAST_UNIQUE_NAME_TYPE), |
| 1466 Token::GT); |
| 1467 |
| 1468 not_string_or_name_if.Then(); |
| 1469 { |
| 1470 // Non-smi, non-Name, non-String: Try to convert to smi in case of |
| 1471 // HeapNumber. |
| 1472 // TODO(danno): This could call some variant of ToString |
| 1473 Push(AddUncasted<HForceRepresentation>(key, Representation::Smi())); |
| 1474 } |
| 1475 not_string_or_name_if.Else(); |
| 1476 { |
| 1477 // String or Name: check explicitly for Name, they can short-circuit |
| 1478 // directly to unique non-index key path. |
| 1479 IfBuilder not_symbol_if(this); |
| 1480 not_symbol_if.If<HCompareNumericAndBranch>( |
| 1481 instance_type, |
| 1482 Add<HConstant>(SYMBOL_TYPE), |
| 1483 Token::NE); |
| 1484 |
| 1485 not_symbol_if.Then(); |
| 1486 { |
| 1487 // String: check whether the String is a String of an index. If it is, |
| 1488 // extract the index value from the hash. |
| 1489 HValue* hash = |
| 1490 Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), |
| 1491 HObjectAccess::ForNameHashField()); |
| 1492 HValue* not_index_mask = Add<HConstant>(static_cast<int>( |
| 1493 String::kContainsCachedArrayIndexMask)); |
| 1494 |
| 1495 HValue* not_index_test = AddUncasted<HBitwise>( |
| 1496 Token::BIT_AND, hash, not_index_mask); |
| 1497 |
| 1498 IfBuilder string_index_if(this); |
| 1499 string_index_if.If<HCompareNumericAndBranch>(not_index_test, |
| 1500 graph()->GetConstant0(), |
| 1501 Token::EQ); |
| 1502 string_index_if.Then(); |
| 1503 { |
| 1504 // String with index in hash: extract string and merge to index path. |
| 1505 Push(BuildDecodeField<String::ArrayIndexValueBits>(hash)); |
| 1506 } |
| 1507 string_index_if.Else(); |
| 1508 { |
| 1509 // Key is a non-index String, check for uniqueness/internalization. If |
| 1510 // it's not, deopt. |
| 1511 HValue* not_internalized_bit = AddUncasted<HBitwise>( |
| 1512 Token::BIT_AND, |
| 1513 instance_type, |
| 1514 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask))); |
| 1515 DeoptimizeIf<HCompareNumericAndBranch>( |
| 1516 not_internalized_bit, |
| 1517 graph()->GetConstant0(), |
| 1518 Token::NE, |
| 1519 "BuildKeyedIndexCheck: string isn't internalized"); |
| 1520 // Key guaranteed to be a unqiue string |
| 1521 Push(key); |
| 1522 } |
| 1523 string_index_if.JoinContinuation(join_continuation); |
| 1524 } |
| 1525 not_symbol_if.Else(); |
| 1526 { |
| 1527 Push(key); // Key is symbol |
| 1528 } |
| 1529 not_symbol_if.JoinContinuation(join_continuation); |
| 1530 } |
| 1531 not_string_or_name_if.JoinContinuation(join_continuation); |
| 1532 } |
| 1533 key_smi_if.JoinContinuation(join_continuation); |
| 1534 } |
| 1535 |
| 1536 |
| 1537 void HGraphBuilder::BuildNonGlobalObjectCheck(HValue* receiver) { |
| 1538 // Get the the instance type of the receiver, and make sure that it is |
| 1539 // not one of the global object types. |
| 1540 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), |
| 1541 HObjectAccess::ForMap()); |
| 1542 HValue* instance_type = |
| 1543 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), |
| 1544 HObjectAccess::ForMapInstanceType()); |
| 1545 STATIC_ASSERT(JS_BUILTINS_OBJECT_TYPE == JS_GLOBAL_OBJECT_TYPE + 1); |
| 1546 HValue* min_global_type = Add<HConstant>(JS_GLOBAL_OBJECT_TYPE); |
| 1547 HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE); |
| 1548 |
| 1549 IfBuilder if_global_object(this); |
| 1550 if_global_object.If<HCompareNumericAndBranch>(instance_type, |
| 1551 max_global_type, |
| 1552 Token::LTE); |
| 1553 if_global_object.And(); |
| 1554 if_global_object.If<HCompareNumericAndBranch>(instance_type, |
| 1555 min_global_type, |
| 1556 Token::GTE); |
| 1557 if_global_object.ThenDeopt("receiver was a global object"); |
| 1558 if_global_object.End(); |
| 1559 } |
| 1560 |
| 1561 |
| 1562 void HGraphBuilder::BuildTestForDictionaryProperties( |
| 1563 HValue* object, |
| 1564 HIfContinuation* continuation) { |
| 1565 HValue* properties = Add<HLoadNamedField>( |
| 1566 object, static_cast<HValue*>(NULL), |
| 1567 HObjectAccess::ForPropertiesPointer()); |
| 1568 HValue* properties_map = |
| 1569 Add<HLoadNamedField>(properties, static_cast<HValue*>(NULL), |
| 1570 HObjectAccess::ForMap()); |
| 1571 HValue* hash_map = Add<HLoadRoot>(Heap::kHashTableMapRootIndex); |
| 1572 IfBuilder builder(this); |
| 1573 builder.If<HCompareObjectEqAndBranch>(properties_map, hash_map); |
| 1574 builder.CaptureContinuation(continuation); |
| 1575 } |
| 1576 |
| 1577 |
| 1578 HValue* HGraphBuilder::BuildKeyedLookupCacheHash(HValue* object, |
| 1579 HValue* key) { |
| 1580 // Load the map of the receiver, compute the keyed lookup cache hash |
| 1581 // based on 32 bits of the map pointer and the string hash. |
| 1582 HValue* object_map = |
| 1583 Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), |
| 1584 HObjectAccess::ForMapAsInteger32()); |
| 1585 HValue* shifted_map = AddUncasted<HShr>( |
| 1586 object_map, Add<HConstant>(KeyedLookupCache::kMapHashShift)); |
| 1587 HValue* string_hash = |
| 1588 Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), |
| 1589 HObjectAccess::ForStringHashField()); |
| 1590 HValue* shifted_hash = AddUncasted<HShr>( |
| 1591 string_hash, Add<HConstant>(String::kHashShift)); |
| 1592 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map, |
| 1593 shifted_hash); |
| 1594 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); |
| 1595 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result, |
| 1596 Add<HConstant>(mask)); |
| 1597 } |
| 1598 |
| 1599 |
1402 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( | 1600 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( |
1403 HValue* elements, | 1601 HValue* elements, |
1404 HValue* key, | 1602 HValue* key, |
1405 HValue* hash, | 1603 HValue* hash, |
1406 HValue* mask, | 1604 HValue* mask, |
1407 int current_probe) { | 1605 int current_probe) { |
1408 if (current_probe == kNumberDictionaryProbes) { | 1606 if (current_probe == kNumberDictionaryProbes) { |
1409 return NULL; | 1607 return NULL; |
1410 } | 1608 } |
1411 | 1609 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1504 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); | 1702 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); |
1505 hash->ClearFlag(HValue::kCanOverflow); | 1703 hash->ClearFlag(HValue::kCanOverflow); |
1506 | 1704 |
1507 // hash = hash ^ (hash >> 16); | 1705 // hash = hash ^ (hash >> 16); |
1508 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); | 1706 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); |
1509 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); | 1707 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
1510 } | 1708 } |
1511 | 1709 |
1512 | 1710 |
1513 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, | 1711 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
1514 HValue* key) { | 1712 HValue* elements, |
1515 HValue* elements = AddLoadElements(receiver); | 1713 HValue* key, |
1516 | 1714 HValue* hash) { |
1517 HValue* hash = BuildElementIndexHash(key); | |
1518 | |
1519 HValue* capacity = Add<HLoadKeyed>( | 1715 HValue* capacity = Add<HLoadKeyed>( |
1520 elements, | 1716 elements, |
1521 Add<HConstant>(NameDictionary::kCapacityIndex), | 1717 Add<HConstant>(NameDictionary::kCapacityIndex), |
1522 static_cast<HValue*>(NULL), | 1718 static_cast<HValue*>(NULL), |
1523 FAST_ELEMENTS); | 1719 FAST_ELEMENTS); |
1524 | 1720 |
1525 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); | 1721 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); |
1526 mask->ChangeRepresentation(Representation::Integer32()); | 1722 mask->ChangeRepresentation(Representation::Integer32()); |
1527 mask->ClearFlag(HValue::kCanOverflow); | 1723 mask->ClearFlag(HValue::kCanOverflow); |
1528 | 1724 |
(...skipping 10619 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12148 if (ShouldProduceTraceOutput()) { | 12344 if (ShouldProduceTraceOutput()) { |
12149 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 12345 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
12150 } | 12346 } |
12151 | 12347 |
12152 #ifdef DEBUG | 12348 #ifdef DEBUG |
12153 graph_->Verify(false); // No full verify. | 12349 graph_->Verify(false); // No full verify. |
12154 #endif | 12350 #endif |
12155 } | 12351 } |
12156 | 12352 |
12157 } } // namespace v8::internal | 12353 } } // namespace v8::internal |
OLD | NEW |