Since it is quite easy to read an int from a byte[] in jdk 9, the
CRC64 implementation can be optimized to operate on an int rather than
byte by byte as part of a multi-release jar. This shows to be 5-7%
faster in a microbenchmark of just the crc64 calculation. In jdk 11 it
speeds up the decompression of the repeating single byte by ~1%.

/*
 * CRC64
 *
 * Authors: Brett Okken <[email protected]>
 *          Lasse Collin <[email protected]>
 *
 * This file has been put into the public domain.
 * You can do whatever you want with this file.
 */

package org.tukaani.xz.check;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;

public class CRC64 extends Check {
    private static final VarHandle LE_INT_HANDLE =
            MethodHandles.byteArrayViewVarHandle(int[].class,
ByteOrder.LITTLE_ENDIAN);
    private static final VarHandle LE_LONG_HANDLE =
            MethodHandles.byteArrayViewVarHandle(long[].class,
ByteOrder.LITTLE_ENDIAN);
    private static final long[][] TABLE = new long[4][256];

    static {
        final long poly64 = 0xC96C5795D7870F42L;

        for (int s = 0; s < 4; ++s) {
            for (int b = 0; b < 256; ++b) {
                long r = s == 0 ? b : TABLE[s - 1][b];
                for (int i = 0; i < 8; ++i) {
                    if ((r & 1) == 1) {
                        r = (r >>> 1) ^ poly64;
                    } else {
                        r >>>= 1;
                    }
                }
                TABLE[s][b] = r;
            }
        }
    }

    private long crc = -1;

    public CRC64() {
        size = 8;
        name = "CRC64";
    }

    @Override
    public void update(byte[] buf, int off, int len) {
        final int end = off + len;
        int i=off;
        if (len > 7) {
            while ((i & 3) != 0) {
                crc = TABLE[0][(buf[i++] & 0xFF) ^ ((int)crc & 0xFF)]
^ (crc >>> 8);
            }
            for (int j = end - 3; i < j; i += 4) {
                int tmp = ((int)crc) ^ (int) LE_INT_HANDLE.get(buf, i);
                crc = TABLE[3][tmp & 0xFF] ^
                      TABLE[2][(tmp >>> 8) & 0xFF] ^
                      (crc >>> 32) ^
                      TABLE[1][(tmp >>> 16) & 0xFF] ^
                      TABLE[0][(tmp >>> 24) & 0xFF];
            }
        }
        while (i < end) {
             crc = TABLE[0][(buf[i++] & 0xFF) ^ ((int)crc & 0xFF)] ^
(crc >>> 8);
        }
    }

    @Override
    public byte[] finish() {
        long value = ~crc;
        crc = -1;

        byte[] buf = new byte[8];
        LE_LONG_HANDLE.set(buf, 0, value);

        return buf;
    }
}

Reply via email to