提交 e52476e7 编写于 作者: R redestad

8224202: Speed up Properties.load

Reviewed-by: rriggs, igerasim
上级 6b125420
...@@ -404,17 +404,15 @@ class Properties extends Hashtable<Object,Object> { ...@@ -404,17 +404,15 @@ class Properties extends Hashtable<Object,Object> {
load0(new LineReader(inStream)); load0(new LineReader(inStream));
} }
private void load0 (LineReader lr) throws IOException { private void load0(LineReader lr) throws IOException {
char[] convtBuf = new char[1024]; StringBuilder outBuffer = new StringBuilder();
int limit; int limit;
int keyLen; int keyLen;
int valueStart; int valueStart;
char c;
boolean hasSep; boolean hasSep;
boolean precedingBackslash; boolean precedingBackslash;
while ((limit = lr.readLine()) >= 0) { while ((limit = lr.readLine()) >= 0) {
c = 0;
keyLen = 0; keyLen = 0;
valueStart = limit; valueStart = limit;
hasSep = false; hasSep = false;
...@@ -422,7 +420,7 @@ class Properties extends Hashtable<Object,Object> { ...@@ -422,7 +420,7 @@ class Properties extends Hashtable<Object,Object> {
//System.out.println("line=<" + new String(lineBuf, 0, limit) + ">"); //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
precedingBackslash = false; precedingBackslash = false;
while (keyLen < limit) { while (keyLen < limit) {
c = lr.lineBuf[keyLen]; char c = lr.lineBuf[keyLen];
//need check if escaped. //need check if escaped.
if ((c == '=' || c == ':') && !precedingBackslash) { if ((c == '=' || c == ':') && !precedingBackslash) {
valueStart = keyLen + 1; valueStart = keyLen + 1;
...@@ -440,7 +438,7 @@ class Properties extends Hashtable<Object,Object> { ...@@ -440,7 +438,7 @@ class Properties extends Hashtable<Object,Object> {
keyLen++; keyLen++;
} }
while (valueStart < limit) { while (valueStart < limit) {
c = lr.lineBuf[valueStart]; char c = lr.lineBuf[valueStart];
if (c != ' ' && c != '\t' && c != '\f') { if (c != ' ' && c != '\t' && c != '\f') {
if (!hasSep && (c == '=' || c == ':')) { if (!hasSep && (c == '=' || c == ':')) {
hasSep = true; hasSep = true;
...@@ -450,8 +448,8 @@ class Properties extends Hashtable<Object,Object> { ...@@ -450,8 +448,8 @@ class Properties extends Hashtable<Object,Object> {
} }
valueStart++; valueStart++;
} }
String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf); String key = loadConvert(lr.lineBuf, 0, keyLen, outBuffer);
String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf); String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, outBuffer);
put(key, value); put(key, value);
} }
} }
...@@ -462,64 +460,56 @@ class Properties extends Hashtable<Object,Object> { ...@@ -462,64 +460,56 @@ class Properties extends Hashtable<Object,Object> {
* Method returns the char length of the "logical line" and stores * Method returns the char length of the "logical line" and stores
* the line in "lineBuf". * the line in "lineBuf".
*/ */
class LineReader { private static class LineReader {
public LineReader(InputStream inStream) { LineReader(InputStream inStream) {
this.inStream = inStream; this.inStream = inStream;
inByteBuf = new byte[8192]; inByteBuf = new byte[8192];
} }
public LineReader(Reader reader) { LineReader(Reader reader) {
this.reader = reader; this.reader = reader;
inCharBuf = new char[8192]; inCharBuf = new char[8192];
} }
byte[] inByteBuf;
char[] inCharBuf;
char[] lineBuf = new char[1024]; char[] lineBuf = new char[1024];
int inLimit = 0; private byte[] inByteBuf;
int inOff = 0; private char[] inCharBuf;
InputStream inStream; private int inLimit = 0;
Reader reader; private int inOff = 0;
private InputStream inStream;
private Reader reader;
int readLine() throws IOException { int readLine() throws IOException {
// use locals to optimize for interpreted performance
int len = 0; int len = 0;
char c = 0; int off = inOff;
int limit = inLimit;
boolean skipWhiteSpace = true; boolean skipWhiteSpace = true;
boolean isCommentLine = false;
boolean isNewLine = true;
boolean appendedLineBegin = false; boolean appendedLineBegin = false;
boolean precedingBackslash = false; boolean precedingBackslash = false;
boolean skipLF = false; boolean fromStream = inStream != null;
byte[] byteBuf = inByteBuf;
char[] charBuf = inCharBuf;
char[] lineBuf = this.lineBuf;
char c;
while (true) { while (true) {
if (inOff >= inLimit) { if (off >= limit) {
inLimit = (inStream==null)?reader.read(inCharBuf) inLimit = limit = fromStream ? inStream.read(byteBuf)
:inStream.read(inByteBuf); : reader.read(charBuf);
inOff = 0; if (limit <= 0) {
if (inLimit <= 0) { if (len == 0) {
if (len == 0 || isCommentLine) {
return -1; return -1;
} }
if (precedingBackslash) { return precedingBackslash ? len - 1 : len;
len--;
}
return len;
}
}
if (inStream != null) {
//The line below is equivalent to calling a
//ISO8859-1 decoder.
c = (char)(inByteBuf[inOff++] & 0xFF);
} else {
c = inCharBuf[inOff++];
}
if (skipLF) {
skipLF = false;
if (c == '\n') {
continue;
} }
off = 0;
} }
// (char)(byte & 0xFF) is equivalent to calling a ISO8859-1 decoder.
c = (fromStream) ? (char)(byteBuf[off++] & 0xFF) : charBuf[off++];
if (skipWhiteSpace) { if (skipWhiteSpace) {
if (c == ' ' || c == '\t' || c == '\f') { if (c == ' ' || c == '\t' || c == '\f') {
continue; continue;
...@@ -529,81 +519,106 @@ class Properties extends Hashtable<Object,Object> { ...@@ -529,81 +519,106 @@ class Properties extends Hashtable<Object,Object> {
} }
skipWhiteSpace = false; skipWhiteSpace = false;
appendedLineBegin = false; appendedLineBegin = false;
} }
if (isNewLine) { if (len == 0) { // Still on a new logical line
isNewLine = false;
if (c == '#' || c == '!') { if (c == '#' || c == '!') {
// Comment, quickly consume the rest of the line, // Comment, quickly consume the rest of the line
// resume on line-break and backslash.
if (inStream != null) { // When checking for new line characters a range check,
while (inOff < inLimit) { // starting with the higher bound ('\r') means one less
byte b = inByteBuf[inOff++]; // branch in the common case.
if (b == '\n' || b == '\r' || b == '\\') { commentLoop: while (true) {
c = (char)(b & 0xFF); if (fromStream) {
break; byte b;
while (off < limit) {
b = byteBuf[off++];
if (b <= '\r' && (b == '\r' || b == '\n'))
break commentLoop;
} }
} if (off == limit) {
} else { inLimit = limit = inStream.read(byteBuf);
while (inOff < inLimit) { if (limit <= 0) { // EOF
c = inCharBuf[inOff++]; return -1;
if (c == '\n' || c == '\r' || c == '\\') { }
break; off = 0;
}
} else {
while (off < limit) {
c = charBuf[off++];
if (c <= '\r' && (c == '\r' || c == '\n'))
break commentLoop;
}
if (off == limit) {
inLimit = limit = reader.read(charBuf);
if (limit <= 0) { // EOF
return -1;
}
off = 0;
} }
} }
} }
isCommentLine = true; skipWhiteSpace = true;
continue;
} }
} }
if (c != '\n' && c != '\r') { if (c != '\n' && c != '\r') {
lineBuf[len++] = c; lineBuf[len++] = c;
if (len == lineBuf.length) { if (len == lineBuf.length) {
int newLength = lineBuf.length * 2; int maxLen = Integer.MAX_VALUE - 8; // VM allocation limit
if (newLength < 0) { int newLen = len * 2;
newLength = Integer.MAX_VALUE; if (newLen < 0 || newLen > maxLen) { // check for under/overflow
newLen = maxLen;
} }
char[] buf = new char[newLength]; if (newLen <= len) { // still not good? last-ditch attempt then
System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length); if (len != Integer.MAX_VALUE) {
lineBuf = buf; newLen = len + 1;
} } else {
//flip the preceding backslash flag throw new OutOfMemoryError("Required array length too large");
if (c == '\\') { }
precedingBackslash = !precedingBackslash; }
} else { lineBuf = new char[newLen];
precedingBackslash = false; System.arraycopy(this.lineBuf, 0, lineBuf, 0, len);
this.lineBuf = lineBuf;
} }
} // flip the preceding backslash flag
else { precedingBackslash = (c == '\\') ? !precedingBackslash : false;
} else {
// reached EOL // reached EOL
if (isCommentLine || len == 0) { if (len == 0) {
isCommentLine = false;
isNewLine = true;
skipWhiteSpace = true; skipWhiteSpace = true;
len = 0;
continue; continue;
} }
if (inOff >= inLimit) { if (off >= limit) {
inLimit = (inStream==null) inLimit = limit = fromStream ? inStream.read(byteBuf)
?reader.read(inCharBuf) : reader.read(charBuf);
:inStream.read(inByteBuf); off = 0;
inOff = 0; if (limit <= 0) { // EOF
if (inLimit <= 0) { return precedingBackslash ? len - 1 : len;
if (precedingBackslash) {
len--;
}
return len;
} }
} }
if (precedingBackslash) { if (precedingBackslash) {
// backslash at EOL is not part of the line
len -= 1; len -= 1;
//skip the leading whitespace characters in following line // skip leading whitespace characters in the following line
skipWhiteSpace = true; skipWhiteSpace = true;
appendedLineBegin = true; appendedLineBegin = true;
precedingBackslash = false; precedingBackslash = false;
// take care not to include any subsequent \n
if (c == '\r') { if (c == '\r') {
skipLF = true; if (fromStream) {
if (byteBuf[off] == '\n') {
off++;
}
} else {
if (charBuf[off] == '\n') {
off++;
}
}
} }
} else { } else {
inOff = off;
return len; return len;
} }
} }
...@@ -615,18 +630,24 @@ class Properties extends Hashtable<Object,Object> { ...@@ -615,18 +630,24 @@ class Properties extends Hashtable<Object,Object> {
* Converts encoded &#92;uxxxx to unicode chars * Converts encoded &#92;uxxxx to unicode chars
* and changes special saved chars to their original forms * and changes special saved chars to their original forms
*/ */
private String loadConvert (char[] in, int off, int len, char[] convtBuf) { private String loadConvert(char[] in, int off, int len, StringBuilder out) {
if (convtBuf.length < len) {
int newLen = len * 2;
if (newLen < 0) {
newLen = Integer.MAX_VALUE;
}
convtBuf = new char[newLen];
}
char aChar; char aChar;
char[] out = convtBuf;
int outLen = 0;
int end = off + len; int end = off + len;
int start = off;
while (off < end) {
aChar = in[off++];
if (aChar == '\\') {
break;
}
}
if (off == end) { // No backslash
return new String(in, start, len);
}
// backslash found at off - 1, reset the shared buffer, rewind offset
out.setLength(0);
off--;
out.append(in, start, off - start);
while (off < end) { while (off < end) {
aChar = in[off++]; aChar = in[off++];
...@@ -654,20 +675,20 @@ class Properties extends Hashtable<Object,Object> { ...@@ -654,20 +675,20 @@ class Properties extends Hashtable<Object,Object> {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Malformed \\uxxxx encoding."); "Malformed \\uxxxx encoding.");
} }
} }
out[outLen++] = (char)value; out.append((char)value);
} else { } else {
if (aChar == 't') aChar = '\t'; if (aChar == 't') aChar = '\t';
else if (aChar == 'r') aChar = '\r'; else if (aChar == 'r') aChar = '\r';
else if (aChar == 'n') aChar = '\n'; else if (aChar == 'n') aChar = '\n';
else if (aChar == 'f') aChar = '\f'; else if (aChar == 'f') aChar = '\f';
out[outLen++] = aChar; out.append(aChar);
} }
} else { } else {
out[outLen++] = aChar; out.append(aChar);
} }
} }
return new String (out, 0, outLen); return out.toString();
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册