8151806: JImage decompress code needs to be revised to be more effective
authorjlaskey
Mon, 04 Apr 2016 09:34:18 -0300
changeset 36855 a05bd99b9040
parent 36854 84179cb88469
child 36856 81c718cdeb09
8151806: JImage decompress code needs to be revised to be more effective Reviewed-by: redestad
jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java	Sun Apr 03 16:28:41 2016 +0100
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java	Mon Apr 04 09:34:18 2016 -0300
@@ -42,107 +42,95 @@
  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
  */
 public class CompressIndexes {
-    private static final int INTEGER_SIZE = 4;
+    private static final int COMPRESSED_FLAG = 1 << (Byte.SIZE - 1);
+    private static final int HEADER_WIDTH = 3;
+    private static final int HEADER_SHIFT = Byte.SIZE - HEADER_WIDTH;
 
     public static List<Integer> decompressFlow(byte[] values) {
         List<Integer> lst = new ArrayList<>();
-        for (int i = 0; i < values.length;) {
-            byte b = values[i];
-            int length = isCompressed(b) ? getLength(b) : INTEGER_SIZE;
+
+        for (int i = 0; i < values.length; i += getHeaderLength(values[i])) {
             int decompressed = decompress(values, i);
             lst.add(decompressed);
-            i += length;
         }
+
         return lst;
     }
 
     public static int readInt(DataInputStream cr) throws IOException {
-        byte[] b = new byte[1];
-        cr.readFully(b);
-        byte firstByte = b[0];
-        boolean compressed = CompressIndexes.isCompressed(firstByte);
-        int toRead = 4;
-        if(compressed) {
-            toRead = CompressIndexes.getLength(firstByte);
+        // Get header byte.
+        byte header = cr.readByte();
+        // Determine size.
+        int size = getHeaderLength(header);
+        // Prepare result.
+        int result = getHeaderValue(header);
+
+        // For each value byte
+        for (int i = 1; i < size; i++) {
+            // Merge byte value.
+            result <<= Byte.SIZE;
+            result |= cr.readByte() & 0xFF;
         }
-        byte[] content = new byte[toRead-1];
-        cr.readFully(content);
-        ByteBuffer bb = ByteBuffer.allocate(content.length+1);
-        bb.put(firstByte);
-        bb.put(content);
-        int index = CompressIndexes.decompress(bb.array(), 0);
-        return index;
+
+        return result;
     }
 
-    public static int getLength(byte b) {
-        return ((byte) (b & 0x60) >> 5);
+    private static boolean isCompressed(byte b) {
+        return (b & COMPRESSED_FLAG) != 0;
     }
 
-    public static boolean isCompressed(byte b) {
-        return b < 0;
+    private static int getHeaderLength(byte b) {
+        return isCompressed(b) ? (b >> HEADER_SHIFT) & 3 : Integer.BYTES;
+    }
+
+    private static int getHeaderValue(byte b) {
+        return isCompressed(b) ? b & (1 << HEADER_SHIFT) - 1 : b;
     }
 
     public static int decompress(byte[] value, int offset) {
-        byte b1 = value[offset];
-        ByteBuffer buffer = ByteBuffer.allocate(INTEGER_SIZE);
-        if (isCompressed(b1)) { // compressed
-            int length = getLength(b1);
-            byte clearedValue = (byte) (b1 & 0x1F);
+        // Get header byte.
+        byte header = value[offset];
+        // Determine size.
+        int size = getHeaderLength(header);
+        // Prepare result.
+        int result = getHeaderValue(header);
 
-            int start = INTEGER_SIZE - length;
-            buffer.put(start, clearedValue);
-            for (int i = offset + 1; i < offset + length; i++) {
-                buffer.put(++start, value[i]);
-            }
-        } else {
-            buffer.put(value, offset, INTEGER_SIZE);
+        // For each value byte
+        for (int i = 1; i < size; i++) {
+            // Merge byte value.
+            result <<= Byte.SIZE;
+            result |= value[offset + i] & 0xFF;
         }
-        return buffer.getInt(0);
+
+        return result;
     }
 
-    public static byte[] compress(int val) {
-        ByteBuffer result = ByteBuffer.allocate(4).putInt(val);
-        byte[] array = result.array();
+    public static byte[] compress(int value) {
+        // Only positive values are supported.
+        if (value < 0) {
+            throw new  IllegalArgumentException("value < 0");
+        }
+
+        // Determine number of significant digits.
+        int width = 32 - Integer.numberOfLeadingZeros(value);
+        // Determine number of byte to represent.  Allow for header if
+        // compressed.
+        int size = Math.min(((width + HEADER_WIDTH - 1) >> 3) + 1, Integer.BYTES);
+
+        // Allocate result buffer.
+        byte[] result = new byte[size];
 
-        if ((val & 0xFF000000) == 0) { // nothing on 4th
-            if ((val & 0x00FF0000) == 0) { // nothing on 3rd
-                if ((val & 0x0000FF00) == 0) { // nothing on 2nd
-                    if ((val & 0x000000E0) == 0) { // only in 1st, encode length in the byte.
-                        //sign bit and size 1 ==> 101X
-                        result = ByteBuffer.allocate(1);
-                        result.put((byte) (0xA0 | array[3]));
-                    } else { // add a byte for size
-                        //sign bit and size 2 ==> 110X
-                        result = ByteBuffer.allocate(2);
-                        result.put((byte) 0xC0);
-                        result.put(array[3]);
-                    }
-                } else { // content in 2nd
-                    if ((val & 0x0000E000) == 0) {// encode length in the byte.
-                        //sign bit and size 2 ==> 110X
-                        result = ByteBuffer.allocate(2);
-                        result.put((byte) (0xC0 | array[2]));
-                        result.put(array[3]);
-                    } else { // add a byte for size
-                        //sign bit and size 3 ==> 111X
-                        result = ByteBuffer.allocate(3);
-                        result.put((byte) 0xE0);
-                        result.put(array[2]);
-                        result.put(array[3]);
-                    }
-                }
-            } else {// content in 3rd
-                if ((val & 0x00E00000) == 0) {// encode length in the byte.
-                    //sign bit and size 3 ==> 111X
-                    result = ByteBuffer.allocate(3);
-                    result.put((byte) (0xE0 | array[1]));
-                    result.put(array[2]);
-                    result.put(array[3]);
-                } else { // add a byte, useless
-                    //
-                }
-            }
+        // Insert significant bytes in result.
+        for (int i = 0; i < size; i++) {
+            result[i] = (byte)(value >> ((size - i - 1) * Byte.SIZE));
         }
-        return result.array();
+
+        // If compressed, mark and insert size.
+        if (size < Integer.BYTES) {
+            result[0] |= (byte)(COMPRESSED_FLAG | (size << HEADER_SHIFT));
+        }
+
+        return result;
     }
+
 }