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 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1447 isolate()->factory()->empty_string(), | 1447 isolate()->factory()->empty_string(), |
| 1448 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1448 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| 1449 1)); | 1449 1)); |
| 1450 } | 1450 } |
| 1451 if_found.End(); | 1451 if_found.End(); |
| 1452 | 1452 |
| 1453 return Pop(); | 1453 return Pop(); |
| 1454 } | 1454 } |
| 1455 | 1455 |
| 1456 | 1456 |
| 1457 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, | |
| 1458 HValue* src_offset, | |
| 1459 String::Encoding src_encoding, | |
| 1460 HValue* dst, | |
| 1461 HValue* dst_offset, | |
| 1462 String::Encoding dst_encoding, | |
| 1463 HValue* length) { | |
| 1464 ASSERT(dst_encoding != String::ONE_BYTE_ENCODING || | |
| 1465 src_encoding == String::ONE_BYTE_ENCODING); | |
| 1466 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); | |
| 1467 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); | |
| 1468 { | |
| 1469 HValue* src_index = Add<HAdd>(src_offset, index); | |
| 1470 HValue* value = Add<HSeqStringGetChar>(src_encoding, src, src_index); | |
| 1471 HValue* dst_index = Add<HAdd>(dst_offset, index); | |
| 1472 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); | |
| 1473 } | |
| 1474 loop.EndBody(); | |
| 1475 } | |
| 1476 | |
| 1477 | |
| 1478 HValue* HGraphBuilder::BuildUncheckedStringAdd(HValue* left, | |
| 1479 HValue* right, | |
| 1480 PretenureFlag pretenure_flag) { | |
| 1481 // Determine the string lengths. | |
| 1482 HValue* left_length = Add<HLoadNamedField>( | |
| 1483 left, HObjectAccess::ForStringLength()); | |
| 1484 HValue* right_length = Add<HLoadNamedField>( | |
| 1485 right, HObjectAccess::ForStringLength()); | |
| 1486 | |
| 1487 // Check if we concatenated the strings here, or if we have to resort to the | |
| 1488 // runtime function. | |
| 1489 HIfContinuation handled(graph()->CreateBasicBlock(), | |
| 1490 graph()->CreateBasicBlock()); | |
| 1491 | |
| 1492 // Check if both parameters do not exceed half the max string length, because | |
| 1493 // exceptionally long strings should be handled in the runtime. This may be | |
| 1494 // too pessimistic, but it's the only portable way to express this in Hydrogen | |
| 1495 // right now. | |
|
mvstanton
2013/11/08 10:17:50
I appreciate the detailed comments on this long an
Benedikt Meurer
2013/11/08 13:21:08
Done.
| |
| 1496 HConstant* max_length = Add<HConstant>( | |
| 1497 static_cast<int32_t>(String::kMaxLength / 2)); | |
| 1498 IfBuilder if_nooverflow(this); | |
| 1499 if_nooverflow.If<HCompareNumericAndBranch>( | |
| 1500 left_length, max_length, Token::LTE); | |
| 1501 if_nooverflow.AndIf<HCompareNumericAndBranch>( | |
| 1502 right_length, max_length, Token::LTE); | |
| 1503 if_nooverflow.Then(); | |
| 1504 { | |
| 1505 // Determine the string instance types. | |
| 1506 HLoadNamedField* left_instance_type = Add<HLoadNamedField>( | |
| 1507 Add<HLoadNamedField>(left, HObjectAccess::ForMap()), | |
| 1508 HObjectAccess::ForMapInstanceType()); | |
| 1509 HLoadNamedField* right_instance_type = Add<HLoadNamedField>( | |
| 1510 Add<HLoadNamedField>(right, HObjectAccess::ForMap()), | |
| 1511 HObjectAccess::ForMapInstanceType()); | |
| 1512 | |
| 1513 // Compute the length of the resulting string. | |
| 1514 HValue* length = Add<HAdd>(left_length, right_length); | |
| 1515 | |
| 1516 // Check if we should create a cons string. | |
| 1517 IfBuilder if_createcons(this); | |
| 1518 if_createcons.If<HCompareNumericAndBranch>( | |
| 1519 length, | |
| 1520 Add<HConstant>(static_cast<int32_t>(ConsString::kMinLength)), | |
| 1521 Token::GTE); | |
| 1522 if_createcons.Then(); | |
| 1523 { | |
| 1524 // Allocate the cons string object. HAllocate does not care whether we | |
| 1525 // pass CONS_STRING_TYPE or CONS_ASCII_STRING_TYPE here, so we just use | |
| 1526 // CONS_STRING_TYPE here. Below we decide whether the cons string is | |
| 1527 // one-byte or two-byte and set the appropriate map. | |
| 1528 HAllocate* string = Add<HAllocate>(Add<HConstant>(ConsString::kSize), | |
| 1529 HType::String(), pretenure_flag, | |
| 1530 CONS_STRING_TYPE); | |
| 1531 | |
| 1532 // We create a one-byte cons string if | |
| 1533 // 1. both strings are one-byte, or | |
| 1534 // 2. at least one of the strings is two-byte, but happens to contain only | |
| 1535 // one-byte characters. | |
| 1536 // To do this, we check | |
| 1537 // 1. if both strings are one-byte, or | |
| 1538 // 2. if the one-byte data hint is set in both strings, or | |
| 1539 // 3. if one of the strings has the one-byte data hint set and the other | |
| 1540 // string is one-byte. | |
| 1541 IfBuilder if_onebyte(this); | |
| 1542 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 1543 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1544 Add<HBitwise>( | |
| 1545 Token::BIT_AND, | |
| 1546 Add<HBitwise>( | |
| 1547 Token::BIT_AND, left_instance_type, right_instance_type), | |
| 1548 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1549 graph()->GetConstant0(), | |
| 1550 Token::NE); | |
| 1551 if_onebyte.Or(); | |
| 1552 STATIC_ASSERT(kOneByteDataHintMask != 0); | |
| 1553 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1554 Add<HBitwise>( | |
| 1555 Token::BIT_AND, | |
| 1556 Add<HBitwise>( | |
| 1557 Token::BIT_AND, left_instance_type, right_instance_type), | |
| 1558 Add<HConstant>(static_cast<int32_t>(kOneByteDataHintMask))), | |
|
mvstanton
2013/11/08 10:17:50
These hurt my eyes. :)
How about a helper function
Benedikt Meurer
2013/11/08 13:21:08
I'm not sure that's going to make it better. Tried
| |
| 1559 graph()->GetConstant0(), | |
| 1560 Token::NE); | |
| 1561 if_onebyte.Or(); | |
| 1562 STATIC_ASSERT(kOneByteStringTag != 0 && | |
| 1563 kOneByteDataHintTag != 0 && | |
| 1564 kOneByteDataHintTag != kOneByteStringTag); | |
| 1565 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1566 Add<HBitwise>( | |
| 1567 Token::BIT_AND, | |
| 1568 Add<HBitwise>( | |
| 1569 Token::BIT_XOR, left_instance_type, right_instance_type), | |
| 1570 Add<HConstant>(static_cast<int32_t>( | |
| 1571 kOneByteStringTag | kOneByteDataHintTag))), | |
| 1572 Add<HConstant>(static_cast<int32_t>( | |
| 1573 kOneByteStringTag | kOneByteDataHintTag)), | |
| 1574 Token::EQ); | |
| 1575 if_onebyte.Then(); | |
| 1576 { | |
| 1577 // We can safely skip the write barrier for storing the map here. | |
| 1578 HStoreNamedField* store_map = AddStoreMapConstant( | |
| 1579 string, isolate()->factory()->cons_ascii_string_map()); | |
| 1580 store_map->SkipWriteBarrier(); | |
| 1581 } | |
| 1582 if_onebyte.Else(); | |
| 1583 { | |
| 1584 // We can safely skip the write barrier for storing the map here. | |
| 1585 HStoreNamedField* store_map = AddStoreMapConstant( | |
| 1586 string, isolate()->factory()->cons_string_map()); | |
| 1587 store_map->SkipWriteBarrier(); | |
| 1588 } | |
| 1589 if_onebyte.End(); | |
| 1590 | |
| 1591 // Initialize the cons string fields. | |
| 1592 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1593 Add<HConstant>(String::kEmptyHashField)); | |
| 1594 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), length); | |
| 1595 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringFirst(), left); | |
| 1596 Add<HStoreNamedField>(string, HObjectAccess::ForConsStringSecond(), | |
| 1597 right); | |
| 1598 | |
| 1599 // Cons string is result. | |
| 1600 Push(string); | |
| 1601 } | |
| 1602 if_createcons.Else(); | |
| 1603 { | |
| 1604 // Check if both strings have the same encoding and both are | |
| 1605 // sequential. | |
| 1606 IfBuilder if_sameencodingandsequential(this); | |
| 1607 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | |
| 1608 Add<HBitwise>( | |
| 1609 Token::BIT_AND, | |
| 1610 Add<HBitwise>( | |
| 1611 Token::BIT_XOR, left_instance_type, right_instance_type), | |
| 1612 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
|
mvstanton
2013/11/08 10:17:50
More instances of your typical pattern here, OP1(O
| |
| 1613 graph()->GetConstant0(), Token::EQ); | |
| 1614 if_sameencodingandsequential.And(); | |
| 1615 if_sameencodingandsequential.If<HCompareNumericAndBranch>( | |
| 1616 Add<HBitwise>( | |
| 1617 Token::BIT_AND, | |
| 1618 Add<HBitwise>( | |
| 1619 Token::BIT_OR, left_instance_type, right_instance_type), | |
| 1620 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), | |
| 1621 Add<HConstant>(static_cast<int32_t>(kSeqStringTag)), Token::EQ); | |
| 1622 if_sameencodingandsequential.Then(); | |
| 1623 { | |
| 1624 // Check if the result is a one-byte string. | |
| 1625 IfBuilder if_onebyte(this); | |
| 1626 if_onebyte.If<HCompareNumericAndBranch>( | |
| 1627 Add<HBitwise>( | |
| 1628 Token::BIT_AND, | |
| 1629 Add<HBitwise>( | |
| 1630 Token::BIT_OR, left_instance_type, right_instance_type), | |
| 1631 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), | |
| 1632 Add<HConstant>(static_cast<int32_t>(kTwoByteStringTag)), Token::NE); | |
| 1633 if_onebyte.Then(); | |
| 1634 { | |
| 1635 // Calculate the number of bytes needed for the characters in the | |
| 1636 // string while observing object alignment. | |
| 1637 STATIC_ASSERT(kOneByteSize == 1); | |
| 1638 STATIC_ASSERT((SeqOneByteString::kHeaderSize & | |
| 1639 kObjectAlignmentMask) == 0); | |
| 1640 HValue* size = Add<HAdd>( | |
| 1641 length, Add<HConstant>(static_cast<int32_t>( | |
| 1642 SeqOneByteString::kHeaderSize + kObjectAlignmentMask))); | |
| 1643 size->ClearFlag(HValue::kCanOverflow); | |
| 1644 size = Add<HBitwise>( | |
| 1645 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | |
| 1646 ~kObjectAlignmentMask))); | |
| 1647 | |
|
mvstanton
2013/11/08 10:17:50
The size operand calculation above is very tricky
Benedikt Meurer
2013/11/08 13:21:08
Done.
| |
| 1648 // Allocate the ASCII string object. | |
| 1649 Handle<Map> map = isolate()->factory()->ascii_string_map(); | |
| 1650 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1651 pretenure_flag, ASCII_STRING_TYPE); | |
| 1652 string->set_known_initial_map(map); | |
| 1653 | |
| 1654 // We can safely skip the write barrier for storing map here. | |
| 1655 HStoreNamedField* store_map = AddStoreMapConstant(string, map); | |
|
mvstanton
2013/11/08 10:17:50
AddStoreMapConstantNoWriteBarrier() again, or as a
Benedikt Meurer
2013/11/08 13:21:08
Done.
| |
| 1656 store_map->SkipWriteBarrier(); | |
| 1657 | |
| 1658 // Copy bytes from the left string. | |
| 1659 BuildCopySeqStringChars( | |
| 1660 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1661 string, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1662 left_length); | |
| 1663 | |
| 1664 // Copy bytes from the right string. | |
| 1665 BuildCopySeqStringChars( | |
| 1666 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, | |
| 1667 string, left_length, String::ONE_BYTE_ENCODING, | |
| 1668 right_length); | |
| 1669 | |
| 1670 // Return the string. | |
| 1671 Push(string); | |
| 1672 } | |
| 1673 if_onebyte.Else(); | |
| 1674 { | |
| 1675 // Calculate the number of bytes needed for the characters in the | |
| 1676 // string while observing object alignment. | |
| 1677 STATIC_ASSERT(kUC16Size == 2); | |
| 1678 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & | |
| 1679 kObjectAlignmentMask) == 0); | |
| 1680 HValue* size = Add<HShl>(length, graph()->GetConstant1()); | |
| 1681 size->ClearFlag(HValue::kCanOverflow); | |
| 1682 size->SetFlag(HValue::kUint32); | |
| 1683 size = Add<HAdd>( | |
| 1684 size, Add<HConstant>(static_cast<int32_t>( | |
| 1685 SeqTwoByteString::kHeaderSize + kObjectAlignmentMask))); | |
| 1686 size->ClearFlag(HValue::kCanOverflow); | |
| 1687 size = Add<HBitwise>( | |
| 1688 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( | |
| 1689 ~kObjectAlignmentMask))); | |
| 1690 | |
| 1691 // Allocate the two-byte string object. | |
| 1692 Handle<Map> map = isolate()->factory()->string_map(); | |
| 1693 HAllocate* string = Add<HAllocate>(size, HType::String(), | |
| 1694 pretenure_flag, STRING_TYPE); | |
| 1695 string->set_known_initial_map(map); | |
| 1696 | |
| 1697 // We can safely skip the write barrier for storing map here. | |
| 1698 HStoreNamedField* store_map = AddStoreMapConstant(string, map); | |
|
mvstanton
2013/11/08 10:17:50
Could you add a variant to AddStoreMapConstant eit
Benedikt Meurer
2013/11/08 13:21:08
Done.
| |
| 1699 store_map->SkipWriteBarrier(); | |
| 1700 | |
| 1701 // Copy bytes from the left string. | |
| 1702 BuildCopySeqStringChars( | |
| 1703 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1704 string, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1705 left_length); | |
| 1706 | |
| 1707 // Copy bytes from the right string. | |
| 1708 BuildCopySeqStringChars( | |
| 1709 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, | |
| 1710 string, left_length, String::TWO_BYTE_ENCODING, | |
| 1711 right_length); | |
| 1712 | |
| 1713 // Return the string. | |
| 1714 Push(string); | |
| 1715 } | |
| 1716 if_onebyte.End(); | |
| 1717 | |
| 1718 // Initialize the (common) string fields. | |
| 1719 HValue* string = Pop(); | |
| 1720 Add<HStoreNamedField>(string, HObjectAccess::ForStringHashField(), | |
| 1721 Add<HConstant>(String::kEmptyHashField)); | |
| 1722 Add<HStoreNamedField>(string, HObjectAccess::ForStringLength(), | |
| 1723 length); | |
| 1724 Push(string); | |
| 1725 } | |
| 1726 if_sameencodingandsequential.JoinContinuation(&handled); | |
| 1727 } | |
| 1728 if_createcons.JoinContinuation(&handled); | |
| 1729 } | |
| 1730 if_nooverflow.JoinContinuation(&handled); | |
| 1731 | |
| 1732 // Check if the strings were concatenated successfully, otherwise fallback to | |
| 1733 // add the strings in the runtime. | |
| 1734 IfBuilder if_handled(this, &handled); | |
| 1735 if_handled.Then(); | |
| 1736 { | |
| 1737 // Count the native string addition. | |
| 1738 AddIncrementCounter(isolate()->counters()->string_add_native()); | |
| 1739 } | |
| 1740 if_handled.Else(); | |
| 1741 { | |
| 1742 // Fallback to the runtime to add the two strings. | |
| 1743 Add<HPushArgument>(left); | |
| 1744 Add<HPushArgument>(right); | |
| 1745 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), | |
| 1746 Runtime::FunctionForId(Runtime::kStringAdd), | |
| 1747 2)); | |
| 1748 } | |
| 1749 if_handled.End(); | |
| 1750 | |
| 1751 return Pop(); | |
| 1752 } | |
| 1753 | |
| 1754 | |
| 1755 HValue* HGraphBuilder::BuildStringAdd(HValue* left, | |
| 1756 HValue* right, | |
| 1757 PretenureFlag pretenure_flag) { | |
| 1758 // Determine the string lengths. | |
| 1759 HValue* left_length = Add<HLoadNamedField>( | |
| 1760 left, HObjectAccess::ForStringLength()); | |
| 1761 HValue* right_length = Add<HLoadNamedField>( | |
| 1762 right, HObjectAccess::ForStringLength()); | |
| 1763 | |
| 1764 // Check if left string is empty. | |
| 1765 IfBuilder if_leftisempty(this); | |
| 1766 if_leftisempty.If<HCompareNumericAndBranch>( | |
| 1767 left_length, graph()->GetConstant0(), Token::EQ); | |
| 1768 if_leftisempty.Then(); | |
| 1769 { | |
| 1770 // Just return the right string. | |
| 1771 Push(right); | |
| 1772 } | |
| 1773 if_leftisempty.Else(); | |
| 1774 { | |
| 1775 // Check if right string is empty. | |
| 1776 IfBuilder if_rightisempty(this); | |
| 1777 if_rightisempty.If<HCompareNumericAndBranch>( | |
| 1778 right_length, graph()->GetConstant0(), Token::EQ); | |
| 1779 if_rightisempty.Then(); | |
| 1780 { | |
| 1781 // Just return the left string. | |
| 1782 Push(left); | |
| 1783 } | |
| 1784 if_rightisempty.Else(); | |
| 1785 { | |
| 1786 // Concatenate the two non-empty strings. | |
| 1787 Push(BuildUncheckedStringAdd(left, right, pretenure_flag)); | |
| 1788 } | |
| 1789 if_rightisempty.End(); | |
| 1790 } | |
| 1791 if_leftisempty.End(); | |
| 1792 | |
| 1793 return Pop(); | |
| 1794 } | |
| 1795 | |
| 1796 | |
| 1457 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 1797 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 1458 HValue* checked_object, | 1798 HValue* checked_object, |
| 1459 HValue* key, | 1799 HValue* key, |
| 1460 HValue* val, | 1800 HValue* val, |
| 1461 bool is_js_array, | 1801 bool is_js_array, |
| 1462 ElementsKind elements_kind, | 1802 ElementsKind elements_kind, |
| 1463 bool is_store, | 1803 bool is_store, |
| 1464 LoadKeyedHoleMode load_mode, | 1804 LoadKeyedHoleMode load_mode, |
| 1465 KeyedAccessStoreMode store_mode) { | 1805 KeyedAccessStoreMode store_mode) { |
| 1466 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); | 1806 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); |
| (...skipping 8389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9856 if (ShouldProduceTraceOutput()) { | 10196 if (ShouldProduceTraceOutput()) { |
| 9857 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10197 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9858 } | 10198 } |
| 9859 | 10199 |
| 9860 #ifdef DEBUG | 10200 #ifdef DEBUG |
| 9861 graph_->Verify(false); // No full verify. | 10201 graph_->Verify(false); // No full verify. |
| 9862 #endif | 10202 #endif |
| 9863 } | 10203 } |
| 9864 | 10204 |
| 9865 } } // namespace v8::internal | 10205 } } // namespace v8::internal |
| OLD | NEW |