/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package sun.misc;
import java.lang.reflect.Field;
import java.security.ProtectionDomain;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.RVMClassLoader;
import org.jikesrvm.classloader.RVMField;
import org.jikesrvm.classloader.RVMType;
import org.jikesrvm.runtime.Magic;
import org.jikesrvm.runtime.RuntimeEntrypoints;
import org.jikesrvm.scheduler.Synchronization;
import org.jikesrvm.runtime.Memory;
import org.jikesrvm.scheduler.RVMThread;
import org.vmmagic.pragma.Inline;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Address;
import static org.jikesrvm.mm.mminterface.Barriers.*;
import org.jikesrvm.runtime.SysCall;
/**
* Our implementation of sun.misc.Unsafe maps the operations to
* the Jikes RVM compiler intrinsics and its runtime service methods.
* <p>
* The OpenJDK class libraries (and normal programs using sun.misc.Unsafe)
* may expect that the methods in this class are compiler intrinsics (because
* that's the case for HotSpot). Therefore, force inlining of all methods
* where performance might matter.
* <p>
* All put* and get* methods that have a parameter with {@code java.lang.Object}
* perform barriers as if the value was written or read to a Java field of the
* appropriate type. Methods without such a parameter are assumed to access native
* memory and thus don't have barriers. Note that HotSpot's {@code sun.misc.Unsafe}
* doesn't make any distinction between barriers for field accesses and those for
* array accesses. The put* and get* methods in this class use barriers for field
* accesses.
*/
public final class Unsafe {
/** use name that Doug Lea's Fork-Join framework appears to expect from class libs */
private static final Unsafe theUnsafe = new Unsafe();
public static final int INVALID_FIELD_OFFSET = -1;
private Unsafe() {}
@Inline
public static Unsafe getUnsafe() {
SecurityManager sm = System.getSecurityManager();
if (sm != null)
sm.checkPropertiesAccess();
return theUnsafe;
}
// Manual memory management
@Inline
public long allocateMemory(long bytes) {
// TODO sysMalloc needs to be changed to Extent because the C
// prototype uses size_t
Address result = SysCall.sysCall.sysMalloc((int)bytes);
if (result.isZero()) {
throw new OutOfMemoryError("Unable to satisfy malloc of " + bytes);
}
return result.toLong();
}
@Inline
public void freeMemory(long address) {
SysCall.sysCall.sysFree(Address.fromLong(address));
}
// Access to underlying platform
@Inline
public int pageSize() {
return Memory.getPagesize();
}
// Reflection
/**
* Ensure the given class has been initialized. This is often
* needed in conjunction with obtaining the static field base of a
* class.
*/
@Inline
public void ensureClassInitialized(Class<?> c) {
RVMType type = JikesRVMSupport.getTypeForClass(c);
if (!type.isInitialized()) {
if (type.isClassType()) {
RuntimeEntrypoints.initializeClassForDynamicLink(type.asClass());
} else {
type.prepareForFirstUse();
}
}
}
@Inline
public Class<?> defineClass(String name, byte[] bytes, int off, int len, final ClassLoader parentClassLoader, ProtectionDomain protectionDomain) {
if (parentClassLoader != null) {
return RVMClassLoader.defineClassInternal(name, bytes, off,len, parentClassLoader).getClassForType();
} else {
ClassLoader callingClassloader = null;
// ClassLoader callingClassloader = VMStackWalker.getCallingClassLoader();
VM.sysFail("Implement me with org.jikesrvm.runtime.StackBrowser or move code " +
"from VMStackWalker.getCallingClassLoader() to a place that's not in the GNU " +
"Classpath namespace");
return RVMClassLoader.defineClassInternal(name, bytes, off,len, callingClassloader).getClassForType();
}
}
@Inline
public Class<?> defineClass(String name, byte[] bytes, int off, int len) {
ClassLoader callingClassloader = null;
// ClassLoader callingClassloader = VMStackWalker.getCallingClassLoader();
VM.sysFail("Implement me with org.jikesrvm.runtime.StackBrowser or move code " +
"from VMStackWalker.getCallingClassLoader() to a place that's not in the GNU " +
"Classpath namespace");
return RVMClassLoader.defineClassInternal(name, bytes, off,len, callingClassloader).getClassForType();
}
@Inline
public long objectFieldOffset(Field field) {
RVMField vmfield = java.lang.reflect.JikesRVMSupport.getFieldOf(field);
return vmfield.getOffset().toLong();
}
@Inline
public int arrayBaseOffset(Class<?> arrayClass) {
return 0;
}
@Inline
public int arrayIndexScale(Class<?> arrayClass) {
RVMType arrayType = java.lang.JikesRVMSupport.getTypeForClass(arrayClass);
if (!arrayType.isArrayType()) {
return 0;
} else {
return 1 << arrayType.asArray().getLogElementSize();
}
}
@Inline
public void throwException(Throwable ex) {
RuntimeEntrypoints.athrow(ex);
}
// Direct memory access
@Inline
public void setMemory(long address, long bytes, byte value) {
for (long i = 0; i < bytes; i++) {
Address.fromLong(address + i).store(value);
}
}
@Inline
public void copyMemory(long srcAddress, long destAddress, long bytes) {
Memory.memcopy(Address.fromLong(destAddress), Address.fromLong(srcAddress), Offset.fromLong(bytes).toWord().toExtent());
}
@Inline
public void unpark(Object thread) {
RVMThread vmthread = java.lang.JikesRVMSupport.getThread((Thread)thread);
if (vmthread != null) {
vmthread.unpark();
}
}
@Inline
public void park(boolean isAbsolute,long time) throws Throwable {
RVMThread vmthread = java.lang.JikesRVMSupport.getThread(Thread.currentThread());
if (vmthread != null) {
vmthread.park(isAbsolute, time);
}
}
// Synchronization primitives
@Inline
public boolean compareAndSwapInt(Object obj, long offset, int expect, int update) {
Offset off = Offset.fromLong(offset);
return Synchronization.tryCompareAndSwap(obj, off, expect, update);
}
@Inline
public boolean compareAndSwapLong(Object obj, long offset, long expect, long update) {
Offset off = Offset.fromLong(offset);
return Synchronization.tryCompareAndSwap(obj, off, expect, update);
}
// Reading and writing of Java data types
@Inline
public boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update) {
Offset off = Offset.fromLong(offset);
return Synchronization.tryCompareAndSwap(obj, off, expect, update);
}
@Inline
public void putOrderedInt(Object obj, long offset, int value) {
Offset off = Offset.fromLong(offset);
Magic.storeStoreBarrier();
if (NEEDS_INT_PUTFIELD_BARRIER) {
intFieldWrite(obj, value, off, 0);
} else {
Magic.setIntAtOffset(obj, off, value);
}
}
@Inline
public void putOrderedLong(Object obj, long offset, long value) {
Offset off = Offset.fromLong(offset);
Magic.storeStoreBarrier();
if (NEEDS_LONG_PUTFIELD_BARRIER) {
longFieldWrite(obj, value, off, 0);
} else {
Magic.setLongAtOffset(obj, off, value);
}
}
@Inline
public void putOrderedObject(Object obj, long offset, Object value) {
Offset off = Offset.fromLong(offset);
Magic.storeStoreBarrier();
if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
objectFieldWrite(obj, value, off, 0);
} else {
Magic.setObjectAtOffset(obj, off, value);
}
}
@Inline
public boolean getBoolean(long address) {
return Address.fromLong(address).loadByte() == 0;
}
@Inline
public boolean getBoolean(Object obj, int offset) {
Offset off = Offset.fromIntSignExtend(offset);
if (NEEDS_BOOLEAN_GETFIELD_BARRIER) {
return booleanFieldRead(obj, off, 0);
} else {
return Magic.getByteAtOffset(obj, off) == 0;
}
}
@Inline
public boolean getBoolean(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_BOOLEAN_GETFIELD_BARRIER) {
return booleanFieldRead(obj, off, 0);
} else {
return Magic.getByteAtOffset(obj, off) == 0;
}
}
@Inline
public void putBoolean(Object obj, long offset, boolean value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_BOOLEAN_PUTFIELD_BARRIER) {
booleanFieldWrite(obj, value, off, 0);
} else {
Magic.setBooleanAtOffset(obj, off, value);
}
}
@Inline
public void putBoolean(long address, boolean x) {
Address.fromLong(address).store(x) ;
}
@Inline
public byte getByte(Object obj, int offset) {
Offset off = Offset.fromIntSignExtend(offset);
if (NEEDS_BYTE_GETFIELD_BARRIER) {
return byteFieldRead(obj, off, 0);
} else {
return Magic.getByteAtOffset(obj, off);
}
}
@Inline
public byte getByte(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_BYTE_GETFIELD_BARRIER) {
return byteFieldRead(obj, off, 0);
} else {
return Magic.getByteAtOffset(obj, off);
}
}
@Inline
public byte getByte(long address) {
return Address.fromLong(address).loadByte();
}
@Inline
public void putByte(Object obj,long offset, byte value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_BYTE_PUTFIELD_BARRIER) {
byteFieldWrite(obj, value, off, 0);
} else {
Magic.setByteAtOffset(obj, off, value);
}
}
@Inline
public void putByte(long address, byte x) {
Address.fromLong(address).store(x);
}
@Inline
public char getChar(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_CHAR_PUTFIELD_BARRIER) {
return charFieldRead(obj, off, 0);
} else {
return Magic.getCharAtOffset(obj, off);
}
}
@Inline
public char getChar(long address) {
return Address.fromLong(address).loadChar();
}
@Inline
public void putChar(Object obj, long offset, char value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_CHAR_PUTFIELD_BARRIER) {
charFieldWrite(obj, value, off, 0);
} else {
Magic.setCharAtOffset(obj, off, value);
}
}
@Inline
public void putChar(long address, char x) {
Address.fromLong(address).store(x);
}
@Inline
public double getDouble(long address) {
return Address.fromLong(address).loadDouble();
}
@Inline
public double getDouble(Object obj, int offset) {
Offset off = Offset.fromIntSignExtend(offset);
if (NEEDS_DOUBLE_GETFIELD_BARRIER) {
return doubleFieldRead(obj, off, 0);
} else {
return Magic.getDoubleAtOffset(obj, off);
}
}
@Inline
public double getDouble(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_DOUBLE_GETFIELD_BARRIER) {
return doubleFieldRead(obj, off, 0);
} else {
return Magic.getDoubleAtOffset(obj, off);
}
}
@Inline
public void putDouble(Object obj,long offset,double value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_DOUBLE_PUTFIELD_BARRIER) {
doubleFieldWrite(obj, value, off, 0);
} else {
Magic.setDoubleAtOffset(obj, off, value);
}
}
@Inline
public void putDouble(long address, double x) {
Address.fromLong(address).store(x) ;
}
@Inline
public float getFloat(long address) {
return Address.fromLong(address).loadFloat();
}
@Inline
public float getFloat(Object obj, int offset) {
Offset off = Offset.fromIntSignExtend(offset);
if (NEEDS_FLOAT_GETFIELD_BARRIER) {
return floatFieldRead(obj, off, 0);
} else {
return Magic.getFloatAtOffset(obj, off);
}
}
@Inline
public float getFloat(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_FLOAT_GETFIELD_BARRIER) {
return floatFieldRead(obj, off, 0);
} else {
return Magic.getFloatAtOffset(obj, off);
}
}
@Inline
public void putFloat(Object obj, long offset, float value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_FLOAT_PUTFIELD_BARRIER) {
floatFieldWrite(obj, value, off, 0);
} else {
Magic.setFloatAtOffset(obj, off, value);
}
}
@Inline
public void putFloat(long address, float x) {
Address.fromLong(address).store(x) ;
}
@Inline
public int getInt(long address) {
return Address.fromLong(address).loadInt();
}
@Inline
public int getInt(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_INT_GETFIELD_BARRIER) {
return intFieldRead(obj, off, 0);
} else {
return Magic.getIntAtOffset(obj, off);
}
}
@Inline
public int getIntVolatile(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
int result;
if (NEEDS_INT_GETFIELD_BARRIER) {
result = intFieldRead(obj, off, 0);
} else {
result = Magic.getIntAtOffset(obj, off);
}
Magic.combinedLoadBarrier();
return result;
}
@Inline
public void putInt(long address, int x) {
Address.fromLong(address).store(x);
}
@Inline
public void putInt(Object obj, long offset, int value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_INT_PUTFIELD_BARRIER) {
intFieldWrite(obj, value, off, 0);
} else {
Magic.setIntAtOffset(obj,off,value);
}
}
@Inline
public void putIntVolatile(Object obj, long offset, int value) {
Magic.storeStoreBarrier();
Offset off = Offset.fromLong(offset);
if (NEEDS_INT_PUTFIELD_BARRIER) {
intFieldWrite(obj, value, off, 0);
} else {
Magic.setIntAtOffset(obj,off,value);
}
Magic.fence();
}
@Inline
public short getShort(long address) {
return Address.fromLong(address).loadShort();
}
@Inline
public void putShort(Object obj, long offset, short value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_SHORT_PUTFIELD_BARRIER) {
shortFieldWrite(obj, value, off, 0);
} else {
Magic.setShortAtOffset(obj, off, value);
}
}
@Inline
public void putShort(long address, short x) {
Address.fromLong(address).store(x);
}
@Inline
public long getLong(long address) {
return Address.fromLong(address).loadLong();
}
@Inline
public long getLong(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
if (NEEDS_LONG_GETFIELD_BARRIER) {
return longFieldRead(obj, off, 0);
} else {
return Magic.getLongAtOffset(obj, off);
}
}
@Inline
public long getLongVolatile(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
long result;
if (NEEDS_LONG_GETFIELD_BARRIER) {
result = longFieldRead(obj, off, 0);
} else {
result = Magic.getLongAtOffset(obj, off);
}
Magic.combinedLoadBarrier();
return result;
}
@Inline
public void putLong(long address, long x) {
Address.fromLong(address).store(x);
}
@Inline
public void putLong(Object obj, long offset, long value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_LONG_PUTFIELD_BARRIER) {
longFieldWrite(obj, value, off, 0);
} else {
Magic.setLongAtOffset(obj,off,value);
}
}
@Inline
public void putLongVolatile(Object obj, long offset, long value) {
Magic.storeStoreBarrier();
Offset off = Offset.fromLong(offset);
if (NEEDS_LONG_PUTFIELD_BARRIER) {
longFieldWrite(obj, value, off, 0);
} else {
Magic.setLongAtOffset(obj,off,value);
}
Magic.fence();
}
@Inline
public Object getObject(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
Object result;
if (NEEDS_OBJECT_GETFIELD_BARRIER) {
result = objectFieldRead(obj, off, 0);
} else {
result = Magic.getObjectAtOffset(obj, off);
}
return result;
}
@Inline
public Object getObjectVolatile(Object obj, long offset) {
Offset off = Offset.fromLong(offset);
Object result;
if (NEEDS_OBJECT_GETFIELD_BARRIER) {
result = objectFieldRead(obj, off, 0);
} else {
result = Magic.getObjectAtOffset(obj, off);
}
Magic.combinedLoadBarrier();
return result;
}
@Inline
public void putObject(Object obj, long offset, Object value) {
Offset off = Offset.fromLong(offset);
if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
objectFieldWrite(obj, value, off, 0);
} else {
Magic.setObjectAtOffset(obj,off,value);
}
}
@Inline
public void putObjectVolatile(Object obj, long offset, Object value) {
Offset off = Offset.fromLong(offset);
Magic.storeStoreBarrier();
if (NEEDS_OBJECT_PUTFIELD_BARRIER) {
objectFieldWrite(obj, value, off, 0);
} else {
Magic.setObjectAtOffset(obj, off, value);
}
Magic.fence();
}
// Memory Barriers
@Inline
public void loadFence() {
Magic.combinedLoadBarrier();
}
@Inline
public void storeFence() {
Magic.fence();
}
@Inline
public void fullFence() {
Magic.fence();
}
}