Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1221 | 1221 |
| 1222 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 1222 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 1223 HBasicBlock* header = graph()->CreateBasicBlock(); | 1223 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 1224 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 1224 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 1225 header->SetInitialEnvironment(entry_env); | 1225 header->SetInitialEnvironment(entry_env); |
| 1226 header->AttachLoopInformation(); | 1226 header->AttachLoopInformation(); |
| 1227 return header; | 1227 return header; |
| 1228 } | 1228 } |
| 1229 | 1229 |
| 1230 | 1230 |
| 1231 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) { | |
| 1232 HValue* map = Add<HLoadNamedField>(object, HObjectAccess::ForMap()); | |
| 1233 | |
| 1234 HValue* bit_field2 = Add<HLoadNamedField>(map, | |
| 1235 HObjectAccess::ForMapBitField2()); | |
| 1236 HValue* unmasked_kind = AddUncasted<HShr>( | |
| 1237 bit_field2, Add<HConstant>(Map::kElementsKindShift)); | |
|
Toon Verwaest
2013/12/04 17:29:26
It seems like ElementsKind should really be a BitF
danno
2014/06/06 15:43:51
Done.
| |
| 1238 int mask = (1 << Map::kElementsKindBitCount) - 1; | |
| 1239 HValue* mask_value = Add<HConstant>(mask); | |
| 1240 return AddUncasted<HBitwise>(Token::BIT_AND, unmasked_kind, mask_value); | |
| 1241 } | |
| 1242 | |
| 1243 | |
| 1231 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { | 1244 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
| 1232 if (obj->type().IsHeapObject()) return obj; | 1245 if (obj->type().IsHeapObject()) return obj; |
| 1233 return Add<HCheckHeapObject>(obj); | 1246 return Add<HCheckHeapObject>(obj); |
| 1234 } | 1247 } |
| 1235 | 1248 |
| 1236 | 1249 |
| 1237 void HGraphBuilder::FinishExitWithHardDeoptimization( | 1250 void HGraphBuilder::FinishExitWithHardDeoptimization( |
| 1238 const char* reason, HBasicBlock* continuation) { | 1251 const char* reason, HBasicBlock* continuation) { |
| 1239 PadEnvironmentForContinuation(current_block(), continuation); | 1252 PadEnvironmentForContinuation(current_block(), continuation); |
| 1240 Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 1253 Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1410 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1423 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
| 1411 array_length, elements_length); | 1424 array_length, elements_length); |
| 1412 | 1425 |
| 1413 if_builder.End(); | 1426 if_builder.End(); |
| 1414 } | 1427 } |
| 1415 | 1428 |
| 1416 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1429 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
| 1417 } | 1430 } |
| 1418 | 1431 |
| 1419 | 1432 |
| 1433 void HGraphBuilder::BuildReceiverCheck(HValue* receiver, | |
| 1434 int bit_field_mask) { | |
| 1435 // Check that the object isn't a smi. | |
| 1436 Add<HCheckHeapObject>(receiver); | |
| 1437 | |
| 1438 // Get the map of the receiver. | |
| 1439 HValue* map = Add<HLoadNamedField>(receiver, HObjectAccess::ForMap()); | |
| 1440 | |
| 1441 if (V8_TARGET_LITTLE_ENDIAN) { | |
| 1442 // Check the instance type and if an access check is needed, this can be | |
| 1443 // done with a single load, since both bytes are adjacent in the map. | |
| 1444 HObjectAccess access(HObjectAccess::ForMapInstanceTypeAndBitField()); | |
| 1445 HValue* instance_type_and_bit_field = Add<HLoadNamedField>(map, access); | |
| 1446 | |
| 1447 HValue* mask = Add<HConstant>(0x00FF | (bit_field_mask << 8)); | |
| 1448 HValue* and_result = AddUncasted<HBitwise>(Token::BIT_AND, | |
| 1449 instance_type_and_bit_field, | |
| 1450 mask); | |
| 1451 HValue* sub_result = AddUncasted<HSub>(and_result, | |
| 1452 Add<HConstant>(JS_OBJECT_TYPE)); | |
| 1453 Add<HBoundsCheck>(sub_result, Add<HConstant>(0x100 - JS_OBJECT_TYPE)); | |
| 1454 } else { | |
| 1455 HValue* instance_type = | |
| 1456 Add<HLoadNamedField>(map, HObjectAccess::ForMapInstanceType()); | |
| 1457 IfBuilder type_check(this); | |
| 1458 type_check.If<HCompareNumericAndBranch>(instance_type, | |
| 1459 Add<HConstant>(JS_OBJECT_TYPE), | |
| 1460 Token::LT); | |
| 1461 type_check.ThenDeopt("receiver check: not JS_OBJECT_TYPE"); | |
| 1462 type_check.End(); | |
| 1463 | |
| 1464 HValue* bit_field2 = | |
| 1465 Add<HLoadNamedField>(map, HObjectAccess::ForMapBitField()); | |
|
Toon Verwaest
2013/12/04 17:29:26
ForMapBitField2 I presume? Is this tested?
Seems t
danno
2014/06/06 15:43:51
Fields swapped, it makes this code much simpler.
| |
| 1466 HValue* and_result = AddUncasted<HBitwise>( | |
| 1467 Token::BIT_AND, | |
| 1468 bit_field2, | |
| 1469 Add<HConstant>(bit_field_mask)); | |
| 1470 IfBuilder access_check(this); | |
| 1471 access_check.If<HCompareNumericAndBranch>(and_result, | |
|
Toon Verwaest
2013/12/04 17:29:26
Use DeoptimizeIf.
danno
2014/06/06 15:43:51
Done.
| |
| 1472 graph()->GetConstant0(), | |
| 1473 Token::NE); | |
| 1474 access_check.ThenDeopt("receiver check: bit field check failed"); | |
| 1475 access_check.End(); | |
| 1476 } | |
| 1477 } | |
| 1478 | |
| 1479 | |
| 1480 HValue* HGraphBuilder::BuildHashToIndex(HValue *hash) { | |
| 1481 // The assert checks that the constants for the maximum number of digits | |
| 1482 // for an array index cached in the hash field and the number of bits | |
| 1483 // reserved for it does not conflict. | |
| 1484 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < | |
| 1485 (1 << String::kArrayIndexValueBits)); | |
| 1486 HValue* index = AddUncasted<HBitwise>( | |
| 1487 Token::BIT_AND, hash, Add<HConstant>(String::kArrayIndexValueMask)); | |
| 1488 return AddUncasted<HShr>(index, Add<HConstant>(String::kHashShift)); | |
|
Toon Verwaest
2013/12/04 17:29:26
A bitfield decoding mechanism would be useful agai
danno
2014/06/06 15:43:51
Done.
| |
| 1489 } | |
| 1490 | |
| 1491 | |
| 1492 void HGraphBuilder::BuildKeyedIndexCheck(HValue* key, | |
| 1493 HIfContinuation* join_continuation) { | |
|
Toon Verwaest
2013/12/04 17:29:26
It took me a while to figure out why the branches
danno
2014/06/06 15:43:51
Done.
| |
| 1494 // Create a joinable continuation. | |
| 1495 IfBuilder key_smi_if(this); | |
| 1496 key_smi_if.If<HIsSmiAndBranch>(key); | |
| 1497 key_smi_if.Then(); | |
| 1498 { | |
| 1499 Push(key); // Nothing to do, just continue to true of continuation. | |
| 1500 } | |
| 1501 key_smi_if.Else(); | |
| 1502 { | |
| 1503 HValue* map = Add<HLoadNamedField>(key, HObjectAccess::ForMap()); | |
| 1504 HValue* instance_type = | |
| 1505 Add<HLoadNamedField>(map, HObjectAccess::ForMapInstanceType()); | |
| 1506 | |
| 1507 // Non-unique string, check for a string with a hash code that is actually | |
| 1508 // an index. | |
| 1509 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); | |
| 1510 IfBuilder not_string_or_name_if(this); | |
|
Toon Verwaest
2013/12/04 17:29:26
I'd swap the condition (use string_or_name rather
danno
2014/06/06 15:43:51
Ordering needs to stay the same due to continuatio
| |
| 1511 not_string_or_name_if.If<HCompareNumericAndBranch>( | |
| 1512 instance_type, | |
| 1513 Add<HConstant>(LAST_UNIQUE_NAME_TYPE), | |
| 1514 Token::GT); | |
| 1515 | |
| 1516 not_string_or_name_if.Then(); | |
| 1517 { | |
| 1518 // Non-smi, non-Name, non-String: Try to convert to smi in case of | |
| 1519 // HeapNumber. | |
| 1520 Push(AddUncasted<HForceRepresentation>(key, Representation::Smi())); | |
| 1521 } | |
| 1522 not_string_or_name_if.Else(); | |
| 1523 { | |
| 1524 // String or Name: check explicitly for Name, they can short-circuit | |
| 1525 // directly to unique non-index key path. | |
| 1526 IfBuilder name_if(this); | |
| 1527 name_if.If<HCompareNumericAndBranch>( | |
|
Toon Verwaest
2013/12/04 17:29:26
And here name_if means that it's not a name. That'
danno
2014/06/06 15:43:51
Ordering needs to stay the same due to continuatio
| |
| 1528 instance_type, | |
| 1529 Add<HConstant>(LAST_UNIQUE_NAME_TYPE), | |
| 1530 Token::NE); | |
| 1531 | |
| 1532 name_if.Then(); | |
| 1533 { | |
| 1534 // String: check whether the String is an String of an index. If it is, | |
| 1535 // extract the index value from the hash. | |
| 1536 HValue* hash = | |
| 1537 Add<HLoadNamedField>(key, HObjectAccess::ForNameHashField()); | |
| 1538 HValue* cached_array_bit = AddUncasted<HBitwise>( | |
| 1539 Token::BIT_AND, | |
| 1540 hash, | |
| 1541 Add<HConstant>(Name::kContainsCachedArrayIndexMask)); | |
|
Toon Verwaest
2013/12/04 17:29:26
Shouldn't kContainsCachedArrayIndex be on String r
danno
2014/06/06 15:43:51
Done.
| |
| 1542 | |
| 1543 IfBuilder string_index_if(this); | |
| 1544 string_index_if.If<HCompareNumericAndBranch>(cached_array_bit, | |
| 1545 graph()->GetConstant0(), | |
| 1546 Token::EQ); | |
| 1547 string_index_if.Then(); | |
| 1548 { | |
| 1549 // String with index in hash: extract string and merge to index path. | |
| 1550 Push(BuildHashToIndex(hash)); | |
|
Toon Verwaest
2013/12/04 17:29:26
BuildHashToIndex could just be a bitfield decoder.
danno
2014/06/06 15:43:51
Done.
| |
| 1551 } | |
| 1552 string_index_if.Else(); | |
| 1553 { | |
| 1554 // Key is a non-index String, check for uniqueness/internalization. If | |
| 1555 // it's not, deopt. | |
| 1556 HValue* not_internalized_bit = AddUncasted<HBitwise>( | |
| 1557 Token::BIT_AND, | |
| 1558 instance_type, | |
| 1559 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask))); | |
| 1560 DeoptimizeIf<HCompareNumericAndBranch>( | |
| 1561 not_internalized_bit, | |
| 1562 graph()->GetConstant0(), | |
| 1563 Token::NE, | |
| 1564 "BuildKeyedIndexCheck: string isn't internalized"); | |
| 1565 // Key guaranteed to be a unqiue string | |
| 1566 Push(key); | |
| 1567 } | |
| 1568 string_index_if.JoinContinuation(join_continuation); | |
| 1569 } | |
| 1570 name_if.Else(); | |
| 1571 { | |
| 1572 Push(key); // Key is name | |
| 1573 } | |
| 1574 name_if.JoinContinuation(join_continuation); | |
| 1575 } | |
| 1576 not_string_or_name_if.JoinContinuation(join_continuation); | |
| 1577 } | |
| 1578 key_smi_if.JoinContinuation(join_continuation); | |
| 1579 } | |
| 1580 | |
| 1581 | |
| 1582 void HGraphBuilder:: BuildGlobalInstanceTypeCheck(HValue* receiver) { | |
| 1583 // Get the the instance type of the receiver, and make sure that it is | |
| 1584 // not one of the global object types. | |
|
Toon Verwaest
2013/12/04 17:29:26
This comment seems to say the opposite of the name
danno
2014/06/06 15:43:51
Done.
| |
| 1585 HValue* map = Add<HLoadNamedField>(receiver, HObjectAccess::ForMap()); | |
| 1586 HValue* instance_type = | |
| 1587 Add<HLoadNamedField>(map, HObjectAccess::ForMapInstanceType()); | |
| 1588 STATIC_ASSERT(JS_BUILTINS_OBJECT_TYPE == JS_GLOBAL_OBJECT_TYPE + 1); | |
| 1589 STATIC_ASSERT(JS_GLOBAL_PROXY_TYPE == JS_BUILTINS_OBJECT_TYPE + 1); | |
| 1590 HValue* smallest_global_type = Add<HConstant>(JS_GLOBAL_OBJECT_TYPE); | |
| 1591 instance_type = AddUncasted<HSub>(instance_type, smallest_global_type); | |
| 1592 int globla_type_count = JS_GLOBAL_PROXY_TYPE - JS_GLOBAL_OBJECT_TYPE; | |
|
Toon Verwaest
2013/12/04 17:29:26
globAL
danno
2014/06/06 15:43:51
Done.
| |
| 1593 Add<HBoundsCheck>(instance_type, Add<HConstant>(globla_type_count)); | |
| 1594 } | |
| 1595 | |
| 1596 | |
| 1597 void HGraphBuilder::BuildCheckForDictionaryProperties( | |
| 1598 HValue* object, | |
| 1599 HIfContinuation* continuation) { | |
| 1600 HValue* properties = Add<HLoadNamedField>( | |
| 1601 object, HObjectAccess::ForPropertiesPointer()); | |
| 1602 HValue* properties_map = Add<HLoadNamedField>( | |
| 1603 properties, HObjectAccess::ForMap()); | |
| 1604 HValue* hash_map = Add<HLoadRoot>(Heap::kHashTableMapRootIndex); | |
| 1605 IfBuilder builder(this); | |
| 1606 builder.If<HCompareObjectEqAndBranch>(properties_map, hash_map); | |
| 1607 builder.CaptureContinuation(continuation); | |
|
Toon Verwaest
2013/12/04 17:29:26
I wonder if the resulting code may be smaller / fa
danno
2014/06/06 15:43:51
This is a copy of what the hand-written stub did I
| |
| 1608 } | |
| 1609 | |
| 1610 | |
| 1611 HValue* HGraphBuilder::BuildKeyedLookupCacheHash(HValue* object, | |
| 1612 HValue* key) { | |
| 1613 // Load the map of the receiver, compute the keyed lookup cache hash | |
| 1614 // based on 32 bits of the map pointer and the string hash. | |
| 1615 HValue* object_map = Add<HLoadNamedField>( | |
| 1616 object, HObjectAccess::ForMapAsInteger32()); | |
| 1617 HValue* shifted_map = AddUncasted<HShr>( | |
| 1618 object_map, Add<HConstant>(KeyedLookupCache::kMapHashShift)); | |
| 1619 HValue* string_hash = Add<HLoadNamedField>( | |
| 1620 key, HObjectAccess::ForStringHashField()); | |
| 1621 HValue* shifted_hash = AddUncasted<HShr>( | |
| 1622 string_hash, Add<HConstant>(String::kHashShift)); | |
| 1623 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map, | |
| 1624 shifted_hash); | |
| 1625 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); | |
| 1626 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result, | |
| 1627 Add<HConstant>(mask)); | |
| 1628 } | |
| 1629 | |
| 1630 | |
| 1420 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( | 1631 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoadHelper( |
| 1421 HValue* elements, | 1632 HValue* elements, |
| 1422 HValue* key, | 1633 HValue* key, |
| 1423 HValue* hash, | 1634 HValue* hash, |
| 1424 HValue* mask, | 1635 HValue* mask, |
| 1425 int current_probe) { | 1636 int current_probe) { |
| 1426 if (current_probe == kNumberDictionaryProbes) { | 1637 if (current_probe == kNumberDictionaryProbes) { |
| 1427 return NULL; | 1638 return NULL; |
| 1428 } | 1639 } |
| 1429 | 1640 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); | 1733 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); |
| 1523 hash->ClearFlag(HValue::kCanOverflow); | 1734 hash->ClearFlag(HValue::kCanOverflow); |
| 1524 | 1735 |
| 1525 // hash = hash ^ (hash >> 16); | 1736 // hash = hash ^ (hash >> 16); |
| 1526 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); | 1737 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); |
| 1527 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); | 1738 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); |
| 1528 } | 1739 } |
| 1529 | 1740 |
| 1530 | 1741 |
| 1531 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, | 1742 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
| 1532 HValue* key) { | 1743 HValue* elements, |
| 1533 HValue* elements = AddLoadElements(receiver); | 1744 HValue* key, |
| 1534 | 1745 HValue* hash) { |
| 1535 HValue* hash = BuildElementIndexHash(key); | |
| 1536 | |
| 1537 HValue* capacity = Add<HLoadKeyed>( | 1746 HValue* capacity = Add<HLoadKeyed>( |
| 1538 elements, | 1747 elements, |
| 1539 Add<HConstant>(NameDictionary::kCapacityIndex), | 1748 Add<HConstant>(NameDictionary::kCapacityIndex), |
| 1540 static_cast<HValue*>(NULL), | 1749 static_cast<HValue*>(NULL), |
| 1541 FAST_SMI_ELEMENTS); | 1750 FAST_SMI_ELEMENTS); |
| 1542 | 1751 |
| 1543 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); | 1752 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); |
| 1544 mask->ChangeRepresentation(Representation::Integer32()); | 1753 mask->ChangeRepresentation(Representation::Integer32()); |
| 1545 mask->ClearFlag(HValue::kCanOverflow); | 1754 mask->ClearFlag(HValue::kCanOverflow); |
| 1546 | 1755 |
| (...skipping 9261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10808 if (ShouldProduceTraceOutput()) { | 11017 if (ShouldProduceTraceOutput()) { |
| 10809 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11018 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 10810 } | 11019 } |
| 10811 | 11020 |
| 10812 #ifdef DEBUG | 11021 #ifdef DEBUG |
| 10813 graph_->Verify(false); // No full verify. | 11022 graph_->Verify(false); // No full verify. |
| 10814 #endif | 11023 #endif |
| 10815 } | 11024 } |
| 10816 | 11025 |
| 10817 } } // namespace v8::internal | 11026 } } // namespace v8::internal |
| OLD | NEW |