Seems like good changes. ObjectStreamClass.java::
- Why not have getClassSignature() return an interned string? (that's if interning is actually essential. Are we sure it's not just overhead?) On Jan 31 2014, at 10:46 , Chris Hegarty <[email protected]> wrote: > Forwarding to correct core-libs-dev list. > > -Chris. > > On 31 Jan 2014, at 14:22, Chris Hegarty <[email protected]> wrote: > >> 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" <[email protected]> >>> *An:* "Robert Stupp" <[email protected]> >>> *Cc:* "[email protected] Libs" <[email protected]> >>> *Betreff:* Re: ObjectIn/OutputStream improvements >>> On 15 Dec 2013, at 10:29, Robert Stupp <[email protected]> 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 >>>> >>>> >
