• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import sun.misc.Unsafe;
34 
35 import java.lang.reflect.Field;
36 import java.nio.Buffer;
37 import java.nio.ByteBuffer;
38 import java.security.AccessController;
39 import java.security.PrivilegedExceptionAction;
40 
41 /**
42  * Utility class for working with unsafe operations.
43  */
44 // TODO(nathanmittler): Add support for Android Memory/MemoryBlock
45 final class UnsafeUtil {
46   private static final sun.misc.Unsafe UNSAFE = getUnsafe();
47   private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
48       supportsUnsafeByteBufferOperations();
49   private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
50   private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
51   private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
52 
UnsafeUtil()53   private UnsafeUtil() {
54   }
55 
hasUnsafeArrayOperations()56   static boolean hasUnsafeArrayOperations() {
57     return HAS_UNSAFE_ARRAY_OPERATIONS;
58   }
59 
hasUnsafeByteBufferOperations()60   static boolean hasUnsafeByteBufferOperations() {
61     return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
62   }
63 
getArrayBaseOffset()64   static long getArrayBaseOffset() {
65     return ARRAY_BASE_OFFSET;
66   }
67 
getByte(byte[] target, long offset)68   static byte getByte(byte[] target, long offset) {
69     return UNSAFE.getByte(target, offset);
70   }
71 
putByte(byte[] target, long offset, byte value)72   static void putByte(byte[] target, long offset, byte value) {
73     UNSAFE.putByte(target, offset, value);
74   }
75 
copyMemory( byte[] src, long srcOffset, byte[] target, long targetOffset, long length)76   static void copyMemory(
77       byte[] src, long srcOffset, byte[] target, long targetOffset, long length) {
78     UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
79   }
80 
getLong(byte[] target, long offset)81   static long getLong(byte[] target, long offset) {
82     return UNSAFE.getLong(target, offset);
83   }
84 
getByte(long address)85   static byte getByte(long address) {
86     return UNSAFE.getByte(address);
87   }
88 
putByte(long address, byte value)89   static void putByte(long address, byte value) {
90     UNSAFE.putByte(address, value);
91   }
92 
getLong(long address)93   static long getLong(long address) {
94     return UNSAFE.getLong(address);
95   }
96 
copyMemory(long srcAddress, long targetAddress, long length)97   static void copyMemory(long srcAddress, long targetAddress, long length) {
98     UNSAFE.copyMemory(srcAddress, targetAddress, length);
99   }
100 
101   /**
102    * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
103    */
addressOffset(ByteBuffer buffer)104   static long addressOffset(ByteBuffer buffer) {
105     return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
106   }
107 
108   /**
109    * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
110    */
getUnsafe()111   private static sun.misc.Unsafe getUnsafe() {
112     sun.misc.Unsafe unsafe = null;
113     try {
114       unsafe =
115           AccessController.doPrivileged(
116               new PrivilegedExceptionAction<Unsafe>() {
117                 @Override
118                 public sun.misc.Unsafe run() throws Exception {
119                   Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
120 
121                   for (Field f : k.getDeclaredFields()) {
122                     f.setAccessible(true);
123                     Object x = f.get(null);
124                     if (k.isInstance(x)) {
125                       return k.cast(x);
126                     }
127                   }
128                   // The sun.misc.Unsafe field does not exist.
129                   return null;
130                 }
131               });
132     } catch (Throwable e) {
133       // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
134       // for Unsafe.
135     }
136     return unsafe;
137   }
138 
139   /**
140    * Indicates whether or not unsafe array operations are supported on this platform.
141    */
supportsUnsafeArrayOperations()142   private static boolean supportsUnsafeArrayOperations() {
143     boolean supported = false;
144     if (UNSAFE != null) {
145       try {
146         Class<?> clazz = UNSAFE.getClass();
147         clazz.getMethod("arrayBaseOffset", Class.class);
148         clazz.getMethod("getByte", Object.class, long.class);
149         clazz.getMethod("putByte", Object.class, long.class, byte.class);
150         clazz.getMethod("getLong", Object.class, long.class);
151         clazz.getMethod(
152             "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
153         supported = true;
154       } catch (Throwable e) {
155         // Do nothing.
156       }
157     }
158     return supported;
159   }
160 
supportsUnsafeByteBufferOperations()161   private static boolean supportsUnsafeByteBufferOperations() {
162     boolean supported = false;
163     if (UNSAFE != null) {
164       try {
165         Class<?> clazz = UNSAFE.getClass();
166         clazz.getMethod("objectFieldOffset", Field.class);
167         clazz.getMethod("getByte", long.class);
168         clazz.getMethod("getLong", Object.class, long.class);
169         clazz.getMethod("putByte", long.class, byte.class);
170         clazz.getMethod("getLong", long.class);
171         clazz.getMethod("copyMemory", long.class, long.class, long.class);
172         supported = true;
173       } catch (Throwable e) {
174         // Do nothing.
175       }
176     }
177     return supported;
178   }
179 
180   /**
181    * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
182    */
byteArrayBaseOffset()183   private static int byteArrayBaseOffset() {
184     return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
185   }
186 
187   /**
188    * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
189    * available.
190    */
fieldOffset(Field field)191   private static long fieldOffset(Field field) {
192     return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
193   }
194 
195   /**
196    * Gets the field with the given name within the class, or {@code null} if not found. If found,
197    * the field is made accessible.
198    */
field(Class<?> clazz, String fieldName)199   private static Field field(Class<?> clazz, String fieldName) {
200     Field field;
201     try {
202       field = clazz.getDeclaredField(fieldName);
203       field.setAccessible(true);
204     } catch (Throwable t) {
205       // Failed to access the fields.
206       field = null;
207     }
208     return field;
209   }
210 }
211