| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 interface HVisitor<R> { | 5 interface HVisitor<R> { |
| 6 R visitAdd(HAdd node); | 6 R visitAdd(HAdd node); |
| 7 R visitBailoutTarget(HBailoutTarget node); | 7 R visitBailoutTarget(HBailoutTarget node); |
| 8 R visitBitAnd(HBitAnd node); | 8 R visitBitAnd(HBitAnd node); |
| 9 R visitBitNot(HBitNot node); | 9 R visitBitNot(HBitNot node); |
| 10 R visitBitOr(HBitOr node); | 10 R visitBitOr(HBitOr node); |
| (...skipping 1538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1549 assert(block.successors[0].id < block.id); | 1549 assert(block.successors[0].id < block.id); |
| 1550 assert(block.dominatedBlocks[0] === block.successors[1]); | 1550 assert(block.dominatedBlocks[0] === block.successors[1]); |
| 1551 } else { | 1551 } else { |
| 1552 assert(block.dominatedBlocks[0] === block.successors[0]); | 1552 assert(block.dominatedBlocks[0] === block.successors[0]); |
| 1553 assert(block.dominatedBlocks[1] === block.successors[1]);; | 1553 assert(block.dominatedBlocks[1] === block.successors[1]);; |
| 1554 } | 1554 } |
| 1555 return result; | 1555 return result; |
| 1556 } | 1556 } |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 /** | |
| 1560 * A wrapper around a SourceString that stores extra information about | |
| 1561 * the (potentially implicit) quoting style of the original string. | |
| 1562 * For most strings, the quotes are included in the [wrappedString], but | |
| 1563 * parts of strings from a string interpolation might be missing one or | |
| 1564 * both quotes. | |
| 1565 */ | |
| 1566 class QuotedString { | |
| 1567 // Bits of flag values. | |
| 1568 static final int NO_FLAGS = 0; | |
| 1569 static final int RAW = 1 << 0; | |
| 1570 static final int MULTI_LINE = 1 << 1; | |
| 1571 static final int HAS_LEFT_QUOTE = 1 << 2; | |
| 1572 static final int HAS_RIGHT_QUOTE = 1 << 3; | |
| 1573 static final int HAS_BOTH_QUOTES = HAS_LEFT_QUOTE | HAS_RIGHT_QUOTE; | |
| 1574 // Whether the string uses single quotes ('). Default is double quotes ("). | |
| 1575 static final int SINGLE_QUOTED = 1 << 4; | |
| 1576 | |
| 1577 final SourceString wrappedString; | |
| 1578 final int flags; | |
| 1579 | |
| 1580 /** | |
| 1581 * Finds the quote type for a string given a part of it containing the | |
| 1582 * starting quote. Returns flags, but doesn't include HAS_LEFT_QUOTE | |
| 1583 * or HAS_RIGHT_QUOTE. | |
| 1584 */ | |
| 1585 static int flagsFromLeftQuote(SourceString sourceString) { | |
| 1586 Iterator<int> source = sourceString.iterator(); | |
| 1587 int flags = 0; | |
| 1588 int start = 0; | |
| 1589 int quoteChar = source.next(); | |
| 1590 if (quoteChar == $AT) { | |
| 1591 flags |= RAW; | |
| 1592 start = 1; | |
| 1593 quoteChar = source.next(); | |
| 1594 } | |
| 1595 if (quoteChar == $SQ) { | |
| 1596 flags |= SINGLE_QUOTED; | |
| 1597 } else { | |
| 1598 assert(quoteChar == $DQ); | |
| 1599 } | |
| 1600 // String has one quote. Check it if has three. | |
| 1601 // If it only have two, the string must be an empty string literal, | |
| 1602 // and end after the second quote. | |
| 1603 if (source.hasNext() && source.next() == quoteChar && source.hasNext()) { | |
| 1604 assert(source.next() == quoteChar); | |
| 1605 flags |= MULTI_LINE; | |
| 1606 } | |
| 1607 return flags; | |
| 1608 } | |
| 1609 | |
| 1610 const QuotedString(this.wrappedString, this.flags); | |
| 1611 | |
| 1612 // TODO(lrn): Make flags RAW for a literal string when we support it. | |
| 1613 QuotedString.literal(String string) : | |
| 1614 this(new SourceString(string), NO_FLAGS); | |
| 1615 | |
| 1616 /** | |
| 1617 * Crates a [QuotedString] from a [SourceString] that contains | |
| 1618 * both its quotes. | |
| 1619 */ | |
| 1620 factory QuotedString.explicit(SourceString string) { | |
| 1621 int flags = flagsFromLeftQuote(string); | |
| 1622 int leftQuotes = leftQuoteLengthFromFlags(flags | HAS_LEFT_QUOTE); | |
| 1623 int rightQuotes = rightQuoteLengthFromFlags(flags | HAS_RIGHT_QUOTE); | |
| 1624 SourceString unquoted = string.copyWithoutQuotes(leftQuotes, rightQuotes); | |
| 1625 return new QuotedString(unquoted, flags); | |
| 1626 } | |
| 1627 | |
| 1628 SourceString unquotedSource() { | |
| 1629 if ((flags & HAS_BOTH_QUOTES) == 0) return wrappedString; | |
| 1630 return wrappedString.copyWithoutQuotes(leftQuoteLength, | |
| 1631 rightQuoteLength); | |
| 1632 } | |
| 1633 | |
| 1634 bool get hasLeftQuote() => (flags & HAS_LEFT_QUOTE) != 0; | |
| 1635 bool get hasRightQuote() => (flags & HAS_RIGHT_QUOTE) != 0; | |
| 1636 bool get isMultiLine() => (flags & MULTI_LINE) != 0; | |
| 1637 bool get isRaw() => (flags & RAW) != 0; | |
| 1638 String get quoteChar() => ((flags & SINGLE_QUOTED) != 0) ? "'" : '"'; | |
| 1639 int get quoteCharCode() => ((flags & SINGLE_QUOTED) != 0) ? $SQ : $DQ; | |
| 1640 | |
| 1641 int get leftQuoteLength() => | |
| 1642 hasLeftQuote ? (isRaw ? 1 : 0) + (isMultiLine ? 3 : 1) : 0; | |
| 1643 int get rightQuoteLength() => | |
| 1644 hasRightQuote ? (isMultiLine ? 3 : 1) : 0; | |
| 1645 static int leftQuoteLengthFromFlags(int flags) { | |
| 1646 if ((flags & HAS_LEFT_QUOTE) == 0) return 0; | |
| 1647 return (flags & (RAW | MULTI_LINE)) + 1; | |
| 1648 } | |
| 1649 static int rightQuoteLengthFromFlags(int flags) { | |
| 1650 if ((flags & HAS_RIGHT_QUOTE) == 0) return 0; | |
| 1651 return (flags & MULTI_LINE) + 1; | |
| 1652 } | |
| 1653 | |
| 1654 bool isEmpty() => unquotedSource().isEmpty(); | |
| 1655 | |
| 1656 static int hexValue(int hexDigit) { | |
| 1657 // hexDigit is one of '0'..'9', 'A'..'F' and 'a'..'f'. | |
| 1658 if (hexDigit <= $9) { | |
| 1659 return hexDigit - $0; | |
| 1660 } | |
| 1661 // Make letters lowercase. | |
| 1662 hexDigit |= $a ^ $A; | |
| 1663 hexDigit -= $a - 10; | |
| 1664 assert(10 <= hexDigit && hexDigit <= 15); | |
| 1665 return hexDigit; | |
| 1666 } | |
| 1667 | |
| 1668 static bool isHexDigit(int characterCode) { | |
| 1669 if ($0 <= characterCode && characterCode <= $9) return true; | |
| 1670 characterCode |= $a ^ $A; | |
| 1671 return ($a <= characterCode && characterCode <= $f); | |
| 1672 } | |
| 1673 | |
| 1674 static int readUnicodeEscape(Iterator<int> iter, | |
| 1675 void cancel(String s)) { | |
| 1676 if (!iter.hasNext()) cancel("Incomplete unicode escape."); | |
| 1677 int code = iter.next(); | |
| 1678 if (code == $OPEN_CURLY_BRACKET) { | |
| 1679 // In Dart, '\u{'x{0..7}'}' is a valid escape, but not in | |
| 1680 // JS. Convert to a \uxxxx escape. | |
| 1681 int value = 0; | |
| 1682 int length = 0; | |
| 1683 if (!iter.hasNext()) cancel("Incomplete unicode escape."); | |
| 1684 int hexDigit = iter.next(); | |
| 1685 do { | |
| 1686 if (!isHexDigit(hexDigit)) { | |
| 1687 cancel("Invalid character in unicode escape"); | |
| 1688 } | |
| 1689 value = value * 16 + hexValue(hexDigit); | |
| 1690 length++; | |
| 1691 if (length > 7) { | |
| 1692 cancel("Invalid unicode escape length."); | |
| 1693 } | |
| 1694 if (!iter.hasNext()) cancel("Incomplete unicode escape."); | |
| 1695 hexDigit = iter.next(); | |
| 1696 } while (hexDigit !== $CLOSE_CURLY_BRACKET); // until '}'. | |
| 1697 return value; | |
| 1698 } | |
| 1699 // Simple four-digit unicode escape. | |
| 1700 int value = 0; | |
| 1701 for (int i = 0; i < 4; i++) { | |
| 1702 if (i > 0) { | |
| 1703 if (!iter.hasNext()) cancel("Incomplete unicode escape."); | |
| 1704 code = iter.next(); | |
| 1705 } | |
| 1706 if (!isHexDigit(code)) cancel("Invalid character in unicode escape"); | |
| 1707 value = value * 16 + hexValue(code); | |
| 1708 } | |
| 1709 return value; | |
| 1710 } | |
| 1711 | |
| 1712 /** | |
| 1713 * Write the contents of the quoted string to a [StringBuffer] in | |
| 1714 * a form that is valid as JavaScript string literal content. | |
| 1715 * The string is assumed quoted by [quote] characters. | |
| 1716 * This method doesn't try to make the shortest string, but rather | |
| 1717 * to be as close to the original string as possible. | |
| 1718 */ | |
| 1719 void writeEscaped(StringBuffer buffer, int quote, void cancel(String s)) { | |
| 1720 bool raw = this.isRaw; | |
| 1721 Iterator<int> iter = | |
| 1722 wrappedString.copyWithoutQuotes(leftQuoteLength, | |
| 1723 rightQuoteLength).iterator(); | |
| 1724 while (iter.hasNext()) { | |
| 1725 int code = iter.next(); | |
| 1726 if (code == quote) { | |
| 1727 // We need to add a backslash before quotes, both in normal | |
| 1728 // and in raw strings. | |
| 1729 buffer.add(@'\'); | |
| 1730 buffer.add(code == $SQ ? "'" : '"'); | |
| 1731 } else if (code == $LF) { | |
| 1732 // Newlines in strings only occour in multiline strings. | |
| 1733 // They need to be written using escapes in JS.. | |
| 1734 assert(isMultiLine); | |
| 1735 buffer.add(@'\n'); | |
| 1736 } else if (code == $CR) { | |
| 1737 assert(isMultiLine); | |
| 1738 buffer.add(@'\r'); | |
| 1739 } else if (code == $LS || code == $PS) { | |
| 1740 // These Unicode line terminators are invalid in JS strings. | |
| 1741 buffer.add(code == $LS ? @'\u2028' : @'\u2029'); | |
| 1742 } else if (code != $BACKSLASH) { | |
| 1743 buffer.add(new String.fromCharCodes([code])); | |
| 1744 } else if (raw) { | |
| 1745 buffer.add(@'\\'); | |
| 1746 } else { | |
| 1747 code = iter.next(); | |
| 1748 // TODO(lrn): Reading \x and \u escapes also validates the | |
| 1749 // escape sequences. This should be done at an earlier step | |
| 1750 // to catch errors even in dead code. | |
| 1751 switch (code) { | |
| 1752 case $u: | |
| 1753 int value = readUnicodeEscape(iter, cancel); | |
| 1754 if (value >= 0xD800 && value <= 0xDFFF || value > 0x10ffff) { | |
| 1755 cancel('Invalid unicode scalar value.'); | |
| 1756 } | |
| 1757 if (value > 0xffff) { | |
| 1758 cancel('Unhandled Unicode value: $value - outside the BMP.'); | |
| 1759 } | |
| 1760 buffer.add(@'\u'); | |
| 1761 for (int j = 12; j >= 0; j -= 4) { | |
| 1762 int digit = (value >> j) & 0xf; | |
| 1763 buffer.add("0123456789abcdef"[digit]); | |
| 1764 } | |
| 1765 break; | |
| 1766 case $x: | |
| 1767 buffer.add(@'\x'); | |
| 1768 List<int> codes = <int>[]; | |
| 1769 for (int i = 0; i < 2; i++) { | |
| 1770 if (!iter.hasNext()) cancel("Incomplete hex escape"); | |
| 1771 code = iter.next(); | |
| 1772 if (!isHexDigit(code)) { | |
| 1773 cancel("Invalid hex digit: " + | |
| 1774 "${new String.fromCharCodes([code])}"); | |
| 1775 } | |
| 1776 codes.add(code); | |
| 1777 } | |
| 1778 buffer.add(new String.fromCharCodes(codes)); | |
| 1779 break; | |
| 1780 // Character escapes that identical in meaning in JS. | |
| 1781 case $b: buffer.add(@'\b'); break; | |
| 1782 case $f: buffer.add(@'\f'); break; | |
| 1783 case $n: buffer.add(@'\n'); break; | |
| 1784 case $r: buffer.add(@'\r'); break; | |
| 1785 case $t: buffer.add(@'\t'); break; | |
| 1786 case $v: buffer.add(@'\v'); break; | |
| 1787 // Identity escapes that must be escaped in JS strings. | |
| 1788 case $BACKSLASH: buffer.add(@'\\'); break; | |
| 1789 case $LF: buffer.add(@'\n'); break; | |
| 1790 case $CR: buffer.add(@'\r'); break; | |
| 1791 case $LS: buffer.add(@'\u2028'); break; | |
| 1792 case $PS: buffer.add(@'\u2029'); break; | |
| 1793 // Quotes may or may not need the escape. | |
| 1794 case $SQ: | |
| 1795 case $DQ: | |
| 1796 // Only escape quotes if they match the generated string quotes. | |
| 1797 if (code == quote) buffer.add(@'\'); | |
| 1798 buffer.add(code === $SQ ? "'" : '"'); | |
| 1799 break; | |
| 1800 default: | |
| 1801 // All other escaped characters are identity escapes, | |
| 1802 // and don't need a backslash in JS. | |
| 1803 buffer.add(new String.fromCharCodes([code])); | |
| 1804 break; | |
| 1805 } | |
| 1806 } | |
| 1807 } | |
| 1808 } | |
| 1809 | |
| 1810 /** | |
| 1811 * Does a conservative test for equality between two quoted strings. | |
| 1812 * Returns true if the two definitly have the same string. | |
| 1813 * Returns false if the strings are different, or if it's not possible | |
| 1814 * to (quickly) determine whether they are equal. | |
| 1815 */ | |
| 1816 bool definitlyEquals(QuotedString other) { | |
| 1817 return flags == other.flags && wrappedString == other.wrappedString; | |
| 1818 } | |
| 1819 | |
| 1820 void printOn(StringBuffer buffer) { | |
| 1821 int start = leftQuoteLength; | |
| 1822 int end = rightQuoteLength; | |
| 1823 if (start == 1 && end == 1) { | |
| 1824 wrappedString.printOn(buffer); | |
| 1825 } else { | |
| 1826 String quote = quoteChar; | |
| 1827 buffer.add(quote); | |
| 1828 wrappedString.copyWithoutQuotes(start, end).printOn(buffer); | |
| 1829 buffer.add(quote); | |
| 1830 } | |
| 1831 } | |
| 1832 } | |
| 1833 | |
| 1834 class HLiteral extends HInstruction { | 1559 class HLiteral extends HInstruction { |
| 1835 final value; | 1560 final value; |
| 1836 HLiteral(this.value, HType type) : super(<HInstruction>[]) { | 1561 HLiteral(this.value, HType type) : super(<HInstruction>[]) { |
| 1837 this.type = type; | 1562 this.type = type; |
| 1838 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? | 1563 tryGenerateAtUseSite(); // Maybe avoid this if the literal is big? |
| 1839 } | 1564 } |
| 1840 void prepareGvn() { | 1565 void prepareGvn() { |
| 1841 // We allow global value numbering of literals, but we still | 1566 // We allow global value numbering of literals, but we still |
| 1842 // prefer generating them at use sites. This allows us to do | 1567 // prefer generating them at use sites. This allows us to do |
| 1843 // better GVN'ing of instructions that use literals as input. | 1568 // better GVN'ing of instructions that use literals as input. |
| (...skipping 420 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2264 | 1989 |
| 2265 HInstruction get expression() => inputs[0]; | 1990 HInstruction get expression() => inputs[0]; |
| 2266 | 1991 |
| 2267 HType computeType() => HType.BOOLEAN; | 1992 HType computeType() => HType.BOOLEAN; |
| 2268 bool hasExpectedType() => true; | 1993 bool hasExpectedType() => true; |
| 2269 | 1994 |
| 2270 accept(HVisitor visitor) => visitor.visitIs(this); | 1995 accept(HVisitor visitor) => visitor.visitIs(this); |
| 2271 | 1996 |
| 2272 toString() => "$expression is $typeExpression"; | 1997 toString() => "$expression is $typeExpression"; |
| 2273 } | 1998 } |
| OLD | NEW |