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 import java.lang.reflect.Field;
     21 import java.lang.reflect.Modifier;
     22 
     23 /**
     24  * The package name notwithstanding, this class is the quasi-standard
     25  * way for Java code to gain access to and use functionality which,
     26  * when unsupervised, would allow one to break the pointer/type safety
     27  * of Java.
     28  */
     29 public final class Unsafe {
     30     /** Traditional dalvik name. */
     31     private static final Unsafe THE_ONE = new Unsafe();
     32     /** Traditional RI name. */
     33     private static final Unsafe theUnsafe = THE_ONE;
     34 
     35     /**
     36      * This class is only privately instantiable.
     37      */
     38     private Unsafe() {}
     39 
     40     /**
     41      * Gets the unique instance of this class. This is only allowed in
     42      * very limited situations.
     43      */
     44     public static Unsafe getUnsafe() {
     45         /*
     46          * Only code on the bootclasspath is allowed to get at the
     47          * Unsafe instance.
     48          */
     49         ClassLoader calling = VMStack.getCallingClassLoader();
     50         if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
     51             throw new SecurityException("Unsafe access denied");
     52         }
     53 
     54         return THE_ONE;
     55     }
     56 
     57     /**
     58      * Gets the raw byte offset from the start of an object's memory to
     59      * the memory used to store the indicated instance field.
     60      *
     61      * @param field non-null; the field in question, which must be an
     62      * instance field
     63      * @return the offset to the field
     64      */
     65     public long objectFieldOffset(Field field) {
     66         if (Modifier.isStatic(field.getModifiers())) {
     67             throw new IllegalArgumentException("valid for instance fields only");
     68         }
     69         return field.getOffset();
     70     }
     71 
     72     /**
     73      * Gets the offset from the start of an array object's memory to
     74      * the memory used to store its initial (zeroeth) element.
     75      *
     76      * @param clazz non-null; class in question; must be an array class
     77      * @return the offset to the initial element
     78      */
     79     public int arrayBaseOffset(Class clazz) {
     80         Class<?> component = clazz.getComponentType();
     81         if (component == null) {
     82             throw new IllegalArgumentException("Valid for array classes only: " + clazz);
     83         }
     84         // TODO: make the following not specific to the object model.
     85         int offset = 12;
     86         if (component == long.class || component == double.class) {
     87             offset += 4;  // 4 bytes of padding.
     88         }
     89         return offset;
     90     }
     91 
     92     /**
     93      * Gets the size of each element of the given array class.
     94      *
     95      * @param clazz non-null; class in question; must be an array class
     96      * @return &gt; 0; the size of each element of the array
     97      */
     98     public int arrayIndexScale(Class clazz) {
     99       Class<?> component = clazz.getComponentType();
    100       if (component == null) {
    101           throw new IllegalArgumentException("Valid for array classes only: " + clazz);
    102       }
    103       // TODO: make the following not specific to the object model.
    104       if (!component.isPrimitive()) {
    105           return 4;
    106       } else  if (component == long.class || component == double.class) {
    107           return 8;
    108       } else if (component == int.class || component == float.class) {
    109           return 4;
    110       } else if (component == char.class || component == short.class) {
    111           return 2;
    112       } else {
    113           // component == byte.class || component == boolean.class.
    114           return 1;
    115       }
    116     }
    117 
    118     /**
    119      * Performs a compare-and-set operation on an <code>int</code>
    120      * field within the given object.
    121      *
    122      * @param obj non-null; object containing the field
    123      * @param offset offset to the field within <code>obj</code>
    124      * @param expectedValue expected value of the field
    125      * @param newValue new value to store in the field if the contents are
    126      * as expected
    127      * @return <code>true</code> if the new value was in fact stored, and
    128      * <code>false</code> if not
    129      */
    130     public native boolean compareAndSwapInt(Object obj, long offset,
    131             int expectedValue, int newValue);
    132 
    133     /**
    134      * Performs a compare-and-set operation on a <code>long</code>
    135      * field within the given object.
    136      *
    137      * @param obj non-null; object containing the field
    138      * @param offset offset to the field within <code>obj</code>
    139      * @param expectedValue expected value of the field
    140      * @param newValue new value to store in the field if the contents are
    141      * as expected
    142      * @return <code>true</code> if the new value was in fact stored, and
    143      * <code>false</code> if not
    144      */
    145     public native boolean compareAndSwapLong(Object obj, long offset,
    146             long expectedValue, long newValue);
    147 
    148     /**
    149      * Performs a compare-and-set operation on an <code>Object</code>
    150      * field (that is, a reference field) within the given object.
    151      *
    152      * @param obj non-null; object containing the field
    153      * @param offset offset to the field within <code>obj</code>
    154      * @param expectedValue expected value of the field
    155      * @param newValue new value to store in the field if the contents are
    156      * as expected
    157      * @return <code>true</code> if the new value was in fact stored, and
    158      * <code>false</code> if not
    159      */
    160     public native boolean compareAndSwapObject(Object obj, long offset,
    161             Object expectedValue, Object newValue);
    162 
    163     /**
    164      * Gets an <code>int</code> field from the given object,
    165      * using <code>volatile</code> semantics.
    166      *
    167      * @param obj non-null; object containing the field
    168      * @param offset offset to the field within <code>obj</code>
    169      * @return the retrieved value
    170      */
    171     public native int getIntVolatile(Object obj, long offset);
    172 
    173     /**
    174      * Stores an <code>int</code> field into the given object,
    175      * using <code>volatile</code> semantics.
    176      *
    177      * @param obj non-null; object containing the field
    178      * @param offset offset to the field within <code>obj</code>
    179      * @param newValue the value to store
    180      */
    181     public native void putIntVolatile(Object obj, long offset, int newValue);
    182 
    183     /**
    184      * Gets a <code>long</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 long getLongVolatile(Object obj, long offset);
    192 
    193     /**
    194      * Stores a <code>long</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 putLongVolatile(Object obj, long offset, long newValue);
    202 
    203     /**
    204      * Gets an <code>Object</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 Object getObjectVolatile(Object obj, long offset);
    212 
    213     /**
    214      * Stores an <code>Object</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 putObjectVolatile(Object obj, long offset,
    222             Object newValue);
    223 
    224     /**
    225      * Gets an <code>int</code> field from the given object.
    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 int getInt(Object obj, long offset);
    232 
    233     /**
    234      * Stores an <code>int</code> field into the given object.
    235      *
    236      * @param obj non-null; object containing the field
    237      * @param offset offset to the field within <code>obj</code>
    238      * @param newValue the value to store
    239      */
    240     public native void putInt(Object obj, long offset, int newValue);
    241 
    242     /**
    243      * Lazy set an int field.
    244      */
    245     public native void putOrderedInt(Object obj, long offset, int newValue);
    246 
    247     /**
    248      * Gets a <code>long</code> field from the given object.
    249      *
    250      * @param obj non-null; object containing the field
    251      * @param offset offset to the field within <code>obj</code>
    252      * @return the retrieved value
    253      */
    254     public native long getLong(Object obj, long offset);
    255 
    256     /**
    257      * Stores a <code>long</code> field into the given object.
    258      *
    259      * @param obj non-null; object containing the field
    260      * @param offset offset to the field within <code>obj</code>
    261      * @param newValue the value to store
    262      */
    263     public native void putLong(Object obj, long offset, long newValue);
    264 
    265     /**
    266      * Lazy set a long field.
    267      */
    268     public native void putOrderedLong(Object obj, long offset, long newValue);
    269 
    270     /**
    271      * Gets an <code>Object</code> field from the given object.
    272      *
    273      * @param obj non-null; object containing the field
    274      * @param offset offset to the field within <code>obj</code>
    275      * @return the retrieved value
    276      */
    277     public native Object getObject(Object obj, long offset);
    278 
    279     /**
    280      * Stores an <code>Object</code> field into the given object.
    281      *
    282      * @param obj non-null; object containing the field
    283      * @param offset offset to the field within <code>obj</code>
    284      * @param newValue the value to store
    285      */
    286     public native void putObject(Object obj, long offset, Object newValue);
    287 
    288     /**
    289      * Lazy set an object field.
    290      */
    291     public native void putOrderedObject(Object obj, long offset,
    292             Object newValue);
    293 
    294     /**
    295      * Parks the calling thread for the specified amount of time,
    296      * unless the "permit" for the thread is already available (due to
    297      * a previous call to {@link #unpark}. This method may also return
    298      * spuriously (that is, without the thread being told to unpark
    299      * and without the indicated amount of time elapsing).
    300      *
    301      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
    302      * in-depth information of the behavior of this method.</p>
    303      *
    304      * @param absolute whether the given time value is absolute
    305      * milliseconds-since-the-epoch (<code>true</code>) or relative
    306      * nanoseconds-from-now (<code>false</code>)
    307      * @param time the (absolute millis or relative nanos) time value
    308      */
    309     public void park(boolean absolute, long time) {
    310         if (absolute) {
    311             Thread.currentThread().parkUntil(time);
    312         } else {
    313             Thread.currentThread().parkFor(time);
    314         }
    315     }
    316 
    317     /**
    318      * Unparks the given object, which must be a {@link Thread}.
    319      *
    320      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
    321      * in-depth information of the behavior of this method.</p>
    322      *
    323      * @param obj non-null; the object to unpark
    324      */
    325     public void unpark(Object obj) {
    326         if (obj instanceof Thread) {
    327             ((Thread) obj).unpark();
    328         } else {
    329             throw new IllegalArgumentException("valid for Threads only");
    330         }
    331     }
    332 
    333     /**
    334      * Allocates an instance of the given class without running the constructor.
    335      * The class' <clinit> will be run, if necessary.
    336      */
    337     public native Object allocateInstance(Class<?> c);
    338 }
    339