Merge change I7d18e38e
* changes:
Added additional DEX checksum.
diff --git a/libcore/luni/src/main/java/java/lang/AbstractStringBuilder.java b/libcore/luni/src/main/java/java/lang/AbstractStringBuilder.java
index 869c694..4cf2d5d 100644
--- a/libcore/luni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/libcore/luni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -181,16 +181,17 @@
}
if (s instanceof String) {
- // BEGIN android-changed
((String) s)._getChars(start, end, value, count);
- // END android-changed
+ } else if (s instanceof AbstractStringBuilder) {
+ AbstractStringBuilder other = (AbstractStringBuilder) s;
+ System.arraycopy(other.value, start, value, count, adding);
} else {
int j = count; // Destination index.
for (int i = start; i < end; i++) {
value[j++] = s.charAt(i);
}
}
-
+
this.count = newSize;
// END android-changed
}
diff --git a/libcore/luni/src/main/java/java/lang/Character.java b/libcore/luni/src/main/java/java/lang/Character.java
index 8e83b48..f643183 100644
--- a/libcore/luni/src/main/java/java/lang/Character.java
+++ b/libcore/luni/src/main/java/java/lang/Character.java
@@ -2578,15 +2578,14 @@
* otherwise.
*/
public static boolean isDigit(char c) {
+ // Optimized case for ASCII
+ if ('0' <= c && c <= '9') {
+ return true;
+ }
+ if (c < 1632) {
+ return false;
+ }
// BEGIN android-changed
- // // Optimized case for ASCII
- // if ('0' <= c && c <= '9') {
- // return true;
- // }
- // if (c < 1632) {
- // return false;
- // }
- // return getType(c) == DECIMAL_DIGIT_NUMBER;
return UCharacter.isDigit(c);
// END android-changed
}
@@ -3023,16 +3022,14 @@
* otherwise.
*/
public static boolean isUpperCase(char c) {
+ // Optimized case for ASCII
+ if ('A' <= c && c <= 'Z') {
+ return true;
+ }
+ if (c < 128) {
+ return false;
+ }
// BEGIN android-changed
- // // Optimized case for ASCII
- // if ('A' <= c && c <= 'Z') {
- // return true;
- // }
- // if (c < 128) {
- // return false;
- // }
- //
- // return getType(c) == UPPERCASE_LETTER;
return UCharacter.isUpperCase(c);
// END android-changed
}
diff --git a/libcore/luni/src/main/java/java/lang/String.java b/libcore/luni/src/main/java/java/lang/String.java
index 6d53357..be9e71f 100644
--- a/libcore/luni/src/main/java/java/lang/String.java
+++ b/libcore/luni/src/main/java/java/lang/String.java
@@ -58,54 +58,9 @@
private static final char REPLACEMENT_CHAR = (char) 0xfffd;
// END android-added
- /**
- * An PrintStream used for System.out which performs the correct character
- * conversion for the console, since the console may use a different
- * conversion than the default file.encoding.
- */
- static class ConsolePrintStream extends java.io.PrintStream {
- private static String charset;
-
- static {
- charset = AccessController.doPrivileged(new PriviAction<String>(
- "console.encoding", "ISO8859_1")); //$NON-NLS-1$ //$NON-NLS-2$
- if (!Charset.isSupported(charset)) {
- charset = "ISO-8859-1"; //$NON-NLS-1$
- }
- }
-
- /**
- * Create a ConsolePrintStream on the specified OutputStream, usually
- * System.out.
- *
- * @param out
- * the console OutputStream
- */
- public ConsolePrintStream(java.io.OutputStream out) {
- super(out, true);
-
- }
-
- /**
- * Override the print(String) method from PrintStream to perform the
- * character conversion using the console character converter.
- *
- * @param str
- * the string to convert
- */
- @Override
- public void print(String str) {
- if (str == null) {
- str = "null"; //$NON-NLS-1$
- }
-
- try {
- write(str.getBytes(charset));
- } catch (java.io.IOException e) {
- setError();
- }
- }
- }
+ // BEGIN android-removed
+ // static class ConsolePrintStream extends java.io.PrintStream ...
+ // END android-removed
/**
* CaseInsensitiveComparator compares Strings ignoring the case of the
diff --git a/libcore/luni/src/main/java/java/util/Formatter.java b/libcore/luni/src/main/java/java/util/Formatter.java
index 8260fda..9aca21a 100644
--- a/libcore/luni/src/main/java/java/util/Formatter.java
+++ b/libcore/luni/src/main/java/java/util/Formatter.java
@@ -4,9 +4,9 @@
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,7 +29,6 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
-import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -125,7 +124,7 @@
* </tr>
* <tr>
* <td width="5%">{@code X}, {@code x}</td>
- * <td width="10%">int, formatted as hexidecimal</td>
+ * <td width="10%">int, formatted as hexadecimal</td>
* <td width="30%">{@code format("%x, %X", 10, 10);}</td>
* <td width="30%">{@code a, A}</td>
* </tr>
@@ -150,7 +149,7 @@
* <tr>
* <td width="5%">{@code #}</td>
* <td width="10%">Print the leading characters that indicate
- * hexidecimal or octal (for use only with hex and octal types) </td>
+ * hexadecimal or octal (for use only with hex and octal types) </td>
* <td width="30%">{@code format("%#o", 010);}</td>
* <td width="30%">{@code 010}</td>
* </tr>
@@ -203,7 +202,7 @@
* </tr>
* <tr>
* <td width="5%">{@code A}, {@code a}</td>
- * <td width="10%">float (or double) formatted as a hexidecimal in exponential
+ * <td width="10%">float (or double) formatted as a hexadecimal in exponential
* notation, where the precision indicates the number of significant digits.</td>
* <td width="30%">{@code format("%A %<.1a %<1.5A %<10A %<6.0A", 123.456f);}</td>
* <td width="30%">{@code 0X1.EDD2F2P6 0x1.fp6 0X1.EDD2FP6 0X1.EDD2F2P6 0X1.FP6}</td>
@@ -805,14 +804,15 @@
* {@code Formatter} has been closed will raise a {@code FormatterClosedException}.
*/
public void close() {
- closed = true;
- try {
- if (out instanceof Closeable) {
- ((Closeable) out).close();
+ if (!closed) {
+ closed = true;
+ try {
+ if (out instanceof Closeable) {
+ ((Closeable) out).close();
+ }
+ } catch (IOException e) {
+ lastIOException = e;
}
- } catch (IOException e) {
-
- lastIOException = e;
}
}
@@ -863,8 +863,9 @@
* @param l
* the {@code Locale} used in the method. If {@code locale} is
* {@code null}, then no localization will be applied. This
- * parameter does not influence the {@code Locale} specified during
- * construction.
+ * parameter does not change this Formatter's default {@code Locale}
+ * as specified during construction, and only applies for the
+ * duration of this call.
* @param format
* a format string.
* @param args
@@ -880,59 +881,81 @@
* if the {@code Formatter} has been closed.
*/
public Formatter format(Locale l, String format, Object... args) {
- checkClosed();
- CharBuffer formatBuffer = CharBuffer.wrap(format);
- ParserStateMachine parser = new ParserStateMachine(formatBuffer);
-
// BEGIN android-changed
- // Reuse the previous transformer if the locale matches.
- if (transformer == null || ! transformer.locale.equals(l)) {
- transformer = new Transformer(this, l);
+ Locale originalLocale = locale;
+ try {
+ this.locale = l;
+ doFormat(format, args);
+ } finally {
+ this.locale = originalLocale;
}
+ return this;
+ // END android-changed
+ }
+
+ // BEGIN android-changed
+ private void doFormat(String format, Object... args) {
+ checkClosed();
+
+ // Reuse the previous transformer if the locale matches.
+ if (transformer == null || ! transformer.locale.equals(locale)) {
+ transformer = new Transformer(this, locale);
+ }
+
+ FormatSpecifierParser fsp = new FormatSpecifierParser();
int currentObjectIndex = 0;
Object lastArgument = null;
boolean hasLastArgumentSet = false;
- while (formatBuffer.hasRemaining()) {
- parser.reset();
- FormatToken token = parser.getNextFormatToken();
- String plainText = token.getPlainText();
- if (token.getConversionType() == (char) FormatToken.UNSET) {
- outputCharSequence(plainText);
- } else {
- plainText = plainText.substring(0, plainText.indexOf('%'));
- outputCharSequence(plainText);
+
+ char[] chars = format.toCharArray();
+ int length = chars.length;
+ int i = 0;
+ while (i < length) {
+ // Find the maximal plain-text sequence...
+ int plainTextStart = i;
+ while (i < length && chars[i] != '%') {
+ ++i;
+ }
+ // ...and output it.
+ int plainTextEnd = i;
+ if (plainTextEnd > plainTextStart) {
+ outputCharSequence(format, plainTextStart, plainTextEnd);
+ }
+ // Do we have a format specifier?
+ if (i < length) {
+ FormatToken token = fsp.parseFormatToken(chars, i + 1);
Object argument = null;
if (token.requireArgument()) {
- int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++
- : token.getArgIndex();
- argument = getArgument(args, index, token, lastArgument,
- hasLastArgumentSet);
+ int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++ : token.getArgIndex();
+ argument = getArgument(args, index, fsp, lastArgument, hasLastArgumentSet);
lastArgument = argument;
hasLastArgumentSet = true;
}
- outputCharSequence(transformer.transform(token, argument));
+
+ CharSequence substitution = transformer.transform(token, argument);
+ if (substitution != null) {
+ outputCharSequence(substitution, 0, substitution.length());
+ }
+ i = fsp.i;
}
}
- // END android-changed
- return this;
}
+ // END android-changed
// BEGIN android-added
// Fixes http://code.google.com/p/android/issues/detail?id=1767.
- private void outputCharSequence(CharSequence cs) {
- if (cs != null) {
- try {
- out.append(cs);
- } catch (IOException e) {
- lastIOException = e;
- }
+ private void outputCharSequence(CharSequence cs, int start, int end) {
+ try {
+ out.append(cs, start, end);
+ } catch (IOException e) {
+ lastIOException = e;
}
}
// END android-added
- private Object getArgument(Object[] args, int index, FormatToken token,
+ private Object getArgument(Object[] args, int index, FormatSpecifierParser fsp,
Object lastArgument, boolean hasLastArgumentSet) {
if (index == FormatToken.LAST_ARGUMENT_INDEX && !hasLastArgumentSet) {
throw new MissingFormatArgumentException("<"); //$NON-NLS-1$
@@ -943,7 +966,7 @@
}
if (index >= args.length) {
- throw new MissingFormatArgumentException(token.getPlainText());
+ throw new MissingFormatArgumentException(fsp.getFormatSpecifierText());
}
if (index == FormatToken.LAST_ARGUMENT_INDEX) {
@@ -983,25 +1006,15 @@
static final int DEFAULT_PRECISION = 6;
static final int FLAG_MINUS = 1;
-
static final int FLAG_SHARP = 1 << 1;
-
static final int FLAG_ADD = 1 << 2;
-
static final int FLAG_SPACE = 1 << 3;
-
static final int FLAG_ZERO = 1 << 4;
-
static final int FLAG_COMMA = 1 << 5;
-
static final int FLAG_PARENTHESIS = 1 << 6;
private static final int FLAGT_TYPE_COUNT = 6;
- private int formatStringStartIndex;
-
- private String plainText;
-
private int argIndex = UNSET;
private int flags = 0;
@@ -1010,7 +1023,7 @@
private int precision = UNSET;
- private StringBuilder strFlags = new StringBuilder(FLAGT_TYPE_COUNT);
+ private StringBuilder strFlags;
private char dateSuffix;// will be used in new feature.
@@ -1036,14 +1049,6 @@
argIndex = index;
}
- String getPlainText() {
- return plainText;
- }
-
- void setPlainText(String plainText) {
- this.plainText = plainText;
- }
-
int getWidth() {
return width;
}
@@ -1061,7 +1066,7 @@
}
String getStrFlags() {
- return strFlags.toString();
+ return (strFlags != null) ? strFlags.toString() : "";
}
int getFlags() {
@@ -1076,7 +1081,7 @@
* Sets qualified char as one of the flags. If the char is qualified,
* sets it as a flag and returns true. Or else returns false.
*/
- boolean setFlag(char c) {
+ boolean setFlag(int c) {
int newFlag;
switch (c) {
case '-': {
@@ -1110,23 +1115,18 @@
default:
return false;
}
- if (0 != (flags & newFlag)) {
+ if ((flags & newFlag) != 0) {
throw new DuplicateFormatFlagsException(String.valueOf(c));
}
- flags = (flags | newFlag);
+ flags |= newFlag;
+ if (strFlags == null) {
+ strFlags = new StringBuilder(FLAGT_TYPE_COUNT);
+ }
strFlags.append(c);
return true;
}
- int getFormatStringStartIndex() {
- return formatStringStartIndex;
- }
-
- void setFormatStringStartIndex(int index) {
- formatStringStartIndex = index;
- }
-
char getConversionType() {
return conversionType;
}
@@ -1273,8 +1273,6 @@
* Transforms the Boolean argument to a formatted string.
*/
private CharSequence transformFromBoolean() {
- StringBuilder result = new StringBuilder();
- int startIndex = 0;
int flags = formatToken.getFlags();
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1290,23 +1288,21 @@
.getStrFlags(), formatToken.getConversionType());
}
- if (null == arg) {
- result.append("false"); //$NON-NLS-1$
- } else if (arg instanceof Boolean) {
- result.append(arg);
+ CharSequence result;
+ if (arg instanceof Boolean) {
+ result = arg.toString();
+ } else if (arg == null) {
+ result = "false"; //$NON-NLS-1$
} else {
- result.append("true"); //$NON-NLS-1$
+ result = "true"; //$NON-NLS-1$
}
- return padding(result, startIndex);
+ return padding(result, 0);
}
/*
* Transforms the hashcode of the argument to a formatted string.
*/
private CharSequence transformFromHashCode() {
- StringBuilder result = new StringBuilder();
-
- int startIndex = 0;
int flags = formatToken.getFlags();
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1322,20 +1318,19 @@
.getStrFlags(), formatToken.getConversionType());
}
- if (null == arg) {
- result.append("null"); //$NON-NLS-1$
+ CharSequence result;
+ if (arg == null) {
+ result = "null"; //$NON-NLS-1$
} else {
- result.append(Integer.toHexString(arg.hashCode()));
+ result = Integer.toHexString(arg.hashCode());
}
- return padding(result, startIndex);
+ return padding(result, 0);
}
/*
* Transforms the String to a formatted string.
*/
private CharSequence transformFromString() {
- StringBuilder result = new StringBuilder();
- int startIndex = 0;
int flags = formatToken.getFlags();
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1376,17 +1371,14 @@
.getStrFlags(), formatToken.getConversionType());
}
- result.append(arg);
- return padding(result, startIndex);
+ CharSequence result = arg != null ? arg.toString() : "null";
+ return padding(result, 0);
}
/*
* Transforms the Character to a formatted string.
*/
private CharSequence transformFromCharacter() {
- StringBuilder result = new StringBuilder();
-
- int startIndex = 0;
int flags = formatToken.getFlags();
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1407,36 +1399,37 @@
.getPrecision());
}
- if (null == arg) {
- result.append("null"); //$NON-NLS-1$
+ CharSequence result;
+ if (arg == null) {
+ result = "null"; //$NON-NLS-1$
} else {
if (arg instanceof Character) {
- result.append(arg);
+ result = String.valueOf(arg);
} else if (arg instanceof Byte) {
byte b = ((Byte) arg).byteValue();
if (!Character.isValidCodePoint(b)) {
throw new IllegalFormatCodePointException(b);
}
- result.append((char) b);
+ result = String.valueOf((char) b);
} else if (arg instanceof Short) {
short s = ((Short) arg).shortValue();
if (!Character.isValidCodePoint(s)) {
throw new IllegalFormatCodePointException(s);
}
- result.append((char) s);
+ result = String.valueOf((char) s);
} else if (arg instanceof Integer) {
int codePoint = ((Integer) arg).intValue();
if (!Character.isValidCodePoint(codePoint)) {
throw new IllegalFormatCodePointException(codePoint);
}
- result.append(String.valueOf(Character.toChars(codePoint)));
+ result = String.valueOf(Character.toChars(codePoint));
} else {
// argument of other class is not acceptable.
throw new IllegalFormatConversionException(formatToken
.getConversionType(), arg.getClass());
}
}
- return padding(result, startIndex);
+ return padding(result, 0);
}
/*
@@ -1444,9 +1437,6 @@
* Precision is illegal.
*/
private CharSequence transformFromPercent() {
- StringBuilder result = new StringBuilder("%"); //$NON-NLS-1$
-
- int startIndex = 0;
int flags = formatToken.getFlags();
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1464,7 +1454,7 @@
throw new IllegalFormatPrecisionException(formatToken
.getPrecision());
}
- return padding(result, startIndex);
+ return padding("%", 0);
}
/*
@@ -1501,29 +1491,21 @@
/*
* Pads characters to the formatted string.
*/
- private CharSequence padding(StringBuilder source, int startIndex) {
+ private CharSequence padding(CharSequence source, int startIndex) {
+ boolean sourceIsStringBuilder = (source instanceof StringBuilder);
+
int start = startIndex;
- boolean paddingRight = formatToken
- .isFlagSet(FormatToken.FLAG_MINUS);
- char paddingChar = '\u0020';// space as padding char.
- if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
- if ('d' == formatToken.getConversionType()) {
- paddingChar = getDecimalFormatSymbols().getZeroDigit();
- } else {
- paddingChar = '0';
- }
- } else {
- // if padding char is space, always padding from the head
- // location.
- start = 0;
- }
int width = formatToken.getWidth();
int precision = formatToken.getPrecision();
int length = source.length();
if (precision >= 0) {
length = Math.min(length, precision);
- source.delete(length, source.length());
+ if (sourceIsStringBuilder) {
+ ((StringBuilder) source).setLength(length);
+ } else {
+ source = source.subSequence(0, length);
+ }
}
if (width > 0) {
width = Math.max(source.length(), width);
@@ -1532,16 +1514,45 @@
return source;
}
- char[] paddings = new char[width - length];
- Arrays.fill(paddings, paddingChar);
- String insertString = new String(paddings);
-
- if (paddingRight) {
- source.append(insertString);
+ char paddingChar = '\u0020'; // space as padding char.
+ if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
+ if (formatToken.getConversionType() == 'd') {
+ paddingChar = getDecimalFormatSymbols().getZeroDigit();
+ } else {
+ paddingChar = '0';
+ }
} else {
- source.insert(start, insertString);
+ // if padding char is space, always pad from the start.
+ start = 0;
}
- return source;
+ char[] paddingChars = new char[width - length];
+ Arrays.fill(paddingChars, paddingChar);
+
+ boolean paddingRight = formatToken.isFlagSet(FormatToken.FLAG_MINUS);
+ StringBuilder result = toStringBuilder(source);
+ if (paddingRight) {
+ result.append(paddingChars);
+ } else {
+ result.insert(start, paddingChars);
+ }
+ return result;
+ }
+
+ private StringBuilder toStringBuilder(CharSequence cs) {
+ return cs instanceof StringBuilder ? (StringBuilder) cs : new StringBuilder(cs);
+ }
+
+ private StringBuilder wrapParentheses(StringBuilder result) {
+ result.setCharAt(0, '('); // Replace the '-'.
+ if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
+ formatToken.setWidth(formatToken.getWidth() - 1);
+ result = (StringBuilder) padding(result, 1);
+ result.append(')');
+ } else {
+ result.append(')');
+ result = (StringBuilder) padding(result, 0);
+ }
+ return result;
}
/*
@@ -1617,13 +1628,13 @@
}
if ('d' == currentConversionType) {
- NumberFormat numberFormat = getNumberFormat();
if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
+ NumberFormat numberFormat = getNumberFormat();
numberFormat.setGroupingUsed(true);
+ result.append(numberFormat.format(arg));
} else {
- numberFormat.setGroupingUsed(false);
+ result.append(value);
}
- result.append(numberFormat.format(arg));
} else {
long BYTE_MASK = 0x00000000000000FFL;
long SHORT_MASK = 0x000000000000FFFFL;
@@ -1659,9 +1670,7 @@
/* pad paddingChar to the output */
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
- result = wrapParentheses(result);
- return result;
-
+ return wrapParentheses(result);
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
startIndex++;
@@ -1669,35 +1678,14 @@
return padding(result, startIndex);
}
- /*
- * add () to the output,if the value is negative and
- * formatToken.FLAG_PARENTHESIS is set. 'result' is used as an in-out
- * parameter.
- */
- private StringBuilder wrapParentheses(StringBuilder result) {
- // delete the '-'
- result.deleteCharAt(0);
- result.insert(0, '(');
- if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
- formatToken.setWidth(formatToken.getWidth() - 1);
- padding(result, 1);
- result.append(')');
- } else {
- result.append(')');
- padding(result, 0);
- }
- return result;
- }
-
private CharSequence transformFromSpecialNumber() {
- String source = null;
-
if (!(arg instanceof Number) || arg instanceof BigDecimal) {
return null;
}
Number number = (Number) arg;
double d = number.doubleValue();
+ String source = null;
if (Double.isNaN(d)) {
source = "NaN"; //$NON-NLS-1$
} else if (Double.isInfinite(d)) {
@@ -1718,19 +1706,18 @@
}
}
- if (null != source) {
- formatToken.setPrecision(FormatToken.UNSET);
- formatToken.setFlags(formatToken.getFlags()
- & (~FormatToken.FLAG_ZERO));
- return padding(new StringBuilder(source), 0);
+ if (source == null) {
+ return null;
}
- return source;
+
+ formatToken.setPrecision(FormatToken.UNSET);
+ formatToken.setFlags(formatToken.getFlags() & (~FormatToken.FLAG_ZERO));
+ return padding(source, 0);
}
private CharSequence transformFromNull() {
- formatToken.setFlags(formatToken.getFlags()
- & (~FormatToken.FLAG_ZERO));
- return padding(new StringBuilder("null"), 0); //$NON-NLS-1$
+ formatToken.setFlags(formatToken.getFlags() & (~FormatToken.FLAG_ZERO));
+ return padding("null", 0); //$NON-NLS-1$
}
/*
@@ -1825,9 +1812,7 @@
/* pad paddingChar to the output */
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
- result = wrapParentheses(result);
- return result;
-
+ return wrapParentheses(result);
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
startIndex++;
@@ -1912,8 +1897,7 @@
if (getDecimalFormatSymbols().getMinusSign() == result.charAt(0)) {
if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
- result = wrapParentheses(result);
- return result;
+ return wrapParentheses(result);
}
} else {
if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
@@ -1943,7 +1927,6 @@
* Transforms a Date to a formatted string.
*/
private CharSequence transformFromDateTime() {
- int startIndex = 0;
char currentConversionType = formatToken.getConversionType();
if (formatToken.isPrecisionSet()) {
@@ -1989,7 +1972,7 @@
StringBuilder result = new StringBuilder();
// output result
dateTimeUtil.transform(formatToken, calendar, result);
- return padding(result, startIndex);
+ return padding(result, 0);
}
}
@@ -2067,7 +2050,7 @@
String formattedString = decimalFormat.format(argument);
result.append(formattedString.replace('E', 'e'));
- // if the flag is sharp and decimal seperator is always given
+ // if the flag is sharp and decimal separator is always given
// out.
if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
&& 0 == formatToken.getPrecision()) {
@@ -2166,7 +2149,7 @@
}
decimalFormat.applyPattern(pattern.toString());
result.append(decimalFormat.format(argument));
- // if the flag is sharp and decimal seperator is always given
+ // if the flag is sharp and decimal separator is always given
// out.
if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
&& 0 == formatToken.getPrecision()) {
@@ -2199,9 +2182,9 @@
int precision = formatToken.getPrecision();
precision = (0 == precision ? 1 : precision);
- int indexOfFirstFracitoanlDigit = result.indexOf(".") + 1; //$NON-NLS-1$
+ int indexOfFirstFractionalDigit = result.indexOf(".") + 1; //$NON-NLS-1$
int indexOfP = result.indexOf("p"); //$NON-NLS-1$
- int fractionalLength = indexOfP - indexOfFirstFracitoanlDigit;
+ int fractionalLength = indexOfP - indexOfFirstFractionalDigit;
if (fractionalLength == precision) {
return;
@@ -2213,7 +2196,7 @@
result.insert(indexOfP, zeros);
return;
}
- result.delete(indexOfFirstFracitoanlDigit + precision, indexOfP);
+ result.delete(indexOfFirstFractionalDigit + precision, indexOfP);
}
}
@@ -2566,6 +2549,7 @@
transform_Y();
}
+ // TODO: this doesn't need a temporary StringBuilder!
private static String paddingZeros(long number, int length) {
int len = length;
StringBuilder result = new StringBuilder();
@@ -2592,256 +2576,138 @@
}
}
- private static class ParserStateMachine {
+ private static class FormatSpecifierParser {
+ private char[] chars;
+ private int startIndex;
+ private int i;
- private static final char EOS = (char) -1;
-
- private static final int EXIT_STATE = 0;
-
- private static final int ENTRY_STATE = 1;
-
- private static final int START_CONVERSION_STATE = 2;
-
- private static final int FLAGS_STATE = 3;
-
- private static final int WIDTH_STATE = 4;
-
- private static final int PRECISION_STATE = 5;
-
- private static final int CONVERSION_TYPE_STATE = 6;
-
- private static final int SUFFIX_STATE = 7;
-
- private FormatToken token;
-
- private int state = ENTRY_STATE;
-
- private char currentChar = 0;
-
- private CharBuffer format = null;
-
- ParserStateMachine(CharBuffer format) {
- this.format = format;
- }
-
- void reset() {
- this.currentChar = (char) FormatToken.UNSET;
- this.state = ENTRY_STATE;
- this.token = null;
- }
-
- /*
- * Gets the information about the current format token. Information is
- * recorded in the FormatToken returned and the position of the stream
- * for the format string will be advanced till the next format token.
+ /**
+ * Returns a FormatToken representing the format specifier starting at 'offset' in 'chars'.
+ * @param offset the first character after the '%'
*/
- FormatToken getNextFormatToken() {
- token = new FormatToken();
- token.setFormatStringStartIndex(format.position());
-
- // FINITE AUTOMATIC MACHINE
- while (true) {
-
- if (ParserStateMachine.EXIT_STATE != state) {
- // exit state does not need to get next char
- currentChar = getNextFormatChar();
- if (EOS == currentChar
- && ParserStateMachine.ENTRY_STATE != state) {
- throw new UnknownFormatConversionException(
- getFormatString());
- }
- }
-
- switch (state) {
- // exit state
- case ParserStateMachine.EXIT_STATE: {
- process_EXIT_STATE();
- return token;
- }
- // plain text state, not yet applied converter
- case ParserStateMachine.ENTRY_STATE: {
- process_ENTRY_STATE();
- break;
- }
- // begins converted string
- case ParserStateMachine.START_CONVERSION_STATE: {
- process_START_CONVERSION_STATE();
- break;
- }
- case ParserStateMachine.FLAGS_STATE: {
- process_FlAGS_STATE();
- break;
- }
- case ParserStateMachine.WIDTH_STATE: {
- process_WIDTH_STATE();
- break;
- }
- case ParserStateMachine.PRECISION_STATE: {
- process_PRECISION_STATE();
- break;
- }
- case ParserStateMachine.CONVERSION_TYPE_STATE: {
- process_CONVERSION_TYPE_STATE();
- break;
- }
- case ParserStateMachine.SUFFIX_STATE: {
- process_SUFFIX_STATE();
- break;
- }
- }
- }
+ FormatToken parseFormatToken(char[] chars, int offset) {
+ this.chars = chars;
+ this.startIndex = offset;
+ this.i = offset;
+ return parseArgumentIndexAndFlags(new FormatToken());
}
- /*
- * Gets next char from the format string.
+ /**
+ * Returns a string corresponding to the last format specifier that was parsed.
+ * Used to construct error messages.
*/
- private char getNextFormatChar() {
- if (format.hasRemaining()) {
- return format.get();
+ String getFormatSpecifierText() {
+ return new String(chars, startIndex, i - startIndex);
+ }
+
+ private int peek() {
+ return (i < chars.length) ? chars[i] : -1;
+ }
+
+ private char advance() {
+ if (i >= chars.length) {
+ throw new UnknownFormatConversionException(getFormatSpecifierText());
}
- return EOS;
+ return chars[i++];
}
- private String getFormatString() {
- int end = format.position();
- format.rewind();
- String formatString = format.subSequence(
- token.getFormatStringStartIndex(), end).toString();
- format.position(end);
- return formatString;
- }
-
- private void process_ENTRY_STATE() {
- if (EOS == currentChar) {
- state = ParserStateMachine.EXIT_STATE;
- } else if ('%' == currentChar) {
- // change to conversion type state
- state = START_CONVERSION_STATE;
- }
- // else remains in ENTRY_STATE
- }
-
- private void process_START_CONVERSION_STATE() {
- if (Character.isDigit(currentChar)) {
- int position = format.position() - 1;
- int number = parseInt(format);
- char nextChar = 0;
- if (format.hasRemaining()) {
- nextChar = format.get();
- }
- if ('$' == nextChar) {
- // the digital sequence stands for the argument
- // index.
- int argIndex = number;
+ private FormatToken parseArgumentIndexAndFlags(FormatToken token) {
+ // Parse the argument index, if there is one.
+ int position = i;
+ int ch = peek();
+ if (Character.isDigit(ch)) {
+ int number = nextInt();
+ if (peek() == '$') {
+ // The number was an argument index.
+ advance(); // Swallow the '$'.
+ if (number == FormatToken.UNSET) {
+ throw new MissingFormatArgumentException(getFormatSpecifierText());
+ }
// k$ stands for the argument whose index is k-1 except that
- // 0$ and 1$ both stands for the first element.
- if (argIndex > 0) {
- token.setArgIndex(argIndex - 1);
- } else if (argIndex == FormatToken.UNSET) {
- throw new MissingFormatArgumentException(
- getFormatString());
- }
- state = FLAGS_STATE;
+ // 0$ and 1$ both stand for the first element.
+ token.setArgIndex(Math.max(0, number - 1));
} else {
- // the digital zero stands for one format flag.
- if ('0' == currentChar) {
- state = FLAGS_STATE;
- format.position(position);
+ if (ch == '0') {
+ // The digit zero is a format flag, so reparse it as such.
+ i = position;
} else {
- // the digital sequence stands for the width.
- state = WIDTH_STATE;
- // do not get the next char.
- format.position(format.position() - 1);
- token.setWidth(number);
+ // The number was a width. This means there are no flags to parse.
+ return parseWidth(token, number);
}
}
- currentChar = nextChar;
- } else if ('<' == currentChar) {
- state = FLAGS_STATE;
+ } else if (ch == '<') {
token.setArgIndex(FormatToken.LAST_ARGUMENT_INDEX);
- } else {
- state = FLAGS_STATE;
- // do not get the next char.
- format.position(format.position() - 1);
+ advance();
}
- }
+ // Parse the flags.
+ while (token.setFlag(peek())) {
+ advance();
+ }
- private void process_FlAGS_STATE() {
- if (token.setFlag(currentChar)) {
- // remains in FLAGS_STATE
- } else if (Character.isDigit(currentChar)) {
- token.setWidth(parseInt(format));
- state = WIDTH_STATE;
- } else if ('.' == currentChar) {
- state = PRECISION_STATE;
+ // What comes next?
+ ch = peek();
+ if (Character.isDigit(ch)) {
+ return parseWidth(token, nextInt());
+ } else if (ch == '.') {
+ return parsePrecision(token);
} else {
- state = CONVERSION_TYPE_STATE;
- // do not get the next char.
- format.position(format.position() - 1);
+ return parseConversionType(token);
}
}
- private void process_WIDTH_STATE() {
- if ('.' == currentChar) {
- state = PRECISION_STATE;
+ // We pass the width in because in some cases we've already parsed it.
+ // (Because of the ambiguity between argument indexes and widths.)
+ private FormatToken parseWidth(FormatToken token, int width) {
+ token.setWidth(width);
+ int ch = peek();
+ if (ch == '.') {
+ return parsePrecision(token);
} else {
- state = CONVERSION_TYPE_STATE;
- // do not get the next char.
- format.position(format.position() - 1);
+ return parseConversionType(token);
}
}
- private void process_PRECISION_STATE() {
- if (Character.isDigit(currentChar)) {
- token.setPrecision(parseInt(format));
+ private FormatToken parsePrecision(FormatToken token) {
+ advance(); // Swallow the '.'.
+ int ch = peek();
+ if (Character.isDigit(ch)) {
+ token.setPrecision(nextInt());
+ return parseConversionType(token);
} else {
- // the precision is required but not given by the
- // format string.
- throw new UnknownFormatConversionException(getFormatString());
+ // The precision is required but not given by the format string.
+ throw new UnknownFormatConversionException(getFormatSpecifierText());
}
- state = CONVERSION_TYPE_STATE;
}
- private void process_CONVERSION_TYPE_STATE() {
- token.setConversionType(currentChar);
- if ('t' == currentChar || 'T' == currentChar) {
- state = SUFFIX_STATE;
- } else {
- state = EXIT_STATE;
+ private FormatToken parseConversionType(FormatToken token) {
+ char ch = advance(); // This is mandatory, so no need to peek.
+ token.setConversionType(ch);
+ if (ch == 't' || ch == 'T') {
+ token.setDateSuffix(advance());
}
-
+ return token;
}
- private void process_SUFFIX_STATE() {
- token.setDateSuffix(currentChar);
- state = EXIT_STATE;
- }
-
- private void process_EXIT_STATE() {
- token.setPlainText(getFormatString());
- }
-
- /*
- * Parses integer value from the given buffer
- */
- private int parseInt(CharBuffer buffer) {
- int start = buffer.position() - 1;
- int end = buffer.limit();
- while (buffer.hasRemaining()) {
- if (!Character.isDigit(buffer.get())) {
- end = buffer.position() - 1;
- break;
+ // Parses an integer (of arbitrary length, but typically just one digit).
+ private int nextInt() {
+ int length = chars.length;
+ long value = 0;
+ while (i < length && Character.isDigit(chars[i])) {
+ value = 10 * value + (chars[i++] - '0');
+ if (value > Integer.MAX_VALUE) {
+ return failNextInt();
}
}
- buffer.position(0);
- String intStr = buffer.subSequence(start, end).toString();
- buffer.position(end);
- try {
- return Integer.parseInt(intStr);
- } catch (NumberFormatException e) {
- return FormatToken.UNSET;
+ return (int) value;
+ }
+
+ // Swallow remaining digits to resync our attempted parse, but return failure.
+ private int failNextInt() {
+ while (Character.isDigit(peek())) {
+ advance();
}
+ return FormatToken.UNSET;
}
}
}
diff --git a/libcore/nio/src/main/java/java/nio/CharBuffer.java b/libcore/nio/src/main/java/java/nio/CharBuffer.java
index 4506614..ea31234 100644
--- a/libcore/nio/src/main/java/java/nio/CharBuffer.java
+++ b/libcore/nio/src/main/java/java/nio/CharBuffer.java
@@ -707,11 +707,11 @@
*/
@Override
public String toString() {
- StringBuffer strbuf = new StringBuffer();
+ StringBuilder result = new StringBuilder(limit - position);
for (int i = position; i < limit; i++) {
- strbuf.append(get(i));
+ result.append(get(i));
}
- return strbuf.toString();
+ return result.toString();
}
/**
diff --git a/vm/Thread.c b/vm/Thread.c
index 71f6324..67683b5 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -2563,15 +2563,17 @@
#endif
/*
- * Sleep briefly. This returns false if we've exceeded the total
- * time limit for this round of sleeping.
+ * Sleep briefly. The iterative sleep call returns false if we've
+ * exceeded the total time limit for this round of sleeping.
*/
if (!dvmIterativeSleep(sleepIter++, spinSleepTime, startWhen)) {
- LOGW("threadid=%d: spin on suspend #%d threadid=%d (h=%d)\n",
- self->threadId, retryCount,
- thread->threadId, (int)thread->handle);
- dumpWedgedThread(thread);
- complained = true;
+ if (spinSleepTime != FIRST_SLEEP) {
+ LOGW("threadid=%d: spin on suspend #%d threadid=%d (h=%d)\n",
+ self->threadId, retryCount,
+ thread->threadId, (int)thread->handle);
+ dumpWedgedThread(thread);
+ complained = true;
+ }
// keep going; could be slow due to valgrind
sleepIter = 0;
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
index 8d31807..f768cc0 100644
--- a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S
@@ -50,6 +50,7 @@
str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
cmp r1, #0 @ null?
str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+ ldr r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
bne .LhandleException @ no, handle exception
bx r2
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
index 00385a5..80a9dd8 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te-vfp.S
@@ -440,6 +440,7 @@
str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
cmp r1, #0 @ null?
str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+ ldr r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
bne .LhandleException @ no, handle exception
bx r2
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
index f452787..a83344a 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -440,6 +440,7 @@
str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
cmp r1, #0 @ null?
str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+ ldr r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
bne .LhandleException @ no, handle exception
bx r2
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
index cfc50fa..cb47011 100644
--- a/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a.S
@@ -440,6 +440,7 @@
str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
cmp r1, #0 @ null?
str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+ ldr r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
bne .LhandleException @ no, handle exception
bx r2