changeset 46933:4564c96b8292

8149790: NegativeArraySizeException with hprof Reviewed-by: lfoltan, ctornqvi, hseigel, dcubed
author gtriantafill
date Wed, 16 Aug 2017 14:49:18 -0400
parents a4fa3280b8df
children 80130bc22863
files test/lib/jdk/test/lib/hprof/model/HackJavaValue.java test/lib/jdk/test/lib/hprof/model/JavaClass.java test/lib/jdk/test/lib/hprof/model/JavaHeapObject.java test/lib/jdk/test/lib/hprof/model/JavaLazyReadObject.java test/lib/jdk/test/lib/hprof/model/JavaObject.java test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java test/lib/jdk/test/lib/hprof/model/JavaObjectRef.java test/lib/jdk/test/lib/hprof/model/JavaThing.java test/lib/jdk/test/lib/hprof/model/JavaValue.java test/lib/jdk/test/lib/hprof/model/JavaValueArray.java test/lib/jdk/test/lib/hprof/model/ReachableObjects.java test/lib/jdk/test/lib/hprof/model/Snapshot.java test/lib/jdk/test/lib/hprof/parser/FileReadBuffer.java test/lib/jdk/test/lib/hprof/parser/MappedReadBuffer.java test/lib/jdk/test/lib/hprof/parser/ReadBuffer.java
diffstat 15 files changed, 281 insertions(+), 370 deletions(-) [+]
line wrap: on
line diff
--- a/test/lib/jdk/test/lib/hprof/model/HackJavaValue.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/HackJavaValue.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -47,9 +47,9 @@
 public class HackJavaValue extends JavaValue {
 
     private String value;
-    private int size;
+    private long size;
 
-    public HackJavaValue(String value, int size) {
+    public HackJavaValue(String value, long size) {
         this.value = value;
         this.size = size;
     }
@@ -58,7 +58,8 @@
         return value;
     }
 
-    public int getSize() {
+    @Override
+    public long getSize() {
         return size;
     }
 
--- a/test/lib/jdk/test/lib/hprof/model/JavaClass.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaClass.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -403,7 +403,8 @@
     /**
      * @return the size of this object
      */
-    public int getSize() {
+    @Override
+    public long getSize() {
         JavaClass cl = mySnapshot.getJavaLangClass();
         if (cl == null) {
             return 0;
--- a/test/lib/jdk/test/lib/hprof/model/JavaHeapObject.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaHeapObject.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -64,7 +64,7 @@
     private int referersLen = 0;        // -1 when resolved
 
     public abstract JavaClass getClazz();
-    public abstract int getSize();
+    public abstract long getSize();
     public abstract long getId();
 
     /**
--- a/test/lib/jdk/test/lib/hprof/model/JavaLazyReadObject.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaLazyReadObject.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -47,7 +47,8 @@
         this.offset = offset;
     }
 
-    public final int getSize() {
+    @Override
+    public final long getSize() {
         return getValueLength() + getClazz().getMinimumObjectSize();
     }
 
@@ -55,8 +56,16 @@
         return offset;
     }
 
+    protected ReadBuffer buf() {
+        return getClazz().getReadBuffer();
+    }
+
+    protected int idSize() {
+        return getClazz().getIdentifierSize();
+    }
+
     // return the length of the data for this object
-    protected final int getValueLength() {
+    protected final long getValueLength() {
         try {
             return readValueLength();
         } catch (IOException exp) {
@@ -67,25 +76,23 @@
     }
 
     // get this object's content as byte array
-    protected final byte[] getValue() {
+    protected final JavaThing[] getValue() {
         try {
             return readValue();
         } catch (IOException exp) {
             System.err.println("lazy read failed at offset " + offset);
             exp.printStackTrace();
-            return Snapshot.EMPTY_BYTE_ARRAY;
+            return Snapshot.EMPTY_JAVATHING_ARRAY;
         }
     }
 
     // get ID of this object
     public final long getId() {
         try {
-            ReadBuffer buf = getClazz().getReadBuffer();
-            int idSize = getClazz().getIdentifierSize();
-            if (idSize == 4) {
-                return ((long)buf.getInt(offset)) & Snapshot.SMALL_ID_MASK;
+        if (idSize() == 4) {
+                return ((long)buf().getInt(offset)) & Snapshot.SMALL_ID_MASK;
             } else {
-                return buf.getLong(offset);
+                return buf().getLong(offset);
             }
         } catch (IOException exp) {
             System.err.println("lazy read failed at offset " + offset);
@@ -94,8 +101,8 @@
         }
     }
 
-    protected abstract int readValueLength() throws IOException;
-    protected abstract byte[] readValue() throws IOException;
+    protected abstract long readValueLength() throws IOException;
+    protected abstract JavaThing[] readValue() throws IOException;
 
     // make Integer or Long for given object ID
     protected static Number makeId(long id) {
@@ -116,61 +123,46 @@
     }
 
     // read object ID from given index from given byte array
-    protected final long objectIdAt(int index, byte[] data) {
-        int idSize = getClazz().getIdentifierSize();
-        if (idSize == 4) {
-            return ((long)intAt(index, data)) & Snapshot.SMALL_ID_MASK;
+    protected final long objectIdAt(long offset) throws IOException {
+        if (idSize() == 4) {
+            return ((long)intAt(offset)) & Snapshot.SMALL_ID_MASK;
         } else {
-            return longAt(index, data);
+            return longAt(offset);
         }
     }
 
     // utility methods to read primitive types from byte array
-    protected static byte byteAt(int index, byte[] value) {
-        return value[index];
+    protected byte byteAt(long offset) throws IOException {
+        return buf().getByte(offset);
     }
 
-    protected static boolean booleanAt(int index, byte[] value) {
-        return (value[index] & 0xff) == 0? false: true;
+    protected boolean booleanAt(long offset) throws IOException {
+        return byteAt(offset) == 0 ? false : true;
     }
 
-    protected static char charAt(int index, byte[] value) {
-        int b1 = ((int) value[index++] & 0xff);
-        int b2 = ((int) value[index++] & 0xff);
-        return (char) ((b1 << 8) + b2);
+    protected char charAt(long offset) throws IOException {
+        return buf().getChar(offset);
     }
 
-    protected static short shortAt(int index, byte[] value) {
-        int b1 = ((int) value[index++] & 0xff);
-        int b2 = ((int) value[index++] & 0xff);
-        return (short) ((b1 << 8) + b2);
+    protected short shortAt(long offset) throws IOException {
+        return buf().getShort(offset);
     }
 
-    protected static int intAt(int index, byte[] value) {
-        int b1 = ((int) value[index++] & 0xff);
-        int b2 = ((int) value[index++] & 0xff);
-        int b3 = ((int) value[index++] & 0xff);
-        int b4 = ((int) value[index++] & 0xff);
-        return ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
+    protected int intAt(long offset) throws IOException {
+        return buf().getInt(offset);
     }
 
-    protected static long longAt(int index, byte[] value) {
-        long val = 0;
-        for (int j = 0; j < 8; j++) {
-            val = val << 8;
-            int b = ((int)value[index++]) & 0xff;
-            val |= b;
-        }
-        return val;
+    protected long longAt(long offset) throws IOException {
+        return buf().getLong(offset);
     }
 
-    protected static float floatAt(int index, byte[] value) {
-        int val = intAt(index, value);
+    protected float floatAt(long offset) throws IOException {
+        int val = intAt(offset);
         return Float.intBitsToFloat(val);
     }
 
-    protected static double doubleAt(int index, byte[] value) {
-        long val = longAt(index, value);
+    protected double doubleAt(long offset) throws IOException {
+        long val = longAt(offset);
         return Double.longBitsToDouble(val);
     }
 }
--- a/test/lib/jdk/test/lib/hprof/model/JavaObject.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObject.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -86,7 +86,7 @@
         // while resolving, parse fields in verbose mode.
         // but, getFields calls parseFields in non-verbose mode
         // to avoid printing warnings repeatedly.
-        parseFields(getValue(), true);
+        parseFields(true);
 
         cl.addInstance(this);
         super.resolve(snapshot);
@@ -114,7 +114,7 @@
     public JavaThing[] getFields() {
         // pass false to verbose mode so that dereference
         // warnings are not printed.
-        return parseFields(getValue(), false);
+        return parseFields(false);
     }
 
     // returns the value of field of given name
@@ -212,35 +212,27 @@
      *     data length (int)
      *     byte[length]
      */
-    protected final int readValueLength() throws IOException {
-        JavaClass cl = getClazz();
-        int idSize = cl.getIdentifierSize();
-        long lengthOffset = getOffset() + 2*idSize + 4;
-        return cl.getReadBuffer().getInt(lengthOffset);
+    @Override
+    protected final long readValueLength() throws IOException {
+        long lengthOffset = getOffset() + 2 * idSize() + 4;
+        return buf().getInt(lengthOffset);
     }
 
-    protected final byte[] readValue() throws IOException {
-        JavaClass cl = getClazz();
-        int idSize = cl.getIdentifierSize();
-        ReadBuffer buf = cl.getReadBuffer();
-        long offset = getOffset() + 2*idSize + 4;
-        int length = buf.getInt(offset);
-        if (length == 0) {
-            return Snapshot.EMPTY_BYTE_ARRAY;
-        } else {
-            byte[] res = new byte[length];
-            buf.get(offset + 4, res);
-            return res;
-        }
+    @Override
+    protected final JavaThing[] readValue() throws IOException {
+        return parseFields(false);
     }
 
-    private JavaThing[] parseFields(byte[] data, boolean verbose) {
+    private long dataStartOffset() {
+        return getOffset() + idSize() + 4 + idSize() + 4;
+    }
+
+    private JavaThing[] parseFields(boolean verbose) {
         JavaClass cl = getClazz();
         int target = cl.getNumFieldsForInstance();
         JavaField[] fields = cl.getFields();
         JavaThing[] fieldValues = new JavaThing[target];
         Snapshot snapshot = cl.getSnapshot();
-        int idSize = snapshot.getIdentifierSize();
         int fieldNo = 0;
         // In the dump file, the fields are stored in this order:
         // fields of most derived class (immediate class) are stored
@@ -254,7 +246,7 @@
         // starts with the top of the inheritance hierarchy and works down.
         target -= fields.length;
         JavaClass currClass = cl;
-        int index = 0;
+        long offset = dataStartOffset();
         for (int i = 0; i < fieldValues.length; i++, fieldNo++) {
             while (fieldNo >= fields.length) {
                 currClass = currClass.getSuperclass();
@@ -264,65 +256,72 @@
             }
             JavaField f = fields[fieldNo];
             char sig = f.getSignature().charAt(0);
-            switch (sig) {
-                case 'L':
-                case '[': {
-                    long id = objectIdAt(index, data);
-                    index += idSize;
-                    JavaObjectRef ref = new JavaObjectRef(id);
-                    fieldValues[target+fieldNo] = ref.dereference(snapshot, f, verbose);
-                    break;
+            try {
+                switch (sig) {
+                    case 'L':
+                    case '[': {
+                        long id = objectIdAt(offset);
+                        offset += idSize();
+                        JavaObjectRef ref = new JavaObjectRef(id);
+                        fieldValues[target+fieldNo] = ref.dereference(snapshot, f, verbose);
+                        break;
+                    }
+                    case 'Z': {
+                        byte value = byteAt(offset);
+                        offset++;
+                        fieldValues[target+fieldNo] = new JavaBoolean(value != 0);
+                        break;
+                    }
+                    case 'B': {
+                        byte value = byteAt(offset);
+                        offset++;
+                        fieldValues[target+fieldNo] = new JavaByte(value);
+                        break;
+                    }
+                    case 'S': {
+                        short value = shortAt(offset);
+                        offset += 2;
+                        fieldValues[target+fieldNo] = new JavaShort(value);
+                        break;
+                    }
+                    case 'C': {
+                        char value = charAt(offset);
+                        offset += 2;
+                        fieldValues[target+fieldNo] = new JavaChar(value);
+                        break;
+                    }
+                    case 'I': {
+                        int value = intAt(offset);
+                        offset += 4;
+                        fieldValues[target+fieldNo] = new JavaInt(value);
+                        break;
+                    }
+                    case 'J': {
+                        long value = longAt(offset);
+                        offset += 8;
+                        fieldValues[target+fieldNo] = new JavaLong(value);
+                        break;
+                    }
+                    case 'F': {
+                        float value = floatAt(offset);
+                        offset += 4;
+                        fieldValues[target+fieldNo] = new JavaFloat(value);
+                        break;
+                    }
+                    case 'D': {
+                        double value = doubleAt(offset);
+                        offset += 8;
+                        fieldValues[target+fieldNo] = new JavaDouble(value);
+                        break;
+                    }
+                    default:
+                        throw new RuntimeException("invalid signature: " + sig);
+
                 }
-                case 'Z': {
-                    byte value = byteAt(index, data);
-                    index++;
-                    fieldValues[target+fieldNo] = new JavaBoolean(value != 0);
-                    break;
-                }
-                case 'B': {
-                    byte value = byteAt(index, data);
-                    index++;
-                    fieldValues[target+fieldNo] = new JavaByte(value);
-                    break;
-                }
-                case 'S': {
-                    short value = shortAt(index, data);
-                    index += 2;
-                    fieldValues[target+fieldNo] = new JavaShort(value);
-                    break;
-                }
-                case 'C': {
-                    char value = charAt(index, data);
-                    index += 2;
-                    fieldValues[target+fieldNo] = new JavaChar(value);
-                    break;
-                }
-                case 'I': {
-                    int value = intAt(index, data);
-                    index += 4;
-                    fieldValues[target+fieldNo] = new JavaInt(value);
-                    break;
-                }
-                case 'J': {
-                    long value = longAt(index, data);
-                    index += 8;
-                    fieldValues[target+fieldNo] = new JavaLong(value);
-                    break;
-                }
-                case 'F': {
-                    float value = floatAt(index, data);
-                    index += 4;
-                    fieldValues[target+fieldNo] = new JavaFloat(value);
-                    break;
-                }
-                case 'D': {
-                    double value = doubleAt(index, data);
-                    index += 8;
-                    fieldValues[target+fieldNo] = new JavaDouble(value);
-                    break;
-                }
-                default:
-                    throw new RuntimeException("invalid signature: " + sig);
+        } catch (IOException exp) {
+            System.err.println("lazy read failed at offset " + offset);
+            exp.printStackTrace();
+            return Snapshot.EMPTY_JAVATHING_ARRAY;
             }
         }
         return fieldValues;
--- a/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObjectArray.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -87,18 +87,7 @@
     }
 
     public JavaThing[] getElements() {
-        Snapshot snapshot = getClazz().getSnapshot();
-        byte[] data = getValue();
-        final int idSize = snapshot.getIdentifierSize();
-        final int numElements = data.length / idSize;
-        JavaThing[] elements = new JavaThing[numElements];
-        int index = 0;
-        for (int i = 0; i < elements.length; i++) {
-            long id = objectIdAt(index, data);
-            index += idSize;
-            elements[i] = snapshot.findThing(id);
-        }
-        return elements;
+        return getValue();
     }
 
     public int compareTo(JavaThing other) {
@@ -109,7 +98,7 @@
     }
 
     public int getLength() {
-        return getValueLength() / getClazz().getIdentifierSize();
+        return (int)(getValueLength() / idSize());
     }
 
     public void visitReferencedObjects(JavaHeapObjectVisitor v) {
@@ -146,27 +135,31 @@
      *     array class ID
      *     array element IDs
      */
-    protected final int readValueLength() throws IOException {
-        JavaClass cl = getClazz();
-        ReadBuffer buf = cl.getReadBuffer();
-        int idSize = cl.getIdentifierSize();
-        long offset = getOffset() + idSize + 4;
-        int len = buf.getInt(offset);
-        return len * cl.getIdentifierSize();
+    @Override
+    protected final long readValueLength() throws IOException {
+        long offset = getOffset() + idSize() + 4;
+        // length of the array in elements
+        long len = buf().getInt(offset);
+        // byte length of array
+        return len * idSize();
+        }
+
+    private long dataStartOffset() {
+        return getOffset() + idSize() + 4 + 4 + idSize();
     }
 
-    protected final byte[] readValue() throws IOException {
-        JavaClass cl = getClazz();
-        ReadBuffer buf = cl.getReadBuffer();
-        int idSize = cl.getIdentifierSize();
-        long offset = getOffset() + idSize + 4;
-        int len = buf.getInt(offset);
-        if (len == 0) {
-            return Snapshot.EMPTY_BYTE_ARRAY;
-        } else {
-            byte[] res = new byte[len * idSize];
-            buf.get(offset + 4 + idSize, res);
-            return res;
-        }
+    @Override
+    protected final JavaThing[] readValue() throws IOException {
+        Snapshot snapshot = getClazz().getSnapshot();
+        int len = getLength();
+        long offset = dataStartOffset();
+
+        JavaThing[] res = new JavaThing[len];
+        for (int i = 0; i < len; i++) {
+            long id = objectIdAt(offset);
+            res[i] = snapshot.findThing(id);
+            offset += idSize();
+         }
+         return res;
     }
 }
--- a/test/lib/jdk/test/lib/hprof/model/JavaObjectRef.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaObjectRef.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -87,7 +87,8 @@
         return result;
     }
 
-    public int getSize() {
+    @Override
+    public long getSize() {
         return 0;
     }
 
--- a/test/lib/jdk/test/lib/hprof/model/JavaThing.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaThing.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -81,7 +81,7 @@
     /**
      * @return the size of this object, in bytes, including VM overhead
      */
-    abstract public int getSize();
+    abstract public long getSize();
 
     /**
      * @return a human-readable string representation of this thing
--- a/test/lib/jdk/test/lib/hprof/model/JavaValue.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaValue.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -52,7 +52,8 @@
 
     abstract public String toString();
 
-    public int getSize() {
+    @Override
+    public long getSize() {
         // The size of a value is already accounted for in the class
         // that has the data member.
         return 0;
--- a/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/JavaValueArray.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -91,38 +91,92 @@
      *
      *    object ID
      *    stack trace serial number (int)
-     *    length of the instance data (int)
+     *    number of elements (int)
      *    element type (byte)
      *    array data
      */
-    protected final int readValueLength() throws IOException {
-        JavaClass cl = getClazz();
-        ReadBuffer buf = cl.getReadBuffer();
-        int idSize = cl.getIdentifierSize();
-        long offset = getOffset() + idSize + 4;
-        // length of the array
-        int len = buf.getInt(offset);
-        // typecode of array element type
-        byte type = buf.getByte(offset + 4);
-        return len * elementSize(type);
+    @Override
+    protected final long readValueLength() throws IOException {
+        long offset = getOffset() + idSize() + 4;
+        // length of the array in elements
+        long len = buf().getInt(offset);
+        // byte length of array
+        return len * elementSize(getElementType());
     }
 
-    protected final byte[] readValue() throws IOException {
-        JavaClass cl = getClazz();
-        ReadBuffer buf = cl.getReadBuffer();
-        int idSize = cl.getIdentifierSize();
-        long offset = getOffset() + idSize + 4;
-        // length of the array
-        int length = buf.getInt(offset);
-        // typecode of array element type
-        byte type = buf.getByte(offset + 4);
-        if (length == 0) {
-            return Snapshot.EMPTY_BYTE_ARRAY;
-        } else {
-            length *= elementSize(type);
-            byte[] res = new byte[length];
-            buf.get(offset + 5, res);
-            return res;
+    private long dataStartOffset() {
+        return getOffset() + idSize() + 4 + 4 + 1;
+    }
+
+
+    @Override
+    protected final JavaThing[] readValue() throws IOException {
+        int len = getLength();
+        long offset = dataStartOffset();
+
+        JavaThing[] res = new JavaThing[len];
+        synchronized (buf()) {
+            switch (getElementType()) {
+                case 'Z': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaBoolean(booleanAt(offset));
+                                  offset += 1;
+                              }
+                              return res;
+                }
+                case 'B': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaByte(byteAt(offset));
+                                  offset += 1;
+                              }
+                              return res;
+                }
+                case 'C': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaChar(charAt(offset));
+                                  offset += 2;
+                              }
+                              return res;
+                }
+                case 'S': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaShort(shortAt(offset));
+                                  offset += 2;
+                              }
+                              return res;
+                }
+                case 'I': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaInt(intAt(offset));
+                                  offset += 4;
+                              }
+                              return res;
+                }
+                case 'J': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaLong(longAt(offset));
+                                  offset += 8;
+                              }
+                              return res;
+                }
+                case 'F': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaFloat(floatAt(offset));
+                                  offset += 4;
+                              }
+                              return res;
+                }
+                case 'D': {
+                              for (int i = 0; i < len; i++) {
+                                  res[i] = new JavaDouble(doubleAt(offset));
+                                  offset += 8;
+                              }
+                              return res;
+                }
+                default: {
+                             throw new RuntimeException("unknown primitive type?");
+                }
+            }
         }
     }
 
@@ -197,83 +251,11 @@
             }
             data |= (divider << LENGTH_DIVIDER_SHIFT);
         }
-        return (getValueLength() / divider);
+        return (int)(getValueLength() / divider);
     }
 
-    public Object getElements() {
-        final int len = getLength();
-        final byte et = getElementType();
-        byte[] data = getValue();
-        int index = 0;
-        switch (et) {
-            case 'Z': {
-                boolean[] res = new boolean[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = booleanAt(index, data);
-                    index++;
-                }
-                return res;
-            }
-            case 'B': {
-                byte[] res = new byte[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = byteAt(index, data);
-                    index++;
-                }
-                return res;
-            }
-            case 'C': {
-                char[] res = new char[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = charAt(index, data);
-                    index += 2;
-                }
-                return res;
-            }
-            case 'S': {
-                short[] res = new short[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = shortAt(index, data);
-                    index += 2;
-                }
-                return res;
-            }
-            case 'I': {
-                int[] res = new int[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = intAt(index, data);
-                    index += 4;
-                }
-                return res;
-            }
-            case 'J': {
-                long[] res = new long[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = longAt(index, data);
-                    index += 8;
-                }
-                return res;
-            }
-            case 'F': {
-                float[] res = new float[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = floatAt(index, data);
-                    index += 4;
-                }
-                return res;
-            }
-            case 'D': {
-                double[] res = new double[len];
-                for (int i = 0; i < len; i++) {
-                    res[i] = doubleAt(index, data);
-                    index += 8;
-                }
-                return res;
-            }
-            default: {
-                throw new RuntimeException("unknown primitive type?");
-            }
-        }
+    public JavaThing[] getElements() {
+        return getValue();
     }
 
     public byte getElementType() {
@@ -292,54 +274,6 @@
         }
     }
 
-    public boolean getBooleanAt(int index) {
-        checkIndex(index);
-        requireType('Z');
-        return booleanAt(index, getValue());
-    }
-
-    public byte getByteAt(int index) {
-        checkIndex(index);
-        requireType('B');
-        return byteAt(index, getValue());
-    }
-
-    public char getCharAt(int index) {
-        checkIndex(index);
-        requireType('C');
-        return charAt(index << 1, getValue());
-    }
-
-    public short getShortAt(int index) {
-        checkIndex(index);
-        requireType('S');
-        return shortAt(index << 1, getValue());
-    }
-
-    public int getIntAt(int index) {
-        checkIndex(index);
-        requireType('I');
-        return intAt(index << 2, getValue());
-    }
-
-    public long getLongAt(int index) {
-        checkIndex(index);
-        requireType('J');
-        return longAt(index << 3, getValue());
-    }
-
-    public float getFloatAt(int index) {
-        checkIndex(index);
-        requireType('F');
-        return floatAt(index << 2, getValue());
-    }
-
-    public double getDoubleAt(int index) {
-        checkIndex(index);
-        requireType('D');
-        return doubleAt(index << 3, getValue());
-    }
-
     public String valueString() {
         return valueString(true);
     }
@@ -347,15 +281,12 @@
     public String valueString(boolean bigLimit) {
         // Char arrays deserve special treatment
         StringBuilder result;
-        byte[] value = getValue();
-        int max = value.length;
+        JavaThing[] things = getValue();
         byte elementSignature = getElementType();
         if (elementSignature == 'C')  {
             result = new StringBuilder();
-            for (int i = 0; i < value.length; ) {
-                char val = charAt(i, value);
-                result.append(val);
-                i += 2;
+            for (int i = 0; i < things.length; i++) {
+                result.append(things[i]);
             }
         } else {
             int limit = 8;
@@ -363,61 +294,52 @@
                 limit = 1000;
             }
             result = new StringBuilder("{");
-            int num = 0;
-            for (int i = 0; i < value.length; ) {
-                if (num > 0) {
+            for (int i = 0; i < things.length; i++) {
+                if (i > 0) {
                     result.append(", ");
                 }
-                if (num >= limit) {
+                if (i >= limit) {
                     result.append("... ");
                     break;
                 }
-                num++;
                 switch (elementSignature) {
                     case 'Z': {
-                        boolean val = booleanAt(i, value);
+                        boolean val = ((JavaBoolean)things[i]).value;
                         if (val) {
                             result.append("true");
                         } else {
                             result.append("false");
                         }
-                        i++;
                         break;
                     }
                     case 'B': {
-                        int val = 0xFF & byteAt(i, value);
+                        byte val = ((JavaByte)things[i]).value;
                         result.append("0x").append(Integer.toString(val, 16));
-                        i++;
                         break;
                     }
                     case 'S': {
-                        short val = shortAt(i, value);
-                        i += 2;
+                        short val = ((JavaShort)things[i]).value;
                         result.append(val);
                         break;
                     }
                     case 'I': {
-                        int val = intAt(i, value);
-                        i += 4;
+                        int val = ((JavaInt)things[i]).value;
                         result.append(val);
                         break;
                     }
                     case 'J': {         // long
-                        long val = longAt(i, value);
+                        long val = ((JavaLong)things[i]).value;
                         result.append(val);
-                        i += 8;
                         break;
                     }
                     case 'F': {
-                        float val = floatAt(i, value);
+                        float val = ((JavaFloat)things[i]).value;
                         result.append(val);
-                        i += 4;
                         break;
                     }
                     case 'D': {         // double
-                        double val = doubleAt(i, value);
+                        double val = ((JavaDouble)things[i]).value;
                         result.append(val);
-                        i += 8;
                         break;
                     }
                     default: {
@@ -429,5 +351,4 @@
         }
         return result.toString();
     }
-
 }
--- a/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/ReachableObjects.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -93,9 +93,9 @@
             public int compare(Object lhs, Object rhs) {
                 JavaThing left = (JavaThing) lhs;
                 JavaThing right = (JavaThing) rhs;
-                int diff = right.getSize() - left.getSize();
+                long diff = right.getSize() - left.getSize();
                 if (diff != 0) {
-                    return diff;
+                    return Long.signum(diff);
                 }
                 return left.compareTo(right);
             }
--- a/test/lib/jdk/test/lib/hprof/model/Snapshot.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/model/Snapshot.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -52,7 +52,7 @@
 public class Snapshot implements AutoCloseable {
 
     public static final long SMALL_ID_MASK = 0x0FFFFFFFFL;
-    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
+    public static final JavaThing[] EMPTY_JAVATHING_ARRAY = new JavaThing[0];
 
     private static final JavaField[] EMPTY_FIELD_ARRAY = new JavaField[0];
     private static final JavaStatic[] EMPTY_STATIC_ARRAY = new JavaStatic[0];
--- a/test/lib/jdk/test/lib/hprof/parser/FileReadBuffer.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/parser/FileReadBuffer.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -57,26 +57,31 @@
         file.read(buf);
     }
 
+    @Override
     public synchronized char getChar(long pos) throws IOException {
         seek(pos);
         return file.readChar();
     }
 
+    @Override
     public synchronized byte getByte(long pos) throws IOException {
         seek(pos);
         return (byte) file.read();
     }
 
+    @Override
     public synchronized short getShort(long pos) throws IOException {
         seek(pos);
         return file.readShort();
     }
 
+    @Override
     public synchronized int getInt(long pos) throws IOException {
         seek(pos);
         return file.readInt();
     }
 
+    @Override
     public synchronized long getLong(long pos) throws IOException {
         seek(pos);
         return file.readLong();
--- a/test/lib/jdk/test/lib/hprof/parser/MappedReadBuffer.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/parser/MappedReadBuffer.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -98,31 +98,31 @@
         buf.position((int)pos);
     }
 
-    public synchronized void get(long pos, byte[] res) throws IOException {
-        seek(pos);
-        buf.get(res);
-    }
-
+    @Override
     public synchronized char getChar(long pos) throws IOException {
         seek(pos);
         return buf.getChar();
     }
 
+    @Override
     public synchronized byte getByte(long pos) throws IOException {
         seek(pos);
         return buf.get();
     }
 
+    @Override
     public synchronized short getShort(long pos) throws IOException {
         seek(pos);
         return buf.getShort();
     }
 
+    @Override
     public synchronized int getInt(long pos) throws IOException {
         seek(pos);
         return buf.getInt();
     }
 
+    @Override
     public synchronized long getLong(long pos) throws IOException {
         seek(pos);
         return buf.getLong();
--- a/test/lib/jdk/test/lib/hprof/parser/ReadBuffer.java	Mon Aug 21 15:19:47 2017 +0200
+++ b/test/lib/jdk/test/lib/hprof/parser/ReadBuffer.java	Wed Aug 16 14:49:18 2017 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -40,9 +40,6 @@
  * @author A. Sundararajan
  */
 public interface ReadBuffer extends AutoCloseable {
-    // read methods - only byte array and int primitive types.
-    // read position has to be specified always.
-    public void  get(long pos, byte[] buf) throws IOException;
     public char  getChar(long pos) throws IOException;
     public byte  getByte(long pos) throws IOException;
     public short getShort(long pos) throws IOException;