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