001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.truffle; 024 025import java.lang.reflect.*; 026import java.util.*; 027 028import sun.misc.*; 029 030import com.oracle.truffle.api.*; 031import com.oracle.truffle.api.frame.*; 032 033/** 034 * More efficient implementation of the Truffle frame that has no safety checks for frame accesses 035 * and therefore is much faster. Should not be used during debugging as potential misuses of the 036 * frame object would show up very late and would be hard to identify. 037 */ 038public final class FrameWithoutBoxing implements VirtualFrame, MaterializedFrame { 039 private final FrameDescriptor descriptor; 040 private final Object[] arguments; 041 private Object[] locals; 042 private long[] primitiveLocals; 043 private byte[] tags; 044 public static final byte OBJECT_TAG = 0; 045 public static final byte ILLEGAL_TAG = 1; 046 public static final byte LONG_TAG = 2; 047 public static final byte INT_TAG = 3; 048 public static final byte DOUBLE_TAG = 4; 049 public static final byte FLOAT_TAG = 5; 050 public static final byte BOOLEAN_TAG = 6; 051 public static final byte BYTE_TAG = 7; 052 053 static { 054 assert OBJECT_TAG == FrameSlotKind.Object.tag; 055 assert ILLEGAL_TAG == FrameSlotKind.Illegal.tag; 056 assert LONG_TAG == FrameSlotKind.Long.tag; 057 assert INT_TAG == FrameSlotKind.Int.tag; 058 assert DOUBLE_TAG == FrameSlotKind.Double.tag; 059 assert FLOAT_TAG == FrameSlotKind.Float.tag; 060 assert BOOLEAN_TAG == FrameSlotKind.Boolean.tag; 061 assert BYTE_TAG == FrameSlotKind.Byte.tag; 062 } 063 064 public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) { 065 this.descriptor = descriptor; 066 this.arguments = arguments; 067 int size = descriptor.getSize(); 068 this.locals = new Object[size]; 069 Object defaultValue = descriptor.getDefaultValue(); 070 if (defaultValue != null) { 071 Arrays.fill(locals, defaultValue); 072 } 073 this.primitiveLocals = new long[size]; 074 this.tags = new byte[size]; 075 } 076 077 @Override 078 public Object[] getArguments() { 079 return unsafeCast(arguments, Object[].class, true, true); 080 } 081 082 @Override 083 public MaterializedFrame materialize() { 084 return this; 085 } 086 087 @Override 088 public Object getObject(FrameSlot slot) throws FrameSlotTypeException { 089 int slotIndex = slot.getIndex(); 090 verifyGet(slotIndex, OBJECT_TAG); 091 return getObjectUnsafe(slotIndex, slot); 092 } 093 094 private Object[] getLocals() { 095 return unsafeCast(locals, Object[].class, true, true); 096 } 097 098 private long[] getPrimitiveLocals() { 099 return unsafeCast(this.primitiveLocals, long[].class, true, true); 100 } 101 102 private byte[] getTags() { 103 return unsafeCast(tags, byte[].class, true, true); 104 } 105 106 private Object getObjectUnsafe(int slotIndex, FrameSlot slot) { 107 boolean condition = this.getTags()[slotIndex] == OBJECT_TAG; 108 return unsafeGetObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, condition, slot); 109 } 110 111 @Override 112 public void setObject(FrameSlot slot, Object value) { 113 int slotIndex = slot.getIndex(); 114 verifySet(slotIndex, OBJECT_TAG); 115 setObjectUnsafe(slotIndex, slot, value); 116 } 117 118 private void setObjectUnsafe(int slotIndex, FrameSlot slot, Object value) { 119 unsafePutObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, slot); 120 } 121 122 @Override 123 public byte getByte(FrameSlot slot) throws FrameSlotTypeException { 124 int slotIndex = slot.getIndex(); 125 verifyGet(slotIndex, BYTE_TAG); 126 return getByteUnsafe(slotIndex, slot); 127 } 128 129 private byte getByteUnsafe(int slotIndex, FrameSlot slot) { 130 long offset = getPrimitiveOffset(slotIndex); 131 boolean condition = this.getTags()[slotIndex] == BYTE_TAG; 132 return (byte) unsafeGetInt(getPrimitiveLocals(), offset, condition, slot); 133 } 134 135 @Override 136 public void setByte(FrameSlot slot, byte value) { 137 int slotIndex = slot.getIndex(); 138 verifySet(slotIndex, BYTE_TAG); 139 setByteUnsafe(slotIndex, slot, value); 140 } 141 142 private void setByteUnsafe(int slotIndex, FrameSlot slot, byte value) { 143 long offset = getPrimitiveOffset(slotIndex); 144 unsafePutInt(getPrimitiveLocals(), offset, value, slot); 145 } 146 147 @Override 148 public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException { 149 int slotIndex = slot.getIndex(); 150 verifyGet(slotIndex, BOOLEAN_TAG); 151 return getBooleanUnsafe(slotIndex, slot); 152 } 153 154 private boolean getBooleanUnsafe(int slotIndex, FrameSlot slot) { 155 long offset = getPrimitiveOffset(slotIndex); 156 boolean condition = this.getTags()[slotIndex] == BOOLEAN_TAG; 157 return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot) != 0; 158 } 159 160 @Override 161 public void setBoolean(FrameSlot slot, boolean value) { 162 int slotIndex = slot.getIndex(); 163 verifySet(slotIndex, BOOLEAN_TAG); 164 setBooleanUnsafe(slotIndex, slot, value); 165 } 166 167 private void setBooleanUnsafe(int slotIndex, FrameSlot slot, boolean value) { 168 long offset = getPrimitiveOffset(slotIndex); 169 unsafePutInt(getPrimitiveLocals(), offset, value ? 1 : 0, slot); 170 } 171 172 @Override 173 public float getFloat(FrameSlot slot) throws FrameSlotTypeException { 174 int slotIndex = slot.getIndex(); 175 verifyGet(slotIndex, FLOAT_TAG); 176 return getFloatUnsafe(slotIndex, slot); 177 } 178 179 private float getFloatUnsafe(int slotIndex, FrameSlot slot) { 180 long offset = getPrimitiveOffset(slotIndex); 181 boolean condition = this.getTags()[slotIndex] == FLOAT_TAG; 182 return unsafeGetFloat(getPrimitiveLocals(), offset, condition, slot); 183 } 184 185 @Override 186 public void setFloat(FrameSlot slot, float value) { 187 int slotIndex = slot.getIndex(); 188 verifySet(slotIndex, FLOAT_TAG); 189 setFloatUnsafe(slotIndex, slot, value); 190 } 191 192 private void setFloatUnsafe(int slotIndex, FrameSlot slot, float value) { 193 long offset = getPrimitiveOffset(slotIndex); 194 unsafePutFloat(getPrimitiveLocals(), offset, value, slot); 195 } 196 197 @Override 198 public long getLong(FrameSlot slot) throws FrameSlotTypeException { 199 int slotIndex = slot.getIndex(); 200 verifyGet(slotIndex, LONG_TAG); 201 return getLongUnsafe(slotIndex, slot); 202 } 203 204 private long getLongUnsafe(int slotIndex, FrameSlot slot) { 205 long offset = getPrimitiveOffset(slotIndex); 206 boolean condition = this.getTags()[slotIndex] == LONG_TAG; 207 return unsafeGetLong(getPrimitiveLocals(), offset, condition, slot); 208 } 209 210 @Override 211 public void setLong(FrameSlot slot, long value) { 212 int slotIndex = slot.getIndex(); 213 verifySet(slotIndex, LONG_TAG); 214 setLongUnsafe(slotIndex, slot, value); 215 } 216 217 private void setLongUnsafe(int slotIndex, FrameSlot slot, long value) { 218 long offset = getPrimitiveOffset(slotIndex); 219 unsafePutLong(getPrimitiveLocals(), offset, value, slot); 220 } 221 222 @Override 223 public int getInt(FrameSlot slot) throws FrameSlotTypeException { 224 int slotIndex = slot.getIndex(); 225 verifyGet(slotIndex, INT_TAG); 226 return getIntUnsafe(slotIndex, slot); 227 } 228 229 private int getIntUnsafe(int slotIndex, FrameSlot slot) { 230 long offset = getPrimitiveOffset(slotIndex); 231 boolean condition = this.getTags()[slot.getIndex()] == INT_TAG; 232 return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot); 233 } 234 235 @Override 236 public void setInt(FrameSlot slot, int value) { 237 int slotIndex = slot.getIndex(); 238 verifySet(slotIndex, INT_TAG); 239 setIntUnsafe(slotIndex, slot, value); 240 } 241 242 private void setIntUnsafe(int slotIndex, FrameSlot slot, int value) { 243 long offset = getPrimitiveOffset(slotIndex); 244 unsafePutInt(getPrimitiveLocals(), offset, value, slot); 245 } 246 247 @Override 248 public double getDouble(FrameSlot slot) throws FrameSlotTypeException { 249 int slotIndex = slot.getIndex(); 250 verifyGet(slotIndex, DOUBLE_TAG); 251 return getDoubleUnsafe(slotIndex, slot); 252 } 253 254 private double getDoubleUnsafe(int slotIndex, FrameSlot slot) { 255 long offset = getPrimitiveOffset(slotIndex); 256 boolean condition = this.getTags()[slotIndex] == DOUBLE_TAG; 257 return unsafeGetDouble(getPrimitiveLocals(), offset, condition, slot); 258 } 259 260 @Override 261 public void setDouble(FrameSlot slot, double value) { 262 int slotIndex = slot.getIndex(); 263 verifySet(slotIndex, DOUBLE_TAG); 264 setDoubleUnsafe(slotIndex, slot, value); 265 } 266 267 private void setDoubleUnsafe(int slotIndex, FrameSlot slot, double value) { 268 long offset = getPrimitiveOffset(slotIndex); 269 unsafePutDouble(getPrimitiveLocals(), offset, value, slot); 270 } 271 272 @Override 273 public FrameDescriptor getFrameDescriptor() { 274 return this.descriptor; 275 } 276 277 private void verifySet(int slotIndex, byte tag) { 278 checkSlotIndex(slotIndex); 279 getTags()[slotIndex] = tag; 280 } 281 282 private void verifyGet(int slotIndex, byte tag) throws FrameSlotTypeException { 283 checkSlotIndex(slotIndex); 284 if (getTags()[slotIndex] != tag) { 285 CompilerDirectives.transferToInterpreter(); 286 throw new FrameSlotTypeException(); 287 } 288 } 289 290 private void checkSlotIndex(int slotIndex) { 291 if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) { 292 if (!resize()) { 293 throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex)); 294 } 295 } 296 } 297 298 private static long getPrimitiveOffset(int slotIndex) { 299 return Unsafe.ARRAY_LONG_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_LONG_INDEX_SCALE; 300 } 301 302 @Override 303 public Object getValue(FrameSlot slot) { 304 int slotIndex = slot.getIndex(); 305 if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) { 306 CompilerDirectives.transferToInterpreter(); 307 resize(); 308 } 309 byte tag = getTags()[slotIndex]; 310 if (tag == BOOLEAN_TAG) { 311 return getBooleanUnsafe(slotIndex, slot); 312 } else if (tag == BYTE_TAG) { 313 return getByteUnsafe(slotIndex, slot); 314 } else if (tag == INT_TAG) { 315 return getIntUnsafe(slotIndex, slot); 316 } else if (tag == DOUBLE_TAG) { 317 return getDoubleUnsafe(slotIndex, slot); 318 } else if (tag == LONG_TAG) { 319 return getLongUnsafe(slotIndex, slot); 320 } else if (tag == FLOAT_TAG) { 321 return getFloatUnsafe(slotIndex, slot); 322 } else { 323 assert tag == OBJECT_TAG; 324 return getObjectUnsafe(slotIndex, slot); 325 } 326 } 327 328 private boolean resize() { 329 int oldSize = tags.length; 330 int newSize = descriptor.getSize(); 331 if (newSize > oldSize) { 332 locals = Arrays.copyOf(locals, newSize); 333 Arrays.fill(locals, oldSize, newSize, descriptor.getDefaultValue()); 334 primitiveLocals = Arrays.copyOf(primitiveLocals, newSize); 335 tags = Arrays.copyOf(tags, newSize); 336 return true; 337 } 338 return false; 339 } 340 341 private byte getTag(FrameSlot slot) { 342 int slotIndex = slot.getIndex(); 343 if (slotIndex >= getTags().length) { 344 CompilerDirectives.transferToInterpreter(); 345 resize(); 346 } 347 return getTags()[slotIndex]; 348 } 349 350 @Override 351 public boolean isObject(FrameSlot slot) { 352 return getTag(slot) == OBJECT_TAG; 353 } 354 355 @Override 356 public boolean isByte(FrameSlot slot) { 357 return getTag(slot) == BYTE_TAG; 358 } 359 360 @Override 361 public boolean isBoolean(FrameSlot slot) { 362 return getTag(slot) == BOOLEAN_TAG; 363 } 364 365 @Override 366 public boolean isInt(FrameSlot slot) { 367 return getTag(slot) == INT_TAG; 368 } 369 370 @Override 371 public boolean isLong(FrameSlot slot) { 372 return getTag(slot) == LONG_TAG; 373 } 374 375 @Override 376 public boolean isFloat(FrameSlot slot) { 377 return getTag(slot) == FLOAT_TAG; 378 } 379 380 @Override 381 public boolean isDouble(FrameSlot slot) { 382 return getTag(slot) == DOUBLE_TAG; 383 } 384 385 @SuppressWarnings({"unchecked", "unused"}) 386 static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) { 387 return (T) value; 388 } 389 390 @SuppressWarnings("unused") 391 static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) { 392 return UNSAFE.getInt(receiver, offset); 393 } 394 395 @SuppressWarnings("unused") 396 static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) { 397 return UNSAFE.getLong(receiver, offset); 398 } 399 400 @SuppressWarnings("unused") 401 static float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity) { 402 return UNSAFE.getFloat(receiver, offset); 403 } 404 405 @SuppressWarnings("unused") 406 static double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity) { 407 return UNSAFE.getDouble(receiver, offset); 408 } 409 410 @SuppressWarnings("unused") 411 static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) { 412 return UNSAFE.getObject(receiver, offset); 413 } 414 415 @SuppressWarnings("unused") 416 static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) { 417 UNSAFE.putInt(receiver, offset, value); 418 } 419 420 @SuppressWarnings("unused") 421 static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) { 422 UNSAFE.putLong(receiver, offset, value); 423 } 424 425 @SuppressWarnings("unused") 426 static void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity) { 427 UNSAFE.putFloat(receiver, offset, value); 428 } 429 430 @SuppressWarnings("unused") 431 static void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity) { 432 UNSAFE.putDouble(receiver, offset, value); 433 } 434 435 @SuppressWarnings("unused") 436 static void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity) { 437 UNSAFE.putObject(receiver, offset, value); 438 } 439 440 private static final Unsafe UNSAFE = getUnsafe(); 441 442 private static Unsafe getUnsafe() { 443 try { 444 return Unsafe.getUnsafe(); 445 } catch (SecurityException e) { 446 } 447 try { 448 Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); 449 theUnsafeInstance.setAccessible(true); 450 return (Unsafe) theUnsafeInstance.get(Unsafe.class); 451 } catch (Exception e) { 452 throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); 453 } 454 } 455}