/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package sun.misc; import java.lang.reflect.Field; import java.security.ProtectionDomain; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.CodeSource; import java.security.Policy; import java.security.cert.Certificate; import java.util.Map; import java.util.HashMap; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.Address; import org.jnode.vm.classmgr.VmStaticField; import org.jnode.vm.classmgr.VmInstanceField; import org.jnode.vm.classmgr.VmConstString; import org.jnode.vm.classmgr.VmField; import org.jnode.vm.classmgr.VmType; import org.jnode.vm.classmgr.VmArray; import org.jnode.vm.classmgr.VmClassLoader; import org.jnode.vm.facade.VmUtils; import org.jnode.vm.scheduler.VmProcessor; import org.jnode.vm.VmMagic; import org.jnode.vm.VmReflection; import org.jnode.annotation.MagicPermission; import org.jnode.annotation.SharedStatics; /** * @author Levente S\u00e1ntha */ @MagicPermission @SharedStatics class NativeUnsafe { static void registerNatives() { } public static int getInt(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getInt((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadInt(); } } public static void putInt(Unsafe instance, Object o, long offset, int x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setInt(x, (int)offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } /** * @see org.jnode.vm.VmReflection#getObject(org.jnode.vm.classmgr.VmField, Object) */ public static Object getObject(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getObject((int)offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadObjectReference().toObject(); } } /** * @see org.jnode.vm.VmReflection#setObject(org.jnode.vm.classmgr.VmField, Object, Object) */ public static void putObject(Unsafe instance, Object o, long offset, Object x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setObject(x, (int)offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(ObjectReference.fromObject(x)); } } public static boolean getBoolean(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getBoolean((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadByte() != 0; } } public static void putBoolean(Unsafe instance, Object o, long offset, boolean x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setBoolean(x, (int)offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store((byte)(x ? 1 : 0)); } } public static byte getByte(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getByte((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadByte(); } } public static void putByte(Unsafe instance, Object o, long offset, byte x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setByte(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static short getShort(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getShort((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadShort(); } } public static void putShort(Unsafe instance, Object o, long offset, short x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setShort(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static char getChar(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getChar((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadChar(); } } public static void putChar(Unsafe instance, Object o, long offset, char x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setChar(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static long getLong(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getLong((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadLong(); } } public static void putLong(Unsafe instance, Object o, long offset, long x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setLong(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static float getFloat(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getFloat((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadFloat(); } } public static void putFloat(Unsafe instance, Object o, long offset, float x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setFloat(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static double getDouble(Unsafe instance, Object o, long offset) { if(o instanceof StaticAccess){ return ((StaticAccess) o).getDouble((int) offset); } else { return ObjectReference.fromObject(o).toAddress().add((int) offset).loadDouble(); } } public static void putDouble(Unsafe instance, Object o, long offset, double x) { if(o instanceof StaticAccess){ ((StaticAccess) o).setDouble(x, (int) offset); } else { ObjectReference.fromObject(o).toAddress().add((int)offset).store(x); } } public static byte getByte(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putByte(Unsafe instance, long address, byte x) { throw new UnsupportedOperationException(); } public static short getShort(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putShort(Unsafe instance, long address, short x) { throw new UnsupportedOperationException(); } public static char getChar(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putChar(Unsafe instance, long address, char x) { throw new UnsupportedOperationException(); } public static int getInt(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putInt(Unsafe instance, long address, int x) { throw new UnsupportedOperationException(); } public static long getLong(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putLong(Unsafe instance, long address, long x) { throw new UnsupportedOperationException(); } public static float getFloat(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putFloat(Unsafe instance, long address, float x) { throw new UnsupportedOperationException(); } public static double getDouble(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putDouble(Unsafe instance, long address, double x) { throw new UnsupportedOperationException(); } public static long getAddress(Unsafe instance, long address) { throw new UnsupportedOperationException(); } public static void putAddress(Unsafe instance, long address, long x) { throw new UnsupportedOperationException(); } public static long allocateMemory(Unsafe instance, long bytes) { throw new UnsupportedOperationException(); } public static long reallocateMemory(Unsafe instance, long address, long bytes) { throw new UnsupportedOperationException(); } public static void setMemory(Unsafe instance, long address, long bytes, byte value) { throw new UnsupportedOperationException(); } public static void copyMemory(Unsafe instance, long srcAddress, long destAddress, long bytes) { throw new UnsupportedOperationException(); } public static void freeMemory(Unsafe instance, long address) { throw new UnsupportedOperationException(); } @MagicPermission static class StaticAccess { protected long address; StaticAccess(long address){ this.address = address; } final boolean getBoolean(int offset){ return Address.fromLong(address).add(offset).loadInt() != 0; } final void setBoolean(boolean value, int offset){ Address.fromLong(address).add(offset).store(value ? 1 : 0); } final byte getByte(int offset) { return (byte) Address.fromLong(address).add(offset).loadInt(); } final void setByte(byte value, int offset) { Address.fromLong(address).add(offset).store((int) value); } final short getShort(int offset){ return (short) Address.fromLong(address).add(offset).loadInt(); } final void setShort(short value, int offset){ Address.fromLong(address).add(offset).store((int) value); } final char getChar(int offset){ return (char) Address.fromLong(address).add(offset).loadInt(); } final void setChar(char value, int offset){ Address.fromLong(address).add(offset).store((int) value); } final int getInt(int offset){ return Address.fromLong(address).add(offset).loadInt(); } final void setInt(int value, int offset){ Address.fromLong(address).add(offset).store(value); } final long getLong(int offset){ return Address.fromLong(address).add(offset).loadLong(); } final void setLong(long value, int offset){ Address.fromLong(address).add(offset).store(value); } final float getFloat(int offset){ return Address.fromLong(address).add(offset).loadFloat(); } final void setFloat(float value, int offset){ Address.fromLong(address).add(offset).store(value); } final double getDouble(int offset){ return Address.fromLong(address).add(offset).loadDouble(); } final void setDouble(double value, int offset){ Address.fromLong(address).add(offset).store(value); } Object getObject(int offset){ return Address.fromLong(address).add(offset).loadObjectReference().toObject(); } void setObject(Object obj, int offset){ Address.fromLong(address).add(offset).store(ObjectReference.fromObject(obj)); } } /** * @see org.jnode.vm.VmReflection#getObject(org.jnode.vm.classmgr.VmField, Object) */ static class IrregularStaticAccess extends StaticAccess { IrregularStaticAccess(long address) { super(address); } @Override Object getObject(int offset){ Object obj = super.getObject(offset); //handles the reflective access to static final String fields, which didn't work. if(obj instanceof VmConstString){ VmConstString cs = (VmConstString) obj; obj = VmUtils.getVm().getSharedStatics().getStringEntry(cs.getSharedStaticsIndex()); } return obj; } @Override void setObject(Object obj, int offset){ //do nothing - since this is access if for final fields throw new UnsupportedOperationException(); } } /** * @see org.jnode.vm.VmReflection#getStaticFieldAddress(org.jnode.vm.classmgr.VmStaticField) */ public static Object staticFieldBase(Unsafe instance, Field f) { final VmProcessor proc = VmProcessor.current(); final Address tablePtr; VmStaticField sf = (VmStaticField) getVmField(f); if (sf.isShared()) { tablePtr = VmMagic.getArrayData(proc.getSharedStaticsTable()); } else { tablePtr = VmMagic.getArrayData(proc.getIsolatedStaticsTable()); } Object ret = tablePtr.loadObjectReference().toObject(); if(sf.isStatic() && sf.isFinal() && f.getType().equals(String.class)) ret = new IrregularStaticAccess(tablePtr.toLong()); else ret = new StaticAccess(tablePtr.toLong()); return ret; } /** * @see org.jnode.vm.VmReflection#getInstanceFieldAddress(Object, org.jnode.vm.classmgr.VmInstanceField) */ public static long staticFieldOffset(Unsafe instance, Field f) { final int offset; VmStaticField sf = (VmStaticField) getVmField(f); if (sf.isShared()) { offset = sf.getSharedStaticsIndex() << 2; } else { offset = sf.getIsolatedStaticsIndex() << 2; } return offset; } public static long objectFieldOffset(Unsafe instance, Field f) { return ((VmInstanceField) getVmField(f)).getOffset(); } private static VmField getVmField(Field f) { VmType<?> vmClass = VmType.fromClass((Class<?>) f.getDeclaringClass()); //vmClass.link(); return vmClass.getDeclaredField(f.getSlot()); } public static void ensureClassInitialized(Unsafe instance, Class<?> c) { VmType.fromClass(c).initialize(); } public static int arrayBaseOffset(Unsafe instance, Class<?> arrayClass) { return VmArray.DATA_OFFSET * VmProcessor.current().getArchitecture().getReferenceSize(); } public static int arrayIndexScale(Unsafe instance, Class<?> arrayClass) { //see VmHeapManager.newArray() final int elemSize; VmType<?> arrayCls = VmType.fromClass(arrayClass); if (arrayCls.isPrimitiveArray()) { switch (arrayCls.getSecondNameChar()) { case 'B': // byte case 'Z': // boolean elemSize = 1; break; case 'C': // char case 'S': // short elemSize = 2; break; case 'I': // int case 'F': // float elemSize = 4; break; case 'D': // double case 'J': // long elemSize = 8; break; default: throw new IllegalArgumentException(arrayCls.getName()); } } else { elemSize = VmProcessor.current().getArchitecture().getReferenceSize(); } return elemSize; } public static int addressSize(Unsafe instance) { return VmProcessor.current().getArchitecture().getReferenceSize(); } public static int pageSize(Unsafe instance) { throw new UnsupportedOperationException(); } public static Class<?> defineClass(Unsafe instance, String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protDomain) { if (protDomain == null) { protDomain = AccessController .doPrivileged(new PrivilegedAction<ProtectionDomain>() { public ProtectionDomain run() { final CodeSource cs = new CodeSource(null, (Certificate[]) null); return new ProtectionDomain(cs, Policy.getPolicy().getPermissions(cs)); } }); } return ((VmClassLoader) loader.getVmClassLoader()). defineClass(name, b, off, len, protDomain).asClass(); } public static Class<?> defineClass(Unsafe instance, String name, byte[] b, int off, int len) { throw new UnsupportedOperationException(); } public static Object allocateInstance(Unsafe instance, Class<?> cls) throws InstantiationException { //todo improve exception handling try { return VmReflection.newInstance(VmType.fromClass(cls).getMethod("<init>", new VmType[]{})); } catch (Exception x) { throw new InstantiationException("Reason: " + x.getMessage()); } } public static void monitorEnter(Unsafe instance, Object o) { throw new UnsupportedOperationException(); } public static void monitorExit(Unsafe instance, Object o) { throw new UnsupportedOperationException(); } public static boolean tryMonitorEnter(Unsafe instance, Object o) { throw new UnsupportedOperationException(); } public static void throwException(Unsafe instance, Throwable ee) throws Throwable{ //todo review it, when inlined in Unsafe the bytecode would be rejected by a verifier throw ee; } public static boolean compareAndSwapObject(Unsafe instance, Object o, long offset, Object expected, Object x) { //todo make sure it's atomic final Address address = ObjectReference.fromObject(o).toAddress().add((int) offset); if(address.loadObjectReference().toObject() == expected){ address.store(ObjectReference.fromObject(x)); return true; } else { return false; } } public static boolean compareAndSwapInt(Unsafe instance, Object o, long offset, int expected, int x) { //todo make sure it's atomic final Address address = ObjectReference.fromObject(o).toAddress().add((int) offset); if(address.loadInt() == expected){ address.store(x); return true; } else { return false; } } public static final boolean compareAndSwapLong(Unsafe instance, Object o, long offset, long expected, long x) { //todo make sure it's atomic final Address address = ObjectReference.fromObject(o).toAddress().add((int) offset); if(address.loadLong() == expected){ address.store(x); return true; } else { return false; } } public static Object getObjectVolatile(Unsafe instance, Object o, long offset) { //todo implement volatile semantics return getObject(instance, o, offset); } public static void putObjectVolatile(Unsafe instance, Object o, long offset, Object x) { //todo implement volatile semantics putObject(instance, o, offset, x); } public static int getIntVolatile(Unsafe instance, Object o, long offset) { //todo implement volatile semantics return getInt(instance, o, offset); } public static void putIntVolatile(Unsafe instance, Object o, long offset, int x) { //todo implement volatile semantics putInt(instance, o, offset, x); } public static boolean getBooleanVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getBoolean(instance, o, offset); } public static void putBooleanVolatile(Unsafe instance, Object o, long offset, boolean x) { //todo ensure volatile semantics putBoolean(instance, o, offset, x); } public static byte getByteVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getByte(instance, o, offset); } public static void putByteVolatile(Unsafe instance, Object o, long offset, byte x) { //todo ensure volatile semantics putByte(instance, o, offset, x); } public static short getShortVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getShort(instance, o, offset); } public static void putShortVolatile(Unsafe instance, Object o, long offset, short x) { //todo ensure volatile semantics putShort(instance, o, offset, x); } public static char getCharVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getChar(instance, o, offset); } public static void putCharVolatile(Unsafe instance, Object o, long offset, char x) { //todo ensure volatile semantics putChar(instance, o, offset, x); } public static long getLongVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getLong(instance, o, offset); } public static void putLongVolatile(Unsafe instance, Object o, long offset, long x) { //todo ensure volatile semantics putLong(instance, o, offset, x); } public static float getFloatVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getFloat(instance, o, offset); } public static void putFloatVolatile(Unsafe instance, Object o, long offset, float x) { //todo ensure volatile semantics putFloat(instance, o, offset, x); } public static double getDoubleVolatile(Unsafe instance, Object o, long offset) { //todo ensure volatile semantics return getDouble(instance, o, offset); } public static void putDoubleVolatile(Unsafe instance, Object o, long offset, double x) { //todo ensure volatile semantics putDouble(instance, o, offset, x); } public static void putOrderedObject(Unsafe instance, Object o, long offset, Object x) { //todo ensure ordered semantics putObject(instance, o, offset, x); } public static void putOrderedInt(Unsafe instance, Object o, long offset, int x) { //todo ensure ordered semantics putInt(instance, o, offset, x); } public static void putOrderedLong(Unsafe instance, Object o, long offset, long x) { //todo ensure ordered semantics putLong(instance, o, offset, x); } static final Map<Object, ThreadParker> parking = new HashMap<Object, ThreadParker>(); @SharedStatics private static class ThreadParker { private synchronized void park(long time){ try { wait(time); }catch (InterruptedException x){ //ignore } } private synchronized void unpark() { notifyAll(); } } /** * @see Unsafe#unpark(Object) */ public static void unpark(Unsafe instance, Object thread) { synchronized (parking){ ThreadParker p =parking.get(thread); if(p != null){ p.unpark(); } else { parking.put(thread, new ThreadParker()); } } } /** * @see Unsafe#park(boolean, long) */ public static void park(Unsafe instance, boolean isAbsolute, long time) { //todo add proper support for nanotime parking ThreadParker p; synchronized (parking){ Thread thread = Thread.currentThread(); p = parking.get(thread); if(p == null){ if(isAbsolute){ time = time - System.currentTimeMillis(); if(time < 0) time = 1; } else if(time > 0) { time = time / 10000000; if(time == 0) time = 1; } else if (time < 0){ time = 1; } p = new ThreadParker(); parking.put(thread, p); } else { p = null; } } if(p != null){ p.park(time); synchronized (parking){ parking.remove(Thread.currentThread()); } } } public static int getLoadAverage(Unsafe instance, double[] loadavg, int nelems) { throw new UnsupportedOperationException(); } }