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