| /* |
| * 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 dalvik.system.VMStack; |
| 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(); |
| |
| /** |
| * This class is only privately instantiable. |
| */ |
| private Unsafe() {} |
| |
| /** |
| * 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. |
| * |
| * @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. |
| * |
| * @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); |
| |
| /** |
| * Lazy set an int field. |
| */ |
| public native void putOrderedInt(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); |
| |
| /** |
| * Lazy set a long field. |
| */ |
| public native void putOrderedLong(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); |
| |
| /** |
| * Lazy set an object field. |
| */ |
| public native void putOrderedObject(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) { |
| Thread.currentThread().parkUntil(time); |
| } else { |
| Thread.currentThread().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) { |
| ((Thread) obj).unpark(); |
| } else { |
| throw new IllegalArgumentException("valid for Threads only"); |
| } |
| } |
| } |