/* * Copyright (C) 2007 The Android Open Source Project * * Licensed 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 * * http://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 sun.misc; import wonka.vm.VMStack; import org.apache.harmony.kernel.vm.LangAccess; import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** * The package name notwithstanding, this class is the quasi-standard * way for Java code to gain access to and use functionality which, * when unsupervised, would allow one to break the pointer/type safety * of Java. */ public final class Unsafe { /** non-null; unique instance of this class */ private static final Unsafe THE_ONE = new Unsafe(); /** non-null; the lang-access utility instance */ private final LangAccess lang; /** * This class is only privately instantiable. */ private Unsafe() { lang = LangAccess.getInstance(); } /** * Gets the unique instance of this class. This is only allowed in * very limited situations. */ public static Unsafe getUnsafe() { /* * Only code on the bootclasspath is allowed to get at the * Unsafe instance. */ ClassLoader calling = VMStack.getCallingClassLoader(); if ((calling != null) && (calling != Unsafe.class.getClassLoader())) { throw new SecurityException("Unsafe access denied"); } return THE_ONE; } /** * Gets the raw byte offset from the start of an object's memory to * the memory used to store the indicated instance field. * * @param field non-null; the field in question, which must be an * instance field * @return the offset to the field */ public long objectFieldOffset(Field field) { if (Modifier.isStatic(field.getModifiers())) { throw new IllegalArgumentException( "valid for instance fields only"); } return objectFieldOffset0(field); } /** * Helper for {@link #objectFieldOffset}, which does all the work, * assuming the parameter is deemed valid. * * @param field non-null; the instance field * @return the offset to the field */ private static native long objectFieldOffset0(Field field); /** * Gets the offset from the start of an array object's memory to * the memory used to store its initial (zeroeth) element. * * @param clazz non-null; class in question; must be an array class * @return the offset to the initial element */ public int arrayBaseOffset(Class clazz) { if (! clazz.isArray()) { throw new IllegalArgumentException( "valid for array classes only"); } return arrayBaseOffset0(clazz); } /** * Helper for {@link #arrayBaseOffset}, which does all the work, * assuming the parameter is deemed valid. * * @param field non-null; the instance field * @return the offset to the field */ private static native int arrayBaseOffset0(Class clazz); /** * Gets the size of each element of the given array class. * * @param clazz non-null; class in question; must be an array class * @return > 0; the size of each element of the array */ public int arrayIndexScale(Class clazz) { if (! clazz.isArray()) { throw new IllegalArgumentException( "valid for array classes only"); } return arrayIndexScale0(clazz); } /** * Helper for {@link #arrayIndexScale}, which does all the work, * assuming the parameter is deemed valid. * * @param field non-null; the instance field * @return the offset to the field */ private static native int arrayIndexScale0(Class clazz); /** * Performs a compare-and-set operation on an <code>int</code> * field within the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param expectedValue expected value of the field * @param newValue new value to store in the field if the contents are * as expected * @return <code>true</code> if the new value was in fact stored, and * <code>false</code> if not */ public native boolean compareAndSwapInt(Object obj, long offset, int expectedValue, int newValue); /** * Performs a compare-and-set operation on a <code>long</code> * field within the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param expectedValue expected value of the field * @param newValue new value to store in the field if the contents are * as expected * @return <code>true</code> if the new value was in fact stored, and * <code>false</code> if not */ public native boolean compareAndSwapLong(Object obj, long offset, long expectedValue, long newValue); /** * Performs a compare-and-set operation on an <code>Object</code> * field (that is, a reference field) within the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param expectedValue expected value of the field * @param newValue new value to store in the field if the contents are * as expected * @return <code>true</code> if the new value was in fact stored, and * <code>false</code> if not */ public native boolean compareAndSwapObject(Object obj, long offset, Object expectedValue, Object newValue); /** * Gets an <code>int</code> field from the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native int getIntVolatile(Object obj, long offset); /** * Stores an <code>int</code> field into the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putIntVolatile(Object obj, long offset, int newValue); /** * Gets a <code>long</code> field from the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native long getLongVolatile(Object obj, long offset); /** * Stores a <code>long</code> field into the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putLongVolatile(Object obj, long offset, long newValue); /** * Gets an <code>Object</code> field from the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native Object getObjectVolatile(Object obj, long offset); /** * Stores an <code>Object</code> field into the given object, * using <code>volatile</code> semantics. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putObjectVolatile(Object obj, long offset, Object newValue); /** * Gets an <code>int</code> field from the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native int getInt(Object obj, long offset); /** * Stores an <code>int</code> field into the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putInt(Object obj, long offset, int newValue); /** * Gets a <code>long</code> field from the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native long getLong(Object obj, long offset); /** * Stores a <code>long</code> field into the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putLong(Object obj, long offset, long newValue); /** * Gets an <code>Object</code> field from the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @return the retrieved value */ public native Object getObject(Object obj, long offset); /** * Stores an <code>Object</code> field into the given object. * * @param obj non-null; object containing the field * @param offset offset to the field within <code>obj</code> * @param newValue the value to store */ public native void putObject(Object obj, long offset, Object newValue); /** * Parks the calling thread for the specified amount of time, * unless the "permit" for the thread is already available (due to * a previous call to {@link #unpark}. This method may also return * spuriously (that is, without the thread being told to unpark * and without the indicated amount of time elapsing). * * <p>See {@link java.util.concurrent.locks.LockSupport} for more * in-depth information of the behavior of this method.</p> * * @param absolute whether the given time value is absolute * milliseconds-since-the-epoch (<code>true</code>) or relative * nanoseconds-from-now (<code>false</code>) * @param time the (absolute millis or relative nanos) time value */ public void park(boolean absolute, long time) { if (absolute) { lang.parkUntil(time); } else { lang.parkFor(time); } } /** * Unparks the given object, which must be a {@link Thread}. * * <p>See {@link java.util.concurrent.locks.LockSupport} for more * in-depth information of the behavior of this method.</p> * * @param obj non-null; the object to unpark */ public void unpark(Object obj) { if (obj instanceof Thread) { lang.unpark((Thread) obj); } else { throw new IllegalArgumentException("valid for Threads only"); } } // TODO(danfuzz): Stuff goes here. }