/*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
*/
package sun.nio.ch; // Formerly in sun.misc
import java.nio.ByteOrder;
import jdk.internal.misc.Unsafe;
// ## In the fullness of time, this class will be eliminated
Proxies for objects that reside in native memory.
/**
* Proxies for objects that reside in native memory.
*/
class NativeObject { // package-private
protected static final Unsafe unsafe = Unsafe.getUnsafe();
// Native allocation address;
// may be smaller than the base address due to page-size rounding
//
protected long allocationAddress;
// Native base address
//
private final long address;
Creates a new native object that is based at the given native address.
/**
* Creates a new native object that is based at the given native address.
*/
NativeObject(long address) {
this.allocationAddress = address;
this.address = address;
}
Creates a new native object allocated at the given native address but
whose base is at the additional offset.
/**
* Creates a new native object allocated at the given native address but
* whose base is at the additional offset.
*/
NativeObject(long address, long offset) {
this.allocationAddress = address;
this.address = address + offset;
}
// Invoked only by AllocatedNativeObject
//
protected NativeObject(int size, boolean pageAligned) {
if (!pageAligned) {
this.allocationAddress = unsafe.allocateMemory(size);
this.address = this.allocationAddress;
} else {
int ps = pageSize();
long a = unsafe.allocateMemory(size + ps);
this.allocationAddress = a;
this.address = a + ps - (a & (ps - 1));
}
}
Returns the native base address of this native object.
Returns: The native base address
/**
* Returns the native base address of this native object.
*
* @return The native base address
*/
long address() {
return address;
}
long allocationAddress() {
return allocationAddress;
}
Creates a new native object starting at the given offset from the base
of this native object.
Params: - offset –
The offset from the base of this native object that is to be
the base of the new native object
Returns: The newly created native object
/**
* Creates a new native object starting at the given offset from the base
* of this native object.
*
* @param offset
* The offset from the base of this native object that is to be
* the base of the new native object
*
* @return The newly created native object
*/
NativeObject subObject(int offset) {
return new NativeObject(offset + address);
}
Reads an address from this native object at the given offset and
constructs a native object using that address.
Params: - offset –
The offset of the address to be read. Note that the size of an
address is implementation-dependent.
Returns: The native object created using the address read from the
given offset
/**
* Reads an address from this native object at the given offset and
* constructs a native object using that address.
*
* @param offset
* The offset of the address to be read. Note that the size of an
* address is implementation-dependent.
*
* @return The native object created using the address read from the
* given offset
*/
NativeObject getObject(int offset) {
long newAddress = 0L;
switch (addressSize()) {
case 8:
newAddress = unsafe.getLong(offset + address);
break;
case 4:
newAddress = unsafe.getInt(offset + address) & 0x00000000FFFFFFFF;
break;
default:
throw new InternalError("Address size not supported");
}
return new NativeObject(newAddress);
}
Writes the base address of the given native object at the given offset
of this native object.
Params: - offset –
The offset at which the address is to be written. Note that the
size of an address is implementation-dependent.
- ob –
The native object whose address is to be written
/**
* Writes the base address of the given native object at the given offset
* of this native object.
*
* @param offset
* The offset at which the address is to be written. Note that the
* size of an address is implementation-dependent.
*
* @param ob
* The native object whose address is to be written
*/
void putObject(int offset, NativeObject ob) {
switch (addressSize()) {
case 8:
putLong(offset, ob.address);
break;
case 4:
putInt(offset, (int)(ob.address & 0x00000000FFFFFFFF));
break;
default:
throw new InternalError("Address size not supported");
}
}
/* -- Value accessors: No range checking! -- */
Reads a byte starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the byte
Returns: The byte value read
/**
* Reads a byte starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the byte
*
* @return The byte value read
*/
final byte getByte(int offset) {
return unsafe.getByte(offset + address);
}
Writes a byte at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the byte
- value –
The byte value to be written
/**
* Writes a byte at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the byte
*
* @param value
* The byte value to be written
*/
final void putByte(int offset, byte value) {
unsafe.putByte(offset + address, value);
}
Reads a short starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the short
Returns: The short value read
/**
* Reads a short starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the short
*
* @return The short value read
*/
final short getShort(int offset) {
return unsafe.getShort(offset + address);
}
Writes a short at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the short
- value –
The short value to be written
/**
* Writes a short at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the short
*
* @param value
* The short value to be written
*/
final void putShort(int offset, short value) {
unsafe.putShort(offset + address, value);
}
Reads a char starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the char
Returns: The char value read
/**
* Reads a char starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the char
*
* @return The char value read
*/
final char getChar(int offset) {
return unsafe.getChar(offset + address);
}
Writes a char at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the char
- value –
The char value to be written
/**
* Writes a char at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the char
*
* @param value
* The char value to be written
*/
final void putChar(int offset, char value) {
unsafe.putChar(offset + address, value);
}
Reads an int starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the int
Returns: The int value read
/**
* Reads an int starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the int
*
* @return The int value read
*/
final int getInt(int offset) {
return unsafe.getInt(offset + address);
}
Writes an int at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the int
- value –
The int value to be written
/**
* Writes an int at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the int
*
* @param value
* The int value to be written
*/
final void putInt(int offset, int value) {
unsafe.putInt(offset + address, value);
}
Reads a long starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the long
Returns: The long value read
/**
* Reads a long starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the long
*
* @return The long value read
*/
final long getLong(int offset) {
return unsafe.getLong(offset + address);
}
Writes a long at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the long
- value –
The long value to be written
/**
* Writes a long at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the long
*
* @param value
* The long value to be written
*/
final void putLong(int offset, long value) {
unsafe.putLong(offset + address, value);
}
Reads a float starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the float
Returns: The float value read
/**
* Reads a float starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the float
*
* @return The float value read
*/
final float getFloat(int offset) {
return unsafe.getFloat(offset + address);
}
Writes a float at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the float
- value –
The float value to be written
/**
* Writes a float at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the float
*
* @param value
* The float value to be written
*/
final void putFloat(int offset, float value) {
unsafe.putFloat(offset + address, value);
}
Reads a double starting at the given offset from base of this native
object.
Params: - offset –
The offset at which to read the double
Returns: The double value read
/**
* Reads a double starting at the given offset from base of this native
* object.
*
* @param offset
* The offset at which to read the double
*
* @return The double value read
*/
final double getDouble(int offset) {
return unsafe.getDouble(offset + address);
}
Writes a double at the specified offset from this native object's
base address.
Params: - offset –
The offset at which to write the double
- value –
The double value to be written
/**
* Writes a double at the specified offset from this native object's
* base address.
*
* @param offset
* The offset at which to write the double
*
* @param value
* The double value to be written
*/
final void putDouble(int offset, double value) {
unsafe.putDouble(offset + address, value);
}
Returns the native architecture's address size in bytes.
Returns: The address size of the native architecture
/**
* Returns the native architecture's address size in bytes.
*
* @return The address size of the native architecture
*/
static int addressSize() {
return unsafe.addressSize();
}
// Cache for byte order
private static ByteOrder byteOrder = null;
Returns the byte order of the underlying hardware.
Returns: An instance of ByteOrder
/**
* Returns the byte order of the underlying hardware.
*
* @return An instance of {@link java.nio.ByteOrder}
*/
static ByteOrder byteOrder() {
if (byteOrder != null)
return byteOrder;
long a = unsafe.allocateMemory(8);
try {
unsafe.putLong(a, 0x0102030405060708L);
byte b = unsafe.getByte(a);
switch (b) {
case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break;
case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break;
default:
assert false;
}
} finally {
unsafe.freeMemory(a);
}
return byteOrder;
}
Cache for page size.
Lazily initialized via a data race; safe because ints are atomic.
/**
* Cache for page size.
* Lazily initialized via a data race; safe because ints are atomic.
*/
private static int pageSize = -1;
Returns the page size of the underlying hardware.
Returns: The page size, in bytes
/**
* Returns the page size of the underlying hardware.
*
* @return The page size, in bytes
*/
static int pageSize() {
int value = pageSize;
if (value == -1)
pageSize = value = unsafe.pageSize();
return value;
}
}