Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(506)

Side by Side Diff: frog/leg/ssa/nodes.dart

Issue 9271037: Inserted string validation as separate task in compiler. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698