RFR JDK-6321472: Add CRC-32C API

Staffan Friberg staffan.friberg at oracle.com
Tue Oct 21 17:28:50 UTC 2014


Hi Peter,

Thanks for the comments..
>
>   217                 if (Unsafe.ADDRESS_SIZE == 4) {
>   218                     // On 32 bit platforms read two ints instead of a single 64bit long
>
> When you're reading from byte[] using Unsafe (updateBytes), you have 
> the option of reading 64bit values on 64bit platforms. When you're 
> reading from DirectByteBuffer memory (updateDirectByteBuffer), you're 
> only using 32bit reads.
I will add a comment in the code for this decision. The reason is that 
read a long results in slightly worse performance in this case, in 
updateBytes it is faster. I was able to get it to run slightly faster by 
working directly with the address instead of always adding address + 
off, but this makes things worse in the 32bit case since all calculation 
will now be using long variables. So using the getInt as in the current 
code feels like the best solution as it strikes the best balance between 
32 and 64bit. Below is how updateByteBuffer looked with the rewrite I 
mentioned.


  ong address = ((DirectBuffer) buffer).address();
  crc = updateDirectByteBuffer(crc, address + pos, address + limit);


      private static int updateDirectByteBuffer(int crc, long adr, long end) {

         // Do only byte reads for arrays so short they can't be aligned
         if (end - adr >= 8) {

             // align on 8 bytes
             int alignLength = (8 - (int) (adr & 0x7)) & 0x7;
             for (long alignEnd = adr + alignLength; adr < alignEnd; adr++) {
                 crc = (crc >>> 8)
                         ^ byteTable[(crc ^ UNSAFE.getByte(adr)) & 0xFF];
             }

             if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
                 crc = Integer.reverseBytes(crc);
             }

             // slicing-by-8
             for (; adr < (end - Long.BYTES); adr += Long.BYTES) {
                 int firstHalf;
                 int secondHalf;
                 if (Unsafe.ADDRESS_SIZE == 4) {
                     // On 32 bit platforms read two ints instead of a single 64bit long
                     firstHalf = UNSAFE.getInt(adr);
                     secondHalf = UNSAFE.getInt(adr + Integer.BYTES);
                 } else {
                     long value = UNSAFE.getLong(adr);
                     if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                         firstHalf = (int) value;
                         secondHalf = (int) (value >>> 32);
                     } else { // ByteOrder.BIG_ENDIAN
                         firstHalf = (int) (value >>> 32);
                         secondHalf = (int) value;
                     }
                 }
                 crc ^= firstHalf;
                 if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                     crc = byteTable7[crc & 0xFF]
                             ^ byteTable6[(crc >>> 8) & 0xFF]
                             ^ byteTable5[(crc >>> 16) & 0xFF]
                             ^ byteTable4[crc >>> 24]
                             ^ byteTable3[secondHalf & 0xFF]
                             ^ byteTable2[(secondHalf >>> 8) & 0xFF]
                             ^ byteTable1[(secondHalf >>> 16) & 0xFF]
                             ^ byteTable0[secondHalf >>> 24];
                 } else { // ByteOrder.BIG_ENDIAN
                     crc = byteTable0[secondHalf & 0xFF]
                             ^ byteTable1[(secondHalf >>> 8) & 0xFF]
                             ^ byteTable2[(secondHalf >>> 16) & 0xFF]
                             ^ byteTable3[secondHalf >>> 24]
                             ^ byteTable4[crc & 0xFF]
                             ^ byteTable5[(crc >>> 8) & 0xFF]
                             ^ byteTable6[(crc >>> 16) & 0xFF]
                             ^ byteTable7[crc >>> 24];
                 }
             }

             if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
                 crc = Integer.reverseBytes(crc);
             }
         }

         // Tail
         for (; adr < end; adr++) {
             crc = (crc >>> 8)
                     ^ byteTable[(crc ^ UNSAFE.getByte(adr)) & 0xFF];
         }

         return crc;
     }


>
> Also, in updateBytes, the usage of 
> Unsafe.ARRAY_INT_INDEX_SCALE/ARRAY_LONG_INDEX_SCALE to index a byte 
> array sounds a little scary. To be ultra portable you could check that 
> ARRAY_BYTE_INDEX_SCALE == 1 first and refuse to use Unsafe for byte 
> arrays if it is not 1. Then use Integer.BYTES/Long.BYTES to manipulate 
> 'offsets' instead. In updateDirectByteBuffer it would be more 
> appropriate to use Integer.BYTES/Long.BYTES too.
Good idea. Added a check in the initial if statement and it will get 
automatically optimized away.

>   225                         firstHalf = (int) (value & 0xFFFFFFFF);
>   226                         secondHalf = (int) (value >>> 32);
>   227                     } else { // ByteOrder.BIG_ENDIAN
>   228                         firstHalf = (int) (value >>> 32);
>   229                         secondHalf = (int) (value & 0xFFFFFFFF);
>
> firstHalf = (int) value; // this is equivalent for line 225
> secondHalf = (int) value; // this is equivalent for line 229
Done.

Here is the latest webrev, 
http://cr.openjdk.java.net/~sfriberg/JDK-6321472/webrev.03

Cheers,
Staffan



More information about the core-libs-dev mailing list