| 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 690 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 | 701 |
| 702 DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false) | 702 DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false) |
| 703 DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true) | 703 DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true) |
| 704 DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false) | 704 DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false) |
| 705 DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false) | 705 DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false) |
| 706 DEFINE_GET_CONSTANT(Null, null, HType::Tagged(), false) | 706 DEFINE_GET_CONSTANT(Null, null, HType::Tagged(), false) |
| 707 | 707 |
| 708 | 708 |
| 709 #undef DEFINE_GET_CONSTANT | 709 #undef DEFINE_GET_CONSTANT |
| 710 | 710 |
| 711 #define DEFINE_IS_CONSTANT(Name, name) \ |
| 712 bool HGraph::IsConstant##Name(HConstant* constant) { \ |
| 713 return constant_##name##_.is_set() && constant == constant_##name##_.get(); \ |
| 714 } |
| 715 DEFINE_IS_CONSTANT(Undefined, undefined) |
| 716 DEFINE_IS_CONSTANT(0, 0) |
| 717 DEFINE_IS_CONSTANT(1, 1) |
| 718 DEFINE_IS_CONSTANT(Minus1, minus1) |
| 719 DEFINE_IS_CONSTANT(True, true) |
| 720 DEFINE_IS_CONSTANT(False, false) |
| 721 DEFINE_IS_CONSTANT(Hole, the_hole) |
| 722 DEFINE_IS_CONSTANT(Null, null) |
| 723 |
| 724 #undef DEFINE_IS_CONSTANT |
| 725 |
| 711 | 726 |
| 712 HConstant* HGraph::GetInvalidContext() { | 727 HConstant* HGraph::GetInvalidContext() { |
| 713 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7); | 728 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7); |
| 714 } | 729 } |
| 715 | 730 |
| 716 | 731 |
| 717 bool HGraph::IsStandardConstant(HConstant* constant) { | 732 bool HGraph::IsStandardConstant(HConstant* constant) { |
| 718 if (constant == GetConstantUndefined()) return true; | 733 if (IsConstantUndefined(constant)) return true; |
| 719 if (constant == GetConstant0()) return true; | 734 if (IsConstant0(constant)) return true; |
| 720 if (constant == GetConstant1()) return true; | 735 if (IsConstant1(constant)) return true; |
| 721 if (constant == GetConstantMinus1()) return true; | 736 if (IsConstantMinus1(constant)) return true; |
| 722 if (constant == GetConstantTrue()) return true; | 737 if (IsConstantTrue(constant)) return true; |
| 723 if (constant == GetConstantFalse()) return true; | 738 if (IsConstantFalse(constant)) return true; |
| 724 if (constant == GetConstantHole()) return true; | 739 if (IsConstantHole(constant)) return true; |
| 725 if (constant == GetConstantNull()) return true; | 740 if (IsConstantNull(constant)) return true; |
| 726 return false; | 741 return false; |
| 727 } | 742 } |
| 728 | 743 |
| 729 | 744 |
| 730 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) | 745 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) |
| 731 : builder_(builder), | 746 : builder_(builder), |
| 732 finished_(false), | 747 finished_(false), |
| 733 deopt_then_(false), | 748 deopt_then_(false), |
| 734 deopt_else_(false), | 749 deopt_else_(false), |
| 735 did_then_(false), | 750 did_then_(false), |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 : first_false_block_; | 852 : first_false_block_; |
| 838 continuation->Capture(true_block, false_block); | 853 continuation->Capture(true_block, false_block); |
| 839 captured_ = true; | 854 captured_ = true; |
| 840 End(); | 855 End(); |
| 841 } | 856 } |
| 842 | 857 |
| 843 | 858 |
| 844 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { | 859 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { |
| 845 ASSERT(!finished_); | 860 ASSERT(!finished_); |
| 846 ASSERT(!captured_); | 861 ASSERT(!captured_); |
| 862 ASSERT(did_then_); |
| 863 if (!did_else_) Else(); |
| 847 HBasicBlock* true_block = last_true_block_ == NULL | 864 HBasicBlock* true_block = last_true_block_ == NULL |
| 848 ? first_true_block_ | 865 ? first_true_block_ |
| 849 : last_true_block_; | 866 : last_true_block_; |
| 850 HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL) | 867 HBasicBlock* false_block = builder_->current_block(); |
| 851 ? builder_->current_block() | |
| 852 : first_false_block_; | |
| 853 if (true_block != NULL && !true_block->IsFinished()) { | 868 if (true_block != NULL && !true_block->IsFinished()) { |
| 854 ASSERT(continuation->IsTrueReachable()); | 869 ASSERT(continuation->IsTrueReachable()); |
| 855 builder_->GotoNoSimulate(true_block, continuation->true_branch()); | 870 builder_->GotoNoSimulate(true_block, continuation->true_branch()); |
| 856 } | 871 } |
| 857 if (false_block != NULL && !false_block->IsFinished()) { | 872 if (false_block != NULL && !false_block->IsFinished()) { |
| 858 ASSERT(continuation->IsFalseReachable()); | 873 ASSERT(continuation->IsFalseReachable()); |
| 859 builder_->GotoNoSimulate(false_block, continuation->false_branch()); | 874 builder_->GotoNoSimulate(false_block, continuation->false_branch()); |
| 860 } | 875 } |
| 861 captured_ = true; | 876 captured_ = true; |
| 862 End(); | 877 End(); |
| (...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1447 isolate()->factory()->empty_string(), | 1462 isolate()->factory()->empty_string(), |
| 1448 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), | 1463 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), |
| 1449 1)); | 1464 1)); |
| 1450 } | 1465 } |
| 1451 if_found.End(); | 1466 if_found.End(); |
| 1452 | 1467 |
| 1453 return Pop(); | 1468 return Pop(); |
| 1454 } | 1469 } |
| 1455 | 1470 |
| 1456 | 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 |
| 1457 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 1808 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 1458 HValue* checked_object, | 1809 HValue* checked_object, |
| 1459 HValue* key, | 1810 HValue* key, |
| 1460 HValue* val, | 1811 HValue* val, |
| 1461 bool is_js_array, | 1812 bool is_js_array, |
| 1462 ElementsKind elements_kind, | 1813 ElementsKind elements_kind, |
| 1463 bool is_store, | 1814 bool is_store, |
| 1464 LoadKeyedHoleMode load_mode, | 1815 LoadKeyedHoleMode load_mode, |
| 1465 KeyedAccessStoreMode store_mode) { | 1816 KeyedAccessStoreMode store_mode) { |
| 1466 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); | 1817 ASSERT(!IsExternalArrayElementsKind(elements_kind) || !is_js_array); |
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2119 // objects we construct, and an int32-to-smi HChange could deopt. Accept | 2470 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 2120 // the deopt possibility now, before allocation occurs. | 2471 // the deopt possibility now, before allocation occurs. |
| 2121 capacity = builder()->Add<HForceRepresentation>(capacity, | 2472 capacity = builder()->Add<HForceRepresentation>(capacity, |
| 2122 Representation::Smi()); | 2473 Representation::Smi()); |
| 2123 length_field = builder()->Add<HForceRepresentation>(length_field, | 2474 length_field = builder()->Add<HForceRepresentation>(length_field, |
| 2124 Representation::Smi()); | 2475 Representation::Smi()); |
| 2125 // Allocate (dealing with failure appropriately) | 2476 // Allocate (dealing with failure appropriately) |
| 2126 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, | 2477 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, |
| 2127 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); | 2478 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| 2128 | 2479 |
| 2480 // Folded array allocation should be aligned if it has fast double elements. |
| 2481 if (IsFastDoubleElementsKind(kind_)) { |
| 2482 new_object->MakeDoubleAligned(); |
| 2483 } |
| 2484 |
| 2129 // Fill in the fields: map, properties, length | 2485 // Fill in the fields: map, properties, length |
| 2130 HValue* map; | 2486 HValue* map; |
| 2131 if (allocation_site_payload_ == NULL) { | 2487 if (allocation_site_payload_ == NULL) { |
| 2132 map = EmitInternalMapCode(); | 2488 map = EmitInternalMapCode(); |
| 2133 } else { | 2489 } else { |
| 2134 map = EmitMapCode(); | 2490 map = EmitMapCode(); |
| 2135 } | 2491 } |
| 2136 elements_location_ = builder()->BuildJSArrayHeader(new_object, | 2492 elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| 2137 map, | 2493 map, |
| 2138 mode_, | 2494 mode_, |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2269 phi_list_(NULL), | 2625 phi_list_(NULL), |
| 2270 uint32_instructions_(NULL), | 2626 uint32_instructions_(NULL), |
| 2271 osr_(NULL), | 2627 osr_(NULL), |
| 2272 info_(info), | 2628 info_(info), |
| 2273 zone_(info->zone()), | 2629 zone_(info->zone()), |
| 2274 is_recursive_(false), | 2630 is_recursive_(false), |
| 2275 use_optimistic_licm_(false), | 2631 use_optimistic_licm_(false), |
| 2276 depends_on_empty_array_proto_elements_(false), | 2632 depends_on_empty_array_proto_elements_(false), |
| 2277 type_change_checksum_(0), | 2633 type_change_checksum_(0), |
| 2278 maximum_environment_size_(0), | 2634 maximum_environment_size_(0), |
| 2279 no_side_effects_scope_count_(0) { | 2635 no_side_effects_scope_count_(0), |
| 2636 disallow_adding_new_values_(false) { |
| 2280 if (info->IsStub()) { | 2637 if (info->IsStub()) { |
| 2281 HydrogenCodeStub* stub = info->code_stub(); | 2638 HydrogenCodeStub* stub = info->code_stub(); |
| 2282 CodeStubInterfaceDescriptor* descriptor = | 2639 CodeStubInterfaceDescriptor* descriptor = |
| 2283 stub->GetInterfaceDescriptor(isolate_); | 2640 stub->GetInterfaceDescriptor(isolate_); |
| 2284 start_environment_ = | 2641 start_environment_ = |
| 2285 new(zone_) HEnvironment(zone_, descriptor->environment_length()); | 2642 new(zone_) HEnvironment(zone_, descriptor->environment_length()); |
| 2286 } else { | 2643 } else { |
| 2287 start_environment_ = | 2644 start_environment_ = |
| 2288 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 2645 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 2289 } | 2646 } |
| (...skipping 2008 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4298 } | 4655 } |
| 4299 } | 4656 } |
| 4300 return true; | 4657 return true; |
| 4301 } | 4658 } |
| 4302 | 4659 |
| 4303 | 4660 |
| 4304 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { | 4661 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { |
| 4305 ASSERT(!HasStackOverflow()); | 4662 ASSERT(!HasStackOverflow()); |
| 4306 ASSERT(current_block() != NULL); | 4663 ASSERT(current_block() != NULL); |
| 4307 ASSERT(current_block()->HasPredecessor()); | 4664 ASSERT(current_block()->HasPredecessor()); |
| 4665 expr->BuildConstantProperties(isolate()); |
| 4308 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); | 4666 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); |
| 4309 HInstruction* literal; | 4667 HInstruction* literal; |
| 4310 | 4668 |
| 4311 // Check whether to use fast or slow deep-copying for boilerplate. | 4669 // Check whether to use fast or slow deep-copying for boilerplate. |
| 4312 int max_properties = kMaxFastLiteralProperties; | 4670 int max_properties = kMaxFastLiteralProperties; |
| 4313 Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()), | 4671 Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()), |
| 4314 isolate()); | 4672 isolate()); |
| 4315 Handle<AllocationSite> site; | 4673 Handle<AllocationSite> site; |
| 4316 Handle<JSObject> boilerplate; | 4674 Handle<JSObject> boilerplate; |
| 4317 if (!literals_cell->IsUndefined()) { | 4675 if (!literals_cell->IsUndefined()) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4419 } else { | 4777 } else { |
| 4420 return ast_context()->ReturnValue(Pop()); | 4778 return ast_context()->ReturnValue(Pop()); |
| 4421 } | 4779 } |
| 4422 } | 4780 } |
| 4423 | 4781 |
| 4424 | 4782 |
| 4425 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { | 4783 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { |
| 4426 ASSERT(!HasStackOverflow()); | 4784 ASSERT(!HasStackOverflow()); |
| 4427 ASSERT(current_block() != NULL); | 4785 ASSERT(current_block() != NULL); |
| 4428 ASSERT(current_block()->HasPredecessor()); | 4786 ASSERT(current_block()->HasPredecessor()); |
| 4787 expr->BuildConstantElements(isolate()); |
| 4429 ZoneList<Expression*>* subexprs = expr->values(); | 4788 ZoneList<Expression*>* subexprs = expr->values(); |
| 4430 int length = subexprs->length(); | 4789 int length = subexprs->length(); |
| 4431 HInstruction* literal; | 4790 HInstruction* literal; |
| 4432 | 4791 |
| 4433 Handle<AllocationSite> site; | 4792 Handle<AllocationSite> site; |
| 4434 Handle<FixedArray> literals(environment()->closure()->literals(), isolate()); | 4793 Handle<FixedArray> literals(environment()->closure()->literals(), isolate()); |
| 4435 bool uninitialized = false; | 4794 bool uninitialized = false; |
| 4436 Handle<Object> literals_cell(literals->get(expr->literal_index()), | 4795 Handle<Object> literals_cell(literals->get(expr->literal_index()), |
| 4437 isolate()); | 4796 isolate()); |
| 4438 Handle<JSObject> boilerplate_object; | 4797 Handle<JSObject> boilerplate_object; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4486 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); | 4845 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); |
| 4487 int literal_index = expr->literal_index(); | 4846 int literal_index = expr->literal_index(); |
| 4488 | 4847 |
| 4489 Add<HPushArgument>(Add<HConstant>(literals)); | 4848 Add<HPushArgument>(Add<HConstant>(literals)); |
| 4490 Add<HPushArgument>(Add<HConstant>(literal_index)); | 4849 Add<HPushArgument>(Add<HConstant>(literal_index)); |
| 4491 Add<HPushArgument>(Add<HConstant>(constants)); | 4850 Add<HPushArgument>(Add<HConstant>(constants)); |
| 4492 | 4851 |
| 4493 // TODO(mvstanton): Consider a flag to turn off creation of any | 4852 // TODO(mvstanton): Consider a flag to turn off creation of any |
| 4494 // AllocationMementos for this call: we are in crankshaft and should have | 4853 // AllocationMementos for this call: we are in crankshaft and should have |
| 4495 // learned enough about transition behavior to stop emitting mementos. | 4854 // learned enough about transition behavior to stop emitting mementos. |
| 4496 Runtime::FunctionId function_id = (expr->depth() > 1) | 4855 Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral; |
| 4497 ? Runtime::kCreateArrayLiteral : Runtime::kCreateArrayLiteralShallow; | |
| 4498 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), | 4856 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 4499 Runtime::FunctionForId(function_id), | 4857 Runtime::FunctionForId(function_id), |
| 4500 3); | 4858 3); |
| 4501 | 4859 |
| 4502 // De-opt if elements kind changed from boilerplate_elements_kind. | 4860 // De-opt if elements kind changed from boilerplate_elements_kind. |
| 4503 Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate()); | 4861 Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate()); |
| 4504 literal = Add<HCheckMaps>(literal, map, top_info()); | 4862 literal = Add<HCheckMaps>(literal, map, top_info()); |
| 4505 } | 4863 } |
| 4506 | 4864 |
| 4507 // The array is expected in the bailout environment during computation | 4865 // The array is expected in the bailout environment during computation |
| (...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5565 HValue* dependency, | 5923 HValue* dependency, |
| 5566 Handle<Map> map, | 5924 Handle<Map> map, |
| 5567 bool is_store, | 5925 bool is_store, |
| 5568 KeyedAccessStoreMode store_mode) { | 5926 KeyedAccessStoreMode store_mode) { |
| 5569 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), | 5927 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), |
| 5570 dependency); | 5928 dependency); |
| 5571 if (dependency) { | 5929 if (dependency) { |
| 5572 checked_object->ClearGVNFlag(kDependsOnElementsKind); | 5930 checked_object->ClearGVNFlag(kDependsOnElementsKind); |
| 5573 } | 5931 } |
| 5574 | 5932 |
| 5933 if (is_store && map->prototype()->IsJSObject()) { |
| 5934 // monomorphic stores need a prototype chain check because shape |
| 5935 // changes could allow callbacks on elements in the chain that |
| 5936 // aren't compatible with monomorphic keyed stores. |
| 5937 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| 5938 Object* holder = map->prototype(); |
| 5939 while (holder->GetPrototype(isolate())->IsJSObject()) { |
| 5940 holder = holder->GetPrototype(isolate()); |
| 5941 } |
| 5942 ASSERT(holder->GetPrototype(isolate())->IsNull()); |
| 5943 |
| 5944 BuildCheckPrototypeMaps(prototype, |
| 5945 Handle<JSObject>(JSObject::cast(holder))); |
| 5946 } |
| 5947 |
| 5575 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 5948 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
| 5576 return BuildUncheckedMonomorphicElementAccess( | 5949 return BuildUncheckedMonomorphicElementAccess( |
| 5577 checked_object, key, val, | 5950 checked_object, key, val, |
| 5578 map->instance_type() == JS_ARRAY_TYPE, | 5951 map->instance_type() == JS_ARRAY_TYPE, |
| 5579 map->elements_kind(), is_store, | 5952 map->elements_kind(), is_store, |
| 5580 load_mode, store_mode); | 5953 load_mode, store_mode); |
| 5581 } | 5954 } |
| 5582 | 5955 |
| 5583 | 5956 |
| 5584 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 5957 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5778 HValue* val, | 6151 HValue* val, |
| 5779 Expression* expr, | 6152 Expression* expr, |
| 5780 bool is_store, | 6153 bool is_store, |
| 5781 bool* has_side_effects) { | 6154 bool* has_side_effects) { |
| 5782 ASSERT(!expr->IsPropertyName()); | 6155 ASSERT(!expr->IsPropertyName()); |
| 5783 HInstruction* instr = NULL; | 6156 HInstruction* instr = NULL; |
| 5784 | 6157 |
| 5785 SmallMapList* types; | 6158 SmallMapList* types; |
| 5786 bool monomorphic = ComputeReceiverTypes(expr, obj, &types); | 6159 bool monomorphic = ComputeReceiverTypes(expr, obj, &types); |
| 5787 | 6160 |
| 6161 bool force_generic = false; |
| 6162 if (is_store && (monomorphic || (types != NULL && !types->is_empty()))) { |
| 6163 // Stores can't be mono/polymorphic if their prototype chain has dictionary |
| 6164 // elements. However a receiver map that has dictionary elements itself |
| 6165 // should be left to normal mono/poly behavior (the other maps may benefit |
| 6166 // from highly optimized stores). |
| 6167 for (int i = 0; i < types->length(); i++) { |
| 6168 Handle<Map> current_map = types->at(i); |
| 6169 if (current_map->DictionaryElementsInPrototypeChainOnly()) { |
| 6170 force_generic = true; |
| 6171 monomorphic = false; |
| 6172 break; |
| 6173 } |
| 6174 } |
| 6175 } |
| 6176 |
| 5788 if (monomorphic) { | 6177 if (monomorphic) { |
| 5789 Handle<Map> map = types->first(); | 6178 Handle<Map> map = types->first(); |
| 5790 if (map->has_slow_elements_kind()) { | 6179 if (map->has_slow_elements_kind()) { |
| 5791 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 6180 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 5792 : BuildLoadKeyedGeneric(obj, key); | 6181 : BuildLoadKeyedGeneric(obj, key); |
| 5793 AddInstruction(instr); | 6182 AddInstruction(instr); |
| 5794 } else { | 6183 } else { |
| 5795 BuildCheckHeapObject(obj); | 6184 BuildCheckHeapObject(obj); |
| 5796 instr = BuildMonomorphicElementAccess( | 6185 instr = BuildMonomorphicElementAccess( |
| 5797 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 6186 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
| 5798 } | 6187 } |
| 5799 } else if (types != NULL && !types->is_empty()) { | 6188 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
| 5800 return HandlePolymorphicElementAccess( | 6189 return HandlePolymorphicElementAccess( |
| 5801 obj, key, val, types, is_store, | 6190 obj, key, val, types, is_store, |
| 5802 expr->GetStoreMode(), has_side_effects); | 6191 expr->GetStoreMode(), has_side_effects); |
| 5803 } else { | 6192 } else { |
| 5804 if (is_store) { | 6193 if (is_store) { |
| 5805 if (expr->IsAssignment() && | 6194 if (expr->IsAssignment() && |
| 5806 expr->AsAssignment()->HasNoTypeInformation()) { | 6195 expr->AsAssignment()->HasNoTypeInformation()) { |
| 5807 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 6196 Add<HDeoptimize>("Insufficient type feedback for keyed store", |
| 5808 Deoptimizer::SOFT); | 6197 Deoptimizer::SOFT); |
| 5809 } | 6198 } |
| (...skipping 499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6309 | 6698 |
| 6310 | 6699 |
| 6311 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { | 6700 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { |
| 6312 if (!FLAG_use_inlining) return kNotInlinable; | 6701 if (!FLAG_use_inlining) return kNotInlinable; |
| 6313 | 6702 |
| 6314 // Precondition: call is monomorphic and we have found a target with the | 6703 // Precondition: call is monomorphic and we have found a target with the |
| 6315 // appropriate arity. | 6704 // appropriate arity. |
| 6316 Handle<JSFunction> caller = current_info()->closure(); | 6705 Handle<JSFunction> caller = current_info()->closure(); |
| 6317 Handle<SharedFunctionInfo> target_shared(target->shared()); | 6706 Handle<SharedFunctionInfo> target_shared(target->shared()); |
| 6318 | 6707 |
| 6708 // Always inline builtins marked for inlining. |
| 6709 if (target->IsBuiltin()) { |
| 6710 return target_shared->inline_builtin() ? 0 : kNotInlinable; |
| 6711 } |
| 6712 |
| 6319 // Do a quick check on source code length to avoid parsing large | 6713 // Do a quick check on source code length to avoid parsing large |
| 6320 // inlining candidates. | 6714 // inlining candidates. |
| 6321 if (target_shared->SourceSize() > | 6715 if (target_shared->SourceSize() > |
| 6322 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { | 6716 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { |
| 6323 TraceInline(target, caller, "target text too big"); | 6717 TraceInline(target, caller, "target text too big"); |
| 6324 return kNotInlinable; | 6718 return kNotInlinable; |
| 6325 } | 6719 } |
| 6326 | 6720 |
| 6327 // Target must be inlineable. | 6721 // Target must be inlineable. |
| 6328 if (!target->IsInlineable()) { | 6722 if (!target_shared->IsInlineable()) { |
| 6329 TraceInline(target, caller, "target not inlineable"); | 6723 TraceInline(target, caller, "target not inlineable"); |
| 6330 return kNotInlinable; | 6724 return kNotInlinable; |
| 6331 } | 6725 } |
| 6332 if (target_shared->dont_inline() || target_shared->dont_optimize()) { | 6726 if (target_shared->dont_inline() || target_shared->dont_optimize()) { |
| 6333 TraceInline(target, caller, "target contains unsupported syntax [early]"); | 6727 TraceInline(target, caller, "target contains unsupported syntax [early]"); |
| 6334 return kNotInlinable; | 6728 return kNotInlinable; |
| 6335 } | 6729 } |
| 6336 | 6730 |
| 6337 int nodes_added = target_shared->ast_node_count(); | 6731 int nodes_added = target_shared->ast_node_count(); |
| 6338 return nodes_added; | 6732 return nodes_added; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 6349 int nodes_added = InliningAstSize(target); | 6743 int nodes_added = InliningAstSize(target); |
| 6350 if (nodes_added == kNotInlinable) return false; | 6744 if (nodes_added == kNotInlinable) return false; |
| 6351 | 6745 |
| 6352 Handle<JSFunction> caller = current_info()->closure(); | 6746 Handle<JSFunction> caller = current_info()->closure(); |
| 6353 | 6747 |
| 6354 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 6748 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
| 6355 TraceInline(target, caller, "target AST is too large [early]"); | 6749 TraceInline(target, caller, "target AST is too large [early]"); |
| 6356 return false; | 6750 return false; |
| 6357 } | 6751 } |
| 6358 | 6752 |
| 6359 #if !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS | |
| 6360 // Target must be able to use caller's context. | |
| 6361 CompilationInfo* outer_info = current_info(); | |
| 6362 if (target->context() != outer_info->closure()->context() || | |
| 6363 outer_info->scope()->contains_with() || | |
| 6364 outer_info->scope()->num_heap_slots() > 0) { | |
| 6365 TraceInline(target, caller, "target requires context change"); | |
| 6366 return false; | |
| 6367 } | |
| 6368 #endif | |
| 6369 | |
| 6370 | |
| 6371 // Don't inline deeper than the maximum number of inlining levels. | 6753 // Don't inline deeper than the maximum number of inlining levels. |
| 6372 HEnvironment* env = environment(); | 6754 HEnvironment* env = environment(); |
| 6373 int current_level = 1; | 6755 int current_level = 1; |
| 6374 while (env->outer() != NULL) { | 6756 while (env->outer() != NULL) { |
| 6375 if (current_level == FLAG_max_inlining_levels) { | 6757 if (current_level == FLAG_max_inlining_levels) { |
| 6376 TraceInline(target, caller, "inline depth limit reached"); | 6758 TraceInline(target, caller, "inline depth limit reached"); |
| 6377 return false; | 6759 return false; |
| 6378 } | 6760 } |
| 6379 if (env->outer()->frame_type() == JS_FUNCTION) { | 6761 if (env->outer()->frame_type() == JS_FUNCTION) { |
| 6380 current_level++; | 6762 current_level++; |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6498 HConstant* undefined = graph()->GetConstantUndefined(); | 6880 HConstant* undefined = graph()->GetConstantUndefined(); |
| 6499 bool undefined_receiver = HEnvironment::UseUndefinedReceiver( | 6881 bool undefined_receiver = HEnvironment::UseUndefinedReceiver( |
| 6500 target, function, call_kind, inlining_kind); | 6882 target, function, call_kind, inlining_kind); |
| 6501 HEnvironment* inner_env = | 6883 HEnvironment* inner_env = |
| 6502 environment()->CopyForInlining(target, | 6884 environment()->CopyForInlining(target, |
| 6503 arguments_count, | 6885 arguments_count, |
| 6504 function, | 6886 function, |
| 6505 undefined, | 6887 undefined, |
| 6506 function_state()->inlining_kind(), | 6888 function_state()->inlining_kind(), |
| 6507 undefined_receiver); | 6889 undefined_receiver); |
| 6508 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS | 6890 |
| 6509 // IA32, ARM and MIPS only, overwrite the caller's context in the | |
| 6510 // deoptimization environment with the correct one. | |
| 6511 // | |
| 6512 // TODO(kmillikin): implement the same inlining on other platforms so we | |
| 6513 // can remove the unsightly ifdefs in this function. | |
| 6514 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); | 6891 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); |
| 6515 inner_env->BindContext(context); | 6892 inner_env->BindContext(context); |
| 6516 #endif | |
| 6517 | 6893 |
| 6518 Add<HSimulate>(return_id); | 6894 Add<HSimulate>(return_id); |
| 6519 current_block()->UpdateEnvironment(inner_env); | 6895 current_block()->UpdateEnvironment(inner_env); |
| 6520 HArgumentsObject* arguments_object = NULL; | 6896 HArgumentsObject* arguments_object = NULL; |
| 6521 | 6897 |
| 6522 // If the function uses arguments object create and bind one, also copy | 6898 // If the function uses arguments object create and bind one, also copy |
| 6523 // current arguments values to use them for materialization. | 6899 // current arguments values to use them for materialization. |
| 6524 if (function->scope()->arguments() != NULL) { | 6900 if (function->scope()->arguments() != NULL) { |
| 6525 ASSERT(function->scope()->arguments()->IsStackAllocated()); | 6901 ASSERT(function->scope()->arguments()->IsStackAllocated()); |
| 6526 HEnvironment* arguments_env = inner_env->arguments_environment(); | 6902 HEnvironment* arguments_env = inner_env->arguments_environment(); |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6716 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7092 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 6717 switch (id) { | 7093 switch (id) { |
| 6718 case kMathExp: | 7094 case kMathExp: |
| 6719 if (!FLAG_fast_math) break; | 7095 if (!FLAG_fast_math) break; |
| 6720 // Fall through if FLAG_fast_math. | 7096 // Fall through if FLAG_fast_math. |
| 6721 case kMathRound: | 7097 case kMathRound: |
| 6722 case kMathFloor: | 7098 case kMathFloor: |
| 6723 case kMathAbs: | 7099 case kMathAbs: |
| 6724 case kMathSqrt: | 7100 case kMathSqrt: |
| 6725 case kMathLog: | 7101 case kMathLog: |
| 6726 case kMathSin: | |
| 6727 case kMathCos: | |
| 6728 case kMathTan: | |
| 6729 if (expr->arguments()->length() == 1) { | 7102 if (expr->arguments()->length() == 1) { |
| 6730 HValue* argument = Pop(); | 7103 HValue* argument = Pop(); |
| 6731 Drop(1); // Receiver. | 7104 Drop(1); // Receiver. |
| 6732 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7105 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 6733 if (drop_extra) Drop(1); // Optionally drop the function. | 7106 if (drop_extra) Drop(1); // Optionally drop the function. |
| 6734 ast_context()->ReturnInstruction(op, expr->id()); | 7107 ast_context()->ReturnInstruction(op, expr->id()); |
| 6735 return true; | 7108 return true; |
| 6736 } | 7109 } |
| 6737 break; | 7110 break; |
| 6738 case kMathImul: | 7111 case kMathImul: |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6797 } | 7170 } |
| 6798 break; | 7171 break; |
| 6799 case kMathExp: | 7172 case kMathExp: |
| 6800 if (!FLAG_fast_math) break; | 7173 if (!FLAG_fast_math) break; |
| 6801 // Fall through if FLAG_fast_math. | 7174 // Fall through if FLAG_fast_math. |
| 6802 case kMathRound: | 7175 case kMathRound: |
| 6803 case kMathFloor: | 7176 case kMathFloor: |
| 6804 case kMathAbs: | 7177 case kMathAbs: |
| 6805 case kMathSqrt: | 7178 case kMathSqrt: |
| 6806 case kMathLog: | 7179 case kMathLog: |
| 6807 case kMathSin: | |
| 6808 case kMathCos: | |
| 6809 case kMathTan: | |
| 6810 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7180 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { |
| 6811 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | 7181 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); |
| 6812 HValue* argument = Pop(); | 7182 HValue* argument = Pop(); |
| 6813 Drop(1); // Receiver. | 7183 Drop(1); // Receiver. |
| 6814 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7184 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 6815 ast_context()->ReturnInstruction(op, expr->id()); | 7185 ast_context()->ReturnInstruction(op, expr->id()); |
| 6816 return true; | 7186 return true; |
| 6817 } | 7187 } |
| 6818 break; | 7188 break; |
| 6819 case kMathPow: | 7189 case kMathPow: |
| (...skipping 1916 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8736 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { | 9106 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { |
| 8737 ASSERT(call->arguments()->length() == 1); | 9107 ASSERT(call->arguments()->length() == 1); |
| 8738 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9108 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8739 HValue* value = Pop(); | 9109 HValue* value = Pop(); |
| 8740 HHasInstanceTypeAndBranch* result = | 9110 HHasInstanceTypeAndBranch* result = |
| 8741 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE); | 9111 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE); |
| 8742 return ast_context()->ReturnControl(result, call->id()); | 9112 return ast_context()->ReturnControl(result, call->id()); |
| 8743 } | 9113 } |
| 8744 | 9114 |
| 8745 | 9115 |
| 9116 void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) { |
| 9117 ASSERT(call->arguments()->length() == 1); |
| 9118 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9119 HValue* value = Pop(); |
| 9120 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value); |
| 9121 return ast_context()->ReturnControl(result, call->id()); |
| 9122 } |
| 9123 |
| 9124 |
| 8746 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { | 9125 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { |
| 8747 ASSERT(call->arguments()->length() == 1); | 9126 ASSERT(call->arguments()->length() == 1); |
| 8748 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9127 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 8749 HValue* value = Pop(); | 9128 HValue* value = Pop(); |
| 8750 HHasCachedArrayIndexAndBranch* result = | 9129 HHasCachedArrayIndexAndBranch* result = |
| 8751 New<HHasCachedArrayIndexAndBranch>(value); | 9130 New<HHasCachedArrayIndexAndBranch>(value); |
| 8752 return ast_context()->ReturnControl(result, call->id()); | 9131 return ast_context()->ReturnControl(result, call->id()); |
| 8753 } | 9132 } |
| 8754 | 9133 |
| 8755 | 9134 |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9119 ASSERT_EQ(2, call->arguments()->length()); | 9498 ASSERT_EQ(2, call->arguments()->length()); |
| 9120 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9499 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9121 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 9500 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 9122 HValue* right = Pop(); | 9501 HValue* right = Pop(); |
| 9123 HValue* left = Pop(); | 9502 HValue* left = Pop(); |
| 9124 HInstruction* result = NewUncasted<HPower>(left, right); | 9503 HInstruction* result = NewUncasted<HPower>(left, right); |
| 9125 return ast_context()->ReturnInstruction(result, call->id()); | 9504 return ast_context()->ReturnInstruction(result, call->id()); |
| 9126 } | 9505 } |
| 9127 | 9506 |
| 9128 | 9507 |
| 9129 void HOptimizedGraphBuilder::GenerateMathSin(CallRuntime* call) { | |
| 9130 ASSERT_EQ(1, call->arguments()->length()); | |
| 9131 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9132 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9133 result->set_transcendental_type(TranscendentalCache::SIN); | |
| 9134 Drop(1); | |
| 9135 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9136 } | |
| 9137 | |
| 9138 | |
| 9139 void HOptimizedGraphBuilder::GenerateMathCos(CallRuntime* call) { | |
| 9140 ASSERT_EQ(1, call->arguments()->length()); | |
| 9141 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9142 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9143 result->set_transcendental_type(TranscendentalCache::COS); | |
| 9144 Drop(1); | |
| 9145 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9146 } | |
| 9147 | |
| 9148 | |
| 9149 void HOptimizedGraphBuilder::GenerateMathTan(CallRuntime* call) { | |
| 9150 ASSERT_EQ(1, call->arguments()->length()); | |
| 9151 CHECK_ALIVE(VisitArgumentList(call->arguments())); | |
| 9152 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | |
| 9153 result->set_transcendental_type(TranscendentalCache::TAN); | |
| 9154 Drop(1); | |
| 9155 return ast_context()->ReturnInstruction(result, call->id()); | |
| 9156 } | |
| 9157 | |
| 9158 | |
| 9159 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { | 9508 void HOptimizedGraphBuilder::GenerateMathLog(CallRuntime* call) { |
| 9160 ASSERT_EQ(1, call->arguments()->length()); | 9509 ASSERT_EQ(1, call->arguments()->length()); |
| 9161 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 9510 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 9162 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); | 9511 HCallStub* result = New<HCallStub>(CodeStub::TranscendentalCache, 1); |
| 9163 result->set_transcendental_type(TranscendentalCache::LOG); | 9512 result->set_transcendental_type(TranscendentalCache::LOG); |
| 9164 Drop(1); | 9513 Drop(1); |
| 9165 return ast_context()->ReturnInstruction(result, call->id()); | 9514 return ast_context()->ReturnInstruction(result, call->id()); |
| 9166 } | 9515 } |
| 9167 | 9516 |
| 9168 | 9517 |
| (...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9819 if (ShouldProduceTraceOutput()) { | 10168 if (ShouldProduceTraceOutput()) { |
| 9820 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10169 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9821 } | 10170 } |
| 9822 | 10171 |
| 9823 #ifdef DEBUG | 10172 #ifdef DEBUG |
| 9824 graph_->Verify(false); // No full verify. | 10173 graph_->Verify(false); // No full verify. |
| 9825 #endif | 10174 #endif |
| 9826 } | 10175 } |
| 9827 | 10176 |
| 9828 } } // namespace v8::internal | 10177 } } // namespace v8::internal |
| OLD | NEW |