Home | History | Annotate | Download | only in misc
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package sun.misc;
     18 
     19 import dalvik.system.VMStack;
     20 
     21 import org.apache.harmony.kernel.vm.LangAccess;
     22 
     23 import java.lang.reflect.Field;
     24 import java.lang.reflect.Modifier;
     25 
     26 /**
     27  * The package name notwithstanding, this class is the quasi-standard
     28  * way for Java code to gain access to and use functionality which,
     29  * when unsupervised, would allow one to break the pointer/type safety
     30  * of Java.
     31  */
     32 public final class Unsafe {
     33     /** non-null; unique instance of this class */
     34     private static final Unsafe THE_ONE = new Unsafe();
     35 
     36     /** non-null; the lang-access utility instance */
     37     private final LangAccess lang;
     38 
     39     /**
     40      * This class is only privately instantiable.
     41      */
     42     private Unsafe() {
     43         lang = LangAccess.getInstance();
     44     }
     45 
     46     /**
     47      * Gets the unique instance of this class. This is only allowed in
     48      * very limited situations.
     49      */
     50     public static Unsafe getUnsafe() {
     51         /*
     52          * Only code on the bootclasspath is allowed to get at the
     53          * Unsafe instance.
     54          */
     55         ClassLoader calling = VMStack.getCallingClassLoader();
     56         if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
     57             throw new SecurityException("Unsafe access denied");
     58         }
     59 
     60         return THE_ONE;
     61     }
     62 
     63     /**
     64      * Gets the raw byte offset from the start of an object's memory to
     65      * the memory used to store the indicated instance field.
     66      *
     67      * @param field non-null; the field in question, which must be an
     68      * instance field
     69      * @return the offset to the field
     70      */
     71     public long objectFieldOffset(Field field) {
     72         if (Modifier.isStatic(field.getModifiers())) {
     73             throw new IllegalArgumentException(
     74                     "valid for instance fields only");
     75         }
     76 
     77         return objectFieldOffset0(field);
     78     }
     79 
     80     /**
     81      * Helper for {@link #objectFieldOffset}, which does all the work,
     82      * assuming the parameter is deemed valid.
     83      *
     84      * @param field non-null; the instance field
     85      * @return the offset to the field
     86      */
     87     private static native long objectFieldOffset0(Field field);
     88 
     89     /**
     90      * Gets the offset from the start of an array object's memory to
     91      * the memory used to store its initial (zeroeth) element.
     92      *
     93      * @param clazz non-null; class in question; must be an array class
     94      * @return the offset to the initial element
     95      */
     96     public int arrayBaseOffset(Class clazz) {
     97         if (! clazz.isArray()) {
     98             throw new IllegalArgumentException(
     99                     "valid for array classes only");
    100         }
    101 
    102         return arrayBaseOffset0(clazz);
    103     }
    104 
    105     /**
    106      * Helper for {@link #arrayBaseOffset}, which does all the work,
    107      * assuming the parameter is deemed valid.
    108      *
    109      * @param field non-null; the instance field
    110      * @return the offset to the field
    111      */
    112     private static native int arrayBaseOffset0(Class clazz);
    113 
    114     /**
    115      * Gets the size of each element of the given array class.
    116      *
    117      * @param clazz non-null; class in question; must be an array class
    118      * @return > 0; the size of each element of the array
    119      */
    120     public int arrayIndexScale(Class clazz) {
    121         if (! clazz.isArray()) {
    122             throw new IllegalArgumentException(
    123                     "valid for array classes only");
    124         }
    125 
    126         return arrayIndexScale0(clazz);
    127     }
    128 
    129     /**
    130      * Helper for {@link #arrayIndexScale}, which does all the work,
    131      * assuming the parameter is deemed valid.
    132      *
    133      * @param field non-null; the instance field
    134      * @return the offset to the field
    135      */
    136     private static native int arrayIndexScale0(Class clazz);
    137 
    138     /**
    139      * Performs a compare-and-set operation on an <code>int</code>
    140      * field within the given object.
    141      *
    142      * @param obj non-null; object containing the field
    143      * @param offset offset to the field within <code>obj</code>
    144      * @param expectedValue expected value of the field
    145      * @param newValue new value to store in the field if the contents are
    146      * as expected
    147      * @return <code>true</code> if the new value was in fact stored, and
    148      * <code>false</code> if not
    149      */
    150     public native boolean compareAndSwapInt(Object obj, long offset,
    151             int expectedValue, int newValue);
    152 
    153     /**
    154      * Performs a compare-and-set operation on a <code>long</code>
    155      * field within the given object.
    156      *
    157      * @param obj non-null; object containing the field
    158      * @param offset offset to the field within <code>obj</code>
    159      * @param expectedValue expected value of the field
    160      * @param newValue new value to store in the field if the contents are
    161      * as expected
    162      * @return <code>true</code> if the new value was in fact stored, and
    163      * <code>false</code> if not
    164      */
    165     public native boolean compareAndSwapLong(Object obj, long offset,
    166             long expectedValue, long newValue);
    167 
    168     /**
    169      * Performs a compare-and-set operation on an <code>Object</code>
    170      * field (that is, a reference field) within the given object.
    171      *
    172      * @param obj non-null; object containing the field
    173      * @param offset offset to the field within <code>obj</code>
    174      * @param expectedValue expected value of the field
    175      * @param newValue new value to store in the field if the contents are
    176      * as expected
    177      * @return <code>true</code> if the new value was in fact stored, and
    178      * <code>false</code> if not
    179      */
    180     public native boolean compareAndSwapObject(Object obj, long offset,
    181             Object expectedValue, Object newValue);
    182 
    183     /**
    184      * Gets an <code>int</code> field from the given object,
    185      * using <code>volatile</code> semantics.
    186      *
    187      * @param obj non-null; object containing the field
    188      * @param offset offset to the field within <code>obj</code>
    189      * @return the retrieved value
    190      */
    191     public native int getIntVolatile(Object obj, long offset);
    192 
    193     /**
    194      * Stores an <code>int</code> field into the given object,
    195      * using <code>volatile</code> semantics.
    196      *
    197      * @param obj non-null; object containing the field
    198      * @param offset offset to the field within <code>obj</code>
    199      * @param newValue the value to store
    200      */
    201     public native void putIntVolatile(Object obj, long offset, int newValue);
    202 
    203     /**
    204      * Gets a <code>long</code> field from the given object,
    205      * using <code>volatile</code> semantics.
    206      *
    207      * @param obj non-null; object containing the field
    208      * @param offset offset to the field within <code>obj</code>
    209      * @return the retrieved value
    210      */
    211     public native long getLongVolatile(Object obj, long offset);
    212 
    213     /**
    214      * Stores a <code>long</code> field into the given object,
    215      * using <code>volatile</code> semantics.
    216      *
    217      * @param obj non-null; object containing the field
    218      * @param offset offset to the field within <code>obj</code>
    219      * @param newValue the value to store
    220      */
    221     public native void putLongVolatile(Object obj, long offset, long newValue);
    222 
    223     /**
    224      * Gets an <code>Object</code> field from the given object,
    225      * using <code>volatile</code> semantics.
    226      *
    227      * @param obj non-null; object containing the field
    228      * @param offset offset to the field within <code>obj</code>
    229      * @return the retrieved value
    230      */
    231     public native Object getObjectVolatile(Object obj, long offset);
    232 
    233     /**
    234      * Stores an <code>Object</code> field into the given object,
    235      * using <code>volatile</code> semantics.
    236      *
    237      * @param obj non-null; object containing the field
    238      * @param offset offset to the field within <code>obj</code>
    239      * @param newValue the value to store
    240      */
    241     public native void putObjectVolatile(Object obj, long offset,
    242             Object newValue);
    243 
    244     /**
    245      * Gets an <code>int</code> field from the given object.
    246      *
    247      * @param obj non-null; object containing the field
    248      * @param offset offset to the field within <code>obj</code>
    249      * @return the retrieved value
    250      */
    251     public native int getInt(Object obj, long offset);
    252 
    253     /**
    254      * Stores an <code>int</code> field into the given object.
    255      *
    256      * @param obj non-null; object containing the field
    257      * @param offset offset to the field within <code>obj</code>
    258      * @param newValue the value to store
    259      */
    260     public native void putInt(Object obj, long offset, int newValue);
    261 
    262     /**
    263      * Gets a <code>long</code> field from the given object.
    264      *
    265      * @param obj non-null; object containing the field
    266      * @param offset offset to the field within <code>obj</code>
    267      * @return the retrieved value
    268      */
    269     public native long getLong(Object obj, long offset);
    270 
    271     /**
    272      * Stores a <code>long</code> field into the given object.
    273      *
    274      * @param obj non-null; object containing the field
    275      * @param offset offset to the field within <code>obj</code>
    276      * @param newValue the value to store
    277      */
    278     public native void putLong(Object obj, long offset, long newValue);
    279 
    280     /**
    281      * Gets an <code>Object</code> field from the given object.
    282      *
    283      * @param obj non-null; object containing the field
    284      * @param offset offset to the field within <code>obj</code>
    285      * @return the retrieved value
    286      */
    287     public native Object getObject(Object obj, long offset);
    288 
    289     /**
    290      * Stores an <code>Object</code> field into the given object.
    291      *
    292      * @param obj non-null; object containing the field
    293      * @param offset offset to the field within <code>obj</code>
    294      * @param newValue the value to store
    295      */
    296     public native void putObject(Object obj, long offset, Object newValue);
    297 
    298     /**
    299      * Parks the calling thread for the specified amount of time,
    300      * unless the "permit" for the thread is already available (due to
    301      * a previous call to {@link #unpark}. This method may also return
    302      * spuriously (that is, without the thread being told to unpark
    303      * and without the indicated amount of time elapsing).
    304      *
    305      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
    306      * in-depth information of the behavior of this method.</p>
    307      *
    308      * @param absolute whether the given time value is absolute
    309      * milliseconds-since-the-epoch (<code>true</code>) or relative
    310      * nanoseconds-from-now (<code>false</code>)
    311      * @param time the (absolute millis or relative nanos) time value
    312      */
    313     public void park(boolean absolute, long time) {
    314         if (absolute) {
    315             lang.parkUntil(time);
    316         } else {
    317             lang.parkFor(time);
    318         }
    319     }
    320 
    321     /**
    322      * Unparks the given object, which must be a {@link Thread}.
    323      *
    324      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
    325      * in-depth information of the behavior of this method.</p>
    326      *
    327      * @param obj non-null; the object to unpark
    328      */
    329     public void unpark(Object obj) {
    330         if (obj instanceof Thread) {
    331             lang.unpark((Thread) obj);
    332         } else {
    333             throw new IllegalArgumentException("valid for Threads only");
    334         }
    335     }
    336 
    337     // TODO(danfuzz): Stuff goes here.
    338 }
    339