Forwarding for correct core-libs-dev list. -Chris.
On 31 Jan 2014, at 15:26, Robert Stupp <sn...@gmx.de> wrote: > Hi Chris, > > fine. I'm a bit proud that my 5ct help to improve JDK9 :) > > The primitive buffer array size rounding was there to reduce the number of > re-allocations when a class requires a slightly bigger primitive buffer than > another. Maybe we can introduce some minimum buffer size - e.g. 64 or 128 > bytes? This should be enough for most classes. Classes that require a bigger > buffer will always force an extend of the buffer - rounded or not. > > Robert > > > Gesendet: Freitag, 31. Januar 2014 um 15:22 Uhr > Von: "Chris Hegarty" <chris.hega...@oracle.com> > An: "Robert Stupp" <sn...@gmx.de>, core-libs-dev-request > <core-libs-dev-requ...@openjdk.java.net> > Betreff: Re: Aw: Re: ObjectIn/OutputStream improvements > Hi Robert, > > I think your patch can be split into two logical, independent, parts. > The first is the use of unsafe to access the String UTF length. The > seconds is to reuse, where possible, the existing StringBuilder > instances, skipping of primitive/object reading/writing where > applicable, and general cleanup. > > Since this is a very sensitive area I would like to consider these > separately. To that end, I have taken the changes that are applicable to > the latter, removed any subjective stylistic changes, and made some > additional cleanup improvements. > > http://cr.openjdk.java.net/~chegar/serial_stupp.00/webrev/ > > Specifically, > * I think for clarify and readability SerialCallbackContext > checkAndSetUsed() should be invoked directly. It makes it very > clear what the intent is. > * Skip primitive/object reading/writing if no primitives/objects in > the stream/class. ( I personally don't see any benefit of rounding > up the size of the array, it just seems to add unnecessary > complexity ) > * Move primitive types into getPrimitiveSignature for better reuse > of code. This retains your change to not create the additional > StringBuilder when it is not necessary. > > I am currently running tests on this change. > > -Chris. > > On 07/01/14 13:03, Robert Stupp wrote: > > Hi, > > I've attached the diff to the original email - it has been stripped. > > Here's a second try (inline). > > I've already signed the OCA and it has been approved :) > > Robert > > # HG changeset patch > > # User snazy > > # Date 1387101091 -3600 > > # Sun Dec 15 10:51:31 2013 +0100 > > # Node ID 6d46d99212453017c88417678d08dc8f10da9606 > > # Parent 9e1be800420265e5dcf264a7ed4abb6f230dd19d > > Removed some unnecessary variable assignments. > > ObjectInputStream: > > - skip primitive/object reading if no primitive/objects in class > > - use shared StringBuilder for string reading (prevent superfluous > > object allocations) > > ObjectOutputStream: > > - skip primitive/object writing if no primitive/objects in class > > - use unsafe access to calculate UTF-length > > - use unsafe access in readBytes() and writeChars() methods to access > > String value field > > - removed cbuf field > > ObjectStreamClass/ObjectStreamField: > > - minor improvement in getClassSignature ; share method code with > > ObjectStreamField > > diff --git a/src/share/classes/java/io/ObjectInputStream.java > > b/src/share/classes/java/io/ObjectInputStream.java > > --- a/src/share/classes/java/io/ObjectInputStream.java > > +++ b/src/share/classes/java/io/ObjectInputStream.java > > @@ -39,8 +39,8 @@ > > import java.util.HashMap; > > import java.util.concurrent.ConcurrentHashMap; > > import java.util.concurrent.ConcurrentMap; > > -import java.util.concurrent.atomic.AtomicBoolean; > > import static java.io.ObjectStreamClass.processQueue; > > + > > import sun.reflect.misc.ReflectUtil; > > > > /** > > @@ -534,7 +534,7 @@ > > if (ctx == null) { > > throw new NotActiveException("not in call to readObject"); > > } > > - Object curObj = ctx.getObj(); > > + ctx.getObj(); > > ObjectStreamClass curDesc = ctx.getDesc(); > > bin.setBlockDataMode(false); > > GetFieldImpl getField = new GetFieldImpl(curDesc); > > @@ -1597,7 +1597,7 @@ > > int descHandle = handles.assign(unshared ? unsharedMarker : desc); > > passHandle = NULL_HANDLE; > > > > - ObjectStreamClass readDesc = null; > > + ObjectStreamClass readDesc; > > try { > > readDesc = readClassDescriptor(); > > } catch (ClassNotFoundException ex) { > > @@ -1976,29 +1976,34 @@ > > } > > > > int primDataSize = desc.getPrimDataSize(); > > - if (primVals == null || primVals.length < primDataSize) { > > - primVals = new byte[primDataSize]; > > - } > > - bin.readFully(primVals, 0, primDataSize, false); > > - if (obj != null) { > > - desc.setPrimFieldValues(obj, primVals); > > - } > > - > > - int objHandle = passHandle; > > - ObjectStreamField[] fields = desc.getFields(false); > > - Object[] objVals = new Object[desc.getNumObjFields()]; > > - int numPrimFields = fields.length - objVals.length; > > - for (int i = 0; i < objVals.length; i++) { > > - ObjectStreamField f = fields[numPrimFields + i]; > > - objVals[i] = readObject0(f.isUnshared()); > > - if (f.getField() != null) { > > - handles.markDependency(objHandle, passHandle); > > + if (primDataSize > 0) { > > + if (primVals == null || primVals.length < primDataSize) { > > + primVals = new byte[ ((primDataSize>>4)+1)<<4 ]; > > + } > > + bin.readFully(primVals, 0, primDataSize, false); > > + if (obj != null) { > > + desc.setPrimFieldValues(obj, primVals); > > } > > } > > - if (obj != null) { > > - desc.setObjFieldValues(obj, objVals); > > + > > + int numObjFields = desc.getNumObjFields(); > > + if (numObjFields > 0) { > > + int objHandle = passHandle; > > + ObjectStreamField[] fields = desc.getFields(false); > > + Object[] objVals = new Object[numObjFields]; > > + int numPrimFields = fields.length - objVals.length; > > + for (int i = 0; i < objVals.length; i++) { > > + ObjectStreamField f = fields[numPrimFields + i]; > > + objVals[i] = readObject0(f.isUnshared()); > > + if (f.getField() != null) { > > + handles.markDependency(objHandle, passHandle); > > + } > > + } > > + if (obj != null) { > > + desc.setObjFieldValues(obj, objVals); > > + } > > + passHandle = objHandle; > > } > > - passHandle = objHandle; > > } > > > > /** > > @@ -2377,8 +2382,10 @@ > > private final byte[] buf = new byte[MAX_BLOCK_SIZE]; > > /** buffer for reading block data headers */ > > private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; > > - /** char buffer for fast string reads */ > > + /** char buffer for fast string reads - used by {@link > > #readUTFSpan(long)} */ > > private final char[] cbuf = new char[CHAR_BUF_SIZE]; > > + /** shared string builder for less object allocations - used by > > {@link #readUTFBody(long)}, {@link #readUTFChar(long)} and {@link > > #readUTFSpan(long)} */ > > + private final StringBuilder sbuf = new > > StringBuilder(CHAR_BUF_SIZE); > > > > /** block data mode */ > > private boolean blkmode = false; > > @@ -3044,19 +3051,19 @@ > > * utflen bytes. > > */ > > private String readUTFBody(long utflen) throws IOException { > > - StringBuilder sbuf = new StringBuilder(); > > if (!blkmode) { > > end = pos = 0; > > } > > > > + sbuf.setLength(0); > > while (utflen > 0) { > > int avail = end - pos; > > if (avail >= 3 || (long) avail == utflen) { > > - utflen -= readUTFSpan(sbuf, utflen); > > + utflen -= readUTFSpan(utflen); > > } else { > > if (blkmode) { > > // near block boundary, read one byte at a time > > - utflen -= readUTFChar(sbuf, utflen); > > + utflen -= readUTFChar(utflen); > > } else { > > // shift and refill buffer manually > > if (avail > 0) { > > @@ -3076,10 +3083,10 @@ > > * Reads span of UTF-encoded characters out of internal buffer > > * (starting at offset pos and ending at or before offset end), > > * consuming no more than utflen bytes. Appends read > > characters to > > - * sbuf. Returns the number of bytes consumed. > > + * {@link #sbuf}. Returns the number of bytes consumed. > > */ > > - private long readUTFSpan(StringBuilder sbuf, long utflen) > > - throws IOException > > + private long readUTFSpan(long utflen) > > + throws IOException > > { > > int cpos = 0; > > int start = pos; > > @@ -3111,19 +3118,19 @@ > > throw new UTFDataFormatException(); > > } > > cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | > > - ((b2 & 0x3F) << 0)); > > + (b2 & 0x3F)); > > break; > > > > case 14: // 3 byte format: 1110xxxx 10xxxxxx > > 10xxxxxx > > b3 = buf[pos + 1]; > > - b2 = buf[pos + 0]; > > + b2 = buf[pos ]; > > pos += 2; > > if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != > > 0x80) { > > throw new UTFDataFormatException(); > > } > > cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) | > > - ((b2 & 0x3F) << 6) | > > - ((b3 & 0x3F) << 0)); > > + ((b2 & 0x3F) << 6) | > > + (b3 & 0x3F)); > > break; > > > > default: // 10xx xxxx, 1111 xxxx > > @@ -3150,12 +3157,12 @@ > > > > /** > > * Reads in single UTF-encoded character one byte at a time, > > appends > > - * the character to sbuf, and returns the number of bytes consumed. > > + * the character to {@link #sbuf}, and returns the number of > > bytes consumed. > > * This method is used when reading in UTF strings written in > > block > > * data mode to handle UTF-encoded characters which (potentially) > > * straddle block-data boundaries. > > */ > > - private int readUTFChar(StringBuilder sbuf, long utflen) > > + private int readUTFChar(long utflen) > > throws IOException > > { > > int b1, b2, b3; > > @@ -3181,8 +3188,7 @@ > > if ((b2 & 0xC0) != 0x80) { > > throw new UTFDataFormatException(); > > } > > - sbuf.append((char) (((b1 & 0x1F) << 6) | > > - ((b2 & 0x3F) << 0))); > > + sbuf.append((char) (((b1 & 0x1F) << 6) | (b2 & 0x3F))); > > return 2; > > > > case 14: // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx > > @@ -3198,8 +3204,8 @@ > > throw new UTFDataFormatException(); > > } > > sbuf.append((char) (((b1 & 0x0F) << 12) | > > - ((b2 & 0x3F) << 6) | > > - ((b3 & 0x3F) << 0))); > > + ((b2 & 0x3F) << 6) | > > + (b3 & 0x3F))); > > return 3; > > > > default: // 10xx xxxx, 1111 xxxx > > diff --git a/src/share/classes/java/io/ObjectOutputStream.java > > b/src/share/classes/java/io/ObjectOutputStream.java > > --- a/src/share/classes/java/io/ObjectOutputStream.java > > +++ b/src/share/classes/java/io/ObjectOutputStream.java > > @@ -35,7 +35,8 @@ > > import java.util.concurrent.ConcurrentHashMap; > > import java.util.concurrent.ConcurrentMap; > > import static java.io.ObjectStreamClass.processQueue; > > -import java.io.SerialCallbackContext; > > + > > +import sun.misc.Unsafe; > > import sun.reflect.misc.ReflectUtil; > > > > /** > > @@ -458,7 +459,7 @@ > > if (ctx == null) { > > throw new NotActiveException("not in call to > > writeObject"); > > } > > - Object curObj = ctx.getObj(); > > + ctx.getObj(); > > ObjectStreamClass curDesc = ctx.getDesc(); > > curPut = new PutFieldImpl(curDesc); > > } > > @@ -1300,7 +1301,7 @@ > > */ > > private void writeString(String str, boolean unshared) throws > > IOException { > > handles.assign(unshared ? null : str); > > - long utflen = bout.getUTFLength(str); > > + long utflen = BlockDataOutputStream.getUTFLength(str); > > if (utflen <= 0xFFFF) { > > bout.writeByte(TC_STRING); > > bout.writeUTF(str, utflen); > > @@ -1527,29 +1528,34 @@ > > desc.checkDefaultSerialize(); > > > > int primDataSize = desc.getPrimDataSize(); > > - if (primVals == null || primVals.length < primDataSize) { > > - primVals = new byte[primDataSize]; > > + if (primDataSize > 0) { > > + if (primVals == null || primVals.length < primDataSize) { > > + primVals = new byte[ ((primDataSize>>4)+1)<<4 ]; > > + } > > + desc.getPrimFieldValues(obj, primVals); > > + bout.write(primVals, 0, primDataSize, false); > > } > > - desc.getPrimFieldValues(obj, primVals); > > - bout.write(primVals, 0, primDataSize, false); > > > > - ObjectStreamField[] fields = desc.getFields(false); > > - Object[] objVals = new Object[desc.getNumObjFields()]; > > - int numPrimFields = fields.length - objVals.length; > > - desc.getObjFieldValues(obj, objVals); > > - for (int i = 0; i < objVals.length; i++) { > > - if (extendedDebugInfo) { > > - debugInfoStack.push( > > - "field (class \"" + desc.getName() + "\", name: \"" + > > - fields[numPrimFields + i].getName() + "\", type: \"" + > > - fields[numPrimFields + i].getType() + "\")"); > > - } > > - try { > > - writeObject0(objVals[i], > > - fields[numPrimFields + i].isUnshared()); > > - } finally { > > + int numObjFields = desc.getNumObjFields(); > > + if (numObjFields > 0) { > > + ObjectStreamField[] fields = desc.getFields(false); > > + Object[] objVals = new Object[numObjFields]; > > + int numPrimFields = fields.length - objVals.length; > > + desc.getObjFieldValues(obj, objVals); > > + for (int i = 0; i < objVals.length; i++) { > > if (extendedDebugInfo) { > > - debugInfoStack.pop(); > > + debugInfoStack.push( > > + "field (class \"" + desc.getName() + "\", name: > > \"" + > > + fields[numPrimFields + i].getName() + "\", > > type: \"" + > > + fields[numPrimFields + i].getType() + "\")"); > > + } > > + try { > > + writeObject0(objVals[i], > > + fields[numPrimFields + i].isUnshared()); > > + } finally { > > + if (extendedDebugInfo) { > > + debugInfoStack.pop(); > > + } > > } > > } > > } > > @@ -1743,15 +1749,11 @@ > > private static final int MAX_BLOCK_SIZE = 1024; > > /** maximum data block header length */ > > private static final int MAX_HEADER_SIZE = 5; > > - /** (tunable) length of char buffer (for writing strings) */ > > - private static final int CHAR_BUF_SIZE = 256; > > > > /** buffer for writing general/block data */ > > private final byte[] buf = new byte[MAX_BLOCK_SIZE]; > > /** buffer for writing block data headers */ > > private final byte[] hbuf = new byte[MAX_HEADER_SIZE]; > > - /** char buffer for fast string writes */ > > - private final char[] cbuf = new char[CHAR_BUF_SIZE]; > > > > /** block data mode */ > > private boolean blkmode = false; > > @@ -1763,6 +1765,18 @@ > > /** loopback stream (for data writes that span data blocks) */ > > private final DataOutputStream dout; > > > > + /** use unsafe to directly access value field in > > java.lang.String */ > > + private static final Unsafe unsafe = Unsafe.getUnsafe(); > > + /** use field offset to directly access value field in > > java.lang.String */ > > + private static final long stringValueOffset; > > + static { > > + try { > > + stringValueOffset = > > unsafe.objectFieldOffset(String.class.getDeclaredField("value")); > > + } catch (NoSuchFieldException e) { > > + throw new InternalError(e); > > + } > > + } > > + > > /** > > * Creates new BlockDataOutputStream on top of given > > underlying stream. > > * Block data mode is turned off by default. > > @@ -1972,35 +1986,23 @@ > > } > > > > public void writeBytes(String s) throws IOException { > > - int endoff = s.length(); > > - int cpos = 0; > > - int csize = 0; > > + char[] sChars = (char[])unsafe.getObject(s, stringValueOffset); > > + int endoff = sChars.length; > > for (int off = 0; off < endoff; ) { > > - if (cpos >= csize) { > > - cpos = 0; > > - csize = Math.min(endoff - off, CHAR_BUF_SIZE); > > - s.getChars(off, off + csize, cbuf, 0); > > - } > > if (pos >= MAX_BLOCK_SIZE) { > > drain(); > > } > > - int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); > > + int n = Math.min(endoff - off, MAX_BLOCK_SIZE - pos); > > int stop = pos + n; > > while (pos < stop) { > > - buf[pos++] = (byte) cbuf[cpos++]; > > + buf[pos++] = (byte) sChars[off++]; > > } > > - off += n; > > } > > } > > > > public void writeChars(String s) throws IOException { > > - int endoff = s.length(); > > - for (int off = 0; off < endoff; ) { > > - int csize = Math.min(endoff - off, CHAR_BUF_SIZE); > > - s.getChars(off, off + csize, cbuf, 0); > > - writeChars(cbuf, 0, csize); > > - off += csize; > > - } > > + char[] sChars = (char[])unsafe.getObject(s, stringValueOffset); > > + writeChars(sChars, 0, sChars.length); > > } > > > > public void writeUTF(String s) throws IOException { > > @@ -2130,25 +2132,21 @@ > > } > > > > /** > > - * Returns the length in bytes of the UTF encoding of the given > > string. > > + * Returns the length in bytes of the UTF encoding of this > > given string. > > */ > > - long getUTFLength(String s) { > > - int len = s.length(); > > + static long getUTFLength(String s) { > > + char[] value = (char[])unsafe.getObject(s, stringValueOffset); > > + int len = value.length; > > long utflen = 0; > > for (int off = 0; off < len; ) { > > - int csize = Math.min(len - off, CHAR_BUF_SIZE); > > - s.getChars(off, off + csize, cbuf, 0); > > - for (int cpos = 0; cpos < csize; cpos++) { > > - char c = cbuf[cpos]; > > - if (c >= 0x0001 && c <= 0x007F) { > > - utflen++; > > - } else if (c > 0x07FF) { > > - utflen += 3; > > - } else { > > - utflen += 2; > > - } > > + char c = value[off++]; > > + if (c >= 0x0001 && c <= 0x007F) { > > + utflen++; > > + } else if (c > 0x07FF) { > > + utflen += 3; > > + } else { > > + utflen += 2; > > } > > - off += csize; > > } > > return utflen; > > } > > @@ -2198,40 +2196,36 @@ > > * 8-byte length header) of the UTF encoding for the given string. > > */ > > private void writeUTFBody(String s) throws IOException { > > + char[] sChars = (char[])unsafe.getObject(s, stringValueOffset); > > + int len = sChars.length; > > int limit = MAX_BLOCK_SIZE - 3; > > - int len = s.length(); > > for (int off = 0; off < len; ) { > > - int csize = Math.min(len - off, CHAR_BUF_SIZE); > > - s.getChars(off, off + csize, cbuf, 0); > > - for (int cpos = 0; cpos < csize; cpos++) { > > - char c = cbuf[cpos]; > > - if (pos <= limit) { > > - if (c <= 0x007F && c != 0) { > > - buf[pos++] = (byte) c; > > - } else if (c > 0x07FF) { > > - buf[pos + 2] = (byte) (0x80 | ((c >> 0) & > > 0x3F)); > > - buf[pos + 1] = (byte) (0x80 | ((c >> 6) & > > 0x3F)); > > - buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & > > 0x0F)); > > - pos += 3; > > - } else { > > - buf[pos + 1] = (byte) (0x80 | ((c >> 0) & > > 0x3F)); > > - buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & > > 0x1F)); > > - pos += 2; > > - } > > - } else { // write one byte at a time to > > normalize block > > - if (c <= 0x007F && c != 0) { > > - write(c); > > - } else if (c > 0x07FF) { > > - write(0xE0 | ((c >> 12) & 0x0F)); > > - write(0x80 | ((c >> 6) & 0x3F)); > > - write(0x80 | ((c >> 0) & 0x3F)); > > - } else { > > - write(0xC0 | ((c >> 6) & 0x1F)); > > - write(0x80 | ((c >> 0) & 0x3F)); > > - } > > + char c = sChars[off++]; > > + if (pos <= limit) { > > + if (c <= 0x007F && c != 0) { > > + buf[pos++] = (byte) c; > > + } else if (c > 0x07FF) { > > + buf[pos + 2] = (byte) (0x80 | ( c & 0x3F)); > > + buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); > > + buf[pos ] = (byte) (0xE0 | ((c >> 12) & 0x0F)); > > + pos += 3; > > + } else { > > + buf[pos + 1] = (byte) (0x80 | ( c & 0x3F)); > > + buf[pos ] = (byte) (0xC0 | ((c >> 6) & 0x1F)); > > + pos += 2; > > + } > > + } else { // write one byte at a time to normalize block > > + if (c <= 0x007F && c != 0) { > > + write(c); > > + } else if (c > 0x07FF) { > > + write(0xE0 | ((c >> 12) & 0x0F)); > > + write(0x80 | ((c >> 6) & 0x3F)); > > + write(0x80 | ( c & 0x3F)); > > + } else { > > + write(0xC0 | ((c >> 6) & 0x1F)); > > + write(0x80 | ( c & 0x3F)); > > } > > } > > - off += csize; > > } > > } > > } > > @@ -2464,7 +2458,10 @@ > > StringBuilder buffer = new StringBuilder(); > > if (!stack.isEmpty()) { > > for(int i = stack.size(); i > 0; i-- ) { > > - buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : "")); > > + buffer.append(stack.get(i - 1)); > > + if (i!=1) { > > + buffer.append('\n'); > > + } > > } > > } > > return buffer.toString(); > > diff --git a/src/share/classes/java/io/ObjectStreamClass.java > > b/src/share/classes/java/io/ObjectStreamClass.java > > --- a/src/share/classes/java/io/ObjectStreamClass.java > > +++ b/src/share/classes/java/io/ObjectStreamClass.java > > @@ -1474,7 +1474,28 @@ > > /** > > * Returns JVM type signature for given class. > > */ > > - private static String getClassSignature(Class<?> cl) { > > + static String getClassSignature(Class<?> cl) { > > + if (cl.isPrimitive()) > > + if (cl == Integer.TYPE) { > > + return "I"; > > + } else if (cl == Byte.TYPE) { > > + return "B"; > > + } else if (cl == Long.TYPE) { > > + return "J"; > > + } else if (cl == Float.TYPE) { > > + return "F"; > > + } else if (cl == Double.TYPE) { > > + return "D"; > > + } else if (cl == Short.TYPE) { > > + return "S"; > > + } else if (cl == Character.TYPE) { > > + return "C"; > > + } else if (cl == Boolean.TYPE) { > > + return "Z"; > > + } else if (cl == Void.TYPE) { > > + return "V"; > > + } > > + > > StringBuilder sbuf = new StringBuilder(); > > while (cl.isArray()) { > > sbuf.append('['); > > @@ -1503,7 +1524,7 @@ > > throw new InternalError(); > > } > > } else { > > - sbuf.append('L' + cl.getName().replace('.', '/') + ';'); > > + sbuf.append('L').append(cl.getName().replace('.', > > '/')).append(';'); > > } > > return sbuf.toString(); > > } > > diff --git a/src/share/classes/java/io/ObjectStreamField.java > > b/src/share/classes/java/io/ObjectStreamField.java > > --- a/src/share/classes/java/io/ObjectStreamField.java > > +++ b/src/share/classes/java/io/ObjectStreamField.java > > @@ -91,7 +91,7 @@ > > this.name = name; > > this.type = type; > > this.unshared = unshared; > > - signature = getClassSignature(type).intern(); > > + signature = ObjectStreamClass.getClassSignature(type).intern(); > > field = null; > > } > > > > @@ -137,7 +137,7 @@ > > name = field.getName(); > > Class<?> ftype = field.getType(); > > type = (showType || ftype.isPrimitive()) ? ftype : Object.class; > > - signature = getClassSignature(ftype).intern(); > > + signature = ObjectStreamClass.getClassSignature(ftype).intern(); > > } > > > > /** > > @@ -286,41 +286,4 @@ > > String getSignature() { > > return signature; > > } > > - > > - /** > > - * Returns JVM type signature for given class. > > - */ > > - private static String getClassSignature(Class<?> cl) { > > - StringBuilder sbuf = new StringBuilder(); > > - while (cl.isArray()) { > > - sbuf.append('['); > > - cl = cl.getComponentType(); > > - } > > - if (cl.isPrimitive()) { > > - if (cl == Integer.TYPE) { > > - sbuf.append('I'); > > - } else if (cl == Byte.TYPE) { > > - sbuf.append('B'); > > - } else if (cl == Long.TYPE) { > > - sbuf.append('J'); > > - } else if (cl == Float.TYPE) { > > - sbuf.append('F'); > > - } else if (cl == Double.TYPE) { > > - sbuf.append('D'); > > - } else if (cl == Short.TYPE) { > > - sbuf.append('S'); > > - } else if (cl == Character.TYPE) { > > - sbuf.append('C'); > > - } else if (cl == Boolean.TYPE) { > > - sbuf.append('Z'); > > - } else if (cl == Void.TYPE) { > > - sbuf.append('V'); > > - } else { > > - throw new InternalError(); > > - } > > - } else { > > - sbuf.append('L' + cl.getName().replace('.', '/') + ';'); > > - } > > - return sbuf.toString(); > > - } > > } > > *Gesendet:* Dienstag, 07. Januar 2014 um 10:05 Uhr > > *Von:* "Chris Hegarty" <chris.hega...@oracle.com> > > *An:* "Robert Stupp" <sn...@gmx.de> > > *Cc:* "core-libs-dev@openjdk.java.net Libs" <core-libs-dev@openjdk.java.net> > > *Betreff:* Re: ObjectIn/OutputStream improvements > > On 15 Dec 2013, at 10:29, Robert Stupp <sn...@gmx.de> wrote: > > > > > Hi, > > > > > > I digged through the object serialization code and found some lines > > that could be optimized to reduce the number of calls to > > System.arraycopy() and temporary object allocations especially during > > string (de)serialization. > > > In short sentences the changes are: > > > ObjectInputStream: > > > - skip primitive/object reading if no primitive/objects in class > > (defaultReadFields method) > > > - use shared StringBuilder for string reading (prevent superfluous > > object allocations of one StingBuilder and one implicit char[] for each > > string being deserialized) > > > ObjectOutputStream: > > > - skip primitive/object writing if no primitive/objects in class > > (defaultWriteFields method) > > > - use unsafe access to calculate UTF-length > > > - use unsafe access in readBytes() and writeChars() methods to access > > String value field > > > - removed cbuf field > > > ObjectStreamClass/ObjectStreamField: > > > - minor improvement in getClassSignature ; share method code with > > ObjectStreamField (return constant string for primitives) > > > > > > I have tested the changes in a big Java installation at a customer > > (backported the Java8 ObjectIn/OutputStream including the changes to > > Java6) and a long running real application performance test resulted in > > reduced CPU usage (from about 60% per server to 50%). > > > The changes I made in openjdk8 pass all tests. > > > > > > Since I have no experience how to contribute code to openjdk in form > > of a push/changeset I have added the diff (hg export -g) to this email. > > > > Did you attach the diffs? I don’t see any attachment, it may be that the > > attachment was stripped. Can you try resending inline? > > > > You should take a look at the OpenJDK How to Contribute page [1]. Paying > > particular attention to the OCA, without it we will not be able to move > > your patch forward. > > > > Thanks, > > -Chris. > > > > [1] http://openjdk.java.net/contribute/ > > > > > > > > Robert > > > > > >