--- old/src/share/classes/java/lang/StringBuffer.java 2013-05-13 03:10:19.011644766 -0400 +++ new/src/share/classes/java/lang/StringBuffer.java 2013-05-13 03:10:17.739572328 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package java.lang; +import java.util.Arrays; /** * A thread-safe, mutable sequence of characters. @@ -102,6 +103,23 @@ static final long serialVersionUID = 3388685877147921107L; /** + * Tracks if our char[] has been shared with a String returned + * from toString(). We implement a copy-on-write-if-shared scheme + * so that we can avoid an array-copy on toString. Each mutating + * operation copies the char[] if it is being shared. + */ + private transient boolean isShared = false; + + /** + * Performs the copy-on-write-if-shared update + */ + private void COWIS() { + if (isShared) { + value = Arrays.copyOf(value, value.length); + isShared = false; + } + } + /** * Constructs a string buffer with no characters in it and an * initial capacity of 16 characters. */ @@ -166,6 +184,7 @@ public synchronized void ensureCapacity(int minimumCapacity) { if (minimumCapacity > value.length) { expandCapacity(minimumCapacity); + isShared = false; } } @@ -174,7 +193,11 @@ */ @Override public synchronized void trimToSize() { + char[] old = value; super.trimToSize(); + if (old != value) { + isShared = false; + } } /** @@ -183,6 +206,7 @@ */ @Override public synchronized void setLength(int newLength) { + COWIS(); super.setLength(newLength); } @@ -247,17 +271,20 @@ public synchronized void setCharAt(int index, char ch) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); + COWIS(); value[index] = ch; } @Override public synchronized StringBuffer append(Object obj) { + COWIS(); super.append(String.valueOf(obj)); return this; } @Override public synchronized StringBuffer append(String str) { + COWIS(); super.append(str); return this; } @@ -287,6 +314,7 @@ * @since 1.4 */ public synchronized StringBuffer append(StringBuffer sb) { + COWIS(); super.append(sb); return this; } @@ -296,6 +324,7 @@ */ @Override synchronized StringBuffer append(AbstractStringBuilder asb) { + COWIS(); super.append(asb); return this; } @@ -325,6 +354,7 @@ public StringBuffer append(CharSequence s) { // Note, synchronization achieved via invocations of other StringBuffer methods after // narrowing of s to specific type + // Ditto for COWIS super.append(s); return this; } @@ -336,12 +366,14 @@ @Override public synchronized StringBuffer append(CharSequence s, int start, int end) { + COWIS(); super.append(s, start, end); return this; } @Override public synchronized StringBuffer append(char[] str) { + COWIS(); super.append(str); return this; } @@ -351,24 +383,28 @@ */ @Override public synchronized StringBuffer append(char[] str, int offset, int len) { + COWIS(); super.append(str, offset, len); return this; } @Override public synchronized StringBuffer append(boolean b) { + COWIS(); super.append(b); return this; } @Override public synchronized StringBuffer append(char c) { + COWIS(); super.append(c); return this; } @Override public synchronized StringBuffer append(int i) { + COWIS(); super.append(i); return this; } @@ -378,24 +414,28 @@ */ @Override public synchronized StringBuffer appendCodePoint(int codePoint) { + COWIS(); super.appendCodePoint(codePoint); return this; } @Override public synchronized StringBuffer append(long lng) { + COWIS(); super.append(lng); return this; } @Override public synchronized StringBuffer append(float f) { + COWIS(); super.append(f); return this; } @Override public synchronized StringBuffer append(double d) { + COWIS(); super.append(d); return this; } @@ -406,6 +446,7 @@ */ @Override public synchronized StringBuffer delete(int start, int end) { + COWIS(); super.delete(start, end); return this; } @@ -416,6 +457,7 @@ */ @Override public synchronized StringBuffer deleteCharAt(int index) { + COWIS(); super.deleteCharAt(index); return this; } @@ -426,6 +468,7 @@ */ @Override public synchronized StringBuffer replace(int start, int end, String str) { + COWIS(); super.replace(start, end, str); return this; } @@ -465,6 +508,7 @@ public synchronized StringBuffer insert(int index, char[] str, int offset, int len) { + COWIS(); super.insert(index, str, offset, len); return this; } @@ -474,6 +518,7 @@ */ @Override public synchronized StringBuffer insert(int offset, Object obj) { + COWIS(); super.insert(offset, String.valueOf(obj)); return this; } @@ -483,6 +528,7 @@ */ @Override public synchronized StringBuffer insert(int offset, String str) { + COWIS(); super.insert(offset, str); return this; } @@ -492,6 +538,7 @@ */ @Override public synchronized StringBuffer insert(int offset, char[] str) { + COWIS(); super.insert(offset, str); return this; } @@ -504,6 +551,7 @@ public StringBuffer insert(int dstOffset, CharSequence s) { // Note, synchronization achieved via invocations of other StringBuffer methods // after narrowing of s to specific type + // Ditto for COWIS super.insert(dstOffset, s); return this; } @@ -516,6 +564,7 @@ public synchronized StringBuffer insert(int dstOffset, CharSequence s, int start, int end) { + COWIS(); super.insert(dstOffset, s, start, end); return this; } @@ -527,6 +576,7 @@ public StringBuffer insert(int offset, boolean b) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of b to String by super class method + // Ditto for COWIS super.insert(offset, b); return this; } @@ -536,6 +586,7 @@ */ @Override public synchronized StringBuffer insert(int offset, char c) { + COWIS(); super.insert(offset, c); return this; } @@ -547,6 +598,7 @@ public StringBuffer insert(int offset, int i) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of i to String by super class method + // Ditto for COWIS super.insert(offset, i); return this; } @@ -558,6 +610,7 @@ public StringBuffer insert(int offset, long l) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of l to String by super class method + // Ditto for COWIS super.insert(offset, l); return this; } @@ -569,6 +622,7 @@ public StringBuffer insert(int offset, float f) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of f to String by super class method + // Ditto for COWIS super.insert(offset, f); return this; } @@ -580,6 +634,7 @@ public StringBuffer insert(int offset, double d) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of d to String by super class method + // Ditto for COWIS super.insert(offset, d); return this; } @@ -623,13 +678,15 @@ */ @Override public synchronized StringBuffer reverse() { + COWIS(); super.reverse(); return this; } @Override public synchronized String toString() { - return new String(value, 0, count); + isShared = true; + return new String(value, true); } /** @@ -672,5 +729,6 @@ java.io.ObjectInputStream.GetField fields = s.readFields(); value = (char[])fields.get("value", null); count = fields.get("count", 0); + isShared = false; } }