• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.internal.misc;
27 
28 import dalvik.annotation.optimization.FastNative;
29 import jdk.internal.HotSpotIntrinsicCandidate;
30 import sun.reflect.Reflection;
31 
32 import java.lang.reflect.Field;
33 import java.lang.reflect.Modifier;
34 
35 /**
36  * A collection of methods for performing low-level, unsafe operations.
37  * Although the class and all methods are public, use of this class is
38  * limited because only trusted code can obtain instances of it.
39  *
40  * @author John R. Rose
41  * @see #getUnsafe
42  */
43 public final class Unsafe {
44     /** Traditional dalvik name. */
45     private static final Unsafe THE_ONE = new Unsafe();
46 
47     private static final Unsafe theUnsafe = THE_ONE;
48     public static final int INVALID_FIELD_OFFSET   = -1;
49 
50     /**
51      * This class is only privately instantiable.
52      */
Unsafe()53     private Unsafe() {}
54 
55     /**
56      * Gets the unique instance of this class. This is only allowed in
57      * very limited situations.
58      */
getUnsafe()59     public static Unsafe getUnsafe() {
60         Class<?> caller = Reflection.getCallerClass();
61         /*
62          * Only code on the bootclasspath is allowed to get at the
63          * Unsafe instance.
64          */
65         ClassLoader calling = (caller == null) ? null : caller.getClassLoader();
66         if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
67             throw new SecurityException("Unsafe access denied");
68         }
69 
70         return THE_ONE;
71     }
72 
73     /**
74      * Gets the raw byte offset from the start of an object's memory to
75      * the memory used to store the indicated instance field.
76      *
77      * @param field non-{@code null}; the field in question, which must be an
78      * instance field
79      * @return the offset to the field
80      */
objectFieldOffset(Field field)81     public long objectFieldOffset(Field field) {
82         if (Modifier.isStatic(field.getModifiers())) {
83             throw new IllegalArgumentException("valid for instance fields only");
84         }
85         return field.getOffset();
86     }
87 
88     /**
89      * Reports the location of the field with a given name in the storage
90      * allocation of its class.
91      *
92      * @throws NullPointerException if any parameter is {@code null}.
93      * @throws InternalError if there is no field named {@code name} declared
94      *         in class {@code c}, i.e., if {@code c.getDeclaredField(name)}
95      *         would throw {@code java.lang.NoSuchFieldException}.
96      *
97      * @see #objectFieldOffset(Field)
98      */
objectFieldOffset(Class<?> c, String name)99     public long objectFieldOffset(Class<?> c, String name) {
100         if (c == null || name == null) {
101             throw new NullPointerException();
102         }
103 
104         Field field = null;
105         Field[] fields = c.getDeclaredFields();
106         for (Field f : fields) {
107             if (f.getName().equals(name)) {
108                 field = f;
109                 break;
110             }
111         }
112         if (field == null) {
113             throw new InternalError();
114         }
115         return objectFieldOffset(field);
116     }
117 
118     /**
119      * Gets the offset from the start of an array object's memory to
120      * the memory used to store its initial (zeroeth) element.
121      *
122      * @param clazz non-{@code null}; class in question; must be an array class
123      * @return the offset to the initial element
124      */
arrayBaseOffset(Class clazz)125     public int arrayBaseOffset(Class clazz) {
126         Class<?> component = clazz.getComponentType();
127         if (component == null) {
128             throw new IllegalArgumentException("Valid for array classes only: " + clazz);
129         }
130         return getArrayBaseOffsetForComponentType(component);
131     }
132 
133     /** The value of {@code arrayBaseOffset(boolean[].class)} */
134     public static final int ARRAY_BOOLEAN_BASE_OFFSET
135             = theUnsafe.arrayBaseOffset(boolean[].class);
136 
137     /** The value of {@code arrayBaseOffset(byte[].class)} */
138     public static final int ARRAY_BYTE_BASE_OFFSET
139             = theUnsafe.arrayBaseOffset(byte[].class);
140 
141     /** The value of {@code arrayBaseOffset(short[].class)} */
142     public static final int ARRAY_SHORT_BASE_OFFSET
143             = theUnsafe.arrayBaseOffset(short[].class);
144 
145     /** The value of {@code arrayBaseOffset(char[].class)} */
146     public static final int ARRAY_CHAR_BASE_OFFSET
147             = theUnsafe.arrayBaseOffset(char[].class);
148 
149     /** The value of {@code arrayBaseOffset(int[].class)} */
150     public static final int ARRAY_INT_BASE_OFFSET
151             = theUnsafe.arrayBaseOffset(int[].class);
152 
153     /** The value of {@code arrayBaseOffset(long[].class)} */
154     public static final int ARRAY_LONG_BASE_OFFSET
155             = theUnsafe.arrayBaseOffset(long[].class);
156 
157     /** The value of {@code arrayBaseOffset(float[].class)} */
158     public static final int ARRAY_FLOAT_BASE_OFFSET
159             = theUnsafe.arrayBaseOffset(float[].class);
160 
161     /** The value of {@code arrayBaseOffset(double[].class)} */
162     public static final int ARRAY_DOUBLE_BASE_OFFSET
163             = theUnsafe.arrayBaseOffset(double[].class);
164 
165     /** The value of {@code arrayBaseOffset(Object[].class)} */
166     public static final int ARRAY_OBJECT_BASE_OFFSET
167             = theUnsafe.arrayBaseOffset(Object[].class);
168 
169     /**
170      * Gets the size of each element of the given array class.
171      *
172      * @param clazz non-{@code null}; class in question; must be an array class
173      * @return &gt; 0; the size of each element of the array
174      */
arrayIndexScale(Class clazz)175     public int arrayIndexScale(Class clazz) {
176       Class<?> component = clazz.getComponentType();
177       if (component == null) {
178           throw new IllegalArgumentException("Valid for array classes only: " + clazz);
179       }
180       return getArrayIndexScaleForComponentType(component);
181     }
182 
183     /** The value of {@code arrayIndexScale(boolean[].class)} */
184     public static final int ARRAY_BOOLEAN_INDEX_SCALE
185             = theUnsafe.arrayIndexScale(boolean[].class);
186 
187     /** The value of {@code arrayIndexScale(byte[].class)} */
188     public static final int ARRAY_BYTE_INDEX_SCALE
189             = theUnsafe.arrayIndexScale(byte[].class);
190 
191     /** The value of {@code arrayIndexScale(short[].class)} */
192     public static final int ARRAY_SHORT_INDEX_SCALE
193             = theUnsafe.arrayIndexScale(short[].class);
194 
195     /** The value of {@code arrayIndexScale(char[].class)} */
196     public static final int ARRAY_CHAR_INDEX_SCALE
197             = theUnsafe.arrayIndexScale(char[].class);
198 
199     /** The value of {@code arrayIndexScale(int[].class)} */
200     public static final int ARRAY_INT_INDEX_SCALE
201             = theUnsafe.arrayIndexScale(int[].class);
202 
203     /** The value of {@code arrayIndexScale(long[].class)} */
204     public static final int ARRAY_LONG_INDEX_SCALE
205             = theUnsafe.arrayIndexScale(long[].class);
206 
207     /** The value of {@code arrayIndexScale(float[].class)} */
208     public static final int ARRAY_FLOAT_INDEX_SCALE
209             = theUnsafe.arrayIndexScale(float[].class);
210 
211     /** The value of {@code arrayIndexScale(double[].class)} */
212     public static final int ARRAY_DOUBLE_INDEX_SCALE
213             = theUnsafe.arrayIndexScale(double[].class);
214 
215     /** The value of {@code arrayIndexScale(Object[].class)} */
216     public static final int ARRAY_OBJECT_INDEX_SCALE
217             = theUnsafe.arrayIndexScale(Object[].class);
218 
219     /** The value of {@code addressSize()} */
220     public static final int ADDRESS_SIZE = theUnsafe.addressSize();
221 
222     @FastNative
getArrayBaseOffsetForComponentType(Class component_class)223     private static native int getArrayBaseOffsetForComponentType(Class component_class);
224     @FastNative
getArrayIndexScaleForComponentType(Class component_class)225     private static native int getArrayIndexScaleForComponentType(Class component_class);
226 
227     /**
228      * Fetches a value at some byte offset into a given Java object.
229      * More specifically, fetches a value within the given object
230      * <code>o</code> at the given offset, or (if <code>o</code> is
231      * null) from the memory address whose numerical value is the
232      * given offset.  <p>
233      *
234      * The specification of this method is the same as {@link
235      * #getLong(Object, long)} except that the offset does not need to
236      * have been obtained from {@link #objectFieldOffset} on the
237      * {@link java.lang.reflect.Field} of some Java field.  The value
238      * in memory is raw data, and need not correspond to any Java
239      * variable.  Unless <code>o</code> is null, the value accessed
240      * must be entirely within the allocated object.  The endianness
241      * of the value in memory is the endianness of the native platform.
242      *
243      * <p> The read will be atomic with respect to the largest power
244      * of two that divides the GCD of the offset and the storage size.
245      * For example, getLongUnaligned will make atomic reads of 2-, 4-,
246      * or 8-byte storage units if the offset is zero mod 2, 4, or 8,
247      * respectively.  There are no other guarantees of atomicity.
248      * <p>
249      * 8-byte atomicity is only guaranteed on platforms on which
250      * support atomic accesses to longs.
251      *
252      * @param o Java heap object in which the value resides, if any, else
253      *        null
254      * @param offset The offset in bytes from the start of the object
255      * @return the value fetched from the indicated object
256      * @throws RuntimeException No defined exceptions are thrown, not even
257      *         {@link NullPointerException}
258      * @since 9
259      */
getLongUnaligned(Object o, long offset)260     public final long getLongUnaligned(Object o, long offset) {
261         if ((offset & 7) == 0) {
262             return getLong(o, offset);
263         } else if ((offset & 3) == 0) {
264             return makeLong(getInt(o, offset),
265                     getInt(o, offset + 4));
266         } else if ((offset & 1) == 0) {
267             return makeLong(getShort(o, offset),
268                     getShort(o, offset + 2),
269                     getShort(o, offset + 4),
270                     getShort(o, offset + 6));
271         } else {
272             return makeLong(getByte(o, offset),
273                     getByte(o, offset + 1),
274                     getByte(o, offset + 2),
275                     getByte(o, offset + 3),
276                     getByte(o, offset + 4),
277                     getByte(o, offset + 5),
278                     getByte(o, offset + 6),
279                     getByte(o, offset + 7));
280         }
281     }
282 
283     /** @see #getLongUnaligned(Object, long) */
getIntUnaligned(Object o, long offset)284     public final int getIntUnaligned(Object o, long offset) {
285         if ((offset & 3) == 0) {
286             return getInt(o, offset);
287         } else if ((offset & 1) == 0) {
288             return makeInt(getShort(o, offset),
289                     getShort(o, offset + 2));
290         } else {
291             return makeInt(getByte(o, offset),
292                     getByte(o, offset + 1),
293                     getByte(o, offset + 2),
294                     getByte(o, offset + 3));
295         }
296     }
297 
298     // These methods construct integers from bytes.  The byte ordering
299     // is the native endianness of this platform.
makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7)300     private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
301         return ((toUnsignedLong(i0))
302                 | (toUnsignedLong(i1) << 8)
303                 | (toUnsignedLong(i2) << 16)
304                 | (toUnsignedLong(i3) << 24)
305                 | (toUnsignedLong(i4) << 32)
306                 | (toUnsignedLong(i5) << 40)
307                 | (toUnsignedLong(i6) << 48)
308                 | (toUnsignedLong(i7) << 56));
309     }
makeLong(short i0, short i1, short i2, short i3)310     private static long makeLong(short i0, short i1, short i2, short i3) {
311         return ((toUnsignedLong(i0))
312                 | (toUnsignedLong(i1) << 16)
313                 | (toUnsignedLong(i2) << 32)
314                 | (toUnsignedLong(i3) << 48));
315     }
makeLong(int i0, int i1)316     private static long makeLong(int i0, int i1) {
317         return (toUnsignedLong(i0))
318                 | (toUnsignedLong(i1) << 32);
319     }
makeInt(short i0, short i1)320     private static int makeInt(short i0, short i1) {
321         return (toUnsignedInt(i0))
322                 | (toUnsignedInt(i1) << 16);
323     }
makeInt(byte i0, byte i1, byte i2, byte i3)324     private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
325         return ((toUnsignedInt(i0))
326                 | (toUnsignedInt(i1) << 8)
327                 | (toUnsignedInt(i2) << 16)
328                 | (toUnsignedInt(i3) << 24));
329     }
makeShort(byte i0, byte i1)330     private static short makeShort(byte i0, byte i1) {
331         return (short)((toUnsignedInt(i0))
332                 | (toUnsignedInt(i1) << 8));
333     }
334 
335     // Zero-extend an integer
toUnsignedInt(byte n)336     private static int toUnsignedInt(byte n)    { return n & 0xff; }
toUnsignedInt(short n)337     private static int toUnsignedInt(short n)   { return n & 0xffff; }
toUnsignedLong(byte n)338     private static long toUnsignedLong(byte n)  { return n & 0xffL; }
toUnsignedLong(short n)339     private static long toUnsignedLong(short n) { return n & 0xffffL; }
toUnsignedLong(int n)340     private static long toUnsignedLong(int n)   { return n & 0xffffffffL; }
341 
342     /**
343      * Performs a compare-and-set operation on an {@code int}
344      * field within the given object.
345      *
346      * @param obj non-{@code null}; object containing the field
347      * @param offset offset to the field within {@code obj}
348      * @param expectedValue expected value of the field
349      * @param newValue new value to store in the field if the contents are
350      * as expected
351      * @return {@code true} if the new value was in fact stored, and
352      * {@code false} if not
353      */
354     @FastNative
compareAndSwapInt(Object obj, long offset, int expectedValue, int newValue)355     public native boolean compareAndSwapInt(Object obj, long offset,
356             int expectedValue, int newValue);
357 
358     /**
359      * Performs a compare-and-set operation on a {@code long}
360      * field within the given object.
361      *
362      * @param obj non-{@code null}; object containing the field
363      * @param offset offset to the field within {@code obj}
364      * @param expectedValue expected value of the field
365      * @param newValue new value to store in the field if the contents are
366      * as expected
367      * @return {@code true} if the new value was in fact stored, and
368      * {@code false} if not
369      */
370     @FastNative
compareAndSwapLong(Object obj, long offset, long expectedValue, long newValue)371     public native boolean compareAndSwapLong(Object obj, long offset,
372             long expectedValue, long newValue);
373 
374     /**
375      * Performs a compare-and-set operation on an {@code obj}
376      * field (that is, a reference field) within the given object.
377      *
378      * @param obj non-{@code null}; object containing the field
379      * @param offset offset to the field within {@code obj}
380      * @param expectedValue expected value of the field
381      * @param newValue new value to store in the field if the contents are
382      * as expected
383      * @return {@code true} if the new value was in fact stored, and
384      * {@code false} if not
385      */
386     @FastNative
compareAndSwapObject(Object obj, long offset, Object expectedValue, Object newValue)387     public native boolean compareAndSwapObject(Object obj, long offset,
388             Object expectedValue, Object newValue);
389 
390     /**
391      * Gets an {@code int} field from the given object,
392      * using {@code volatile} semantics.
393      *
394      * @param obj non-{@code null}; object containing the field
395      * @param offset offset to the field within {@code obj}
396      * @return the retrieved value
397      */
398     @FastNative
getIntVolatile(Object obj, long offset)399     public native int getIntVolatile(Object obj, long offset);
400 
401     /**
402      * Stores an {@code int} field into the given object,
403      * using {@code volatile} semantics.
404      *
405      * @param obj non-{@code null}; object containing the field
406      * @param offset offset to the field within {@code obj}
407      * @param newValue the value to store
408      */
409     @FastNative
putIntVolatile(Object obj, long offset, int newValue)410     public native void putIntVolatile(Object obj, long offset, int newValue);
411 
412     /**
413      * Gets a {@code long} field from the given object,
414      * using {@code volatile} semantics.
415      *
416      * @param obj non-{@code null}; object containing the field
417      * @param offset offset to the field within {@code obj}
418      * @return the retrieved value
419      */
420     @FastNative
getLongVolatile(Object obj, long offset)421     public native long getLongVolatile(Object obj, long offset);
422 
423     /**
424      * Stores a {@code long} field into the given object,
425      * using {@code volatile} semantics.
426      *
427      * @param obj non-{@code null}; object containing the field
428      * @param offset offset to the field within {@code obj}
429      * @param newValue the value to store
430      */
431     @FastNative
putLongVolatile(Object obj, long offset, long newValue)432     public native void putLongVolatile(Object obj, long offset, long newValue);
433 
434     /**
435      * Gets an {@code obj} field from the given object,
436      * using {@code volatile} semantics.
437      *
438      * @param obj non-{@code null}; object containing the field
439      * @param offset offset to the field within {@code obj}
440      * @return the retrieved value
441      */
442     @FastNative
getObjectVolatile(Object obj, long offset)443     public native Object getObjectVolatile(Object obj, long offset);
444 
445     /**
446      * Stores an {@code obj} field into the given object,
447      * using {@code volatile} semantics.
448      *
449      * @param obj non-{@code null}; object containing the field
450      * @param offset offset to the field within {@code obj}
451      * @param newValue the value to store
452      */
453     @FastNative
putObjectVolatile(Object obj, long offset, Object newValue)454     public native void putObjectVolatile(Object obj, long offset,
455             Object newValue);
456 
457     /**
458      * Gets an {@code int} field from the given object.
459      *
460      * @param obj non-{@code null}; object containing int field
461      * @param offset offset to the field within {@code obj}
462      * @return the retrieved value
463      */
464     @FastNative
getInt(Object obj, long offset)465     public native int getInt(Object obj, long offset);
466 
467     /**
468      * Stores an {@code int} field into the given object.
469      *
470      * @param obj non-{@code null}; object containing int field
471      * @param offset offset to the field within {@code obj}
472      * @param newValue the value to store
473      */
474     @FastNative
putInt(Object obj, long offset, int newValue)475     public native void putInt(Object obj, long offset, int newValue);
476 
477     /**
478      * Lazy set an int field.
479      *
480      * @param obj non-{@code null}; object containing the field
481      * @param offset offset to the field within {@code obj}
482      * @param newValue the value to store
483      */
484     @FastNative
putOrderedInt(Object obj, long offset, int newValue)485     public native void putOrderedInt(Object obj, long offset, int newValue);
486 
487     /**
488      * Gets a {@code long} field from the given object.
489      *
490      * @param obj non-{@code null}; object containing the field
491      * @param offset offset to the field within {@code obj}
492      * @return the retrieved value
493      */
494     @FastNative
getLong(Object obj, long offset)495     public native long getLong(Object obj, long offset);
496 
497     /**
498      * Stores a {@code long} field into the given object.
499      *
500      * @param obj non-{@code null}; object containing the field
501      * @param offset offset to the field within {@code obj}
502      * @param newValue the value to store
503      */
504     @FastNative
putLong(Object obj, long offset, long newValue)505     public native void putLong(Object obj, long offset, long newValue);
506 
507     /**
508      * Lazy set a long field.
509      *
510      * @param obj non-{@code null}; object containing the field
511      * @param offset offset to the field within {@code obj}
512      * @param newValue the value to store
513      */
514     @FastNative
putOrderedLong(Object obj, long offset, long newValue)515     public native void putOrderedLong(Object obj, long offset, long newValue);
516 
517     /**
518      * Gets an {@code obj} field from the given object.
519      *
520      * @param obj non-{@code null}; object containing the field
521      * @param offset offset to the field within {@code obj}
522      * @return the retrieved value
523      */
524     @FastNative
getObject(Object obj, long offset)525     public native Object getObject(Object obj, long offset);
526 
527     /**
528      * Stores an {@code obj} field into the given object.
529      *
530      * @param obj non-{@code null}; object containing the field
531      * @param offset offset to the field within {@code obj}
532      * @param newValue the value to store
533      */
534     @FastNative
putObject(Object obj, long offset, Object newValue)535     public native void putObject(Object obj, long offset, Object newValue);
536 
537     /**
538      * Lazy set an object field.
539      *
540      * @param obj non-{@code null}; object containing the field
541      * @param offset offset to the field within {@code obj}
542      * @param newValue the value to store
543      */
544     @FastNative
putOrderedObject(Object obj, long offset, Object newValue)545     public native void putOrderedObject(Object obj, long offset,
546             Object newValue);
547 
548     /**
549      * Gets a {@code boolean} field from the given object.
550      *
551      * @param obj non-{@code null}; object containing boolean field
552      * @param offset offset to the field within {@code obj}
553      * @return the retrieved value
554      */
555     @FastNative
getBoolean(Object obj, long offset)556     public native boolean getBoolean(Object obj, long offset);
557 
558     /**
559      * Stores a {@code boolean} field into the given object.
560      *
561      * @param obj non-{@code null}; object containing boolean field
562      * @param offset offset to the field within {@code obj}
563      * @param newValue the value to store
564      */
565     @FastNative
putBoolean(Object obj, long offset, boolean newValue)566     public native void putBoolean(Object obj, long offset, boolean newValue);
567 
568     /**
569      * Gets a {@code byte} field from the given object.
570      *
571      * @param obj non-{@code null}; object containing byte field
572      * @param offset offset to the field within {@code obj}
573      * @return the retrieved value
574      */
575     @FastNative
getByte(Object obj, long offset)576     public native byte getByte(Object obj, long offset);
577 
578     /**
579      * Stores a {@code byte} field into the given object.
580      *
581      * @param obj non-{@code null}; object containing byte field
582      * @param offset offset to the field within {@code obj}
583      * @param newValue the value to store
584      */
585     @FastNative
putByte(Object obj, long offset, byte newValue)586     public native void putByte(Object obj, long offset, byte newValue);
587 
588     /**
589      * Gets a {@code char} field from the given object.
590      *
591      * @param obj non-{@code null}; object containing char field
592      * @param offset offset to the field within {@code obj}
593      * @return the retrieved value
594      */
595     @FastNative
getChar(Object obj, long offset)596     public native char getChar(Object obj, long offset);
597 
598     /**
599      * Stores a {@code char} field into the given object.
600      *
601      * @param obj non-{@code null}; object containing char field
602      * @param offset offset to the field within {@code obj}
603      * @param newValue the value to store
604      */
605     @FastNative
putChar(Object obj, long offset, char newValue)606     public native void putChar(Object obj, long offset, char newValue);
607 
608     /**
609      * Gets a {@code short} field from the given object.
610      *
611      * @param obj non-{@code null}; object containing short field
612      * @param offset offset to the field within {@code obj}
613      * @return the retrieved value
614      */
615     @FastNative
getShort(Object obj, long offset)616     public native short getShort(Object obj, long offset);
617 
618     /**
619      * Stores a {@code short} field into the given object.
620      *
621      * @param obj non-{@code null}; object containing short field
622      * @param offset offset to the field within {@code obj}
623      * @param newValue the value to store
624      */
625     @FastNative
putShort(Object obj, long offset, short newValue)626     public native void putShort(Object obj, long offset, short newValue);
627 
628     /**
629      * Gets a {@code float} field from the given object.
630      *
631      * @param obj non-{@code null}; object containing float field
632      * @param offset offset to the field within {@code obj}
633      * @return the retrieved value
634      */
635     @FastNative
getFloat(Object obj, long offset)636     public native float getFloat(Object obj, long offset);
637 
638     /**
639      * Stores a {@code float} field into the given object.
640      *
641      * @param obj non-{@code null}; object containing float field
642      * @param offset offset to the field within {@code obj}
643      * @param newValue the value to store
644      */
645     @FastNative
putFloat(Object obj, long offset, float newValue)646     public native void putFloat(Object obj, long offset, float newValue);
647 
648     /**
649      * Gets a {@code double} field from the given object.
650      *
651      * @param obj non-{@code null}; object containing double field
652      * @param offset offset to the field within {@code obj}
653      * @return the retrieved value
654      */
655     @FastNative
getDouble(Object obj, long offset)656     public native double getDouble(Object obj, long offset);
657 
658     /**
659      * Stores a {@code double} field into the given object.
660      *
661      * @param obj non-{@code null}; object containing double field
662      * @param offset offset to the field within {@code obj}
663      * @param newValue the value to store
664      */
665     @FastNative
putDouble(Object obj, long offset, double newValue)666     public native void putDouble(Object obj, long offset, double newValue);
667 
668     /**
669      * Parks the calling thread for the specified amount of time,
670      * unless the "permit" for the thread is already available (due to
671      * a previous call to {@link #unpark}. This method may also return
672      * spuriously (that is, without the thread being told to unpark
673      * and without the indicated amount of time elapsing).
674      *
675      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
676      * in-depth information of the behavior of this method.</p>
677      *
678      * @param absolute whether the given time value is absolute
679      * milliseconds-since-the-epoch ({@code true}) or relative
680      * nanoseconds-from-now ({@code false})
681      * @param time the (absolute millis or relative nanos) time value
682      */
683 
park(boolean absolute, long time)684     public native void park(boolean absolute, long time);
685     /**
686      * Unparks the given object, which must be a {@link Thread}.
687      *
688      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
689      * in-depth information of the behavior of this method.</p>
690      *
691      * @param obj non-{@code null}; the object to unpark
692      */
693     @FastNative
unpark(Object obj)694     public native void unpark(Object obj);
695 
696     /**
697      * Allocates an instance of the given class without running the constructor.
698      * The class' <clinit> will be run, if necessary.
699      */
allocateInstance(Class<?> c)700     public native Object allocateInstance(Class<?> c);
701 
702     /**
703      * Gets the size of the address value, in bytes.
704      *
705      * @return the size of the address, in bytes
706      */
707     @FastNative
addressSize()708     public native int addressSize();
709 
710     /**
711      * Gets the size of the memory page, in bytes.
712      *
713      * @return the size of the page
714      */
715     @FastNative
pageSize()716     public native int pageSize();
717 
718     /**
719      * Allocates a memory block of size {@code bytes}.
720      *
721      * @param bytes size of the memory block
722      * @return address of the allocated memory
723      */
724     @FastNative
allocateMemory(long bytes)725     public native long allocateMemory(long bytes);
726 
727     /**
728      * Frees previously allocated memory at given address.
729      *
730      * @param address address of the freed memory
731      */
732     @FastNative
freeMemory(long address)733     public native void freeMemory(long address);
734 
735     /**
736      * Fills given memory block with a given value.
737      *
738      * @param address address of the memoory block
739      * @param bytes length of the memory block, in bytes
740      * @param value fills memory with this value
741      */
742     @FastNative
setMemory(long address, long bytes, byte value)743     public native void setMemory(long address, long bytes, byte value);
744 
745     /**
746      * Gets {@code byte} from given address in memory.
747      *
748      * @param address address in memory
749      * @return {@code byte} value
750      */
751     @FastNative
getByte(long address)752     public native byte getByte(long address);
753 
754     /**
755      * Stores a {@code byte} into the given memory address.
756      *
757      * @param address address in memory where to store the value
758      * @param newValue the value to store
759      */
760     @FastNative
putByte(long address, byte x)761     public native void putByte(long address, byte x);
762 
763     /**
764      * Gets {@code short} from given address in memory.
765      *
766      * @param address address in memory
767      * @return {@code short} value
768      */
769     @FastNative
getShort(long address)770     public native short getShort(long address);
771 
772     /**
773      * Stores a {@code short} into the given memory address.
774      *
775      * @param address address in memory where to store the value
776      * @param newValue the value to store
777      */
778     @FastNative
putShort(long address, short x)779     public native void putShort(long address, short x);
780 
781     /**
782      * Gets {@code char} from given address in memory.
783      *
784      * @param address address in memory
785      * @return {@code char} value
786      */
787     @FastNative
getChar(long address)788     public native char getChar(long address);
789 
790     /**
791      * Stores a {@code char} into the given memory address.
792      *
793      * @param address address in memory where to store the value
794      * @param newValue the value to store
795      */
796     @FastNative
putChar(long address, char x)797     public native void putChar(long address, char x);
798 
799     /**
800      * Gets {@code int} from given address in memory.
801      *
802      * @param address address in memory
803      * @return {@code int} value
804      */
805     @FastNative
getInt(long address)806     public native int getInt(long address);
807 
808     /**
809      * Stores a {@code int} into the given memory address.
810      *
811      * @param address address in memory where to store the value
812      * @param newValue the value to store
813      */
814     @FastNative
putInt(long address, int x)815     public native void putInt(long address, int x);
816 
817 
818     /**
819      * Gets {@code long} from given address in memory.
820      *
821      * @param address address in memory
822      * @return {@code long} value
823      */
824     @FastNative
getLong(long address)825     public native long getLong(long address);
826 
827     /**
828      * Stores a {@code long} into the given memory address.
829      *
830      * @param address address in memory where to store the value
831      * @param newValue the value to store
832      */
833     @FastNative
putLong(long address, long x)834     public native void putLong(long address, long x);
835 
836     /**
837      * Gets {@code long} from given address in memory.
838      *
839      * @param address address in memory
840      * @return {@code long} value
841      */
842     @FastNative
getFloat(long address)843     public native float getFloat(long address);
844 
845     /**
846      * Stores a {@code float} into the given memory address.
847      *
848      * @param address address in memory where to store the value
849      * @param newValue the value to store
850      */
851     @FastNative
putFloat(long address, float x)852     public native void putFloat(long address, float x);
853 
854     /**
855      * Gets {@code double} from given address in memory.
856      *
857      * @param address address in memory
858      * @return {@code double} value
859      */
860     @FastNative
getDouble(long address)861     public native double getDouble(long address);
862 
863     /**
864      * Stores a {@code double} into the given memory address.
865      *
866      * @param address address in memory where to store the value
867      * @param newValue the value to store
868      */
869     @FastNative
putDouble(long address, double x)870     public native void putDouble(long address, double x);
871 
872     /**
873      * Sets all bytes in a given block of memory to a copy of another
874      * block.
875      *
876      * This method is to be used to copy memory between array objects. The
877      * offsets used should be relative to the value reported by {@link
878      * #arrayBaseOffset}. For example to copy all elements of an integer
879      * array to another:
880      *
881      * <pre> {@code
882      *   unsafe.copyMemory(srcArray, Unsafe.ARRAY_INT_BASE_OFFSET,
883      *                     destArray, Unsafe.ARRAY_INT_BASE_OFFSET,
884      *                     srcArray.length * 4);
885      * }</pre>
886      *
887      * @param srcBase The source array object from which to copy
888      * @param srcOffset The offset within the object from where to copy
889      * @param destBase The destination array object to which to copy
890      * @param destOffset The offset within the object to where to copy
891      * @param bytes The number of bytes to copy
892      *
893      * @throws RuntimeException if any of the arguments is invalid
894      */
copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)895     public void copyMemory(Object srcBase, long srcOffset,
896                            Object destBase, long destOffset,
897                            long bytes) {
898         copyMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes);
899 
900         if (bytes == 0) {
901             return;
902         }
903 
904         copyMemory0(srcBase, srcOffset, destBase, destOffset, bytes);
905     }
906 
907     /**
908      * Sets all bytes in a given block of memory to a copy of another block.
909      *
910      * @param srcAddr address of the source memory to be copied from
911      * @param dstAddr address of the destination memory to copy to
912      * @param bytes number of bytes to copy
913      */
copyMemory(long srcAddr, long dstAddr, long bytes)914     public void copyMemory(long srcAddr, long dstAddr, long bytes) {
915         copyMemory(null, srcAddr, null, dstAddr, bytes);
916     }
917 
918     /**
919      * Validate the arguments to copyMemory
920      *
921      * @throws RuntimeException if any of the arguments is invalid
922      *         (<em>Note:</em> after optimization, invalid inputs may
923      *         go undetected, which will lead to unpredictable
924      *         behavior)
925      */
copyMemoryChecks(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)926     private void copyMemoryChecks(Object srcBase, long srcOffset,
927                                   Object destBase, long destOffset,
928                                   long bytes) {
929         checkSize(bytes);
930         checkPrimitivePointer(srcBase, srcOffset);
931         checkPrimitivePointer(destBase, destOffset);
932     }
933 
934     @HotSpotIntrinsicCandidate
935     @FastNative
copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)936     private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
937 
938     /**
939      * Atomically updates Java variable to {@code x} if it is currently
940      * holding {@code expected}.
941      *
942      * <p>This operation has memory semantics of a {@code volatile} read
943      * and write.  Corresponds to C11 atomic_compare_exchange_strong.
944      *
945      * @return {@code true} if successful
946      */
947     @HotSpotIntrinsicCandidate
948     @FastNative
compareAndSetInt(Object o, long offset, int expected, int x)949     public final native boolean compareAndSetInt(Object o, long offset,
950                                                  int expected,
951                                                  int x);
952 
953     /**
954      * Atomically updates Java variable to {@code x} if it is currently
955      * holding {@code expected}.
956      *
957      * <p>This operation has memory semantics of a {@code volatile} read
958      * and write.  Corresponds to C11 atomic_compare_exchange_strong.
959      *
960      * @return {@code true} if successful
961      */
962     @HotSpotIntrinsicCandidate
963     @FastNative
compareAndSetLong(Object o, long offset, long expected, long x)964     public final native boolean compareAndSetLong(Object o, long offset,
965                                                   long expected,
966                                                   long x);
967 
968     /**
969      * Atomically updates Java variable to {@code x} if it is currently
970      * holding {@code expected}.
971      *
972      * <p>This operation has memory semantics of a {@code volatile} read
973      * and write.  Corresponds to C11 atomic_compare_exchange_strong.
974      *
975      * @return {@code true} if successful
976      */
977     @HotSpotIntrinsicCandidate
978     @FastNative
compareAndSetObject(Object o, long offset, Object expected, Object x)979     public final native boolean compareAndSetObject(Object o, long offset,
980                                                     Object expected,
981                                                     Object x);
982 
983     // The following contain CAS-based Java implementations used on
984     // platforms not supporting native instructions
985 
986     /**
987      * Atomically adds the given value to the current value of a field
988      * or array element within the given object {@code o}
989      * at the given {@code offset}.
990      *
991      * @param o object/array to update the field/element in
992      * @param offset field/element offset
993      * @param delta the value to add
994      * @return the previous value
995      * @since 1.8
996      */
997     @HotSpotIntrinsicCandidate
getAndAddInt(Object o, long offset, int delta)998     public final int getAndAddInt(Object o, long offset, int delta) {
999         int v;
1000         do {
1001             v = getIntVolatile(o, offset);
1002         } while (!compareAndSwapInt(o, offset, v, v + delta));
1003         return v;
1004     }
1005 
1006     /**
1007      * Atomically adds the given value to the current value of a field
1008      * or array element within the given object {@code o}
1009      * at the given {@code offset}.
1010      *
1011      * @param o object/array to update the field/element in
1012      * @param offset field/element offset
1013      * @param delta the value to add
1014      * @return the previous value
1015      * @since 1.8
1016      */
1017     @HotSpotIntrinsicCandidate
getAndAddLong(Object o, long offset, long delta)1018     public final long getAndAddLong(Object o, long offset, long delta) {
1019         long v;
1020         do {
1021             v = getLongVolatile(o, offset);
1022         } while (!compareAndSwapLong(o, offset, v, v + delta));
1023         return v;
1024     }
1025 
1026     /**
1027      * Atomically exchanges the given value with the current value of
1028      * a field or array element within the given object {@code o}
1029      * at the given {@code offset}.
1030      *
1031      * @param o object/array to update the field/element in
1032      * @param offset field/element offset
1033      * @param newValue new value
1034      * @return the previous value
1035      * @since 1.8
1036      */
1037     @HotSpotIntrinsicCandidate
getAndSetInt(Object o, long offset, int newValue)1038     public final int getAndSetInt(Object o, long offset, int newValue) {
1039         int v;
1040         do {
1041             v = getIntVolatile(o, offset);
1042         } while (!compareAndSwapInt(o, offset, v, newValue));
1043         return v;
1044     }
1045 
1046     /**
1047      * Atomically exchanges the given value with the current value of
1048      * a field or array element within the given object {@code o}
1049      * at the given {@code offset}.
1050      *
1051      * @param o object/array to update the field/element in
1052      * @param offset field/element offset
1053      * @param newValue new value
1054      * @return the previous value
1055      * @since 1.8
1056      */
1057     @HotSpotIntrinsicCandidate
getAndSetLong(Object o, long offset, long newValue)1058     public final long getAndSetLong(Object o, long offset, long newValue) {
1059         long v;
1060         do {
1061             v = getLongVolatile(o, offset);
1062         } while (!compareAndSwapLong(o, offset, v, newValue));
1063         return v;
1064     }
1065 
1066     /**
1067      * Atomically exchanges the given reference value with the current
1068      * reference value of a field or array element within the given
1069      * object {@code o} at the given {@code offset}.
1070      *
1071      * @param o object/array to update the field/element in
1072      * @param offset field/element offset
1073      * @param newValue new value
1074      * @return the previous value
1075      * @since 1.8
1076      */
1077     @HotSpotIntrinsicCandidate
getAndSetObject(Object o, long offset, Object newValue)1078     public final Object getAndSetObject(Object o, long offset, Object newValue) {
1079         Object v;
1080         do {
1081             v = getObjectVolatile(o, offset);
1082         } while (!compareAndSwapObject(o, offset, v, newValue));
1083         return v;
1084     }
1085 
1086     /** Release version of {@link #putIntVolatile(Object, long, int)} */
1087     @HotSpotIntrinsicCandidate
putIntRelease(Object o, long offset, int x)1088     public final void putIntRelease(Object o, long offset, int x) {
1089         putIntVolatile(o, offset, x);
1090     }
1091 
1092     /** Acquire version of {@link #getIntVolatile(Object, long)} */
1093     @HotSpotIntrinsicCandidate
getIntAcquire(Object o, long offset)1094     public final int getIntAcquire(Object o, long offset) {
1095         return getIntVolatile(o, offset);
1096     }
1097 
1098     /** Release version of {@link #putLongVolatile(Object, long, long)} */
1099     @HotSpotIntrinsicCandidate
putLongRelease(Object o, long offset, long x)1100     public final void putLongRelease(Object o, long offset, long x) {
1101         putLongVolatile(o, offset, x);
1102     }
1103 
1104     /** Acquire version of {@link #getLongVolatile(Object, long)} */
1105     @HotSpotIntrinsicCandidate
getLongAcquire(Object o, long offset)1106     public final long getLongAcquire(Object o, long offset) {
1107         return getLongVolatile(o, offset);
1108     }
1109 
1110     /** Release version of {@link #putObjectVolatile(Object, long, Object)} */
1111     @HotSpotIntrinsicCandidate
putObjectRelease(Object o, long offset, Object x)1112     public final void putObjectRelease(Object o, long offset, Object x) {
1113         putObjectVolatile(o, offset, x);
1114     }
1115 
1116     /** Acquire version of {@link #getObjectVolatile(Object, long)} */
1117     @HotSpotIntrinsicCandidate
getObjectAcquire(Object o, long offset)1118     public final Object getObjectAcquire(Object o, long offset) {
1119         return getObjectVolatile(o, offset);
1120     }
1121 
1122     /**
1123      * Ensures that loads before the fence will not be reordered with loads and
1124      * stores after the fence; a "LoadLoad plus LoadStore barrier".
1125      *
1126      * Corresponds to C11 atomic_thread_fence(memory_order_acquire)
1127      * (an "acquire fence").
1128      *
1129      * A pure LoadLoad fence is not provided, since the addition of LoadStore
1130      * is almost always desired, and most current hardware instructions that
1131      * provide a LoadLoad barrier also provide a LoadStore barrier for free.
1132      * @since 1.8
1133      */
1134     @HotSpotIntrinsicCandidate
1135     @FastNative
loadFence()1136     public native void loadFence();
1137 
1138     /**
1139      * Ensures that loads and stores before the fence will not be reordered with
1140      * stores after the fence; a "StoreStore plus LoadStore barrier".
1141      *
1142      * Corresponds to C11 atomic_thread_fence(memory_order_release)
1143      * (a "release fence").
1144      *
1145      * A pure StoreStore fence is not provided, since the addition of LoadStore
1146      * is almost always desired, and most current hardware instructions that
1147      * provide a StoreStore barrier also provide a LoadStore barrier for free.
1148      * @since 1.8
1149      */
1150     @HotSpotIntrinsicCandidate
1151     @FastNative
storeFence()1152     public native void storeFence();
1153 
1154     /**
1155      * Ensures that loads and stores before the fence will not be reordered
1156      * with loads and stores after the fence.  Implies the effects of both
1157      * loadFence() and storeFence(), and in addition, the effect of a StoreLoad
1158      * barrier.
1159      *
1160      * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
1161      * @since 1.8
1162      */
1163     @HotSpotIntrinsicCandidate
1164     @FastNative
fullFence()1165     public native void fullFence();
1166 
1167     /**
1168      * Ensures the given class has been initialized. This is often
1169      * needed in conjunction with obtaining the static field base of a
1170      * class.
1171      */
ensureClassInitialized(Class<?> c)1172     public void ensureClassInitialized(Class<?> c) {
1173         if (c == null) {
1174             throw new NullPointerException();
1175         }
1176 
1177         // Android-changed: Implementation not yet available natively (b/202380950)
1178         // ensureClassInitialized0(c);
1179         try {
1180             Class.forName(c.getName(), true, c.getClassLoader());
1181         } catch (ClassNotFoundException e) {
1182             // The function doesn't specify that it's throwing ClassNotFoundException, so it needs
1183             // to be caught here. We could rethrow as NoClassDefFoundError, however that is not
1184             // documented for this function and the upstream implementation does not throw an
1185             // exception.
1186         }
1187     }
1188 
1189 
1190     /// helper methods for validating various types of objects/values
1191 
1192     /**
1193      * Create an exception reflecting that some of the input was invalid
1194      *
1195      * <em>Note:</em> It is the resposibility of the caller to make
1196      * sure arguments are checked before the methods are called. While
1197      * some rudimentary checks are performed on the input, the checks
1198      * are best effort and when performance is an overriding priority,
1199      * as when methods of this class are optimized by the runtime
1200      * compiler, some or all checks (if any) may be elided. Hence, the
1201      * caller must not rely on the checks and corresponding
1202      * exceptions!
1203      *
1204      * @return an exception object
1205      */
invalidInput()1206     private RuntimeException invalidInput() {
1207         return new IllegalArgumentException();
1208     }
1209 
1210     /**
1211      * Check if a value is 32-bit clean (32 MSB are all zero)
1212      *
1213      * @param value the 64-bit value to check
1214      *
1215      * @return true if the value is 32-bit clean
1216      */
is32BitClean(long value)1217     private boolean is32BitClean(long value) {
1218         return value >>> 32 == 0;
1219     }
1220 
1221     /**
1222      * Check the validity of a size (the equivalent of a size_t)
1223      *
1224      * @throws RuntimeException if the size is invalid
1225      *         (<em>Note:</em> after optimization, invalid inputs may
1226      *         go undetected, which will lead to unpredictable
1227      *         behavior)
1228      */
checkSize(long size)1229     private void checkSize(long size) {
1230         if (ADDRESS_SIZE == 4) {
1231             // Note: this will also check for negative sizes
1232             if (!is32BitClean(size)) {
1233                 throw invalidInput();
1234             }
1235         } else if (size < 0) {
1236             throw invalidInput();
1237         }
1238     }
1239 
1240     /**
1241      * Check the validity of a native address (the equivalent of void*)
1242      *
1243      * @throws RuntimeException if the address is invalid
1244      *         (<em>Note:</em> after optimization, invalid inputs may
1245      *         go undetected, which will lead to unpredictable
1246      *         behavior)
1247      */
checkNativeAddress(long address)1248     private void checkNativeAddress(long address) {
1249         if (ADDRESS_SIZE == 4) {
1250             // Accept both zero and sign extended pointers. A valid
1251             // pointer will, after the +1 below, either have produced
1252             // the value 0x0 or 0x1. Masking off the low bit allows
1253             // for testing against 0.
1254             if ((((address >> 32) + 1) & ~1) != 0) {
1255                 throw invalidInput();
1256             }
1257         }
1258     }
1259 
1260     /**
1261      * Check the validity of an offset, relative to a base object
1262      *
1263      * @param o the base object
1264      * @param offset the offset to check
1265      *
1266      * @throws RuntimeException if the size is invalid
1267      *         (<em>Note:</em> after optimization, invalid inputs may
1268      *         go undetected, which will lead to unpredictable
1269      *         behavior)
1270      */
checkOffset(Object o, long offset)1271     private void checkOffset(Object o, long offset) {
1272         if (ADDRESS_SIZE == 4) {
1273             // Note: this will also check for negative offsets
1274             if (!is32BitClean(offset)) {
1275                 throw invalidInput();
1276             }
1277         } else if (offset < 0) {
1278             throw invalidInput();
1279         }
1280     }
1281 
1282     /**
1283      * Check the validity of a double-register pointer
1284      *
1285      * Note: This code deliberately does *not* check for NPE for (at
1286      * least) three reasons:
1287      *
1288      * 1) NPE is not just NULL/0 - there is a range of values all
1289      * resulting in an NPE, which is not trivial to check for
1290      *
1291      * 2) It is the responsibility of the callers of Unsafe methods
1292      * to verify the input, so throwing an exception here is not really
1293      * useful - passing in a NULL pointer is a critical error and the
1294      * must not expect an exception to be thrown anyway.
1295      *
1296      * 3) the actual operations will detect NULL pointers anyway by
1297      * means of traps and signals (like SIGSEGV).
1298      *
1299      * @param o Java heap object, or null
1300      * @param offset indication of where the variable resides in a Java heap
1301      *        object, if any, else a memory address locating the variable
1302      *        statically
1303      *
1304      * @throws RuntimeException if the pointer is invalid
1305      *         (<em>Note:</em> after optimization, invalid inputs may
1306      *         go undetected, which will lead to unpredictable
1307      *         behavior)
1308      */
checkPointer(Object o, long offset)1309     private void checkPointer(Object o, long offset) {
1310         if (o == null) {
1311             checkNativeAddress(offset);
1312         } else {
1313             checkOffset(o, offset);
1314         }
1315     }
1316 
1317     /**
1318      * Check if a type is a primitive array type
1319      *
1320      * @param c the type to check
1321      *
1322      * @return true if the type is a primitive array type
1323      */
checkPrimitiveArray(Class<?> c)1324     private void checkPrimitiveArray(Class<?> c) {
1325         Class<?> componentType = c.getComponentType();
1326         if (componentType == null || !componentType.isPrimitive()) {
1327             throw invalidInput();
1328         }
1329     }
1330 
1331     /**
1332      * Check that a pointer is a valid primitive array type pointer
1333      *
1334      * Note: pointers off-heap are considered to be primitive arrays
1335      *
1336      * @throws RuntimeException if the pointer is invalid
1337      *         (<em>Note:</em> after optimization, invalid inputs may
1338      *         go undetected, which will lead to unpredictable
1339      *         behavior)
1340      */
checkPrimitivePointer(Object o, long offset)1341     private void checkPrimitivePointer(Object o, long offset) {
1342         checkPointer(o, offset);
1343 
1344         if (o != null) {
1345             // If on heap, it must be a primitive array
1346             checkPrimitiveArray(o.getClass());
1347         }
1348     }
1349 
1350 
1351 
1352 }
1353