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 <chris.hega...@oracle.com> wrote:

> Forwarding to correct core-libs-dev list.
> 
> -Chris.
> 
> On 31 Jan 2014, at 14:22, Chris Hegarty <chris.hega...@oracle.com> 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" <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
>>>> 
>>>> 
> 

Reply via email to