diff options
| -rw-r--r-- | compiler/optimizing/intrinsics_arm64.cc | 168 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_arm_vixl.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_mips64.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86.cc | 1 | ||||
| -rw-r--r-- | compiler/optimizing/intrinsics_x86_64.cc | 1 | ||||
| -rw-r--r-- | runtime/hidden_api.h | 1 | ||||
| -rw-r--r-- | runtime/image.cc | 2 | ||||
| -rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 1 | ||||
| -rw-r--r-- | runtime/intrinsics_list.h | 1 | ||||
| -rw-r--r-- | test/580-crc32/src/Main.java | 186 |
11 files changed, 310 insertions, 54 deletions
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 0b17c9d27e..7fb69b7463 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -2954,58 +2954,20 @@ void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) { __ Mvn(out, tmp); } -// The threshold for sizes of arrays to use the library provided implementation -// of CRC32.updateBytes instead of the intrinsic. -static constexpr int32_t kCRC32UpdateBytesThreshold = 64 * 1024; - -void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { - if (!codegen_->GetInstructionSetFeatures().HasCRC()) { - return; - } - - LocationSummary* locations - = new (allocator_) LocationSummary(invoke, - LocationSummary::kCallOnSlowPath, - kIntrinsified); - - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetInAt(2, Location::RegisterOrConstant(invoke->InputAt(2))); - locations->SetInAt(3, Location::RequiresRegister()); - locations->AddTemp(Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister()); -} - -// Lower the invoke of CRC32.updateBytes(int crc, byte[] b, int off, int len) +// Generate code using CRC32 instructions which calculates +// a CRC32 value of a byte. // -// Note: The intrinsic is not used if len exceeds a threshold. -void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { - DCHECK(codegen_->GetInstructionSetFeatures().HasCRC()); - - auto masm = GetVIXLAssembler(); - auto locations = invoke->GetLocations(); - - auto slow_path = - new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke); - codegen_->AddSlowPath(slow_path); - - Register length = WRegisterFrom(locations->InAt(3)); - __ Cmp(length, kCRC32UpdateBytesThreshold); - __ B(slow_path->GetEntryLabel(), hi); - - const uint32_t array_data_offset = - mirror::Array::DataOffset(Primitive::kPrimByte).Uint32Value(); - Register ptr = XRegisterFrom(locations->GetTemp(0)); - Register array = XRegisterFrom(locations->InAt(1)); - auto offset = locations->InAt(2); - if (offset.IsConstant()) { - int32_t offset_value = offset.GetConstant()->AsIntConstant()->GetValue(); - __ Add(ptr, array, array_data_offset + offset_value); - } else { - __ Add(ptr, array, array_data_offset); - __ Add(ptr, ptr, XRegisterFrom(offset)); - } - +// Parameters: +// masm - VIXL macro assembler +// crc - a register holding an initial CRC value +// ptr - a register holding a memory address of bytes +// length - a register holding a number of bytes to process +// out - a register to put a result of calculation +static void GenerateCodeForCalculationCRC32ValueOfBytes(MacroAssembler* masm, + const Register& crc, + const Register& ptr, + const Register& length, + const Register& out) { // The algorithm of CRC32 of bytes is: // crc = ~crc // process a few first bytes to make the array 8-byte aligned @@ -3029,8 +2991,7 @@ void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { Register len = temps.AcquireW(); Register array_elem = temps.AcquireW(); - Register out = WRegisterFrom(locations->Out()); - __ Mvn(out, WRegisterFrom(locations->InAt(0))); + __ Mvn(out, crc); __ Mov(len, length); __ Tbz(ptr, 0, &aligned2); @@ -3095,10 +3056,111 @@ void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { __ Bind(&done); __ Mvn(out, out); +} + +// The threshold for sizes of arrays to use the library provided implementation +// of CRC32.updateBytes instead of the intrinsic. +static constexpr int32_t kCRC32UpdateBytesThreshold = 64 * 1024; + +void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { + if (!codegen_->GetInstructionSetFeatures().HasCRC()) { + return; + } + + LocationSummary* locations = + new (allocator_) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(2, Location::RegisterOrConstant(invoke->InputAt(2))); + locations->SetInAt(3, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); +} + +// Lower the invoke of CRC32.updateBytes(int crc, byte[] b, int off, int len) +// +// Note: The intrinsic is not used if len exceeds a threshold. +void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateBytes(HInvoke* invoke) { + DCHECK(codegen_->GetInstructionSetFeatures().HasCRC()); + + auto masm = GetVIXLAssembler(); + auto locations = invoke->GetLocations(); + + auto slow_path = + new (codegen_->GetScopedAllocator()) IntrinsicSlowPathARM64(invoke); + codegen_->AddSlowPath(slow_path); + + Register length = WRegisterFrom(locations->InAt(3)); + __ Cmp(length, kCRC32UpdateBytesThreshold); + __ B(slow_path->GetEntryLabel(), hi); + + const uint32_t array_data_offset = + mirror::Array::DataOffset(Primitive::kPrimByte).Uint32Value(); + Register ptr = XRegisterFrom(locations->GetTemp(0)); + Register array = XRegisterFrom(locations->InAt(1)); + auto offset = locations->InAt(2); + if (offset.IsConstant()) { + int32_t offset_value = offset.GetConstant()->AsIntConstant()->GetValue(); + __ Add(ptr, array, array_data_offset + offset_value); + } else { + __ Add(ptr, array, array_data_offset); + __ Add(ptr, ptr, XRegisterFrom(offset)); + } + + Register crc = WRegisterFrom(locations->InAt(0)); + Register out = WRegisterFrom(locations->Out()); + + GenerateCodeForCalculationCRC32ValueOfBytes(masm, crc, ptr, length, out); __ Bind(slow_path->GetExitLabel()); } +void IntrinsicLocationsBuilderARM64::VisitCRC32UpdateByteBuffer(HInvoke* invoke) { + if (!codegen_->GetInstructionSetFeatures().HasCRC()) { + return; + } + + LocationSummary* locations = + new (allocator_) LocationSummary(invoke, + LocationSummary::kNoCall, + kIntrinsified); + + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetInAt(2, Location::RequiresRegister()); + locations->SetInAt(3, Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister()); +} + +// Lower the invoke of CRC32.updateByteBuffer(int crc, long addr, int off, int len) +// +// There is no need to generate code checking if addr is 0. +// The method updateByteBuffer is a private method of java.util.zip.CRC32. +// This guarantees no calls outside of the CRC32 class. +// An address of DirectBuffer is always passed to the call of updateByteBuffer. +// It might be an implementation of an empty DirectBuffer which can use a zero +// address but it must have the length to be zero. The current generated code +// correctly works with the zero length. +void IntrinsicCodeGeneratorARM64::VisitCRC32UpdateByteBuffer(HInvoke* invoke) { + DCHECK(codegen_->GetInstructionSetFeatures().HasCRC()); + + auto masm = GetVIXLAssembler(); + auto locations = invoke->GetLocations(); + + Register addr = XRegisterFrom(locations->InAt(1)); + Register ptr = XRegisterFrom(locations->GetTemp(0)); + __ Add(ptr, addr, XRegisterFrom(locations->InAt(2))); + + Register crc = WRegisterFrom(locations->InAt(0)); + Register length = WRegisterFrom(locations->InAt(3)); + Register out = WRegisterFrom(locations->Out()); + GenerateCodeForCalculationCRC32ValueOfBytes(masm, crc, ptr, length, out); +} + UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 88f1457c20..95752fcd01 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -3061,6 +3061,7 @@ UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update) UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateBytes) +UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32UpdateByteBuffer) UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 08ba0a0adf..8092a1c030 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -2698,6 +2698,7 @@ UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(MIPS, CRC32Update) UNIMPLEMENTED_INTRINSIC(MIPS, CRC32UpdateBytes) +UNIMPLEMENTED_INTRINSIC(MIPS, CRC32UpdateByteBuffer) UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 59d3ba2488..f5577c3efc 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -2348,6 +2348,7 @@ UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32Update) UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32UpdateBytes) +UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32UpdateByteBuffer) UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 1d94950e4d..5ad94697e8 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -3072,6 +3072,7 @@ UNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit) UNIMPLEMENTED_INTRINSIC(X86, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86, CRC32UpdateBytes) +UNIMPLEMENTED_INTRINSIC(X86, CRC32UpdateByteBuffer) UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOfAfter); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 4f0b61d88e..62ccd49adf 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2739,6 +2739,7 @@ UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite) UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update) UNIMPLEMENTED_INTRINSIC(X86_64, CRC32UpdateBytes) +UNIMPLEMENTED_INTRINSIC(X86_64, CRC32UpdateByteBuffer) UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf); UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter); diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h index 13bead28be..a0eeae2950 100644 --- a/runtime/hidden_api.h +++ b/runtime/hidden_api.h @@ -236,6 +236,7 @@ ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method) case Intrinsics::kUnsafeFullFence: case Intrinsics::kCRC32Update: case Intrinsics::kCRC32UpdateBytes: + case Intrinsics::kCRC32UpdateByteBuffer: case Intrinsics::kStringNewStringFromBytes: case Intrinsics::kStringNewStringFromChars: case Intrinsics::kStringNewStringFromString: diff --git a/runtime/image.cc b/runtime/image.cc index fe1d88fc42..b6bb0b15b4 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -29,7 +29,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '3', '\0' }; // Image reservation. +const uint8_t ImageHeader::kImageVersion[] = { '0', '7', '4', '\0' }; // CRC32UpdateBB intrinsic ImageHeader::ImageHeader(uint32_t image_reservation_size, uint32_t component_count, diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc index 16e118c9cf..2127f1d7bf 100644 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ b/runtime/interpreter/interpreter_intrinsics.cc @@ -560,6 +560,7 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */) UNIMPLEMENTED_CASE(CRC32Update /* (II)I */) UNIMPLEMENTED_CASE(CRC32UpdateBytes /* (I[BII)I */) + UNIMPLEMENTED_CASE(CRC32UpdateByteBuffer /* (IJII)I */) INTRINSIC_CASE(VarHandleFullFence) INTRINSIC_CASE(VarHandleAcquireFence) INTRINSIC_CASE(VarHandleReleaseFence) diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h index db43b243df..57e81a7a37 100644 --- a/runtime/intrinsics_list.h +++ b/runtime/intrinsics_list.h @@ -221,6 +221,7 @@ V(ReachabilityFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/ref/Reference;", "reachabilityFence", "(Ljava/lang/Object;)V") \ V(CRC32Update, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/util/zip/CRC32;", "update", "(II)I") \ V(CRC32UpdateBytes, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "updateBytes", "(I[BII)I") \ + V(CRC32UpdateByteBuffer, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/util/zip/CRC32;", "updateByteBuffer", "(IJII)I") \ SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V) #endif // ART_RUNTIME_INTRINSICS_LIST_H_ diff --git a/test/580-crc32/src/Main.java b/test/580-crc32/src/Main.java index 6199e9b2a9..dfc0b3c007 100644 --- a/test/580-crc32/src/Main.java +++ b/test/580-crc32/src/Main.java @@ -16,6 +16,7 @@ import java.util.zip.CRC32; import java.util.Random; +import java.nio.ByteBuffer; /** * The ART compiler can use intrinsics for the java.util.zip.CRC32 methods: @@ -343,8 +344,193 @@ public class Main { CRC32ByteArray(bytes, off, len)); } + private static long CRC32ByteBuffer(byte[] bytes, int off, int len) { + ByteBuffer buf = ByteBuffer.wrap(bytes, 0, off + len); + buf.position(off); + CRC32 crc32 = new CRC32(); + crc32.update(buf); + return crc32.getValue(); + } + + private static void TestCRC32UpdateByteBuffer() { + assertEqual(0L, CRC32ByteBuffer(new byte[] {}, 0, 0)); + assertEqual(0L, CRC32ByteBuffer(new byte[] {0}, 0, 0)); + assertEqual(0L, CRC32ByteBuffer(new byte[] {0}, 1, 0)); + assertEqual(0L, CRC32ByteBuffer(new byte[] {0, 0}, 1, 0)); + + assertEqual(CRC32Byte(0), CRC32ByteBuffer(new byte[] {0}, 0, 1)); + assertEqual(CRC32Byte(1), CRC32ByteBuffer(new byte[] {1}, 0, 1)); + assertEqual(CRC32Byte(0x0f), CRC32ByteBuffer(new byte[] {0x0f}, 0, 1)); + assertEqual(CRC32Byte(0xff), CRC32ByteBuffer(new byte[] {-1}, 0, 1)); + assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0), + CRC32ByteBuffer(new byte[] {0, 0, 0}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1), + CRC32ByteBuffer(new byte[] {1, 1, 1}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f), + CRC32ByteBuffer(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff), + CRC32ByteBuffer(new byte[] {-1, -1, -1}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(1, 2), + CRC32ByteBuffer(new byte[] {1, 2}, 0, 2)); + assertEqual( + CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE), + CRC32ByteBuffer(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4)); + + byte[] bytes = new byte[128 * 1024]; + Random rnd = new Random(0); + rnd.nextBytes(bytes); + + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024), + CRC32ByteBuffer(bytes, 0, 8 * 1024)); + + int off = rnd.nextInt(bytes.length / 2); + for (int len = 0; len <= 16; ++len) { + assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len), + CRC32ByteBuffer(bytes, off, len)); + } + + // Check there are no issues with unaligned accesses. + for (int o = 1; o < 8; ++o) { + for (int l = 0; l <= 16; ++l) { + assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l), + CRC32ByteBuffer(bytes, o, l)); + } + } + + int len = bytes.length / 2; + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1), + CRC32ByteBuffer(bytes, 0, len - 1)); + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len), + CRC32ByteBuffer(bytes, 0, len)); + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1), + CRC32ByteBuffer(bytes, 0, len + 1)); + + len = rnd.nextInt(bytes.length + 1); + off = rnd.nextInt(bytes.length - len); + assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len), + CRC32ByteBuffer(bytes, off, len)); + } + + private static long CRC32DirectByteBuffer(byte[] bytes, int off, int len) { + final int total_len = off + len; + ByteBuffer buf = ByteBuffer.allocateDirect(total_len).put(bytes, 0, total_len); + buf.position(off); + CRC32 crc32 = new CRC32(); + crc32.update(buf); + return crc32.getValue(); + } + + private static long CRC32ByteAndDirectByteBuffer(int value, byte[] bytes) { + ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes); + buf.position(0); + CRC32 crc32 = new CRC32(); + crc32.update(value); + crc32.update(buf); + return crc32.getValue(); + } + + private static long CRC32DirectByteBufferAndByte(byte[] bytes, int value) { + ByteBuffer buf = ByteBuffer.allocateDirect(bytes.length).put(bytes); + buf.position(0); + CRC32 crc32 = new CRC32(); + crc32.update(buf); + crc32.update(value); + return crc32.getValue(); + } + + private static void TestCRC32UpdateDirectByteBuffer() { + assertEqual(0L, CRC32DirectByteBuffer(new byte[] {}, 0, 0)); + assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0}, 0, 0)); + assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0}, 1, 0)); + assertEqual(0L, CRC32DirectByteBuffer(new byte[] {0, 0}, 1, 0)); + + assertEqual(CRC32Byte(0), CRC32DirectByteBuffer(new byte[] {0}, 0, 1)); + assertEqual(CRC32Byte(1), CRC32DirectByteBuffer(new byte[] {1}, 0, 1)); + assertEqual(CRC32Byte(0x0f), CRC32DirectByteBuffer(new byte[] {0x0f}, 0, 1)); + assertEqual(CRC32Byte(0xff), CRC32DirectByteBuffer(new byte[] {-1}, 0, 1)); + assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0), + CRC32DirectByteBuffer(new byte[] {0, 0, 0}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1), + CRC32DirectByteBuffer(new byte[] {1, 1, 1}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f), + CRC32DirectByteBuffer(new byte[] {0x0f, 0x0f, 0x0f}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff), + CRC32DirectByteBuffer(new byte[] {-1, -1, -1}, 0, 3)); + assertEqual(CRC32BytesUsingUpdateInt(1, 2), + CRC32DirectByteBuffer(new byte[] {1, 2}, 0, 2)); + assertEqual( + CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE), + CRC32DirectByteBuffer(new byte[] {0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE}, 0, 4)); + + assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0), + CRC32ByteAndDirectByteBuffer(0, new byte[] {0, 0})); + assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1), + CRC32ByteAndDirectByteBuffer(1, new byte[] {1, 1})); + assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f), + CRC32ByteAndDirectByteBuffer(0x0f, new byte[] {0x0f, 0x0f})); + assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff), + CRC32ByteAndDirectByteBuffer(-1, new byte[] {-1, -1})); + assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3), + CRC32ByteAndDirectByteBuffer(1, new byte[] {2, 3})); + assertEqual( + CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE), + CRC32ByteAndDirectByteBuffer(0, new byte[] {-1, Byte.MIN_VALUE, Byte.MAX_VALUE})); + + assertEqual(CRC32BytesUsingUpdateInt(0, 0, 0), + CRC32DirectByteBufferAndByte(new byte[] {0, 0}, 0)); + assertEqual(CRC32BytesUsingUpdateInt(1, 1, 1), + CRC32DirectByteBufferAndByte(new byte[] {1, 1}, 1)); + assertEqual(CRC32BytesUsingUpdateInt(0x0f, 0x0f, 0x0f), + CRC32DirectByteBufferAndByte(new byte[] {0x0f, 0x0f}, 0x0f)); + assertEqual(CRC32BytesUsingUpdateInt(0xff, 0xff, 0xff), + CRC32DirectByteBufferAndByte(new byte[] {-1, -1}, -1)); + assertEqual(CRC32BytesUsingUpdateInt(1, 2, 3), + CRC32DirectByteBufferAndByte(new byte[] {1, 2}, 3)); + assertEqual( + CRC32BytesUsingUpdateInt(0, -1, Byte.MIN_VALUE, Byte.MAX_VALUE), + CRC32DirectByteBufferAndByte(new byte[] {0, -1, Byte.MIN_VALUE}, Byte.MAX_VALUE)); + + byte[] bytes = new byte[128 * 1024]; + Random rnd = new Random(0); + rnd.nextBytes(bytes); + + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, bytes.length), + CRC32DirectByteBuffer(bytes, 0, bytes.length)); + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, 8 * 1024), + CRC32DirectByteBuffer(bytes, 0, 8 * 1024)); + + int off = rnd.nextInt(bytes.length / 2); + for (int len = 0; len <= 16; ++len) { + assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len), + CRC32DirectByteBuffer(bytes, off, len)); + } + + // Check there are no issues with unaligned accesses. + for (int o = 1; o < 8; ++o) { + for (int l = 0; l <= 16; ++l) { + assertEqual(CRC32BytesUsingUpdateInt(bytes, o, l), + CRC32DirectByteBuffer(bytes, o, l)); + } + } + + int len = bytes.length / 2; + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len - 1), + CRC32DirectByteBuffer(bytes, 0, len - 1)); + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len), + CRC32DirectByteBuffer(bytes, 0, len)); + assertEqual(CRC32BytesUsingUpdateInt(bytes, 0, len + 1), + CRC32DirectByteBuffer(bytes, 0, len + 1)); + + len = rnd.nextInt(bytes.length + 1); + off = rnd.nextInt(bytes.length - len); + assertEqual(CRC32BytesUsingUpdateInt(bytes, off, len), + CRC32DirectByteBuffer(bytes, off, len)); + } + public static void main(String args[]) { TestCRC32Update(); TestCRC32UpdateBytes(); + TestCRC32UpdateByteBuffer(); + TestCRC32UpdateDirectByteBuffer(); } } |