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; } }
