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
17package sun.misc;
18
19import dalvik.system.VMStack;
20import java.lang.reflect.Field;
21import 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 */
29public final class Unsafe {
30    /** non-null; unique instance of this class */
31    private static final Unsafe THE_ONE = new Unsafe();
32
33    /**
34     * This class is only privately instantiable.
35     */
36    private Unsafe() {}
37
38    /**
39     * Gets the unique instance of this class. This is only allowed in
40     * very limited situations.
41     */
42    public static Unsafe getUnsafe() {
43        /*
44         * Only code on the bootclasspath is allowed to get at the
45         * Unsafe instance.
46         */
47        ClassLoader calling = VMStack.getCallingClassLoader();
48        if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
49            throw new SecurityException("Unsafe access denied");
50        }
51
52        return THE_ONE;
53    }
54
55    /**
56     * Gets the raw byte offset from the start of an object's memory to
57     * the memory used to store the indicated instance field.
58     *
59     * @param field non-null; the field in question, which must be an
60     * instance field
61     * @return the offset to the field
62     */
63    public long objectFieldOffset(Field field) {
64        if (Modifier.isStatic(field.getModifiers())) {
65            throw new IllegalArgumentException(
66                    "valid for instance fields only");
67        }
68
69        return objectFieldOffset0(field);
70    }
71
72    /**
73     * Helper for {@link #objectFieldOffset}, which does all the work,
74     * assuming the parameter is deemed valid.
75     *
76     * @param field non-null; the instance field
77     * @return the offset to the field
78     */
79    private static native long objectFieldOffset0(Field field);
80
81    /**
82     * Gets the offset from the start of an array object's memory to
83     * the memory used to store its initial (zeroeth) element.
84     *
85     * @param clazz non-null; class in question; must be an array class
86     * @return the offset to the initial element
87     */
88    public int arrayBaseOffset(Class clazz) {
89        if (! clazz.isArray()) {
90            throw new IllegalArgumentException(
91                    "valid for array classes only");
92        }
93
94        return arrayBaseOffset0(clazz);
95    }
96
97    /**
98     * Helper for {@link #arrayBaseOffset}, which does all the work,
99     * assuming the parameter is deemed valid.
100     *
101     * @return the offset to the field
102     */
103    private static native int arrayBaseOffset0(Class clazz);
104
105    /**
106     * Gets the size of each element of the given array class.
107     *
108     * @param clazz non-null; class in question; must be an array class
109     * @return > 0; the size of each element of the array
110     */
111    public int arrayIndexScale(Class clazz) {
112        if (! clazz.isArray()) {
113            throw new IllegalArgumentException(
114                    "valid for array classes only");
115        }
116
117        return arrayIndexScale0(clazz);
118    }
119
120    /**
121     * Helper for {@link #arrayIndexScale}, which does all the work,
122     * assuming the parameter is deemed valid.
123     *
124     * @return the offset to the field
125     */
126    private static native int arrayIndexScale0(Class clazz);
127
128    /**
129     * Performs a compare-and-set operation on an <code>int</code>
130     * field within the given object.
131     *
132     * @param obj non-null; object containing the field
133     * @param offset offset to the field within <code>obj</code>
134     * @param expectedValue expected value of the field
135     * @param newValue new value to store in the field if the contents are
136     * as expected
137     * @return <code>true</code> if the new value was in fact stored, and
138     * <code>false</code> if not
139     */
140    public native boolean compareAndSwapInt(Object obj, long offset,
141            int expectedValue, int newValue);
142
143    /**
144     * Performs a compare-and-set operation on a <code>long</code>
145     * field within the given object.
146     *
147     * @param obj non-null; object containing the field
148     * @param offset offset to the field within <code>obj</code>
149     * @param expectedValue expected value of the field
150     * @param newValue new value to store in the field if the contents are
151     * as expected
152     * @return <code>true</code> if the new value was in fact stored, and
153     * <code>false</code> if not
154     */
155    public native boolean compareAndSwapLong(Object obj, long offset,
156            long expectedValue, long newValue);
157
158    /**
159     * Performs a compare-and-set operation on an <code>Object</code>
160     * field (that is, a reference field) within the given object.
161     *
162     * @param obj non-null; object containing the field
163     * @param offset offset to the field within <code>obj</code>
164     * @param expectedValue expected value of the field
165     * @param newValue new value to store in the field if the contents are
166     * as expected
167     * @return <code>true</code> if the new value was in fact stored, and
168     * <code>false</code> if not
169     */
170    public native boolean compareAndSwapObject(Object obj, long offset,
171            Object expectedValue, Object newValue);
172
173    /**
174     * Gets an <code>int</code> field from 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     * @return the retrieved value
180     */
181    public native int getIntVolatile(Object obj, long offset);
182
183    /**
184     * Stores an <code>int</code> field into 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     * @param newValue the value to store
190     */
191    public native void putIntVolatile(Object obj, long offset, int newValue);
192
193    /**
194     * Gets a <code>long</code> field from 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     * @return the retrieved value
200     */
201    public native long getLongVolatile(Object obj, long offset);
202
203    /**
204     * Stores a <code>long</code> field into 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     * @param newValue the value to store
210     */
211    public native void putLongVolatile(Object obj, long offset, long newValue);
212
213    /**
214     * Gets an <code>Object</code> field from 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     * @return the retrieved value
220     */
221    public native Object getObjectVolatile(Object obj, long offset);
222
223    /**
224     * Stores an <code>Object</code> field into 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     * @param newValue the value to store
230     */
231    public native void putObjectVolatile(Object obj, long offset,
232            Object newValue);
233
234    /**
235     * Gets an <code>int</code> field from the given object.
236     *
237     * @param obj non-null; object containing the field
238     * @param offset offset to the field within <code>obj</code>
239     * @return the retrieved value
240     */
241    public native int getInt(Object obj, long offset);
242
243    /**
244     * Stores an <code>int</code> field into the given object.
245     *
246     * @param obj non-null; object containing the field
247     * @param offset offset to the field within <code>obj</code>
248     * @param newValue the value to store
249     */
250    public native void putInt(Object obj, long offset, int newValue);
251
252    /**
253     * Lazy set an int field.
254     */
255    public native void putOrderedInt(Object obj, long offset, int newValue);
256
257    /**
258     * Gets a <code>long</code> field from the given object.
259     *
260     * @param obj non-null; object containing the field
261     * @param offset offset to the field within <code>obj</code>
262     * @return the retrieved value
263     */
264    public native long getLong(Object obj, long offset);
265
266    /**
267     * Stores a <code>long</code> field into the given object.
268     *
269     * @param obj non-null; object containing the field
270     * @param offset offset to the field within <code>obj</code>
271     * @param newValue the value to store
272     */
273    public native void putLong(Object obj, long offset, long newValue);
274
275    /**
276     * Lazy set a long field.
277     */
278    public native void putOrderedLong(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     * Lazy set an object field.
300     */
301    public native void putOrderedObject(Object obj, long offset,
302            Object newValue);
303
304    /**
305     * Parks the calling thread for the specified amount of time,
306     * unless the "permit" for the thread is already available (due to
307     * a previous call to {@link #unpark}. This method may also return
308     * spuriously (that is, without the thread being told to unpark
309     * and without the indicated amount of time elapsing).
310     *
311     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
312     * in-depth information of the behavior of this method.</p>
313     *
314     * @param absolute whether the given time value is absolute
315     * milliseconds-since-the-epoch (<code>true</code>) or relative
316     * nanoseconds-from-now (<code>false</code>)
317     * @param time the (absolute millis or relative nanos) time value
318     */
319    public void park(boolean absolute, long time) {
320        if (absolute) {
321            Thread.currentThread().parkUntil(time);
322        } else {
323            Thread.currentThread().parkFor(time);
324        }
325    }
326
327    /**
328     * Unparks the given object, which must be a {@link Thread}.
329     *
330     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
331     * in-depth information of the behavior of this method.</p>
332     *
333     * @param obj non-null; the object to unpark
334     */
335    public void unpark(Object obj) {
336        if (obj instanceof Thread) {
337            ((Thread) obj).unpark();
338        } else {
339            throw new IllegalArgumentException("valid for Threads only");
340        }
341    }
342}
343