1 /* 2 * Copyright (c) 2015, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.core.common.util; 26 27 import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe; 28 29 import sun.misc.Unsafe; 30 31 /** 32 * Provides low-level read access from a byte[] array for signed and unsigned values of size 1, 2, 33 * 4, and 8 bytes. 34 * 35 * The class can either be instantiated for sequential access to the byte[] array; or static methods 36 * can be used to read values without the overhead of creating an instance. 37 * 38 * The flag {@code supportsUnalignedMemoryAccess} must be set according to the capabilities of the 39 * hardware architecture: the value {@code true} allows more efficient memory access on 40 * architectures that support unaligned memory accesses; the value {@code false} is the safe 41 * fallback that works on every hardware. 42 */ 43 public abstract class UnsafeArrayTypeReader extends AbstractTypeReader { 44 45 private static final Unsafe UNSAFE = getUnsafe(); 46 47 public static int getS1(byte[] data, long byteIndex) { 48 return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES)); 49 } 50 51 public static int getU1(byte[] data, long byteIndex) { 52 return UNSAFE.getByte(data, readOffset(data, byteIndex, Byte.BYTES)) & 0xFF; 53 } 54 55 public static int getS2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 56 if (supportsUnalignedMemoryAccess) { 57 return UnalignedUnsafeArrayTypeReader.getS2(data, byteIndex); 58 } else { 59 return AlignedUnsafeArrayTypeReader.getS2(data, byteIndex); 60 } 61 } 62 63 public static int getU2(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 64 return getS2(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFF; 65 } 66 67 public static int getS4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 68 if (supportsUnalignedMemoryAccess) { 69 return UnalignedUnsafeArrayTypeReader.getS4(data, byteIndex); 70 } else { 71 return AlignedUnsafeArrayTypeReader.getS4(data, byteIndex); 72 } 73 } 74 75 public static long getU4(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 76 return getS4(data, byteIndex, supportsUnalignedMemoryAccess) & 0xFFFFFFFFL; 77 } 78 79 public static long getS8(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 80 if (supportsUnalignedMemoryAccess) { 81 return UnalignedUnsafeArrayTypeReader.getS8(data, byteIndex); 82 } else { 83 return AlignedUnsafeArrayTypeReader.getS8(data, byteIndex); 84 } 85 } 86 87 protected static long readOffset(byte[] data, long byteIndex, int numBytes) { 88 assert byteIndex >= 0; 89 assert numBytes > 0; 90 assert byteIndex + numBytes <= data.length; 91 assert Unsafe.ARRAY_BYTE_INDEX_SCALE == 1; 92 93 return byteIndex + Unsafe.ARRAY_BYTE_BASE_OFFSET; 94 } 95 96 public static UnsafeArrayTypeReader create(byte[] data, long byteIndex, boolean supportsUnalignedMemoryAccess) { 97 if (supportsUnalignedMemoryAccess) { 98 return new UnalignedUnsafeArrayTypeReader(data, byteIndex); 99 } else { 100 return new AlignedUnsafeArrayTypeReader(data, byteIndex); 101 } 102 } 103 104 protected final byte[] data; 105 protected long byteIndex; 106 107 protected UnsafeArrayTypeReader(byte[] data, long byteIndex) { 108 this.data = data; 109 this.byteIndex = byteIndex; 110 } 111 112 @Override 113 public long getByteIndex() { 114 return byteIndex; 115 } 116 117 @Override 118 public void setByteIndex(long byteIndex) { 119 this.byteIndex = byteIndex; 120 } 121 122 @Override 123 public final int getS1() { 124 int result = getS1(data, byteIndex); 125 byteIndex += Byte.BYTES; 126 return result; 127 } 128 129 @Override 130 public final int getU1() { 131 int result = getU1(data, byteIndex); 132 byteIndex += Byte.BYTES; 133 return result; 134 } 135 136 @Override 137 public final int getU2() { 138 return getS2() & 0xFFFF; 139 } 140 141 @Override 142 public final long getU4() { 143 return getS4() & 0xFFFFFFFFL; 144 } 145 } 146 147 final class UnalignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader { 148 private static final Unsafe UNSAFE = getUnsafe(); 149 150 protected static int getS2(byte[] data, long byteIndex) { 151 return UNSAFE.getShort(data, readOffset(data, byteIndex, Short.BYTES)); 152 } 153 154 protected static int getS4(byte[] data, long byteIndex) { 155 return UNSAFE.getInt(data, readOffset(data, byteIndex, Integer.BYTES)); 156 } 157 158 protected static long getS8(byte[] data, long byteIndex) { 159 return UNSAFE.getLong(data, readOffset(data, byteIndex, Long.BYTES)); 160 } 161 162 protected UnalignedUnsafeArrayTypeReader(byte[] data, long byteIndex) { 163 super(data, byteIndex); 164 } 165 166 @Override 167 public int getS2() { 168 int result = getS2(data, byteIndex); 169 byteIndex += Short.BYTES; 170 return result; 171 } 172 173 @Override 174 public int getS4() { 175 int result = getS4(data, byteIndex); 176 byteIndex += Integer.BYTES; 177 return result; 178 } 179 180 @Override 181 public long getS8() { 182 long result = getS8(data, byteIndex); 183 byteIndex += Long.BYTES; 184 return result; 185 } 186 } 187 188 class AlignedUnsafeArrayTypeReader extends UnsafeArrayTypeReader { 189 private static final Unsafe UNSAFE = getUnsafe(); 190 191 protected static int getS2(byte[] data, long byteIndex) { 192 long offset = readOffset(data, byteIndex, Short.BYTES); 193 return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | // 194 (UNSAFE.getByte(data, offset + 1) << 8); 195 } 196 197 protected static int getS4(byte[] data, long byteIndex) { 198 long offset = readOffset(data, byteIndex, Integer.BYTES); 199 return ((UNSAFE.getByte(data, offset + 0) & 0xFF) << 0) | // 200 ((UNSAFE.getByte(data, offset + 1) & 0xFF) << 8) | // 201 ((UNSAFE.getByte(data, offset + 2) & 0xFF) << 16) | // 202 (UNSAFE.getByte(data, offset + 3) << 24); 203 } 204 205 protected static long getS8(byte[] data, long byteIndex) { 206 long offset = readOffset(data, byteIndex, Long.BYTES); 207 return ((long) ((UNSAFE.getByte(data, offset + 0) & 0xFF)) << 0) | // 208 ((long) ((UNSAFE.getByte(data, offset + 1) & 0xFF)) << 8) | // 209 ((long) ((UNSAFE.getByte(data, offset + 2) & 0xFF)) << 16) | // 210 ((long) ((UNSAFE.getByte(data, offset + 3) & 0xFF)) << 24) | // 211 ((long) ((UNSAFE.getByte(data, offset + 4) & 0xFF)) << 32) | // 212 ((long) ((UNSAFE.getByte(data, offset + 5) & 0xFF)) << 40) | // 213 ((long) ((UNSAFE.getByte(data, offset + 6) & 0xFF)) << 48) | // 214 ((long) (UNSAFE.getByte(data, offset + 7)) << 56); 215 } 216 217 protected AlignedUnsafeArrayTypeReader(byte[] data, long byteIndex) { 218 super(data, byteIndex); 219 } 220 221 @Override 222 public int getS2() { 223 int result = getS2(data, byteIndex); 224 byteIndex += Short.BYTES; 225 return result; 226 } 227 228 @Override 229 public int getS4() { 230 int result = getS4(data, byteIndex); 231 byteIndex += Integer.BYTES; 232 return result; 233 } 234 235 @Override 236 public long getS8() { 237 long result = getS8(data, byteIndex); 238 byteIndex += Long.BYTES; 239 return result; 240 } 241 }