2021-03-19 17:22:28 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2021 The Netty Project
|
|
|
|
*
|
|
|
|
* The Netty Project licenses this file to you under the Apache License,
|
|
|
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
|
|
|
* with the License. You may obtain a copy of the License at:
|
|
|
|
*
|
|
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
* License for the specific language governing permissions and limitations
|
|
|
|
* under the License.
|
|
|
|
*/
|
|
|
|
package io.netty.buffer.api.unsafe;
|
|
|
|
|
|
|
|
import io.netty.buffer.api.AllocatorControl;
|
|
|
|
import io.netty.buffer.api.Buffer;
|
|
|
|
import io.netty.buffer.api.BufferAllocator;
|
|
|
|
import io.netty.buffer.api.ByteCursor;
|
|
|
|
import io.netty.buffer.api.Drop;
|
|
|
|
import io.netty.buffer.api.Owned;
|
|
|
|
import io.netty.buffer.api.RcSupport;
|
|
|
|
import io.netty.buffer.api.ReadableComponent;
|
|
|
|
import io.netty.buffer.api.ReadableComponentProcessor;
|
|
|
|
import io.netty.buffer.api.WritableComponent;
|
|
|
|
import io.netty.buffer.api.WritableComponentProcessor;
|
|
|
|
import io.netty.buffer.api.internal.ArcDrop;
|
|
|
|
import io.netty.buffer.api.internal.Statics;
|
|
|
|
import io.netty.util.internal.PlatformDependent;
|
|
|
|
|
|
|
|
import java.lang.ref.Reference;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.ByteOrder;
|
|
|
|
|
|
|
|
import static io.netty.buffer.api.internal.Statics.bufferIsClosed;
|
|
|
|
import static io.netty.buffer.api.internal.Statics.bufferIsReadOnly;
|
|
|
|
import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;
|
|
|
|
|
|
|
|
public class UnsafeBuffer extends RcSupport<Buffer, UnsafeBuffer> implements Buffer, ReadableComponent,
|
|
|
|
WritableComponent {
|
|
|
|
private static final int CLOSED_SIZE = -1;
|
|
|
|
private static final boolean ACCESS_UNALIGNED = PlatformDependent.isUnaligned();
|
|
|
|
private UnsafeMemory memory; // The memory liveness; monitored by Cleaner.
|
|
|
|
private Object base; // On-heap address reference object, or null for off-heap.
|
|
|
|
private long baseOffset; // Offset of this buffer into the memory.
|
|
|
|
private long address; // Resolved address (baseOffset + memory.address).
|
|
|
|
private int rsize;
|
|
|
|
private int wsize;
|
|
|
|
private final AllocatorControl control;
|
|
|
|
private ByteOrder order;
|
|
|
|
private boolean flipBytes;
|
|
|
|
private boolean readOnly;
|
|
|
|
private int roff;
|
|
|
|
private int woff;
|
|
|
|
|
|
|
|
public UnsafeBuffer(UnsafeMemory memory, long offset, int size, AllocatorControl allocatorControl,
|
|
|
|
Drop<UnsafeBuffer> drop) {
|
|
|
|
super(new MakeInaccisbleOnDrop(ArcDrop.wrap(drop)));
|
|
|
|
this.memory = memory;
|
|
|
|
base = memory.base;
|
|
|
|
baseOffset = offset;
|
|
|
|
address = memory.address + offset;
|
|
|
|
rsize = size;
|
|
|
|
wsize = size;
|
|
|
|
control = allocatorControl;
|
|
|
|
order = ByteOrder.nativeOrder();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "Buffer[roff:" + roff + ", woff:" + woff + ", cap:" + rsize + ']';
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer order(ByteOrder order) {
|
|
|
|
this.order = order;
|
|
|
|
flipBytes = order != ByteOrder.nativeOrder();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteOrder order() {
|
|
|
|
return order;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int capacity() {
|
2021-03-27 13:40:25 +01:00
|
|
|
return Math.max(0, rsize); // Use Math.max to make capacity of closed buffer equal to zero.
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readerOffset() {
|
|
|
|
return roff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer readerOffset(int offset) {
|
2021-03-27 13:20:07 +01:00
|
|
|
checkRead(offset, 0);
|
2021-03-19 17:22:28 +01:00
|
|
|
roff = offset;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int writerOffset() {
|
|
|
|
return woff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writerOffset(int offset) {
|
2021-03-27 13:20:07 +01:00
|
|
|
checkWrite(offset, 0);
|
2021-03-19 17:22:28 +01:00
|
|
|
woff = offset;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer fill(byte value) {
|
|
|
|
checkSet(0, capacity());
|
2021-03-27 13:20:07 +01:00
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
2021-03-19 17:22:28 +01:00
|
|
|
try {
|
|
|
|
PlatformDependent.setMemory(base, address, rsize, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long nativeAddress() {
|
|
|
|
return base == null? address : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer readOnly(boolean readOnly) {
|
|
|
|
this.readOnly = readOnly;
|
|
|
|
wsize = readOnly? CLOSED_SIZE : rsize;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readOnly() {
|
|
|
|
return readOnly;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer slice(int offset, int length) {
|
2021-03-27 13:40:25 +01:00
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("Length cannot be negative: " + length + '.');
|
|
|
|
}
|
2021-03-27 13:20:07 +01:00
|
|
|
checkGet(offset, length);
|
2021-03-19 17:22:28 +01:00
|
|
|
ArcDrop<UnsafeBuffer> drop = (ArcDrop<UnsafeBuffer>) unsafeGetDrop();
|
|
|
|
drop.increment();
|
|
|
|
return new UnsafeBuffer(memory, baseOffset + offset, length, control, drop)
|
|
|
|
.writerOffset(length)
|
|
|
|
.order(order)
|
|
|
|
.readOnly(readOnly);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, byte[] dest, int destPos, int length) {
|
|
|
|
checkCopyIntoArgs(srcPos, length, destPos, dest.length);
|
|
|
|
copyIntoArray(srcPos, dest, destPos, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void copyIntoArray(int srcPos, byte[] dest, int destPos, int length) {
|
|
|
|
long destOffset = PlatformDependent.byteArrayBaseOffset();
|
|
|
|
try {
|
|
|
|
PlatformDependent.copyMemory(base, address + srcPos, dest, destOffset + destPos, length);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
Reference.reachabilityFence(dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, ByteBuffer dest, int destPos, int length) {
|
|
|
|
checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
|
|
|
|
if (dest.hasArray()) {
|
|
|
|
copyIntoArray(srcPos, dest.array(), dest.arrayOffset() + destPos, length);
|
|
|
|
} else {
|
|
|
|
assert dest.isDirect();
|
|
|
|
long destAddr = PlatformDependent.directBufferAddress(dest);
|
|
|
|
try {
|
|
|
|
PlatformDependent.copyMemory(base, address + srcPos, null, destAddr + destPos, length);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
Reference.reachabilityFence(dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkCopyIntoArgs(int srcPos, int length, int destPos, int destLength) {
|
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
|
|
|
if (srcPos < 0) {
|
|
|
|
throw new IllegalArgumentException("The srcPos cannot be negative: " + srcPos + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (rsize < srcPos + length) {
|
|
|
|
throw new IllegalArgumentException("The srcPos + length is beyond the end of the buffer: " +
|
|
|
|
"srcPos = " + srcPos + ", length = " + length + '.');
|
|
|
|
}
|
|
|
|
if (destPos < 0) {
|
|
|
|
throw new IllegalArgumentException("The destPos cannot be negative: " + destPos + '.');
|
|
|
|
}
|
|
|
|
if (destLength < destPos + length) {
|
|
|
|
throw new IllegalArgumentException("The destPos + length is beyond the end of the destination: " +
|
|
|
|
"destPos = " + destPos + ", length = " + length + '.');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void copyInto(int srcPos, Buffer dest, int destPos, int length) {
|
|
|
|
checkCopyIntoArgs(srcPos, length, destPos, dest.capacity());
|
2021-03-27 13:20:07 +01:00
|
|
|
if (dest.readOnly()) {
|
|
|
|
throw bufferIsReadOnly();
|
|
|
|
}
|
2021-03-19 17:22:28 +01:00
|
|
|
long nativeAddress = dest.nativeAddress();
|
|
|
|
try {
|
|
|
|
if (nativeAddress != 0) {
|
2021-03-27 13:20:07 +01:00
|
|
|
PlatformDependent.copyMemory(base, address + srcPos, null, nativeAddress + destPos, length);
|
2021-03-19 17:22:28 +01:00
|
|
|
} else if (dest instanceof UnsafeBuffer) {
|
|
|
|
UnsafeBuffer destUnsafe = (UnsafeBuffer) dest;
|
|
|
|
PlatformDependent.copyMemory(
|
|
|
|
base, address + srcPos, destUnsafe.base, destUnsafe.address + destPos, length);
|
|
|
|
} else {
|
|
|
|
Statics.copyToViaReverseCursor(this, srcPos, dest, destPos, length);
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
Reference.reachabilityFence(dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteCursor openCursor() {
|
|
|
|
return openCursor(readerOffset(), readableBytes());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteCursor openCursor(int fromOffset, int length) {
|
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
|
|
|
if (fromOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (capacity() < fromOffset + length) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset + length is beyond the end of the buffer: " +
|
|
|
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
|
|
|
}
|
|
|
|
return new ByteCursor() {
|
|
|
|
final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive.
|
|
|
|
final Object baseObj = base;
|
|
|
|
final long baseAddress = address;
|
|
|
|
int index = fromOffset;
|
|
|
|
final int end = index + length;
|
|
|
|
long longValue = -1;
|
|
|
|
byte byteValue = -1;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readLong() {
|
|
|
|
if (index + Long.BYTES <= end) {
|
|
|
|
try {
|
|
|
|
long value = PlatformDependent.getLong(baseObj, baseAddress + index);
|
|
|
|
longValue = BIG_ENDIAN_NATIVE_ORDER? value : Long.reverseBytes(value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
index += Long.BYTES;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getLong() {
|
|
|
|
return longValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readByte() {
|
|
|
|
if (index < end) {
|
|
|
|
try {
|
|
|
|
byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
|
|
|
return end - index;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteCursor openReverseCursor(int fromOffset, int length) {
|
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
|
|
|
if (fromOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset cannot be negative: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (length < 0) {
|
|
|
|
throw new IllegalArgumentException("The length cannot be negative: " + length + '.');
|
|
|
|
}
|
|
|
|
if (capacity() <= fromOffset) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset is beyond the end of the buffer: " + fromOffset + '.');
|
|
|
|
}
|
|
|
|
if (fromOffset - length < -1) {
|
|
|
|
throw new IllegalArgumentException("The fromOffset - length would underflow the buffer: " +
|
|
|
|
"fromOffset = " + fromOffset + ", length = " + length + '.');
|
|
|
|
}
|
|
|
|
return new ByteCursor() {
|
|
|
|
final UnsafeMemory memory = UnsafeBuffer.this.memory; // Keep memory alive.
|
|
|
|
final Object baseObj = base;
|
|
|
|
final long baseAddress = address;
|
|
|
|
int index = fromOffset;
|
|
|
|
final int end = index - length;
|
|
|
|
long longValue = -1;
|
|
|
|
byte byteValue = -1;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readLong() {
|
|
|
|
if (index - Long.BYTES >= end) {
|
|
|
|
index -= 7;
|
|
|
|
try {
|
|
|
|
long value = PlatformDependent.getLong(baseObj, baseAddress + index);
|
2021-03-27 13:20:07 +01:00
|
|
|
longValue = BIG_ENDIAN_NATIVE_ORDER? Long.reverseBytes(value) : value;
|
2021-03-19 17:22:28 +01:00
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
index--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getLong() {
|
|
|
|
return longValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean readByte() {
|
|
|
|
if (index > end) {
|
|
|
|
try {
|
|
|
|
byteValue = PlatformDependent.getByte(baseObj, baseAddress + index);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
index--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte getByte() {
|
|
|
|
return byteValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int currentOffset() {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int bytesLeft() {
|
|
|
|
return index - end;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-04-22 16:57:31 +02:00
|
|
|
public void ensureWritable(int size, int minimumGrowth, boolean allowCompaction) {
|
2021-03-19 17:22:28 +01:00
|
|
|
if (!isOwned()) {
|
|
|
|
throw attachTrace(new IllegalStateException(
|
|
|
|
"Buffer is not owned. Only owned buffers can call ensureWritable."));
|
|
|
|
}
|
|
|
|
if (size < 0) {
|
|
|
|
throw new IllegalArgumentException("Cannot ensure writable for a negative size: " + size + '.');
|
|
|
|
}
|
2021-04-22 16:57:31 +02:00
|
|
|
if (minimumGrowth < 0) {
|
|
|
|
throw new IllegalArgumentException("The minimum growth cannot be negative: " + minimumGrowth + '.');
|
|
|
|
}
|
2021-03-19 17:22:28 +01:00
|
|
|
if (rsize != wsize) {
|
|
|
|
throw bufferIsReadOnly();
|
|
|
|
}
|
|
|
|
if (writableBytes() >= size) {
|
|
|
|
// We already have enough space.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (allowCompaction && writableBytes() + readerOffset() >= size) {
|
|
|
|
// We can solve this with compaction.
|
|
|
|
compact();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate a bigger buffer.
|
2021-04-22 16:57:31 +02:00
|
|
|
long newSize = capacity() + (long) Math.max(size - writableBytes(), minimumGrowth);
|
2021-03-19 17:22:28 +01:00
|
|
|
BufferAllocator.checkSize(newSize);
|
|
|
|
UnsafeMemory memory = (UnsafeMemory) control.allocateUntethered(this, (int) newSize);
|
|
|
|
|
|
|
|
// Copy contents.
|
|
|
|
try {
|
|
|
|
PlatformDependent.copyMemory(base, address, memory.base, memory.address, rsize);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(this.memory);
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release old memory:
|
|
|
|
var drop = (Drop<UnsafeBuffer>) unsafeGetDrop();
|
|
|
|
int roff = this.roff;
|
|
|
|
int woff = this.woff;
|
|
|
|
drop.drop(this);
|
|
|
|
while (drop instanceof ArcDrop) {
|
|
|
|
drop = ((ArcDrop<UnsafeBuffer>) drop).unwrap();
|
|
|
|
}
|
|
|
|
unsafeSetDrop(new ArcDrop<>(drop));
|
|
|
|
this.roff = roff;
|
|
|
|
this.woff = woff;
|
|
|
|
|
|
|
|
this.memory = memory;
|
|
|
|
base = memory.base;
|
|
|
|
baseOffset = 0;
|
|
|
|
address = memory.address;
|
|
|
|
rsize = memory.size;
|
|
|
|
wsize = memory.size;
|
|
|
|
drop.attach(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2021-04-29 15:34:04 +02:00
|
|
|
public Buffer split(int splitOffset) {
|
2021-04-22 16:57:31 +02:00
|
|
|
if (splitOffset < 0) {
|
|
|
|
throw new IllegalArgumentException("The split offset cannot be negative: " + splitOffset + '.');
|
|
|
|
}
|
|
|
|
if (capacity() < splitOffset) {
|
|
|
|
throw new IllegalArgumentException("The split offset cannot be greater than the buffer capacity, " +
|
|
|
|
"but the split offset was " + splitOffset + ", and capacity is " + capacity() + '.');
|
|
|
|
}
|
2021-03-19 17:22:28 +01:00
|
|
|
if (!isOwned()) {
|
2021-04-29 15:34:04 +02:00
|
|
|
throw attachTrace(new IllegalStateException("Cannot split a buffer that is not owned."));
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
var drop = (ArcDrop<UnsafeBuffer>) unsafeGetDrop();
|
|
|
|
unsafeSetDrop(new ArcDrop<>(drop));
|
|
|
|
// TODO maybe incrementing the existing ArcDrop is enough; maybe we don't need to wrap it in another ArcDrop.
|
2021-04-29 15:34:04 +02:00
|
|
|
var splitBuffer = new UnsafeBuffer(memory, baseOffset, splitOffset, control, new ArcDrop<>(drop.increment()));
|
|
|
|
splitBuffer.woff = Math.min(woff, splitOffset);
|
|
|
|
splitBuffer.roff = Math.min(roff, splitOffset);
|
|
|
|
splitBuffer.order(order());
|
2021-03-19 17:22:28 +01:00
|
|
|
boolean readOnly = readOnly();
|
2021-04-29 15:34:04 +02:00
|
|
|
splitBuffer.readOnly(readOnly);
|
2021-04-22 16:57:31 +02:00
|
|
|
rsize -= splitOffset;
|
|
|
|
baseOffset += splitOffset;
|
|
|
|
address += splitOffset;
|
2021-03-19 17:22:28 +01:00
|
|
|
if (!readOnly) {
|
|
|
|
wsize = rsize;
|
|
|
|
}
|
2021-04-22 16:57:31 +02:00
|
|
|
woff = Math.max(woff, splitOffset) - splitOffset;
|
|
|
|
roff = Math.max(roff, splitOffset) - splitOffset;
|
2021-04-29 15:34:04 +02:00
|
|
|
return splitBuffer;
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void compact() {
|
|
|
|
if (!isOwned()) {
|
|
|
|
throw attachTrace(new IllegalStateException("Buffer must be owned in order to compact."));
|
|
|
|
}
|
|
|
|
if (readOnly()) {
|
|
|
|
throw new IllegalStateException("Buffer must be writable in order to compact, but was read-only.");
|
|
|
|
}
|
|
|
|
if (roff == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
PlatformDependent.copyMemory(base, address + roff, base, address, woff - roff);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
woff -= roff;
|
|
|
|
roff = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countComponents() {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countReadableComponents() {
|
|
|
|
return readableBytes() > 0? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countWritableComponents() {
|
|
|
|
return writableBytes() > 0? 1 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// <editor-fold defaultstate="collapsed" desc="Readable/WritableComponent implementation.">
|
|
|
|
@Override
|
|
|
|
public boolean hasReadableArray() {
|
|
|
|
return base instanceof byte[];
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte[] readableArray() {
|
|
|
|
checkHasReadableArray();
|
|
|
|
return (byte[]) base;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readableArrayOffset() {
|
|
|
|
checkHasReadableArray();
|
|
|
|
return Math.toIntExact(address + roff - PlatformDependent.byteArrayBaseOffset());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkHasReadableArray() {
|
|
|
|
if (!hasReadableArray()) {
|
|
|
|
throw new UnsupportedOperationException("No readable array available.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readableArrayLength() {
|
|
|
|
return woff - roff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readableNativeAddress() {
|
|
|
|
return nativeAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteBuffer readableBuffer() {
|
|
|
|
final ByteBuffer buf;
|
|
|
|
if (hasReadableArray()) {
|
|
|
|
buf = ByteBuffer.wrap(readableArray()).slice(readableArrayOffset(), readableArrayLength());
|
|
|
|
} else {
|
|
|
|
buf = PlatformDependent.directBuffer(address + roff, readableBytes());
|
|
|
|
}
|
|
|
|
return buf.asReadOnlyBuffer().order(order());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasWritableArray() {
|
|
|
|
return hasReadableArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte[] writableArray() {
|
|
|
|
checkHasWritableArray();
|
|
|
|
return (byte[]) base;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int writableArrayOffset() {
|
|
|
|
checkHasWritableArray();
|
|
|
|
return Math.toIntExact(address + woff - PlatformDependent.byteArrayBaseOffset());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkHasWritableArray() {
|
|
|
|
if (!hasReadableArray()) {
|
|
|
|
throw new UnsupportedOperationException("No writable array available.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int writableArrayLength() {
|
|
|
|
return capacity() - woff;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long writableNativeAddress() {
|
|
|
|
return nativeAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteBuffer writableBuffer() {
|
|
|
|
final ByteBuffer buf;
|
|
|
|
if (hasWritableArray()) {
|
|
|
|
buf = ByteBuffer.wrap(writableArray()).slice(writableArrayOffset(), writableArrayLength());
|
|
|
|
} else {
|
|
|
|
buf = PlatformDependent.directBuffer(address + woff, writableBytes());
|
|
|
|
}
|
|
|
|
return buf.order(order());
|
|
|
|
}
|
|
|
|
// </editor-fold>
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public <E extends Exception> int forEachReadable(int initialIndex, ReadableComponentProcessor<E> processor)
|
|
|
|
throws E {
|
|
|
|
checkRead(readerOffset(), Math.max(1, readableBytes()));
|
|
|
|
return processor.process(initialIndex, this)? 1 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public <E extends Exception> int forEachWritable(int initialIndex, WritableComponentProcessor<E> processor)
|
|
|
|
throws E {
|
|
|
|
checkWrite(writerOffset(), Math.max(1, writableBytes()));
|
|
|
|
return processor.process(initialIndex, this)? 1 : -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte readByte() {
|
|
|
|
checkRead(roff, Byte.BYTES);
|
|
|
|
try {
|
|
|
|
var value = loadByte(address + roff);
|
|
|
|
roff += Byte.BYTES;
|
|
|
|
return value;
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte getByte(int roff) {
|
|
|
|
checkGet(roff, Byte.BYTES);
|
|
|
|
try {
|
|
|
|
return loadByte(address + roff);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedByte() {
|
|
|
|
return readByte() & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getUnsignedByte(int roff) {
|
|
|
|
return getByte(roff) & 0xFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeByte(byte value) {
|
|
|
|
checkWrite(woff, Byte.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Byte.BYTES;
|
|
|
|
try {
|
|
|
|
storeByte(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setByte(int woff, byte value) {
|
|
|
|
checkSet(woff, Byte.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeByte(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeUnsignedByte(int value) {
|
|
|
|
checkWrite(woff, Byte.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Byte.BYTES;
|
|
|
|
try {
|
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setUnsignedByte(int woff, int value) {
|
|
|
|
checkSet(woff, Byte.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char readChar() {
|
|
|
|
checkRead(roff, Character.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Character.BYTES;
|
|
|
|
return loadChar(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public char getChar(int roff) {
|
|
|
|
checkGet(roff, Character.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadChar(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeChar(char value) {
|
|
|
|
checkWrite(woff, Character.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Character.BYTES;
|
|
|
|
try {
|
|
|
|
storeChar(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setChar(int woff, char value) {
|
|
|
|
checkSet(woff, Character.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeChar(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public short readShort() {
|
|
|
|
checkRead(roff, Short.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Short.BYTES;
|
|
|
|
return loadShort(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public short getShort(int roff) {
|
|
|
|
checkGet(roff, Short.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadShort(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedShort() {
|
|
|
|
return readShort() & 0xFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getUnsignedShort(int roff) {
|
|
|
|
return getShort(roff) & 0xFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeShort(short value) {
|
|
|
|
checkWrite(woff, Short.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Short.BYTES;
|
|
|
|
try {
|
|
|
|
storeShort(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setShort(int woff, short value) {
|
|
|
|
checkSet(woff, Short.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeShort(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeUnsignedShort(int value) {
|
|
|
|
checkWrite(woff, Short.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Short.BYTES;
|
|
|
|
try {
|
|
|
|
storeShort(offset, (short) (value & 0xFFFF));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setUnsignedShort(int woff, int value) {
|
|
|
|
checkSet(woff, Short.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeShort(offset, (short) (value & 0xFFFF));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readMedium() {
|
|
|
|
checkRead(roff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + roff;
|
2021-03-19 17:22:28 +01:00
|
|
|
int value = order() == ByteOrder.BIG_ENDIAN ?
|
2021-03-27 13:20:07 +01:00
|
|
|
loadByte(offset) << 16 |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) & 0xFF :
|
|
|
|
loadByte(offset) & 0xFF |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) << 16;
|
2021-03-19 17:22:28 +01:00
|
|
|
roff += 3;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getMedium(int roff) {
|
|
|
|
checkGet(roff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + roff;
|
2021-03-19 17:22:28 +01:00
|
|
|
return order() == ByteOrder.BIG_ENDIAN?
|
2021-03-27 13:20:07 +01:00
|
|
|
loadByte(offset) << 16 |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) & 0xFF :
|
|
|
|
loadByte(offset) & 0xFF |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) << 16;
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readUnsignedMedium() {
|
|
|
|
checkRead(roff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + roff;
|
2021-03-19 17:22:28 +01:00
|
|
|
int value = order() == ByteOrder.BIG_ENDIAN?
|
2021-03-27 13:20:07 +01:00
|
|
|
(loadByte(offset) << 16 |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) & 0xFF) & 0xFFFFFF :
|
|
|
|
(loadByte(offset) & 0xFF |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) << 16) & 0xFFFFFF;
|
2021-03-19 17:22:28 +01:00
|
|
|
roff += 3;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getUnsignedMedium(int roff) {
|
|
|
|
checkGet(roff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + roff;
|
2021-03-19 17:22:28 +01:00
|
|
|
return order() == ByteOrder.BIG_ENDIAN?
|
2021-03-27 13:20:07 +01:00
|
|
|
(loadByte(offset) << 16 |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) & 0xFF) & 0xFFFFFF :
|
|
|
|
(loadByte(offset) & 0xFF |
|
|
|
|
(loadByte(offset + 1) & 0xFF) << 8 |
|
|
|
|
loadByte(offset + 2) << 16) & 0xFFFFFF;
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeMedium(int value) {
|
|
|
|
checkWrite(woff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + woff;
|
2021-03-19 17:22:28 +01:00
|
|
|
if (order() == ByteOrder.BIG_ENDIAN) {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value >> 16));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
} else {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value >> 16 & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
woff += 3;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setMedium(int woff, int value) {
|
|
|
|
checkSet(woff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + woff;
|
2021-03-19 17:22:28 +01:00
|
|
|
if (order() == ByteOrder.BIG_ENDIAN) {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value >> 16));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
} else {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value >> 16 & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeUnsignedMedium(int value) {
|
|
|
|
checkWrite(woff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + woff;
|
2021-03-19 17:22:28 +01:00
|
|
|
if (order() == ByteOrder.BIG_ENDIAN) {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value >> 16));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
} else {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value >> 16 & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
woff += 3;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setUnsignedMedium(int woff, int value) {
|
|
|
|
checkSet(woff, 3);
|
2021-03-27 13:20:07 +01:00
|
|
|
long offset = address + woff;
|
2021-03-19 17:22:28 +01:00
|
|
|
if (order() == ByteOrder.BIG_ENDIAN) {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value >> 16));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
} else {
|
2021-03-27 13:20:07 +01:00
|
|
|
storeByte(offset, (byte) (value & 0xFF));
|
|
|
|
storeByte(offset + 1, (byte) (value >> 8 & 0xFF));
|
|
|
|
storeByte(offset + 2, (byte) (value >> 16 & 0xFF));
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int readInt() {
|
|
|
|
checkRead(roff, Integer.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Integer.BYTES;
|
|
|
|
return loadInt(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getInt(int roff) {
|
|
|
|
checkGet(roff, Integer.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadInt(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readUnsignedInt() {
|
|
|
|
return readInt() & 0x0000_0000_FFFF_FFFFL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getUnsignedInt(int roff) {
|
|
|
|
return getInt(roff) & 0x0000_0000_FFFF_FFFFL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeInt(int value) {
|
|
|
|
checkWrite(woff, Integer.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Integer.BYTES;
|
|
|
|
try {
|
|
|
|
storeInt(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setInt(int woff, int value) {
|
|
|
|
checkSet(woff, Integer.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeInt(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeUnsignedInt(long value) {
|
|
|
|
checkWrite(woff, Integer.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Integer.BYTES;
|
|
|
|
try {
|
|
|
|
storeInt(offset, (int) (value & 0xFFFF_FFFFL));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setUnsignedInt(int woff, long value) {
|
|
|
|
checkSet(woff, Integer.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeInt(offset, (int) (value & 0xFFFF_FFFFL));
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float readFloat() {
|
|
|
|
checkRead(roff, Float.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Float.BYTES;
|
|
|
|
return loadFloat(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public float getFloat(int roff) {
|
|
|
|
checkGet(roff, Float.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadFloat(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeFloat(float value) {
|
|
|
|
checkWrite(woff, Float.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Float.BYTES;
|
|
|
|
try {
|
|
|
|
storeFloat(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setFloat(int woff, float value) {
|
|
|
|
checkSet(woff, Float.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeFloat(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long readLong() {
|
|
|
|
checkRead(roff, Long.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Long.BYTES;
|
|
|
|
return loadLong(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getLong(int roff) {
|
|
|
|
checkGet(roff, Long.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadLong(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeLong(long value) {
|
|
|
|
checkWrite(woff, Long.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Long.BYTES;
|
|
|
|
try {
|
|
|
|
storeLong(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setLong(int woff, long value) {
|
|
|
|
checkSet(woff, Long.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeLong(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double readDouble() {
|
|
|
|
checkRead(roff, Double.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
roff += Double.BYTES;
|
|
|
|
return loadDouble(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public double getDouble(int roff) {
|
|
|
|
checkGet(roff, Double.BYTES);
|
|
|
|
try {
|
|
|
|
long offset = address + roff;
|
|
|
|
return loadDouble(offset);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer writeDouble(double value) {
|
|
|
|
checkWrite(woff, Double.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
woff += Double.BYTES;
|
|
|
|
try {
|
|
|
|
storeDouble(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Buffer setDouble(int woff, double value) {
|
|
|
|
checkSet(woff, Double.BYTES);
|
|
|
|
long offset = address + woff;
|
|
|
|
try {
|
|
|
|
storeDouble(offset, value);
|
|
|
|
} finally {
|
|
|
|
Reference.reachabilityFence(memory);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Owned<UnsafeBuffer> prepareSend() {
|
|
|
|
var order = order();
|
|
|
|
var roff = this.roff;
|
|
|
|
var woff = this.woff;
|
|
|
|
var readOnly = readOnly();
|
|
|
|
UnsafeMemory memory = this.memory;
|
|
|
|
AllocatorControl control = this.control;
|
|
|
|
long baseOffset = this.baseOffset;
|
|
|
|
int rsize = this.rsize;
|
|
|
|
makeInaccessible();
|
|
|
|
return new Owned<UnsafeBuffer>() {
|
|
|
|
@Override
|
|
|
|
public UnsafeBuffer transferOwnership(Drop<UnsafeBuffer> drop) {
|
|
|
|
UnsafeBuffer copy = new UnsafeBuffer(memory, baseOffset, rsize, control, drop);
|
|
|
|
copy.order(order);
|
|
|
|
copy.roff = roff;
|
|
|
|
copy.woff = woff;
|
|
|
|
copy.readOnly(readOnly);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Drop<UnsafeBuffer> unsafeGetDrop() {
|
|
|
|
MakeInaccisbleOnDrop drop = (MakeInaccisbleOnDrop) super.unsafeGetDrop();
|
|
|
|
return drop.delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void unsafeSetDrop(Drop<UnsafeBuffer> replacement) {
|
|
|
|
super.unsafeSetDrop(new MakeInaccisbleOnDrop(replacement));
|
|
|
|
}
|
|
|
|
|
|
|
|
private static final class MakeInaccisbleOnDrop implements Drop<UnsafeBuffer> {
|
|
|
|
final Drop<UnsafeBuffer> delegate;
|
|
|
|
|
|
|
|
private MakeInaccisbleOnDrop(Drop<UnsafeBuffer> delegate) {
|
|
|
|
this.delegate = delegate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void drop(UnsafeBuffer buf) {
|
|
|
|
try {
|
|
|
|
delegate.drop(buf);
|
|
|
|
} finally {
|
|
|
|
buf.makeInaccessible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void attach(UnsafeBuffer buf) {
|
|
|
|
delegate.attach(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "UnsafeDrop(" + delegate + ')';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void makeInaccessible() {
|
2021-03-27 13:40:25 +01:00
|
|
|
roff = 0;
|
|
|
|
woff = 0;
|
2021-03-19 17:22:28 +01:00
|
|
|
rsize = CLOSED_SIZE;
|
|
|
|
wsize = CLOSED_SIZE;
|
2021-03-27 13:20:07 +01:00
|
|
|
readOnly = false;
|
2021-03-19 17:22:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isOwned() {
|
|
|
|
return super.isOwned() && ((ArcDrop<UnsafeBuffer>) unsafeGetDrop()).isOwned();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int countBorrows() {
|
|
|
|
return super.countBorrows() + ((ArcDrop<UnsafeBuffer>) unsafeGetDrop()).countBorrows();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkRead(int index, int size) {
|
|
|
|
if (index < 0 || woff < index + size) {
|
|
|
|
throw readAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkGet(int index, int size) {
|
|
|
|
if (index < 0 || rsize < index + size) {
|
|
|
|
throw readAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkWrite(int index, int size) {
|
|
|
|
if (index < roff || wsize < index + size) {
|
|
|
|
throw writeAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkSet(int index, int size) {
|
|
|
|
if (index < 0 || wsize < index + size) {
|
|
|
|
throw writeAccessCheckException(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private RuntimeException readAccessCheckException(int index) {
|
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
|
|
|
return outOfBounds(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
private RuntimeException writeAccessCheckException(int index) {
|
|
|
|
if (rsize == CLOSED_SIZE) {
|
|
|
|
throw bufferIsClosed();
|
|
|
|
}
|
|
|
|
if (wsize != rsize) {
|
|
|
|
return bufferIsReadOnly();
|
|
|
|
}
|
|
|
|
return outOfBounds(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
private IndexOutOfBoundsException outOfBounds(int index) {
|
|
|
|
return new IndexOutOfBoundsException(
|
|
|
|
"Index " + index + " is out of bounds: [read 0 to " + woff + ", write 0 to " +
|
|
|
|
rsize + "].");
|
|
|
|
}
|
|
|
|
|
|
|
|
private byte loadByte(long off) {
|
|
|
|
return PlatformDependent.getByte(base, off);
|
|
|
|
}
|
|
|
|
|
|
|
|
private char loadChar(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
var value = PlatformDependent.getChar(base, offset);
|
|
|
|
return flipBytes? Character.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
return loadCharUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private char loadCharUnaligned(long offset) {
|
|
|
|
final char value;
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 1) == 0) {
|
|
|
|
value = PlatformDependent.getChar(b, offset);
|
|
|
|
} else {
|
|
|
|
value = (char) (PlatformDependent.getByte(b, offset) << 8 |
|
|
|
|
PlatformDependent.getByte(b, offset + 1));
|
|
|
|
}
|
|
|
|
return flipBytes? Character.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private short loadShort(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
var value = PlatformDependent.getShort(base, offset);
|
|
|
|
return flipBytes? Short.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
return loadShortUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private short loadShortUnaligned(long offset) {
|
|
|
|
final short value;
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 1) == 0) {
|
|
|
|
value = PlatformDependent.getShort(b, offset);
|
|
|
|
} else {
|
|
|
|
value = (short) (PlatformDependent.getByte(b, offset) << 8 |
|
|
|
|
PlatformDependent.getByte(b, offset + 1));
|
|
|
|
}
|
|
|
|
return flipBytes? Short.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private int loadInt(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
var value = PlatformDependent.getInt(base, offset);
|
|
|
|
return flipBytes? Integer.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
return loadIntUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private int loadIntUnaligned(long offset) {
|
|
|
|
final int value;
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 3) == 0) {
|
|
|
|
value = PlatformDependent.getInt(b, offset);
|
|
|
|
} else if ((offset & 1) == 0) {
|
|
|
|
value = PlatformDependent.getShort(b, offset) << 16 |
|
|
|
|
PlatformDependent.getShort(b, offset + 2);
|
|
|
|
} else {
|
|
|
|
value = PlatformDependent.getByte(b, offset) << 24 |
|
|
|
|
PlatformDependent.getByte(b, offset + 1) << 16 |
|
|
|
|
PlatformDependent.getByte(b, offset + 2) << 8 |
|
|
|
|
PlatformDependent.getByte(b, offset + 3);
|
|
|
|
}
|
|
|
|
return flipBytes? Integer.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private float loadFloat(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
if (flipBytes) {
|
|
|
|
var value = PlatformDependent.getInt(base, offset);
|
|
|
|
return Float.intBitsToFloat(Integer.reverseBytes(value));
|
|
|
|
}
|
|
|
|
return PlatformDependent.getFloat(base, offset);
|
|
|
|
}
|
|
|
|
return loadFloatUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private float loadFloatUnaligned(long offset) {
|
|
|
|
return Float.intBitsToFloat(loadIntUnaligned(offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
private long loadLong(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
var value = PlatformDependent.getLong(base, offset);
|
|
|
|
return flipBytes? Long.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
return loadLongUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private long loadLongUnaligned(long offset) {
|
|
|
|
final long value;
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 7) == 0) {
|
|
|
|
value = PlatformDependent.getLong(b, offset);
|
|
|
|
} else if ((offset & 3) == 0) {
|
|
|
|
value = (long) PlatformDependent.getInt(b, offset) << 32 |
|
|
|
|
PlatformDependent.getInt(b, offset + 4);
|
|
|
|
} else if ((offset & 1) == 0) {
|
|
|
|
value = (long) PlatformDependent.getShort(b, offset) << 48 |
|
|
|
|
(long) PlatformDependent.getShort(b, offset + 2) << 32 |
|
|
|
|
(long) PlatformDependent.getShort(b, offset + 4) << 16 |
|
|
|
|
PlatformDependent.getShort(b, offset + 6);
|
|
|
|
} else {
|
|
|
|
value = (long) PlatformDependent.getByte(b, offset) << 54 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 1) << 48 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 2) << 40 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 3) << 32 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 4) << 24 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 5) << 16 |
|
|
|
|
(long) PlatformDependent.getByte(b, offset + 6) << 8 |
|
|
|
|
PlatformDependent.getByte(b, offset + 7);
|
|
|
|
}
|
|
|
|
return flipBytes? Long.reverseBytes(value) : value;
|
|
|
|
}
|
|
|
|
|
|
|
|
private double loadDouble(long offset) {
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
if (flipBytes) {
|
|
|
|
var value = PlatformDependent.getLong(base, offset);
|
|
|
|
return Double.longBitsToDouble(Long.reverseBytes(value));
|
|
|
|
}
|
|
|
|
return PlatformDependent.getDouble(base, offset);
|
|
|
|
}
|
|
|
|
return loadDoubleUnaligned(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private double loadDoubleUnaligned(long offset) {
|
|
|
|
return Double.longBitsToDouble(loadLongUnaligned(offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeByte(long offset, byte value) {
|
|
|
|
PlatformDependent.putByte(base, offset, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeChar(long offset, char value) {
|
|
|
|
if (flipBytes) {
|
|
|
|
value = Character.reverseBytes(value);
|
|
|
|
}
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
PlatformDependent.putChar(base, offset, value);
|
|
|
|
} else {
|
|
|
|
storeCharUnaligned(offset, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeCharUnaligned(long offset, char value) {
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 1) == 0) {
|
|
|
|
PlatformDependent.putChar(b, offset, value);
|
|
|
|
} else {
|
|
|
|
PlatformDependent.putByte(b, offset, (byte) (value >> 8));
|
|
|
|
PlatformDependent.putByte(b, offset + 1, (byte) value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeShort(long offset, short value) {
|
|
|
|
if (flipBytes) {
|
|
|
|
value = Short.reverseBytes(value);
|
|
|
|
}
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
PlatformDependent.putShort(base, offset, value);
|
|
|
|
} else {
|
|
|
|
storeShortUnaligned(offset, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeShortUnaligned(long offset, short value) {
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 1) == 0) {
|
|
|
|
PlatformDependent.putShort(b, offset, value);
|
|
|
|
} else {
|
|
|
|
PlatformDependent.putByte(b, offset, (byte) (value >> 8));
|
|
|
|
PlatformDependent.putByte(b, offset + 1, (byte) value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeInt(long offset, int value) {
|
|
|
|
if (flipBytes) {
|
|
|
|
value = Integer.reverseBytes(value);
|
|
|
|
}
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
PlatformDependent.putInt(base, offset, value);
|
|
|
|
} else {
|
|
|
|
storeIntUnaligned(offset, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeIntUnaligned(long offset, int value) {
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 3) == 0) {
|
|
|
|
PlatformDependent.putInt(b, offset, value);
|
|
|
|
} else if ((offset & 1) == 0) {
|
|
|
|
PlatformDependent.putShort(b, offset, (short) (value >> 16));
|
|
|
|
PlatformDependent.putShort(b, offset + 2, (short) value);
|
|
|
|
} else {
|
|
|
|
PlatformDependent.putByte(b, offset, (byte) (value >> 24));
|
|
|
|
PlatformDependent.putByte(b, offset + 1, (byte) (value >> 16));
|
|
|
|
PlatformDependent.putByte(b, offset + 2, (byte) (value >> 8));
|
|
|
|
PlatformDependent.putByte(b, offset + 3, (byte) value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeFloat(long offset, float value) {
|
|
|
|
storeInt(offset, Float.floatToRawIntBits(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeLong(long offset, long value) {
|
|
|
|
if (flipBytes) {
|
|
|
|
value = Long.reverseBytes(value);
|
|
|
|
}
|
|
|
|
if (ACCESS_UNALIGNED) {
|
|
|
|
PlatformDependent.putLong(base, offset, value);
|
|
|
|
} else {
|
|
|
|
storeLongUnaligned(offset, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeLongUnaligned(long offset, long value) {
|
|
|
|
Object b = base;
|
|
|
|
if ((offset & 7) == 0) {
|
|
|
|
PlatformDependent.putLong(b, offset, value);
|
|
|
|
} else if ((offset & 3) == 0) {
|
|
|
|
PlatformDependent.putInt(b, offset, (int) (value >> 32));
|
|
|
|
PlatformDependent.putInt(b, offset + 4, (int) value);
|
|
|
|
} else if ((offset & 1) == 0) {
|
|
|
|
PlatformDependent.putShort(b, offset, (short) (value >> 48));
|
|
|
|
PlatformDependent.putShort(b, offset + 16, (short) (value >> 32));
|
|
|
|
PlatformDependent.putShort(b, offset + 32, (short) (value >> 16));
|
|
|
|
PlatformDependent.putShort(b, offset + 48, (short) value);
|
|
|
|
} else {
|
|
|
|
PlatformDependent.putByte(b, offset, (byte) (value >> 56));
|
|
|
|
PlatformDependent.putByte(b, offset + 1, (byte) (value >> 48));
|
|
|
|
PlatformDependent.putByte(b, offset + 2, (byte) (value >> 40));
|
|
|
|
PlatformDependent.putByte(b, offset + 3, (byte) (value >> 32));
|
|
|
|
PlatformDependent.putByte(b, offset + 4, (byte) (value >> 24));
|
|
|
|
PlatformDependent.putByte(b, offset + 5, (byte) (value >> 16));
|
|
|
|
PlatformDependent.putByte(b, offset + 6, (byte) (value >> 8));
|
|
|
|
PlatformDependent.putByte(b, offset + 7, (byte) value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void storeDouble(long offset, double value) {
|
|
|
|
storeLong(offset, Double.doubleToRawLongBits(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
Object recover() {
|
|
|
|
return memory;
|
|
|
|
}
|
|
|
|
}
|