Adding a case to handle read-only BB.

This commit is contained in:
Sunil Ramchandra Pawar 2025-03-27 13:04:59 +05:30
parent fb2aa5f386
commit 6f413eef87
2 changed files with 37 additions and 3 deletions

View File

@ -163,6 +163,7 @@ public class FastByteOperations
*/ */
static final long BYTE_ARRAY_BASE_OFFSET; static final long BYTE_ARRAY_BASE_OFFSET;
static final long DIRECT_BUFFER_ADDRESS_OFFSET; static final long DIRECT_BUFFER_ADDRESS_OFFSET;
static final long HEAP_HB_FIELD;
static static
{ {
@ -195,6 +196,8 @@ public class FastByteOperations
{ {
BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address"));
HEAP_HB_FIELD = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb"));
} }
catch (Exception e) catch (Exception e)
{ {
@ -269,16 +272,31 @@ public class FastByteOperations
{ {
Object src; Object src;
long srcOffset; long srcOffset;
if (srcBuf.hasArray())
// Heap ByteBuffer (Mutable)
if (srcBuf.hasArray() && !srcBuf.isReadOnly())
{ {
src = srcBuf.array(); src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD);
srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); srcOffset = BYTE_ARRAY_BASE_OFFSET;
} }
// Read-Only Heap ByteBuffer (Still has hb but read-only)
else if (srcBuf.isReadOnly() && !srcBuf.isDirect())
{
src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD);
srcOffset = BYTE_ARRAY_BASE_OFFSET;
if (src == null)
{
throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct.");
}
}
// Direct ByteBuffer
else else
{ {
src = null; src = null;
srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET); srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET);
} }
copy(src, srcOffset + srcPosition, trgBuf, trgPosition, length); copy(src, srcOffset + srcPosition, trgBuf, trgPosition, length);
} }

View File

@ -50,6 +50,22 @@ public class FastByteOperationsTest
testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, false), UO); testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, false), UO);
} }
@Test
public void testFastByteCopyReadOnly()
{
byte[] bytes1 = new byte[128];
byte[] empty = new byte[128];
rand.nextBytes(bytes1);
testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, true), PJO);
testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, false), PJO);
testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, true), PJO);
testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, false), PJO);
testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, true), UO);
testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, false), UO);
testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, true), UO);
testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, false), UO);
}
private void testCopy(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops) private void testCopy(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops)
{ {
byte[] result = new byte[src.remaining()]; byte[] result = new byte[src.remaining()];