1 /*
   2  * Copyright (c) 2011, 2012, 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 package com.oracle.graal.hotspot.meta;
  24 
  25 import static com.oracle.graal.api.code.CallingConvention.Type.*;
  26 import static com.oracle.graal.api.code.DeoptimizationAction.*;
  27 import static com.oracle.graal.api.code.MemoryBarriers.*;
  28 import static com.oracle.graal.api.code.Register.RegisterFlag.*;
  29 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
  30 import static com.oracle.graal.api.meta.Value.*;
  31 import static com.oracle.graal.graph.UnsafeAccess.*;
  32 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
  33 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
  34 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
  35 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
  36 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
  37 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
  38 import static com.oracle.graal.replacements.Log.*;
  39 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
  40 
  41 import java.lang.reflect.*;
  42 import java.util.*;
  43 
  44 import sun.misc.*;
  45 
  46 import com.oracle.graal.api.code.*;
  47 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
  48 import com.oracle.graal.api.code.CompilationResult.Call;
  49 import com.oracle.graal.api.code.CompilationResult.DataPatch;
  50 import com.oracle.graal.api.code.CompilationResult.Mark;
  51 import com.oracle.graal.api.code.CompilationResult.Infopoint;
  52 import com.oracle.graal.api.code.Register.RegisterFlag;
  53 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
  54 import com.oracle.graal.api.meta.*;
  55 import com.oracle.graal.graph.*;
  56 import com.oracle.graal.hotspot.*;
  57 import com.oracle.graal.hotspot.bridge.*;
  58 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
  59 import com.oracle.graal.hotspot.nodes.*;
  60 import com.oracle.graal.hotspot.phases.*;
  61 import com.oracle.graal.hotspot.replacements.*;
  62 import com.oracle.graal.hotspot.stubs.*;
  63 import com.oracle.graal.java.*;
  64 import com.oracle.graal.nodes.*;
  65 import com.oracle.graal.nodes.calc.*;
  66 import com.oracle.graal.nodes.extended.*;
  67 import com.oracle.graal.nodes.extended.WriteNode.WriteBarrierType;
  68 import com.oracle.graal.nodes.java.*;
  69 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
  70 import com.oracle.graal.nodes.spi.*;
  71 import com.oracle.graal.nodes.type.*;
  72 import com.oracle.graal.phases.*;
  73 import com.oracle.graal.printer.*;
  74 import com.oracle.graal.replacements.*;
  75 import com.oracle.graal.word.*;
  76 
  77 /**
  78  * HotSpot implementation of {@link GraalCodeCacheProvider}.
  79  */
  80 public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider {
  81 
  82     public final HotSpotVMConfig config;
  83 
  84     protected final RegisterConfig regConfig;
  85     protected final RegisterConfig globalStubRegConfig;
  86     protected final HotSpotGraalRuntime graalRuntime;
  87 
  88     private CheckCastSnippets.Templates checkcastSnippets;
  89     private InstanceOfSnippets.Templates instanceofSnippets;
  90     private NewObjectSnippets.Templates newObjectSnippets;
  91     private MonitorSnippets.Templates monitorSnippets;
  92     private WriteBarrierSnippets.Templates writeBarrierSnippets;
  93     private BoxingSnippets.Templates boxingSnippets;
  94     private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
  95 
  96     private final Map<Descriptor, HotSpotRuntimeCallTarget> runtimeCalls = new HashMap<>();
  97     private final Map<ResolvedJavaMethod, Stub> stubs = new HashMap<>();
  98 
  99     /**
 100      * Holds onto objects that will be embedded in compiled code. HotSpot treats oops embedded in
 101      * code as weak references so without an external strong root, such an embedded oop will quickly
 102      * die. This in turn will cause the nmethod to be unloaded.
 103      */
 104     private final Map<Object, Object> gcRoots = new HashMap<>();
 105 
 106     /**
 107      * The offset from the origin of an array to the first element.
 108      * 
 109      * @return the offset in bytes
 110      */
 111     public static int getArrayBaseOffset(Kind kind) {
 112         switch (kind) {
 113             case Boolean:
 114                 return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
 115             case Byte:
 116                 return Unsafe.ARRAY_BYTE_BASE_OFFSET;
 117             case Char:
 118                 return Unsafe.ARRAY_CHAR_BASE_OFFSET;
 119             case Short:
 120                 return Unsafe.ARRAY_SHORT_BASE_OFFSET;
 121             case Int:
 122                 return Unsafe.ARRAY_INT_BASE_OFFSET;
 123             case Long:
 124                 return Unsafe.ARRAY_LONG_BASE_OFFSET;
 125             case Float:
 126                 return Unsafe.ARRAY_FLOAT_BASE_OFFSET;
 127             case Double:
 128                 return Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
 129             case Object:
 130                 return Unsafe.ARRAY_OBJECT_BASE_OFFSET;
 131             default:
 132                 throw GraalInternalError.shouldNotReachHere();
 133         }
 134     }
 135 
 136     /**
 137      * The scale used for the index when accessing elements of an array of this kind.
 138      * 
 139      * @return the scale in order to convert the index into a byte offset
 140      */
 141     public static int getArrayIndexScale(Kind kind) {
 142         switch (kind) {
 143             case Boolean:
 144                 return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
 145             case Byte:
 146                 return Unsafe.ARRAY_BYTE_INDEX_SCALE;
 147             case Char:
 148                 return Unsafe.ARRAY_CHAR_INDEX_SCALE;
 149             case Short:
 150                 return Unsafe.ARRAY_SHORT_INDEX_SCALE;
 151             case Int:
 152                 return Unsafe.ARRAY_INT_INDEX_SCALE;
 153             case Long:
 154                 return Unsafe.ARRAY_LONG_INDEX_SCALE;
 155             case Float:
 156                 return Unsafe.ARRAY_FLOAT_INDEX_SCALE;
 157             case Double:
 158                 return Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
 159             case Object:
 160                 return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
 161             default:
 162                 throw GraalInternalError.shouldNotReachHere();
 163         }
 164     }
 165 
 166     protected Value ret(Kind kind) {
 167         if (kind == Kind.Void) {
 168             return ILLEGAL;
 169         }
 170         return globalStubRegConfig.getReturnRegister(kind).asValue(kind);
 171     }
 172 
 173     protected Value[] javaCallingConvention(Kind... arguments) {
 174         return callingConvention(arguments, RuntimeCall);
 175     }
 176 
 177     protected Value[] nativeCallingConvention(Kind... arguments) {
 178         return callingConvention(arguments, NativeCall);
 179     }
 180 
 181     private Value[] callingConvention(Kind[] arguments, CallingConvention.Type type) {
 182         Value[] result = new Value[arguments.length];
 183 
 184         TargetDescription target = graalRuntime.getTarget();
 185         int currentStackOffset = 0;
 186         for (int i = 0; i < arguments.length; i++) {
 187             Kind kind = arguments[i];
 188             RegisterFlag flag = kind == Kind.Float || kind == Kind.Double ? FPU : CPU;
 189             Register[] ccRegs = globalStubRegConfig.getCallingConventionRegisters(type, flag);
 190             if (i < ccRegs.length) {
 191                 result[i] = ccRegs[i].asValue(kind);
 192             } else {
 193                 result[i] = StackSlot.get(kind.getStackKind(), currentStackOffset, false);
 194                 currentStackOffset += Math.max(target.sizeInBytes(kind), target.wordSize);
 195             }
 196         }
 197         return result;
 198     }
 199 
 200     public HotSpotRuntime(HotSpotVMConfig config, HotSpotGraalRuntime graalRuntime) {
 201         this.config = config;
 202         this.graalRuntime = graalRuntime;
 203         regConfig = createRegisterConfig(false);
 204         globalStubRegConfig = createRegisterConfig(true);
 205 
 206         // @formatter:off
 207 
 208         addRuntimeCall(OnStackReplacementPhase.OSR_MIGRATION_END, config.osrMigrationEndStub,
 209                         /*           temps */ null,
 210                         /*             ret */ ret(Kind.Void),
 211                         /* arg0:      long */ javaCallingConvention(Kind.Long));
 212 
 213         addRuntimeCall(REGISTER_FINALIZER, config.registerFinalizerStub,
 214                         /*           temps */ null,
 215                         /*             ret */ ret(Kind.Void),
 216                         /* arg0:    object */ javaCallingConvention(Kind.Object));
 217 
 218         addRuntimeCall(CREATE_NULL_POINTER_EXCEPTION, config.createNullPointerExceptionStub,
 219                         /*           temps */ null,
 220                         /*             ret */ ret(Kind.Object));
 221 
 222         addRuntimeCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, config.createOutOfBoundsExceptionStub,
 223                         /*           temps */ null,
 224                         /*             ret */ ret(Kind.Object),
 225                         /* arg0:     index */ javaCallingConvention(Kind.Int));
 226 
 227         addRuntimeCall(JAVA_TIME_MILLIS, config.javaTimeMillisStub,
 228                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
 229                         /*             ret */ ret(Kind.Long));
 230 
 231         addRuntimeCall(JAVA_TIME_NANOS, config.javaTimeNanosStub,
 232                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
 233                         /*             ret */ ret(Kind.Long));
 234 
 235         addRuntimeCall(ARITHMETIC_SIN, config.arithmeticSinStub,
 236                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
 237                         /*             ret */ ret(Kind.Double),
 238                         /* arg0:     index */ javaCallingConvention(Kind.Double));
 239 
 240         addRuntimeCall(ARITHMETIC_COS, config.arithmeticCosStub,
 241                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
 242                         /*             ret */ ret(Kind.Double),
 243                         /* arg0:     index */ javaCallingConvention(Kind.Double));
 244 
 245         addRuntimeCall(ARITHMETIC_TAN, config.arithmeticTanStub,
 246                         /*           temps */ this.regConfig.getCallerSaveRegisters(),
 247                         /*             ret */ ret(Kind.Double),
 248                         /* arg0:     index */ javaCallingConvention(Kind.Double));
 249 
 250         addRuntimeCall(LOG_PRIMITIVE, config.logPrimitiveStub,
 251                         /*           temps */ null,
 252                         /*             ret */ ret(Kind.Void),
 253                         /* arg0:  typeChar */ javaCallingConvention(Kind.Int,
 254                         /* arg1:     value */                       Kind.Long,
 255                         /* arg2:   newline */                       Kind.Boolean));
 256 
 257         addRuntimeCall(LOG_PRINTF, config.logPrintfStub,
 258                         /*           temps */ null,
 259                         /*             ret */ ret(Kind.Void),
 260                         /* arg0:    format */ javaCallingConvention(Kind.Object,
 261                         /* arg1:     value */                       Kind.Long,
 262                         /* arg2:     value */                       Kind.Long,
 263                         /* arg3:     value */                       Kind.Long));
 264 
 265         addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub,
 266                         /*           temps */ null,
 267                         /*             ret */ ret(Kind.Void),
 268                         /* arg0:    format */ javaCallingConvention(Kind.Long,
 269                         /* arg1:     value */                       Kind.Long,
 270                         /* arg2:     value */                       Kind.Long,
 271                         /* arg3:     value */                       Kind.Long));
 272 
 273         addRuntimeCall(LOG_OBJECT, config.logObjectStub,
 274                         /*           temps */ null,
 275                         /*             ret */ ret(Kind.Void),
 276                         /* arg0:    object */ javaCallingConvention(Kind.Object,
 277                         /* arg1:     flags */                       Kind.Int));
 278         // @formatter:on
 279     }
 280 
 281     /**
 282      * Registers the details for linking a call to a compiled {@link Stub}.
 283      * 
 284      * @param descriptor name and signature of the call
 285      * @param ret where the call returns its result
 286      * @param args where arguments are passed to the call
 287      */
 288     protected RuntimeCallTarget addStubCall(Descriptor descriptor, Value ret, Value... args) {
 289         return addRuntimeCall(descriptor, 0L, null, ret, args);
 290     }
 291 
 292     /**
 293      * Registers the details for linking a runtime call.
 294      * 
 295      * @param descriptor name and signature of the call
 296      * @param address target address of the call
 297      * @param tempRegs temporary registers used (and killed) by the call (null if none)
 298      * @param ret where the call returns its result
 299      * @param args where arguments are passed to the call
 300      */
 301     protected RuntimeCallTarget addRuntimeCall(Descriptor descriptor, long address, Register[] tempRegs, Value ret, Value... args) {
 302         Value[] temps = tempRegs == null || tempRegs.length == 0 ? Value.NONE : new Value[tempRegs.length];
 303         for (int i = 0; i < temps.length; i++) {
 304             temps[i] = tempRegs[i].asValue();
 305         }
 306         assert checkAssignable(descriptor.getResultType(), ret) : descriptor + " incompatible with result location " + ret;
 307         Class[] argTypes = descriptor.getArgumentTypes();
 308         assert argTypes.length == args.length : descriptor + " incompatible with number of argument locations: " + args.length;
 309         for (int i = 0; i < argTypes.length; i++) {
 310             assert checkAssignable(argTypes[i], args[i]) : descriptor + " incompatible with argument location " + i + ": " + args[i];
 311         }
 312         HotSpotRuntimeCallTarget runtimeCall = new HotSpotRuntimeCallTarget(descriptor, address, new CallingConvention(temps, 0, ret, args), graalRuntime.getCompilerToVM());
 313         runtimeCalls.put(descriptor, runtimeCall);
 314         return runtimeCall;
 315     }
 316 
 317     private boolean checkAssignable(Class spec, Value value) {
 318         Kind kind = value.getKind();
 319         if (kind == Kind.Illegal) {
 320             kind = Kind.Void;
 321         }
 322         if (WordBase.class.isAssignableFrom(spec)) {
 323             return kind == graalRuntime.getTarget().wordKind;
 324         }
 325         return kind == Kind.fromJavaClass(spec);
 326     }
 327 
 328     protected abstract RegisterConfig createRegisterConfig(boolean globalStubConfig);
 329 
 330     public void registerReplacements(Replacements replacements) {
 331         if (GraalOptions.IntrinsifyObjectMethods) {
 332             replacements.registerSubstitutions(ObjectSubstitutions.class);
 333         }
 334         if (GraalOptions.IntrinsifySystemMethods) {
 335             replacements.registerSubstitutions(SystemSubstitutions.class);
 336         }
 337         if (GraalOptions.IntrinsifyThreadMethods) {
 338             replacements.registerSubstitutions(ThreadSubstitutions.class);
 339         }
 340         if (GraalOptions.IntrinsifyUnsafeMethods) {
 341             replacements.registerSubstitutions(UnsafeSubstitutions.class);
 342         }
 343         if (GraalOptions.IntrinsifyClassMethods) {
 344             replacements.registerSubstitutions(ClassSubstitutions.class);
 345         }
 346         if (GraalOptions.IntrinsifyAESMethods) {
 347             replacements.registerSubstitutions(AESCryptSubstitutions.class);
 348             replacements.registerSubstitutions(CipherBlockChainingSubstitutions.class);
 349         }
 350         if (GraalOptions.IntrinsifyReflectionMethods) {
 351             replacements.registerSubstitutions(ReflectionSubstitutions.class);
 352         }
 353 
 354         checkcastSnippets = new CheckCastSnippets.Templates(this, replacements, graalRuntime.getTarget());
 355         instanceofSnippets = new InstanceOfSnippets.Templates(this, replacements, graalRuntime.getTarget());
 356         newObjectSnippets = new NewObjectSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useTLAB);
 357         monitorSnippets = new MonitorSnippets.Templates(this, replacements, graalRuntime.getTarget(), config.useFastLocking);
 358         writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, replacements, graalRuntime.getTarget());
 359         boxingSnippets = new BoxingSnippets.Templates(this, replacements, graalRuntime.getTarget());
 360         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, replacements, graalRuntime.getTarget());
 361 
 362         registerStub(new NewInstanceStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_INSTANCE)));
 363         registerStub(new NewArrayStub(this, replacements, graalRuntime.getTarget(), runtimeCalls.get(NEW_ARRAY)));
 364     }
 365 
 366     private void registerStub(Stub stub) {
 367         stub.getLinkage().setStub(stub);
 368         stubs.put(stub.getMethod(), stub);
 369     }
 370 
 371     public HotSpotGraalRuntime getGraalRuntime() {
 372         return graalRuntime;
 373     }
 374 
 375     /**
 376      * Gets the register holding the current thread.
 377      */
 378     public abstract Register threadRegister();
 379 
 380     /**
 381      * Gets the stack pointer register.
 382      */
 383     public abstract Register stackPointerRegister();
 384 
 385     @Override
 386     public String disassemble(CompilationResult compResult, InstalledCode installedCode) {
 387         byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode();
 388         long start = installedCode == null ? 0L : installedCode.getStart();
 389         TargetDescription target = graalRuntime.getTarget();
 390         HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8);
 391         if (compResult != null) {
 392             HexCodeFile.addAnnotations(hcf, compResult.getAnnotations());
 393             addExceptionHandlersComment(compResult, hcf);
 394             Register fp = regConfig.getFrameRegister();
 395             RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0);
 396             for (Infopoint infopoint : compResult.getInfopoints()) {
 397                 if (infopoint instanceof Call) {
 398                     Call call = (Call) infopoint;
 399                     if (call.debugInfo != null) {
 400                         hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString());
 401                     }
 402                     addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}");
 403                 } else {
 404                     if (infopoint.debugInfo != null) {
 405                         hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString());
 406                     }
 407                     addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}");
 408                 }
 409             }
 410             for (DataPatch site : compResult.getDataReferences()) {
 411                 hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}");
 412             }
 413             for (Mark mark : compResult.getMarks()) {
 414                 hcf.addComment(mark.pcOffset, getMarkName(mark));
 415             }
 416         }
 417         return hcf.toEmbeddedString();
 418     }
 419 
 420     /**
 421      * Decodes a call target to a mnemonic if possible.
 422      */
 423     private String getTargetName(Call call) {
 424         Field[] fields = config.getClass().getDeclaredFields();
 425         for (Field f : fields) {
 426             if (f.getName().endsWith("Stub")) {
 427                 f.setAccessible(true);
 428                 try {
 429                     Object address = f.get(config);
 430                     if (address.equals(call.target)) {
 431                         return f.getName() + ":0x" + Long.toHexString((Long) address);
 432                     }
 433                 } catch (Exception e) {
 434                 }
 435             }
 436         }
 437         return String.valueOf(call.target);
 438     }
 439 
 440     /**
 441      * Decodes a mark to a mnemonic if possible.
 442      */
 443     private static String getMarkName(Mark mark) {
 444         Field[] fields = Marks.class.getDeclaredFields();
 445         for (Field f : fields) {
 446             if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) {
 447                 f.setAccessible(true);
 448                 try {
 449                     if (f.get(null).equals(mark.id)) {
 450                         return f.getName();
 451                     }
 452                 } catch (Exception e) {
 453                 }
 454             }
 455         }
 456         return "MARK:" + mark.id;
 457     }
 458 
 459     private static void addExceptionHandlersComment(CompilationResult tm, HexCodeFile hcf) {
 460         if (!tm.getExceptionHandlers().isEmpty()) {
 461             String nl = HexCodeFile.NEW_LINE;
 462             StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl);
 463             for (CompilationResult.ExceptionHandler e : tm.getExceptionHandlers()) {
 464                 buf.append("    ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl);
 465                 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]");
 466                 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]");
 467             }
 468             hcf.addComment(0, buf.toString());
 469         }
 470     }
 471 
 472     private static void addOperandComment(HexCodeFile hcf, int pos, String comment) {
 473         String oldValue = hcf.addOperandComment(pos, comment);
 474         assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue;
 475     }
 476 
 477     @Override
 478     public ResolvedJavaType lookupJavaType(Constant constant) {
 479         if (constant.getKind() != Kind.Object || constant.isNull()) {
 480             return null;
 481         }
 482         Object o = constant.asObject();
 483         return HotSpotResolvedObjectType.fromClass(o.getClass());
 484     }
 485 
 486     @Override
 487     public Signature parseMethodDescriptor(String signature) {
 488         return new HotSpotSignature(signature);
 489     }
 490 
 491     @Override
 492     public boolean constantEquals(Constant x, Constant y) {
 493         return x.equals(y);
 494     }
 495 
 496     @Override
 497     public RegisterConfig lookupRegisterConfig() {
 498         return regConfig;
 499     }
 500 
 501     @Override
 502     public int getMinimumOutgoingSize() {
 503         return config.runtimeCallStackSize;
 504     }
 505 
 506     @Override
 507     public int lookupArrayLength(Constant array) {
 508         if (array.getKind() != Kind.Object || array.isNull() || !array.asObject().getClass().isArray()) {
 509             throw new IllegalArgumentException(array + " is not an array");
 510         }
 511         return Array.getLength(array.asObject());
 512     }
 513 
 514     @Override
 515     public void lower(Node n, LoweringTool tool) {
 516         StructuredGraph graph = (StructuredGraph) n.graph();
 517         Kind wordKind = graalRuntime.getTarget().wordKind;
 518         if (n instanceof ArrayLengthNode) {
 519             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
 520             ValueNode array = arrayLengthNode.array();
 521             ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
 522             arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
 523             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
 524         } else if (n instanceof Invoke) {
 525             Invoke invoke = (Invoke) n;
 526             if (invoke.callTarget() instanceof MethodCallTargetNode) {
 527                 MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
 528                 NodeInputList<ValueNode> parameters = callTarget.arguments();
 529                 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
 530                 if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) {
 531                     invoke.asNode().dependencies().add(tool.createNullCheckGuard(receiver));
 532                 }
 533                 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 534 
 535                 LoweredCallTargetNode loweredCallTarget = null;
 536                 if (callTarget.invokeKind() == InvokeKind.Virtual && GraalOptions.InlineVTableStubs && (GraalOptions.AlwaysInlineVTableStubs || invoke.isPolymorphic())) {
 537 
 538                     HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
 539                     if (!hsMethod.getDeclaringClass().isInterface()) {
 540                         int vtableEntryOffset = hsMethod.vtableEntryOffset();
 541                         if (vtableEntryOffset > 0) {
 542                             // We use LocationNode.ANY_LOCATION for the reads that access the vtable
 543                             // entry and the compiled code entry
 544                             // as HotSpot does not guarantee they are final values.
 545                             assert vtableEntryOffset > 0;
 546                             LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind));
 547                             ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph),
 548                                             StampFactory.forKind(wordKind())));
 549                             ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
 550                                             StampFactory.forKind(wordKind())));
 551 
 552                             loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
 553                                             CallingConvention.Type.JavaCall));
 554 
 555                             graph.addBeforeFixed(invoke.asNode(), hub);
 556                             graph.addAfterFixed(hub, metaspaceMethod);
 557                             graph.addAfterFixed(metaspaceMethod, compiledEntry);
 558                         }
 559                     }
 560                 }
 561 
 562                 if (loweredCallTarget == null) {
 563                     loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
 564                                     callTarget.invokeKind()));
 565                 }
 566                 callTarget.replaceAndDelete(loweredCallTarget);
 567             }
 568         } else if (n instanceof LoadFieldNode) {
 569             LoadFieldNode loadField = (LoadFieldNode) n;
 570             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
 571             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
 572             assert loadField.kind() != Kind.Illegal;
 573             ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
 574             memoryRead.dependencies().add(tool.createNullCheckGuard(object));
 575 
 576             graph.replaceFixedWithFixed(loadField, memoryRead);
 577 
 578             if (loadField.isVolatile()) {
 579                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
 580                 graph.addBeforeFixed(memoryRead, preMembar);
 581                 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
 582                 graph.addAfterFixed(memoryRead, postMembar);
 583             }
 584         } else if (n instanceof StoreFieldNode) {
 585             StoreFieldNode storeField = (StoreFieldNode) n;
 586             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
 587             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
 588             LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
 589             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
 590             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
 591             memoryWrite.dependencies().add(tool.createNullCheckGuard(object));
 592             memoryWrite.setStateAfter(storeField.stateAfter());
 593             graph.replaceFixedWithFixed(storeField, memoryWrite);
 594             FixedWithNextNode last = memoryWrite;
 595             FixedWithNextNode first = memoryWrite;
 596 
 597             if (storeField.isVolatile()) {
 598                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
 599                 graph.addBeforeFixed(first, preMembar);
 600                 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
 601                 graph.addAfterFixed(last, postMembar);
 602             }
 603         } else if (n instanceof CompareAndSwapNode) {
 604             // Separate out GC barrier semantics
 605             CompareAndSwapNode cas = (CompareAndSwapNode) n;
 606             LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
 607             cas.setLocation(location);
 608             cas.setWriteBarrierType(getCompareAndSwapBarrier(cas));
 609         } else if (n instanceof LoadIndexedNode) {
 610             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
 611             ValueNode boundsCheck = createBoundsCheck(loadIndexed, tool);
 612             Kind elementKind = loadIndexed.elementKind();
 613             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
 614             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp()));
 615             memoryRead.dependencies().add(boundsCheck);
 616             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
 617         } else if (n instanceof StoreIndexedNode) {
 618             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
 619             ValueNode boundsCheck = createBoundsCheck(storeIndexed, tool);
 620             Kind elementKind = storeIndexed.elementKind();
 621             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
 622             ValueNode value = storeIndexed.value();
 623             ValueNode array = storeIndexed.array();
 624             if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) {
 625                 // Store check!
 626                 ResolvedJavaType arrayType = array.objectStamp().type();
 627                 if (arrayType != null && array.objectStamp().isExactType()) {
 628                     ResolvedJavaType elementType = arrayType.getComponentType();
 629                     if (!MetaUtil.isJavaLangObject(elementType)) {
 630                         CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null));
 631                         graph.addBeforeFixed(storeIndexed, checkcast);
 632                         value = checkcast;
 633                     }
 634                 } else {
 635                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
 636                     LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
 637                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
 638                     CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value));
 639                     graph.addBeforeFixed(storeIndexed, checkcast);
 640                     graph.addBeforeFixed(checkcast, arrayClass);
 641                     value = checkcast;
 642                 }
 643             }
 644             WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
 645             WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType));
 646             memoryWrite.dependencies().add(boundsCheck);
 647             memoryWrite.setStateAfter(storeIndexed.stateAfter());
 648             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 649 
 650         } else if (n instanceof UnsafeLoadNode) {
 651             UnsafeLoadNode load = (UnsafeLoadNode) n;
 652             assert load.kind() != Kind.Illegal;
 653             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1);
 654             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
 655             // An unsafe read must not floating outside its block as may float above an explicit
 656             // null check on its object.
 657             memoryRead.dependencies().add(BeginNode.prevBegin(load));
 658             graph.replaceFixedWithFixed(load, memoryRead);
 659         } else if (n instanceof UnsafeStoreNode) {
 660             UnsafeStoreNode store = (UnsafeStoreNode) n;
 661             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, 1);
 662             ValueNode object = store.object();
 663             WriteBarrierType barrierType = getUnsafeStoreBarrierType(store);
 664             WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType));
 665             write.setStateAfter(store.stateAfter());
 666             graph.replaceFixedWithFixed(store, write);
 667 
 668         } else if (n instanceof LoadHubNode) {
 669             LoadHubNode loadHub = (LoadHubNode) n;
 670             assert loadHub.kind() == wordKind;
 671             LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
 672             ValueNode object = loadHub.object();
 673             assert !object.isConstant() || object.asConstant().isNull();
 674             ValueNode guard = tool.createNullCheckGuard(object);
 675             ReadNode hub = graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind())));
 676             hub.dependencies().add(guard);
 677             graph.replaceFixed(loadHub, hub);
 678         } else if (n instanceof FixedGuardNode) {
 679             FixedGuardNode node = (FixedGuardNode) n;
 680             ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated())));
 681             graph.replaceFixedWithFixed(node, newAnchor);
 682         } else if (n instanceof CheckCastNode) {
 683             checkcastSnippets.lower((CheckCastNode) n, tool);
 684         } else if (n instanceof CheckCastDynamicNode) {
 685             checkcastSnippets.lower((CheckCastDynamicNode) n);
 686         } else if (n instanceof InstanceOfNode) {
 687             instanceofSnippets.lower((InstanceOfNode) n, tool);
 688         } else if (n instanceof InstanceOfDynamicNode) {
 689             instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
 690         } else if (n instanceof NewInstanceNode) {
 691             newObjectSnippets.lower((NewInstanceNode) n, tool);
 692         } else if (n instanceof NewArrayNode) {
 693             newObjectSnippets.lower((NewArrayNode) n, tool);
 694         } else if (n instanceof MonitorEnterNode) {
 695             monitorSnippets.lower((MonitorEnterNode) n, tool);
 696         } else if (n instanceof MonitorExitNode) {
 697             monitorSnippets.lower((MonitorExitNode) n, tool);
 698         } else if (n instanceof SerialWriteBarrier) {
 699             writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
 700         } else if (n instanceof SerialArrayRangeWriteBarrier) {
 701             writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
 702         } else if (n instanceof TLABAllocateNode) {
 703             newObjectSnippets.lower((TLABAllocateNode) n, tool);
 704         } else if (n instanceof InitializeObjectNode) {
 705             newObjectSnippets.lower((InitializeObjectNode) n, tool);
 706         } else if (n instanceof InitializeArrayNode) {
 707             newObjectSnippets.lower((InitializeArrayNode) n, tool);
 708         } else if (n instanceof NewMultiArrayNode) {
 709             newObjectSnippets.lower((NewMultiArrayNode) n, tool);
 710         } else if (n instanceof LoadExceptionObjectNode) {
 711             exceptionObjectSnippets.lower((LoadExceptionObjectNode) n);
 712         } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
 713             // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
 714             // zero and the MIN_VALUE / -1 cases.
 715         } else if (n instanceof UnwindNode || n instanceof DeoptimizeNode) {
 716             // Nothing to do, using direct LIR lowering for these nodes.
 717         } else if (n instanceof BoxNode) {
 718             boxingSnippets.lower((BoxNode) n);
 719         } else if (n instanceof UnboxNode) {
 720             boxingSnippets.lower((UnboxNode) n);
 721         } else {
 722             assert false : "Node implementing Lowerable not handled: " + n;
 723             throw GraalInternalError.shouldNotReachHere();
 724         }
 725     }
 726 
 727     private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
 728         WriteBarrierType barrierType = WriteBarrierType.NONE;
 729         if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) {
 730             barrierType = WriteBarrierType.IMPRECISE;
 731         }
 732         return barrierType;
 733     }
 734 
 735     private static WriteBarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
 736         WriteBarrierType barrierType = WriteBarrierType.NONE;
 737         if (store.elementKind() == Kind.Object && !store.value().objectStamp().alwaysNull()) {
 738             barrierType = WriteBarrierType.PRECISE;
 739         }
 740         return barrierType;
 741     }
 742 
 743     private static WriteBarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
 744         WriteBarrierType barrierType = WriteBarrierType.NONE;
 745         if (store.value().kind() == Kind.Object && !store.value().objectStamp().alwaysNull()) {
 746             ResolvedJavaType type = store.object().objectStamp().type();
 747             if (type != null && type.isArray()) {
 748                 barrierType = WriteBarrierType.PRECISE;
 749             } else {
 750                 barrierType = WriteBarrierType.IMPRECISE;
 751             }
 752         }
 753         return barrierType;
 754     }
 755 
 756     private static WriteBarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) {
 757         WriteBarrierType barrierType = WriteBarrierType.NONE;
 758         if (cas.expected().kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) {
 759             ResolvedJavaType type = cas.object().objectStamp().type();
 760             if (type != null && type.isArray()) {
 761                 barrierType = WriteBarrierType.PRECISE;
 762             } else {
 763                 barrierType = WriteBarrierType.IMPRECISE;
 764             }
 765         }
 766         return barrierType;
 767     }
 768 
 769     private IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
 770         int scale = this.graalRuntime.getTarget().sizeInBytes(elementKind);
 771         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
 772     }
 773 
 774     private static ValueNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
 775         StructuredGraph graph = (StructuredGraph) n.graph();
 776         ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
 777         ValueNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
 778 
 779         graph.addBeforeFixed(n, arrayLength);
 780         return guard;
 781     }
 782 
 783     public ResolvedJavaType lookupJavaType(Class<?> clazz) {
 784         return HotSpotResolvedObjectType.fromClass(clazz);
 785     }
 786 
 787     /**
 788      * Gets the stub corresponding to a given method.
 789      * 
 790      * @return the stub {@linkplain Stub#getMethod() implemented} by {@code method} or null if
 791      *         {@code method} does not implement a stub
 792      */
 793     public Stub asStub(ResolvedJavaMethod method) {
 794         return stubs.get(method);
 795     }
 796 
 797     public HotSpotRuntimeCallTarget lookupRuntimeCall(Descriptor descriptor) {
 798         HotSpotRuntimeCallTarget callTarget = runtimeCalls.get(descriptor);
 799         assert runtimeCalls != null : descriptor;
 800         callTarget.finalizeAddress(graalRuntime.getBackend());
 801         return callTarget;
 802     }
 803 
 804     public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) {
 805         CompilerToVM c2vm = graalRuntime.getCompilerToVM();
 806         HotSpotResolvedObjectType[] resultHolder = {null};
 807         long metaspaceMethod = c2vm.getMetaspaceMethod(reflectionMethod, resultHolder);
 808         assert metaspaceMethod != 0L;
 809         return resultHolder[0].createMethod(metaspaceMethod);
 810     }
 811 
 812     public ResolvedJavaMethod lookupJavaConstructor(Constructor reflectionConstructor) {
 813         CompilerToVM c2vm = graalRuntime.getCompilerToVM();
 814         HotSpotResolvedObjectType[] resultHolder = {null};
 815         long metaspaceMethod = c2vm.getMetaspaceConstructor(reflectionConstructor, resultHolder);
 816         assert metaspaceMethod != 0L;
 817         return resultHolder[0].createMethod(metaspaceMethod);
 818     }
 819 
 820     public ResolvedJavaField lookupJavaField(Field reflectionField) {
 821         return graalRuntime.getCompilerToVM().getJavaField(reflectionField);
 822     }
 823 
 824     public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, Graph graph, int entryBCI, CompilationResult compResult) {
 825         HotSpotInstalledCode installedCode = new HotSpotInstalledCode(method, graph, true);
 826         graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(method, entryBCI, compResult), installedCode, method.getSpeculationLog());
 827         return installedCode;
 828     }
 829 
 830     @Override
 831     public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
 832         return addMethod(method, compResult, null);
 833     }
 834 
 835     @Override
 836     public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) {
 837         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
 838         HotSpotInstalledCode code = new HotSpotInstalledCode(hotspotMethod, graph, false);
 839         CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompilationResult(hotspotMethod, -1, compResult), code, null);
 840         if (result != CodeInstallResult.OK) {
 841             return null;
 842         }
 843         return code;
 844     }
 845 
 846     @Override
 847     public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) {
 848         final int actionShift = 0;
 849         final int reasonShift = 3;
 850 
 851         int actionValue = convertDeoptAction(action);
 852         int reasonValue = convertDeoptReason(reason);
 853         return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift)));
 854     }
 855 
 856     public int convertDeoptAction(DeoptimizationAction action) {
 857         switch (action) {
 858             case None:
 859                 return config.deoptActionNone;
 860             case RecompileIfTooManyDeopts:
 861                 return config.deoptActionMaybeRecompile;
 862             case InvalidateReprofile:
 863                 return config.deoptActionReinterpret;
 864             case InvalidateRecompile:
 865                 return config.deoptActionMakeNotEntrant;
 866             case InvalidateStopCompiling:
 867                 return config.deoptActionMakeNotCompilable;
 868             default:
 869                 throw GraalInternalError.shouldNotReachHere();
 870         }
 871     }
 872 
 873     public int convertDeoptReason(DeoptimizationReason reason) {
 874         switch (reason) {
 875             case None:
 876                 return config.deoptReasonNone;
 877             case NullCheckException:
 878                 return config.deoptReasonNullCheck;
 879             case BoundsCheckException:
 880                 return config.deoptReasonRangeCheck;
 881             case ClassCastException:
 882                 return config.deoptReasonClassCheck;
 883             case ArrayStoreException:
 884                 return config.deoptReasonArrayCheck;
 885             case UnreachedCode:
 886                 return config.deoptReasonUnreached0;
 887             case TypeCheckedInliningViolated:
 888                 return config.deoptReasonTypeCheckInlining;
 889             case OptimizedTypeCheckViolated:
 890                 return config.deoptReasonOptimizedTypeCheck;
 891             case NotCompiledExceptionHandler:
 892                 return config.deoptReasonNotCompiledExceptionHandler;
 893             case Unresolved:
 894                 return config.deoptReasonUnresolved;
 895             case JavaSubroutineMismatch:
 896                 return config.deoptReasonJsrMismatch;
 897             case ArithmeticException:
 898                 return config.deoptReasonDiv0Check;
 899             case RuntimeConstraint:
 900                 return config.deoptReasonConstraint;
 901             default:
 902                 throw GraalInternalError.shouldNotReachHere();
 903         }
 904     }
 905 
 906     public boolean needsDataPatch(Constant constant) {
 907         return constant.getPrimitiveAnnotation() != null;
 908     }
 909 
 910     /**
 911      * Registers an object created by the compiler and referenced by some generated code. HotSpot
 912      * treats oops embedded in code as weak references so without an external strong root, such an
 913      * embedded oop will quickly die. This in turn will cause the nmethod to be unloaded.
 914      */
 915     public synchronized Object registerGCRoot(Object object) {
 916         Object existing = gcRoots.get(object);
 917         if (existing != null) {
 918             return existing;
 919         }
 920         gcRoots.put(object, object);
 921         return object;
 922     }
 923 
 924     @Override
 925     public Constant readUnsafeConstant(Kind kind, Object base, long displacement) {
 926         switch (kind) {
 927             case Boolean:
 928                 return Constant.forBoolean(base == null ? unsafe.getByte(displacement) != 0 : unsafe.getBoolean(base, displacement));
 929             case Byte:
 930                 return Constant.forByte(base == null ? unsafe.getByte(displacement) : unsafe.getByte(base, displacement));
 931             case Char:
 932                 return Constant.forChar(base == null ? unsafe.getChar(displacement) : unsafe.getChar(base, displacement));
 933             case Short:
 934                 return Constant.forShort(base == null ? unsafe.getShort(displacement) : unsafe.getShort(base, displacement));
 935             case Int:
 936                 return Constant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement));
 937             case Long:
 938                 return Constant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement));
 939             case Float:
 940                 return Constant.forFloat(base == null ? unsafe.getFloat(displacement) : unsafe.getFloat(base, displacement));
 941             case Double:
 942                 return Constant.forDouble(base == null ? unsafe.getDouble(displacement) : unsafe.getDouble(base, displacement));
 943             case Object:
 944                 return Constant.forObject(unsafe.getObject(base, displacement));
 945             default:
 946                 throw GraalInternalError.shouldNotReachHere();
 947         }
 948     }
 949 
 950     @Override
 951     public TargetDescription getTarget() {
 952         return graalRuntime.getTarget();
 953     }
 954 
 955     public String disassemble(InstalledCode code) {
 956         if (code.isValid()) {
 957             long nmethod = ((HotSpotInstalledCode) code).getMethodAddress();
 958             return graalRuntime.getCompilerToVM().disassembleNMethod(nmethod);
 959         }
 960         return null;
 961     }
 962 
 963     public String disassemble(ResolvedJavaMethod method) {
 964         return new BytecodeDisassembler().disassemble(method);
 965     }
 966 }