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.meta.DeoptimizationReason.*;
  29 import static com.oracle.graal.api.meta.LocationIdentity.*;
  30 import static com.oracle.graal.graph.UnsafeAccess.*;
  31 import static com.oracle.graal.hotspot.HotSpotBackend.*;
  32 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
  33 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
  34 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
  35 import static com.oracle.graal.hotspot.nodes.MonitorExitStubCall.*;
  36 import static com.oracle.graal.hotspot.nodes.NewArrayStubCall.*;
  37 import static com.oracle.graal.hotspot.nodes.NewInstanceStubCall.*;
  38 import static com.oracle.graal.hotspot.nodes.NewMultiArrayStubCall.*;
  39 import static com.oracle.graal.hotspot.nodes.VMErrorNode.*;
  40 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
  41 import static com.oracle.graal.hotspot.replacements.MonitorSnippets.*;
  42 import static com.oracle.graal.hotspot.replacements.NewObjectSnippets.*;
  43 import static com.oracle.graal.hotspot.replacements.SystemSubstitutions.*;
  44 import static com.oracle.graal.hotspot.replacements.ThreadSubstitutions.*;
  45 import static com.oracle.graal.hotspot.replacements.WriteBarrierSnippets.*;
  46 import static com.oracle.graal.hotspot.stubs.ExceptionHandlerStub.*;
  47 import static com.oracle.graal.hotspot.stubs.NewArrayStub.*;
  48 import static com.oracle.graal.hotspot.stubs.NewInstanceStub.*;
  49 import static com.oracle.graal.hotspot.stubs.StubUtil.*;
  50 import static com.oracle.graal.hotspot.stubs.UnwindExceptionToCallerStub.*;
  51 import static com.oracle.graal.java.GraphBuilderPhase.RuntimeCalls.*;
  52 import static com.oracle.graal.nodes.java.RegisterFinalizerNode.*;
  53 import static com.oracle.graal.phases.GraalOptions.*;
  54 import static com.oracle.graal.replacements.Log.*;
  55 import static com.oracle.graal.replacements.MathSubstitutionsX86.*;
  56 
  57 import java.lang.reflect.*;
  58 import java.util.*;
  59 
  60 import sun.misc.*;
  61 
  62 import com.oracle.graal.api.code.*;
  63 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
  64 import com.oracle.graal.api.code.CompilationResult.Call;
  65 import com.oracle.graal.api.code.CompilationResult.DataPatch;
  66 import com.oracle.graal.api.code.CompilationResult.Infopoint;
  67 import com.oracle.graal.api.code.CompilationResult.Mark;
  68 import com.oracle.graal.api.meta.*;
  69 import com.oracle.graal.graph.*;
  70 import com.oracle.graal.hotspot.*;
  71 import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect;
  72 import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition;
  73 import com.oracle.graal.hotspot.bridge.*;
  74 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
  75 import com.oracle.graal.hotspot.nodes.*;
  76 import com.oracle.graal.hotspot.phases.*;
  77 import com.oracle.graal.hotspot.replacements.*;
  78 import com.oracle.graal.hotspot.stubs.*;
  79 import com.oracle.graal.java.*;
  80 import com.oracle.graal.nodes.*;
  81 import com.oracle.graal.nodes.HeapAccess.WriteBarrierType;
  82 import com.oracle.graal.nodes.calc.*;
  83 import com.oracle.graal.nodes.extended.*;
  84 import com.oracle.graal.nodes.java.*;
  85 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
  86 import com.oracle.graal.nodes.spi.*;
  87 import com.oracle.graal.nodes.spi.Lowerable.LoweringType;
  88 import com.oracle.graal.nodes.type.*;
  89 import com.oracle.graal.nodes.virtual.*;
  90 import com.oracle.graal.phases.tiers.*;
  91 import com.oracle.graal.printer.*;
  92 import com.oracle.graal.replacements.*;
  93 import com.oracle.graal.word.*;
  94 
  95 /**
  96  * HotSpot implementation of {@link GraalCodeCacheProvider}.
  97  */
  98 public abstract class HotSpotRuntime implements GraalCodeCacheProvider, DisassemblerProvider, BytecodeDisassemblerProvider, SuitesProvider {
  99 
 100     public static final ForeignCallDescriptor OSR_MIGRATION_END = new ForeignCallDescriptor("OSR_migration_end", void.class, long.class);
 101     public static final ForeignCallDescriptor IDENTITY_HASHCODE = new ForeignCallDescriptor("identity_hashcode", int.class, Object.class);
 102     public static final ForeignCallDescriptor VERIFY_OOP = new ForeignCallDescriptor("verify_oop", Object.class, Object.class);
 103     public static final ForeignCallDescriptor LOAD_AND_CLEAR_EXCEPTION = new ForeignCallDescriptor("load_and_clear_exception", Object.class, Word.class);
 104 
 105     public final HotSpotVMConfig config;
 106 
 107     protected final RegisterConfig regConfig;
 108     protected final HotSpotGraalRuntime graalRuntime;
 109     private final Suites defaultSuites;
 110 
 111     private CheckCastSnippets.Templates checkcastSnippets;
 112     private InstanceOfSnippets.Templates instanceofSnippets;
 113     private NewObjectSnippets.Templates newObjectSnippets;
 114     private MonitorSnippets.Templates monitorSnippets;
 115     private WriteBarrierSnippets.Templates writeBarrierSnippets;
 116     private BoxingSnippets.Templates boxingSnippets;
 117     private LoadExceptionObjectSnippets.Templates exceptionObjectSnippets;
 118 
 119     private final Map<ForeignCallDescriptor, HotSpotForeignCallLinkage> foreignCalls = new HashMap<>();
 120 
 121     /**
 122      * The offset from the origin of an array to the first element.
 123      * 
 124      * @return the offset in bytes
 125      */
 126     public static int getArrayBaseOffset(Kind kind) {
 127         switch (kind) {
 128             case Boolean:
 129                 return Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
 130             case Byte:
 131                 return Unsafe.ARRAY_BYTE_BASE_OFFSET;
 132             case Char:
 133                 return Unsafe.ARRAY_CHAR_BASE_OFFSET;
 134             case Short:
 135                 return Unsafe.ARRAY_SHORT_BASE_OFFSET;
 136             case Int:
 137                 return Unsafe.ARRAY_INT_BASE_OFFSET;
 138             case Long:
 139                 return Unsafe.ARRAY_LONG_BASE_OFFSET;
 140             case Float:
 141                 return Unsafe.ARRAY_FLOAT_BASE_OFFSET;
 142             case Double:
 143                 return Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
 144             case Object:
 145                 return Unsafe.ARRAY_OBJECT_BASE_OFFSET;
 146             default:
 147                 throw GraalInternalError.shouldNotReachHere();
 148         }
 149     }
 150 
 151     /**
 152      * The scale used for the index when accessing elements of an array of this kind.
 153      * 
 154      * @return the scale in order to convert the index into a byte offset
 155      */
 156     public static int getArrayIndexScale(Kind kind) {
 157         switch (kind) {
 158             case Boolean:
 159                 return Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
 160             case Byte:
 161                 return Unsafe.ARRAY_BYTE_INDEX_SCALE;
 162             case Char:
 163                 return Unsafe.ARRAY_CHAR_INDEX_SCALE;
 164             case Short:
 165                 return Unsafe.ARRAY_SHORT_INDEX_SCALE;
 166             case Int:
 167                 return Unsafe.ARRAY_INT_INDEX_SCALE;
 168             case Long:
 169                 return Unsafe.ARRAY_LONG_INDEX_SCALE;
 170             case Float:
 171                 return Unsafe.ARRAY_FLOAT_INDEX_SCALE;
 172             case Double:
 173                 return Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
 174             case Object:
 175                 return Unsafe.ARRAY_OBJECT_INDEX_SCALE;
 176             default:
 177                 throw GraalInternalError.shouldNotReachHere();
 178         }
 179     }
 180 
 181     public HotSpotRuntime(HotSpotVMConfig c, HotSpotGraalRuntime graalRuntime) {
 182         this.config = c;
 183         this.graalRuntime = graalRuntime;
 184         regConfig = createRegisterConfig();
 185         defaultSuites = createSuites();
 186     }
 187 
 188     protected abstract RegisterConfig createRegisterConfig();
 189 
 190     /**
 191      * Registers the linkage for a foreign call.
 192      */
 193     protected HotSpotForeignCallLinkage register(HotSpotForeignCallLinkage linkage) {
 194         assert !foreignCalls.containsKey(linkage.getDescriptor()) : "already registered linkage for " + linkage.getDescriptor();
 195         foreignCalls.put(linkage.getDescriptor(), linkage);
 196         return linkage;
 197     }
 198 
 199     /**
 200      * Creates and registers the details for linking a foreign call to a {@link Stub}.
 201      * 
 202      * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side
 203      *            effects. Deoptimization will not return to a point before a stub call that cannot
 204      *            be re-executed.
 205      * @param killedLocations the memory locations killed by the stub call
 206      */
 207     protected HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor, boolean reexecutable, LocationIdentity... killedLocations) {
 208         return register(HotSpotForeignCallLinkage.create(descriptor, 0L, PRESERVES_REGISTERS, JavaCallee, NOT_LEAF, reexecutable, killedLocations));
 209     }
 210 
 211     /**
 212      * Creates and registers the linkage for a foreign call.
 213      * 
 214      * @param reexecutable specifies if the stub call can be re-executed without (meaningful) side
 215      *            effects. Deoptimization will not return to a point before a stub call that cannot
 216      *            be re-executed.
 217      * @param killedLocations the memory locations killed by the stub call
 218      */
 219     protected HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type ccType, RegisterEffect effect, Transition transition,
 220                     boolean reexecutable, LocationIdentity... killedLocations) {
 221         Class<?> resultType = descriptor.getResultType();
 222         assert transition == LEAF || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor;
 223         return register(HotSpotForeignCallLinkage.create(descriptor, address, effect, ccType, transition, reexecutable, killedLocations));
 224     }
 225 
 226     private static void link(Stub stub) {
 227         stub.getLinkage().setCompiledStub(stub);
 228     }
 229 
 230     /**
 231      * Creates a {@linkplain ForeignCallStub stub} for a non-leaf foreign call.
 232      * 
 233      * @param descriptor the signature of the call to this stub
 234      * @param address the address of the code to call
 235      * @param prependThread true if the JavaThread value for the current thread is to be prepended
 236      *            to the arguments for the call to {@code address}
 237      * @param reexecutable specifies if the foreign call can be re-executed without (meaningful)
 238      *            side effects. Deoptimization will not return to a point before a foreign call that
 239      *            cannot be re-executed.
 240      * @param killedLocations the memory locations killed by the foreign call
 241      */
 242     private void linkForeignCall(Replacements replacements, ForeignCallDescriptor descriptor, long address, boolean prependThread, boolean reexecutable, LocationIdentity... killedLocations) {
 243         ForeignCallStub stub = new ForeignCallStub(this, replacements, address, descriptor, prependThread, reexecutable, killedLocations);
 244         HotSpotForeignCallLinkage linkage = stub.getLinkage();
 245         HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage();
 246         linkage.setCompiledStub(stub);
 247         register(linkage);
 248         register(targetLinkage);
 249     }
 250 
 251     public static final boolean PREPEND_THREAD = true;
 252     public static final boolean DONT_PREPEND_THREAD = !PREPEND_THREAD;
 253 
 254     public static final boolean REEXECUTABLE = true;
 255     public static final boolean NOT_REEXECUTABLE = !REEXECUTABLE;
 256 
 257     public static final LocationIdentity[] NO_LOCATIONS = {};
 258 
 259     public void registerReplacements(Replacements r) {
 260         HotSpotVMConfig c = config;
 261         TargetDescription target = getTarget();
 262 
 263         registerForeignCall(UNCOMMON_TRAP, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 264         registerForeignCall(DEOPT_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 265         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub, NativeCall, PRESERVES_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 266 
 267         registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 268         registerForeignCall(JAVA_TIME_NANOS, c.javaTimeNanosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 269         registerForeignCall(ARITHMETIC_SIN, c.arithmeticSinAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 270         registerForeignCall(ARITHMETIC_COS, c.arithmeticCosAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 271         registerForeignCall(ARITHMETIC_TAN, c.arithmeticTanAddress, NativeCall, DESTROYS_REGISTERS, LEAF, REEXECUTABLE, NO_LOCATIONS);
 272         registerForeignCall(LOAD_AND_CLEAR_EXCEPTION, c.loadAndClearExceptionAddress, NativeCall, DESTROYS_REGISTERS, LEAF, NOT_REEXECUTABLE, ANY_LOCATION);
 273 
 274         registerForeignCall(EXCEPTION_HANDLER_FOR_PC, c.exceptionHandlerForPcAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
 275         registerForeignCall(EXCEPTION_HANDLER_FOR_RETURN_ADDRESS, c.exceptionHandlerForReturnAddressAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
 276         registerForeignCall(NEW_ARRAY_C, c.newArrayAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
 277         registerForeignCall(NEW_INSTANCE_C, c.newInstanceAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, ANY_LOCATION);
 278         registerForeignCall(VM_MESSAGE_C, c.vmMessageAddress, NativeCall, DESTROYS_REGISTERS, NOT_LEAF, REEXECUTABLE, NO_LOCATIONS);
 279 
 280         link(new NewInstanceStub(this, r, target, registerStubCall(NEW_INSTANCE, REEXECUTABLE, ANY_LOCATION)));
 281         link(new NewArrayStub(this, r, target, registerStubCall(NEW_ARRAY, REEXECUTABLE, ANY_LOCATION)));
 282         link(new ExceptionHandlerStub(this, r, target, foreignCalls.get(EXCEPTION_HANDLER)));
 283         link(new UnwindExceptionToCallerStub(this, r, target, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, ANY_LOCATION)));
 284         link(new VerifyOopStub(this, r, target, registerStubCall(VERIFY_OOP, REEXECUTABLE, NO_LOCATIONS)));
 285 
 286         linkForeignCall(r, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
 287         linkForeignCall(r, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, NOT_REEXECUTABLE, ANY_LOCATION);
 288         linkForeignCall(r, CREATE_NULL_POINTER_EXCEPTION, c.createNullPointerExceptionAddress, PREPEND_THREAD, REEXECUTABLE, ANY_LOCATION);
 289         linkForeignCall(r, CREATE_OUT_OF_BOUNDS_EXCEPTION, c.createOutOfBoundsExceptionAddress, PREPEND_THREAD, REEXECUTABLE, ANY_LOCATION);
 290         linkForeignCall(r, MONITORENTER, c.monitorenterAddress, PREPEND_THREAD, NOT_REEXECUTABLE, ANY_LOCATION);
 291         linkForeignCall(r, MONITOREXIT, c.monitorexitAddress, PREPEND_THREAD, NOT_REEXECUTABLE, ANY_LOCATION);
 292         linkForeignCall(r, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, REEXECUTABLE, ANY_LOCATION);
 293         linkForeignCall(r, DYNAMIC_NEW_ARRAY, c.dynamicNewArrayAddress, PREPEND_THREAD, REEXECUTABLE, ANY_LOCATION);
 294         linkForeignCall(r, LOG_PRINTF, c.logPrintfAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 295         linkForeignCall(r, LOG_OBJECT, c.logObjectAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 296         linkForeignCall(r, LOG_PRIMITIVE, c.logPrimitiveAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 297         linkForeignCall(r, THREAD_IS_INTERRUPTED, c.threadIsInterruptedAddress, PREPEND_THREAD, NOT_REEXECUTABLE, ANY_LOCATION);
 298         linkForeignCall(r, VM_ERROR, c.vmErrorAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 299         linkForeignCall(r, OSR_MIGRATION_END, c.osrMigrationEndAddress, DONT_PREPEND_THREAD, NOT_REEXECUTABLE, NO_LOCATIONS);
 300         linkForeignCall(r, G1WBPRECALL, c.writeBarrierPreAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 301         linkForeignCall(r, G1WBPOSTCALL, c.writeBarrierPostAddress, PREPEND_THREAD, REEXECUTABLE, NO_LOCATIONS);
 302         if (IntrinsifyObjectMethods.getValue()) {
 303             r.registerSubstitutions(ObjectSubstitutions.class);
 304         }
 305         if (IntrinsifySystemMethods.getValue()) {
 306             r.registerSubstitutions(SystemSubstitutions.class);
 307         }
 308         if (IntrinsifyThreadMethods.getValue()) {
 309             r.registerSubstitutions(ThreadSubstitutions.class);
 310         }
 311         if (IntrinsifyUnsafeMethods.getValue()) {
 312             r.registerSubstitutions(UnsafeSubstitutions.class);
 313         }
 314         if (IntrinsifyClassMethods.getValue()) {
 315             r.registerSubstitutions(ClassSubstitutions.class);
 316         }
 317         if (IntrinsifyAESMethods.getValue()) {
 318             r.registerSubstitutions(AESCryptSubstitutions.class);
 319             r.registerSubstitutions(CipherBlockChainingSubstitutions.class);
 320         }
 321         if (IntrinsifyReflectionMethods.getValue()) {
 322             r.registerSubstitutions(ReflectionSubstitutions.class);
 323         }
 324 
 325         checkcastSnippets = new CheckCastSnippets.Templates(this, r, graalRuntime.getTarget());
 326         instanceofSnippets = new InstanceOfSnippets.Templates(this, r, graalRuntime.getTarget());
 327         newObjectSnippets = new NewObjectSnippets.Templates(this, r, graalRuntime.getTarget());
 328         monitorSnippets = new MonitorSnippets.Templates(this, r, graalRuntime.getTarget(), c.useFastLocking);
 329         writeBarrierSnippets = new WriteBarrierSnippets.Templates(this, r, graalRuntime.getTarget());
 330         boxingSnippets = new BoxingSnippets.Templates(this, r, graalRuntime.getTarget());
 331         exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(this, r, graalRuntime.getTarget());
 332 
 333         r.registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(this, r, graalRuntime.getTarget()));
 334     }
 335 
 336     public HotSpotGraalRuntime getGraalRuntime() {
 337         return graalRuntime;
 338     }
 339 
 340     /**
 341      * Gets the register holding the current thread.
 342      */
 343     public abstract Register threadRegister();
 344 
 345     /**
 346      * Gets the stack pointer register.
 347      */
 348     public abstract Register stackPointerRegister();
 349 
 350     @Override
 351     public String disassemble(CompilationResult compResult, InstalledCode installedCode) {
 352         byte[] code = installedCode == null ? Arrays.copyOf(compResult.getTargetCode(), compResult.getTargetCodeSize()) : installedCode.getCode();
 353         long start = installedCode == null ? 0L : installedCode.getStart();
 354         TargetDescription target = graalRuntime.getTarget();
 355         HexCodeFile hcf = new HexCodeFile(code, start, target.arch.getName(), target.wordSize * 8);
 356         if (compResult != null) {
 357             HexCodeFile.addAnnotations(hcf, compResult.getAnnotations());
 358             addExceptionHandlersComment(compResult, hcf);
 359             Register fp = regConfig.getFrameRegister();
 360             RefMapFormatter slotFormatter = new RefMapFormatter(target.arch, target.wordSize, fp, 0);
 361             for (Infopoint infopoint : compResult.getInfopoints()) {
 362                 if (infopoint instanceof Call) {
 363                     Call call = (Call) infopoint;
 364                     if (call.debugInfo != null) {
 365                         hcf.addComment(call.pcOffset + call.size, CodeUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString());
 366                     }
 367                     addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}");
 368                 } else {
 369                     if (infopoint.debugInfo != null) {
 370                         hcf.addComment(infopoint.pcOffset, CodeUtil.append(new StringBuilder(100), infopoint.debugInfo, slotFormatter).toString());
 371                     }
 372                     addOperandComment(hcf, infopoint.pcOffset, "{infopoint: " + infopoint.reason + "}");
 373                 }
 374             }
 375             for (DataPatch site : compResult.getDataReferences()) {
 376                 hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}");
 377             }
 378             for (Mark mark : compResult.getMarks()) {
 379                 hcf.addComment(mark.pcOffset, getMarkName(mark));
 380             }
 381         }
 382         return hcf.toEmbeddedString();
 383     }
 384 
 385     /**
 386      * Decodes a call target to a mnemonic if possible.
 387      */
 388     private String getTargetName(Call call) {
 389         Field[] fields = config.getClass().getDeclaredFields();
 390         for (Field f : fields) {
 391             if (f.getName().endsWith("Stub")) {
 392                 f.setAccessible(true);
 393                 try {
 394                     Object address = f.get(config);
 395                     if (address.equals(call.target)) {
 396                         return f.getName() + ":0x" + Long.toHexString((Long) address);
 397                     }
 398                 } catch (Exception e) {
 399                 }
 400             }
 401         }
 402         return String.valueOf(call.target);
 403     }
 404 
 405     /**
 406      * Decodes a mark to a mnemonic if possible.
 407      */
 408     private static String getMarkName(Mark mark) {
 409         Field[] fields = Marks.class.getDeclaredFields();
 410         for (Field f : fields) {
 411             if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) {
 412                 f.setAccessible(true);
 413                 try {
 414                     if (f.get(null).equals(mark.id)) {
 415                         return f.getName();
 416                     }
 417                 } catch (Exception e) {
 418                 }
 419             }
 420         }
 421         return "MARK:" + mark.id;
 422     }
 423 
 424     private static void addExceptionHandlersComment(CompilationResult compResult, HexCodeFile hcf) {
 425         if (!compResult.getExceptionHandlers().isEmpty()) {
 426             String nl = HexCodeFile.NEW_LINE;
 427             StringBuilder buf = new StringBuilder("------ Exception Handlers ------").append(nl);
 428             for (CompilationResult.ExceptionHandler e : compResult.getExceptionHandlers()) {
 429                 buf.append("    ").append(e.pcOffset).append(" -> ").append(e.handlerPos).append(nl);
 430                 hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]");
 431                 hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]");
 432             }
 433             hcf.addComment(0, buf.toString());
 434         }
 435     }
 436 
 437     private static void addOperandComment(HexCodeFile hcf, int pos, String comment) {
 438         String oldValue = hcf.addOperandComment(pos, comment);
 439         assert oldValue == null : "multiple comments for operand of instruction at " + pos + ": " + comment + ", " + oldValue;
 440     }
 441 
 442     @Override
 443     public ResolvedJavaType lookupJavaType(Constant constant) {
 444         if (constant.getKind() != Kind.Object || constant.isNull()) {
 445             return null;
 446         }
 447         Object o = constant.asObject();
 448         return HotSpotResolvedObjectType.fromClass(o.getClass());
 449     }
 450 
 451     @Override
 452     public Signature parseMethodDescriptor(String signature) {
 453         return new HotSpotSignature(signature);
 454     }
 455 
 456     @Override
 457     public boolean constantEquals(Constant x, Constant y) {
 458         return x.equals(y);
 459     }
 460 
 461     @Override
 462     public RegisterConfig lookupRegisterConfig() {
 463         return regConfig;
 464     }
 465 
 466     @Override
 467     public int getMinimumOutgoingSize() {
 468         return config.runtimeCallStackSize;
 469     }
 470 
 471     @Override
 472     public int lookupArrayLength(Constant array) {
 473         if (array.getKind() != Kind.Object || array.isNull() || !array.asObject().getClass().isArray()) {
 474             throw new IllegalArgumentException(array + " is not an array");
 475         }
 476         return Array.getLength(array.asObject());
 477     }
 478 
 479     @Override
 480     public void lower(Node n, LoweringTool tool) {
 481         StructuredGraph graph = (StructuredGraph) n.graph();
 482         Kind wordKind = graalRuntime.getTarget().wordKind;
 483         if (n instanceof ArrayLengthNode) {
 484             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
 485             ValueNode array = arrayLengthNode.array();
 486             ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt(),
 487                             WriteBarrierType.NONE, false));
 488             tool.createNullCheckGuard(arrayLengthRead, array);
 489             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
 490         } else if (n instanceof Invoke) {
 491             Invoke invoke = (Invoke) n;
 492             if (invoke.callTarget() instanceof MethodCallTargetNode) {
 493 
 494                 MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
 495                 NodeInputList<ValueNode> parameters = callTarget.arguments();
 496                 ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0);
 497                 GuardingNode receiverNullCheck = null;
 498                 if (!callTarget.isStatic() && receiver.kind() == Kind.Object && !receiver.objectStamp().nonNull()) {
 499                     receiverNullCheck = tool.createNullCheckGuard(invoke, receiver);
 500                 }
 501                 JavaType[] signature = MetaUtil.signatureToTypes(callTarget.targetMethod().getSignature(), callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass());
 502 
 503                 LoweredCallTargetNode loweredCallTarget = null;
 504                 if (callTarget.invokeKind() == InvokeKind.Virtual && InlineVTableStubs.getValue() && (AlwaysInlineVTableStubs.getValue() || invoke.isPolymorphic())) {
 505 
 506                     HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod();
 507                     if (!hsMethod.getDeclaringClass().isInterface()) {
 508                         if (hsMethod.isInVirtualMethodTable()) {
 509                             int vtableEntryOffset = hsMethod.vtableEntryOffset();
 510                             assert vtableEntryOffset > 0;
 511                             ReadNode hub = createReadHub(graph, wordKind, receiver);
 512 
 513                             if (receiverNullCheck != null) {
 514                                 hub.setGuard(receiverNullCheck);
 515                             }
 516 
 517                             ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, hub, hsMethod);
 518                             // We use LocationNode.ANY_LOCATION for the reads that access the
 519                             // compiled code entry as HotSpot does not guarantee they are final
 520                             // values.
 521                             ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
 522                                             StampFactory.forKind(wordKind()), WriteBarrierType.NONE, false));
 523 
 524                             loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
 525                                             CallingConvention.Type.JavaCall));
 526 
 527                             graph.addBeforeFixed(invoke.asNode(), hub);
 528                             graph.addAfterFixed(hub, metaspaceMethod);
 529                             graph.addAfterFixed(metaspaceMethod, compiledEntry);
 530                         }
 531                     }
 532                 }
 533 
 534                 if (loweredCallTarget == null) {
 535                     loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(), CallingConvention.Type.JavaCall,
 536                                     callTarget.invokeKind()));
 537                 }
 538                 callTarget.replaceAndDelete(loweredCallTarget);
 539             }
 540         } else if (n instanceof LoadFieldNode) {
 541             LoadFieldNode loadField = (LoadFieldNode) n;
 542             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
 543             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
 544             assert loadField.kind() != Kind.Illegal;
 545             WriteBarrierType barrierType = getFieldLoadBarrierType(field);
 546             ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
 547             tool.createNullCheckGuard(memoryRead, object);
 548 
 549             graph.replaceFixedWithFixed(loadField, memoryRead);
 550 
 551             if (loadField.isVolatile()) {
 552                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
 553                 graph.addBeforeFixed(memoryRead, preMembar);
 554                 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
 555                 graph.addAfterFixed(memoryRead, postMembar);
 556             }
 557         } else if (n instanceof StoreFieldNode) {
 558             StoreFieldNode storeField = (StoreFieldNode) n;
 559             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
 560             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
 561             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
 562             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType, storeField.field().getKind() == Kind.Object));
 563             tool.createNullCheckGuard(memoryWrite, object);
 564             memoryWrite.setStateAfter(storeField.stateAfter());
 565             graph.replaceFixedWithFixed(storeField, memoryWrite);
 566             FixedWithNextNode last = memoryWrite;
 567             FixedWithNextNode first = memoryWrite;
 568 
 569             if (storeField.isVolatile()) {
 570                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
 571                 graph.addBeforeFixed(first, preMembar);
 572                 MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
 573                 graph.addAfterFixed(last, postMembar);
 574             }
 575         } else if (n instanceof CompareAndSwapNode) {
 576             // Separate out GC barrier semantics
 577             CompareAndSwapNode cas = (CompareAndSwapNode) n;
 578             LocationNode location = IndexedLocationNode.create(ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
 579             cas.setLocation(location);
 580             cas.setWriteBarrierType(getCompareAndSwapBarrier(cas));
 581             if (cas.expected().kind() == Kind.Object) {
 582                 cas.setCompress();
 583             }
 584         } else if (n instanceof LoadIndexedNode) {
 585             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
 586             GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
 587             Kind elementKind = loadIndexed.elementKind();
 588             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
 589             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), WriteBarrierType.NONE, elementKind == Kind.Object));
 590             memoryRead.setGuard(boundsCheck);
 591             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
 592         } else if (n instanceof StoreIndexedNode) {
 593             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
 594             GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
 595             Kind elementKind = storeIndexed.elementKind();
 596             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
 597             ValueNode value = storeIndexed.value();
 598             ValueNode array = storeIndexed.array();
 599             if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) {
 600                 // Store check!
 601                 ResolvedJavaType arrayType = array.objectStamp().type();
 602                 if (arrayType != null && array.objectStamp().isExactType()) {
 603                     ResolvedJavaType elementType = arrayType.getComponentType();
 604                     if (!MetaUtil.isJavaLangObject(elementType)) {
 605                         CheckCastNode checkcast = graph.add(new CheckCastNode(elementType, value, null, true));
 606                         graph.addBeforeFixed(storeIndexed, checkcast);
 607                         value = checkcast;
 608                     }
 609                 } else {
 610                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
 611                     LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
 612                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
 613                     CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value, true));
 614                     graph.addBeforeFixed(storeIndexed, checkcast);
 615                     graph.addBeforeFixed(checkcast, arrayClass);
 616                     value = checkcast;
 617                 }
 618             }
 619             WriteBarrierType barrierType = getArrayStoreBarrierType(storeIndexed);
 620             WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation, barrierType, elementKind == Kind.Object));
 621             memoryWrite.setGuard(boundsCheck);
 622             memoryWrite.setStateAfter(storeIndexed.stateAfter());
 623             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 624 
 625         } else if (n instanceof UnsafeLoadNode) {
 626             UnsafeLoadNode load = (UnsafeLoadNode) n;
 627             assert load.kind() != Kind.Illegal;
 628             lowerUnsafeLoad(load, tool);
 629         } else if (n instanceof UnsafeStoreNode) {
 630             UnsafeStoreNode store = (UnsafeStoreNode) n;
 631             IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, store.accessKind(), store.displacement(), store.offset(), graph, 1);
 632             ValueNode object = store.object();
 633             WriteBarrierType barrierType = getUnsafeStoreBarrierType(store);
 634             WriteNode write = graph.add(new WriteNode(object, store.value(), location, barrierType, store.value().kind() == Kind.Object));
 635             write.setStateAfter(store.stateAfter());
 636             graph.replaceFixedWithFixed(store, write);
 637         } else if (n instanceof LoadHubNode) {
 638             LoadHubNode loadHub = (LoadHubNode) n;
 639             assert loadHub.kind() == wordKind;
 640             ValueNode object = loadHub.object();
 641             ReadNode hub = createReadHub(graph, wordKind, object);
 642             // A hub read must not float outside its block otherwise
 643             // it may float above an explicit null check on its object.
 644             hub.setGuard(AbstractBeginNode.prevBegin(loadHub));
 645             graph.replaceFixed(loadHub, hub);
 646         } else if (n instanceof LoadMethodNode) {
 647             LoadMethodNode loadMethodNode = (LoadMethodNode) n;
 648             ResolvedJavaMethod method = loadMethodNode.getMethod();
 649             ReadNode metaspaceMethod = createReadVirtualMethod(graph, wordKind, loadMethodNode.getHub(), method);
 650             graph.replaceFixed(loadMethodNode, metaspaceMethod);
 651         } else if (n instanceof FixedGuardNode) {
 652             FixedGuardNode node = (FixedGuardNode) n;
 653             GuardingNode guard = tool.createGuard(node.condition(), node.getReason(), node.getAction(), node.isNegated());
 654             ValueAnchorNode newAnchor = graph.add(new ValueAnchorNode(guard.asNode()));
 655             node.replaceAtUsages(guard.asNode());
 656             graph.replaceFixedWithFixed(node, newAnchor);
 657         } else if (n instanceof CommitAllocationNode) {
 658             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 659                 CommitAllocationNode commit = (CommitAllocationNode) n;
 660 
 661                 ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
 662                 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 663                     VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
 664                     int entryCount = virtual.entryCount();
 665 
 666                     FixedWithNextNode newObject;
 667                     if (virtual instanceof VirtualInstanceNode) {
 668                         newObject = graph.add(new NewInstanceNode(virtual.type(), true));
 669                     } else {
 670                         ResolvedJavaType element = ((VirtualArrayNode) virtual).componentType();
 671                         newObject = graph.add(new NewArrayNode(element, ConstantNode.forInt(entryCount, graph), true));
 672                     }
 673                     graph.addBeforeFixed(commit, newObject);
 674                     allocations[objIndex] = newObject;
 675                 }
 676                 int valuePos = 0;
 677                 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 678                     VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
 679                     int entryCount = virtual.entryCount();
 680 
 681                     ValueNode newObject = allocations[objIndex];
 682                     if (virtual instanceof VirtualInstanceNode) {
 683                         VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
 684                         for (int i = 0; i < entryCount; i++) {
 685                             ValueNode value = commit.getValues().get(valuePos++);
 686                             if (value instanceof VirtualObjectNode) {
 687                                 value = allocations[commit.getVirtualObjects().indexOf(value)];
 688                             }
 689                             if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
 690                                 WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i)), WriteBarrierType.NONE,
 691                                                 virtualInstance.field(i).getKind() == Kind.Object);
 692 
 693                                 graph.addBeforeFixed(commit, graph.add(write));
 694                             }
 695                         }
 696 
 697                     } else {
 698                         VirtualArrayNode array = (VirtualArrayNode) virtual;
 699                         ResolvedJavaType element = array.componentType();
 700                         for (int i = 0; i < entryCount; i++) {
 701                             ValueNode value = commit.getValues().get(valuePos++);
 702                             if (value instanceof VirtualObjectNode) {
 703                                 int indexOf = commit.getVirtualObjects().indexOf(value);
 704                                 assert indexOf != -1 : commit + " " + value;
 705                                 value = allocations[indexOf];
 706                             }
 707                             if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
 708                                 WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)), WriteBarrierType.NONE,
 709                                                 value.kind() == Kind.Object);
 710                                 graph.addBeforeFixed(commit, graph.add(write));
 711                             }
 712                         }
 713                     }
 714                 }
 715                 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 716                     FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
 717                     allocations[objIndex] = anchor;
 718                     graph.addBeforeFixed(commit, anchor);
 719                 }
 720                 for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 721                     for (int lockDepth : commit.getLocks().get(objIndex)) {
 722                         MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], lockDepth));
 723                         graph.addBeforeFixed(commit, enter);
 724                     }
 725                 }
 726                 for (Node usage : commit.usages().snapshot()) {
 727                     AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
 728                     int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
 729                     graph.replaceFloating(addObject, allocations[index]);
 730                 }
 731                 graph.removeFixed(commit);
 732             }
 733         } else if (n instanceof CheckCastNode) {
 734             checkcastSnippets.lower((CheckCastNode) n, tool);
 735         } else if (n instanceof OSRStartNode) {
 736             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 737                 OSRStartNode osrStart = (OSRStartNode) n;
 738                 StartNode newStart = graph.add(new StartNode());
 739                 LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind())));
 740                 ForeignCallNode migrationEnd = graph.add(new ForeignCallNode(this, OSR_MIGRATION_END, buffer));
 741                 migrationEnd.setStateAfter(osrStart.stateAfter());
 742 
 743                 newStart.setNext(migrationEnd);
 744                 FixedNode next = osrStart.next();
 745                 osrStart.setNext(null);
 746                 migrationEnd.setNext(next);
 747                 graph.setStart(newStart);
 748 
 749                 // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
 750                 int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
 751                 for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
 752                     int size = FrameStateBuilder.stackSlots(osrLocal.kind());
 753                     int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
 754                     IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, osrLocal.kind(), offset, ConstantNode.forLong(0, graph), graph, 1);
 755                     ReadNode load = graph.add(new ReadNode(buffer, location, osrLocal.stamp(), WriteBarrierType.NONE, false));
 756                     osrLocal.replaceAndDelete(load);
 757                     graph.addBeforeFixed(migrationEnd, load);
 758                 }
 759                 osrStart.replaceAtUsages(newStart);
 760                 osrStart.safeDelete();
 761             }
 762         } else if (n instanceof CheckCastDynamicNode) {
 763             checkcastSnippets.lower((CheckCastDynamicNode) n);
 764         } else if (n instanceof InstanceOfNode) {
 765             instanceofSnippets.lower((InstanceOfNode) n, tool);
 766         } else if (n instanceof InstanceOfDynamicNode) {
 767             instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
 768         } else if (n instanceof NewInstanceNode) {
 769             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 770                 newObjectSnippets.lower((NewInstanceNode) n);
 771             }
 772         } else if (n instanceof NewArrayNode) {
 773             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 774                 newObjectSnippets.lower((NewArrayNode) n);
 775             }
 776         } else if (n instanceof DynamicNewArrayNode) {
 777             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 778                 newObjectSnippets.lower((DynamicNewArrayNode) n);
 779             }
 780         } else if (n instanceof MonitorEnterNode) {
 781             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 782                 monitorSnippets.lower((MonitorEnterNode) n, tool);
 783             }
 784         } else if (n instanceof MonitorExitNode) {
 785             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 786                 monitorSnippets.lower((MonitorExitNode) n, tool);
 787             }
 788         } else if (n instanceof G1PreWriteBarrier) {
 789             writeBarrierSnippets.lower((G1PreWriteBarrier) n, tool);
 790         } else if (n instanceof G1PostWriteBarrier) {
 791             writeBarrierSnippets.lower((G1PostWriteBarrier) n, tool);
 792         } else if (n instanceof SerialWriteBarrier) {
 793             writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
 794         } else if (n instanceof SerialArrayRangeWriteBarrier) {
 795             writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
 796         } else if (n instanceof G1ArrayRangePreWriteBarrier) {
 797             writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, tool);
 798         } else if (n instanceof G1ArrayRangePostWriteBarrier) {
 799             writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, tool);
 800         } else if (n instanceof NewMultiArrayNode) {
 801             if (tool.getLoweringType() == LoweringType.AFTER_GUARDS) {
 802                 newObjectSnippets.lower((NewMultiArrayNode) n);
 803             }
 804         } else if (n instanceof LoadExceptionObjectNode) {
 805             exceptionObjectSnippets.lower((LoadExceptionObjectNode) n);
 806         } else if (n instanceof IntegerDivNode || n instanceof IntegerRemNode || n instanceof UnsignedDivNode || n instanceof UnsignedRemNode) {
 807             // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
 808             // zero and the MIN_VALUE / -1 cases.
 809         } else if (n instanceof UnwindNode || n instanceof DeoptimizeNode) {
 810             // Nothing to do, using direct LIR lowering for these nodes.
 811         } else if (n instanceof BoxNode) {
 812             boxingSnippets.lower((BoxNode) n, tool);
 813         } else if (n instanceof UnboxNode) {
 814             boxingSnippets.lower((UnboxNode) n, tool);
 815         } else {
 816             assert false : "Node implementing Lowerable not handled: " + n;
 817             throw GraalInternalError.shouldNotReachHere();
 818         }
 819     }
 820 
 821     private static ReadNode createReadVirtualMethod(StructuredGraph graph, Kind wordKind, ValueNode hub, ResolvedJavaMethod method) {
 822         HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
 823         assert !hsMethod.getDeclaringClass().isInterface();
 824         assert hsMethod.isInVirtualMethodTable();
 825 
 826         int vtableEntryOffset = hsMethod.vtableEntryOffset();
 827         assert vtableEntryOffset > 0;
 828         // We use LocationNode.ANY_LOCATION for the reads that access the vtable
 829         // entry as HotSpot does not guarantee that this is a final value.
 830         ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind()), WriteBarrierType.NONE,
 831                         false));
 832         return metaspaceMethod;
 833     }
 834 
 835     private ReadNode createReadHub(StructuredGraph graph, Kind wordKind, ValueNode object) {
 836         LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, wordKind, config.hubOffset, graph);
 837         assert !object.isConstant() || object.asConstant().isNull();
 838         return graph.add(new ReadNode(object, location, StampFactory.forKind(wordKind()), WriteBarrierType.NONE, false));
 839     }
 840 
 841     public static long referentOffset() {
 842         try {
 843             return unsafe.objectFieldOffset(java.lang.ref.Reference.class.getDeclaredField("referent"));
 844         } catch (Exception e) {
 845             throw new GraalInternalError(e);
 846         }
 847     }
 848 
 849     /**
 850      * The following method lowers the unsafe load node. If any GC besides G1 is used, the unsafe
 851      * load is lowered normally to a read node. However, if the G1 is used and the unsafe load could
 852      * not be canonicalized to a load field, a runtime check has to be inserted in order to a add a
 853      * g1-pre barrier if the loaded field is the referent field of the java.lang.ref.Reference
 854      * class. The following code constructs the runtime check:
 855      * 
 856      * <pre>
 857      * if (offset == referentOffset() && type == java.lang.ref.Reference) {
 858      *     read;
 859      *     G1PreWriteBarrier(read);
 860      * } else {
 861      *     read;
 862      * }
 863      * 
 864      * </pre>
 865      * 
 866      * TODO (ck): Replace the code below with a snippet, properly fix the issue with the unsafe
 867      * loads generated by the array copy intrinsics (robust assertions).
 868      * 
 869      */
 870     private void lowerUnsafeLoad(UnsafeLoadNode load, LoweringTool tool) {
 871         StructuredGraph graph = load.graph();
 872         boolean compress = (!load.object().isNullConstant() && load.accessKind() == Kind.Object);
 873         if (config().useG1GC && load.object().kind() == Kind.Object && load.accessKind() == Kind.Object && !load.object().objectStamp().alwaysNull() && load.object().objectStamp().type() != null &&
 874                         !(load.object().objectStamp().type().isArray()) && tool.getLoweringType() != LoweringType.AFTER_GUARDS) {
 875             IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1);
 876             // Calculate offset+displacement
 877             IntegerAddNode addNode = graph.add(new IntegerAddNode(Kind.Long, load.offset(), ConstantNode.forLong(load.displacement(), graph)));
 878             // Compare previous result with referent offset (16)
 879             CompareNode offsetCondition = CompareNode.createCompareNode(Condition.EQ, addNode, ConstantNode.forLong(referentOffset(), graph));
 880             // Instance of unsafe load is java.lang.ref.Reference
 881             InstanceOfNode instanceOfNode = graph.add(new InstanceOfNode(lookupJavaType(java.lang.ref.Reference.class), load.object(), null));
 882             // The two barriers
 883             ReadNode memoryReadNoBarrier = graph.add(new ReadNode(load.object(), location, load.stamp(), WriteBarrierType.NONE, compress));
 884             ReadNode memoryReadBarrier = graph.add(new ReadNode(load.object(), location, load.stamp(), WriteBarrierType.PRECISE, compress));
 885 
 886             // EndNodes
 887             EndNode leftTrue = graph.add(new EndNode());
 888             EndNode leftFalse = graph.add(new EndNode());
 889             EndNode rightFirst = graph.add(new EndNode());
 890             EndNode rightSecond = graph.add(new EndNode());
 891 
 892             // MergeNodes
 893             MergeNode mergeNoBarrier = graph.add(new MergeNode());
 894             MergeNode mergeFinal = graph.add(new MergeNode());
 895 
 896             // IfNodes
 897             IfNode ifNodeType = graph.add(new IfNode(instanceOfNode, memoryReadBarrier, leftFalse, 0.1));
 898             IfNode ifNodeOffset = graph.add(new IfNode(offsetCondition, ifNodeType, rightFirst, 0.1));
 899 
 900             // Both branches are true (i.e. Add the barrier)
 901             memoryReadBarrier.setNext(leftTrue);
 902             mergeNoBarrier.addForwardEnd(rightFirst);
 903             mergeNoBarrier.addForwardEnd(leftFalse);
 904             mergeNoBarrier.setNext(memoryReadNoBarrier);
 905             memoryReadNoBarrier.setNext(rightSecond);
 906             mergeFinal.addForwardEnd(leftTrue);
 907             mergeFinal.addForwardEnd(rightSecond);
 908 
 909             PhiNode phiNode = graph.add(new PhiNode(load.accessKind(), mergeFinal));
 910             phiNode.addInput(memoryReadBarrier);
 911             phiNode.addInput(memoryReadNoBarrier);
 912 
 913             // An unsafe read must not floating outside its block as may float above an explicit
 914             // null check on its object.
 915             memoryReadNoBarrier.setGuard(AbstractBeginNode.prevBegin(memoryReadNoBarrier));
 916             memoryReadBarrier.setGuard(AbstractBeginNode.prevBegin(memoryReadBarrier));
 917 
 918             assert load.successors().count() == 1;
 919             Node next = load.successors().first();
 920             load.replaceAndDelete(ifNodeOffset);
 921             mergeFinal.setNext((FixedNode) next);
 922             ifNodeOffset.replaceAtUsages(phiNode);
 923         } else {
 924             IndexedLocationNode location = IndexedLocationNode.create(ANY_LOCATION, load.accessKind(), load.displacement(), load.offset(), graph, 1);
 925             // Unsafe access to a metaspace or to any
 926             // absolute address do not perform uncompression.
 927             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp(), WriteBarrierType.NONE, compress));
 928             // An unsafe read must not float outside its block otherwise
 929             // it may float above an explicit null check on its object.
 930             memoryRead.setGuard(AbstractBeginNode.prevBegin(load));
 931             graph.replaceFixedWithFixed(load, memoryRead);
 932         }
 933     }
 934 
 935     private static WriteBarrierType getFieldLoadBarrierType(HotSpotResolvedJavaField loadField) {
 936         WriteBarrierType barrierType = WriteBarrierType.NONE;
 937         if (config().useG1GC && loadField.getKind() == Kind.Object && loadField.getDeclaringClass().mirror() == java.lang.ref.Reference.class && loadField.getName().equals("referent")) {
 938             barrierType = WriteBarrierType.PRECISE;
 939         }
 940         return barrierType;
 941     }
 942 
 943     private static WriteBarrierType getFieldStoreBarrierType(StoreFieldNode storeField) {
 944         WriteBarrierType barrierType = WriteBarrierType.NONE;
 945         if (storeField.field().getKind() == Kind.Object && !storeField.value().objectStamp().alwaysNull()) {
 946             barrierType = WriteBarrierType.IMPRECISE;
 947         }
 948         return barrierType;
 949     }
 950 
 951     private static WriteBarrierType getArrayStoreBarrierType(StoreIndexedNode store) {
 952         WriteBarrierType barrierType = WriteBarrierType.NONE;
 953         if (store.elementKind() == Kind.Object && !store.value().objectStamp().alwaysNull()) {
 954             barrierType = WriteBarrierType.PRECISE;
 955         }
 956         return barrierType;
 957     }
 958 
 959     private static WriteBarrierType getUnsafeStoreBarrierType(UnsafeStoreNode store) {
 960         WriteBarrierType barrierType = WriteBarrierType.NONE;
 961         if (store.value().kind() == Kind.Object && !store.value().objectStamp().alwaysNull()) {
 962             ResolvedJavaType type = store.object().objectStamp().type();
 963             if (type != null && type.isArray()) {
 964                 barrierType = WriteBarrierType.PRECISE;
 965             } else {
 966                 barrierType = WriteBarrierType.IMPRECISE;
 967             }
 968         }
 969         return barrierType;
 970     }
 971 
 972     private static WriteBarrierType getCompareAndSwapBarrier(CompareAndSwapNode cas) {
 973         WriteBarrierType barrierType = WriteBarrierType.NONE;
 974         if (cas.expected().kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) {
 975             ResolvedJavaType type = cas.object().objectStamp().type();
 976             if (type != null && type.isArray()) {
 977                 barrierType = WriteBarrierType.PRECISE;
 978             } else {
 979                 barrierType = WriteBarrierType.IMPRECISE;
 980             }
 981         }
 982         return barrierType;
 983     }
 984 
 985     protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) {
 986         return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
 987     }
 988 
 989     public int getScalingFactor(Kind kind) {
 990         if (config.useCompressedOops && kind == Kind.Object) {
 991             return this.graalRuntime.getTarget().arch.getSizeInBytes(Kind.Int);
 992         } else {
 993             return this.graalRuntime.getTarget().arch.getSizeInBytes(kind);
 994         }
 995     }
 996 
 997     protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
 998         int scale = getScalingFactor(elementKind);
 999         return IndexedLocationNode.create(NamedLocationIdentity.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
1000     }
1001 
1002     private static GuardingNode createBoundsCheck(AccessIndexedNode n, LoweringTool tool) {
1003         StructuredGraph graph = n.graph();
1004         ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
1005         GuardingNode guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), BoundsCheckException, InvalidateReprofile);
1006 
1007         graph.addBeforeFixed(n, arrayLength);
1008         return guard;
1009     }
1010 
1011     public ResolvedJavaType lookupJavaType(Class<?> clazz) {
1012         return HotSpotResolvedObjectType.fromClass(clazz);
1013     }
1014 
1015     public HotSpotForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor) {
1016         HotSpotForeignCallLinkage callTarget = foreignCalls.get(descriptor);
1017         assert foreignCalls != null : descriptor;
1018         callTarget.finalizeAddress(graalRuntime.getBackend());
1019         return callTarget;
1020     }
1021 
1022     public ResolvedJavaMethod lookupJavaMethod(Method reflectionMethod) {
1023         CompilerToVM c2vm = graalRuntime.getCompilerToVM();
1024         HotSpotResolvedObjectType[] resultHolder = {null};
1025         long metaspaceMethod = c2vm.getMetaspaceMethod(reflectionMethod, resultHolder);
1026         assert metaspaceMethod != 0L;
1027         return resultHolder[0].createMethod(metaspaceMethod);
1028     }
1029 
1030     public ResolvedJavaMethod lookupJavaConstructor(Constructor reflectionConstructor) {
1031         CompilerToVM c2vm = graalRuntime.getCompilerToVM();
1032         HotSpotResolvedObjectType[] resultHolder = {null};
1033         long metaspaceMethod = c2vm.getMetaspaceConstructor(reflectionConstructor, resultHolder);
1034         assert metaspaceMethod != 0L;
1035         return resultHolder[0].createMethod(metaspaceMethod);
1036     }
1037 
1038     public ResolvedJavaField lookupJavaField(Field reflectionField) {
1039         return graalRuntime.getCompilerToVM().getJavaField(reflectionField);
1040     }
1041 
1042     public HotSpotInstalledCode installMethod(HotSpotResolvedJavaMethod method, int entryBCI, CompilationResult compResult) {
1043         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, true, null);
1044         graalRuntime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(method, entryBCI, compResult), installedCode, method.getSpeculationLog());
1045         return installedCode;
1046     }
1047 
1048     @Override
1049     public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult) {
1050         return addMethod(method, compResult, null);
1051     }
1052 
1053     @Override
1054     public InstalledCode addMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) {
1055         HotSpotResolvedJavaMethod hotspotMethod = (HotSpotResolvedJavaMethod) method;
1056         HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, false, graph);
1057         CodeInstallResult result = graalRuntime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(hotspotMethod, -1, compResult), code, null);
1058         if (result != CodeInstallResult.OK) {
1059             return null;
1060         }
1061         return code;
1062     }
1063 
1064     public InstalledCode addExternalMethod(ResolvedJavaMethod method, CompilationResult compResult, Graph graph) {
1065 
1066         // compResult.getTargetCode() == assembled PTX method string
1067 
1068         HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) method;
1069         HotSpotInstalledCode icode = new HotSpotNmethod(javaMethod, false, true, graph);
1070         HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(javaMethod, -1, compResult);
1071         CompilerToVM vm = graalRuntime.getCompilerToVM();
1072         CodeInstallResult result = vm.installCode(compiled, icode, null);
1073         if (result != CodeInstallResult.OK) {
1074             return null;
1075         }
1076         return icode;
1077     }
1078 
1079     @Override
1080     public int encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason) {
1081         final int actionShift = 0;
1082         final int reasonShift = 3;
1083 
1084         int actionValue = convertDeoptAction(action);
1085         int reasonValue = convertDeoptReason(reason);
1086         return (~(((reasonValue) << reasonShift) + ((actionValue) << actionShift)));
1087     }
1088 
1089     public int convertDeoptAction(DeoptimizationAction action) {
1090         switch (action) {
1091             case None:
1092                 return config.deoptActionNone;
1093             case RecompileIfTooManyDeopts:
1094                 return config.deoptActionMaybeRecompile;
1095             case InvalidateReprofile:
1096                 return config.deoptActionReinterpret;
1097             case InvalidateRecompile:
1098                 return config.deoptActionMakeNotEntrant;
1099             case InvalidateStopCompiling:
1100                 return config.deoptActionMakeNotCompilable;
1101             default:
1102                 throw GraalInternalError.shouldNotReachHere();
1103         }
1104     }
1105 
1106     public int convertDeoptReason(DeoptimizationReason reason) {
1107         switch (reason) {
1108             case None:
1109                 return config.deoptReasonNone;
1110             case NullCheckException:
1111                 return config.deoptReasonNullCheck;
1112             case BoundsCheckException:
1113                 return config.deoptReasonRangeCheck;
1114             case ClassCastException:
1115                 return config.deoptReasonClassCheck;
1116             case ArrayStoreException:
1117                 return config.deoptReasonArrayCheck;
1118             case UnreachedCode:
1119                 return config.deoptReasonUnreached0;
1120             case TypeCheckedInliningViolated:
1121                 return config.deoptReasonTypeCheckInlining;
1122             case OptimizedTypeCheckViolated:
1123                 return config.deoptReasonOptimizedTypeCheck;
1124             case NotCompiledExceptionHandler:
1125                 return config.deoptReasonNotCompiledExceptionHandler;
1126             case Unresolved:
1127                 return config.deoptReasonUnresolved;
1128             case JavaSubroutineMismatch:
1129                 return config.deoptReasonJsrMismatch;
1130             case ArithmeticException:
1131                 return config.deoptReasonDiv0Check;
1132             case RuntimeConstraint:
1133                 return config.deoptReasonConstraint;
1134             case LoopLimitCheck:
1135                 return config.deoptReasonLoopLimitCheck;
1136             default:
1137                 throw GraalInternalError.shouldNotReachHere();
1138         }
1139     }
1140 
1141     public boolean needsDataPatch(Constant constant) {
1142         return constant.getPrimitiveAnnotation() != null;
1143     }
1144 
1145     @Override
1146     public Constant readUnsafeConstant(Kind kind, Object base, long displacement, boolean compressedPointer) {
1147         switch (kind) {
1148             case Boolean:
1149                 return Constant.forBoolean(base == null ? unsafe.getByte(displacement) != 0 : unsafe.getBoolean(base, displacement));
1150             case Byte:
1151                 return Constant.forByte(base == null ? unsafe.getByte(displacement) : unsafe.getByte(base, displacement));
1152             case Char:
1153                 return Constant.forChar(base == null ? unsafe.getChar(displacement) : unsafe.getChar(base, displacement));
1154             case Short:
1155                 return Constant.forShort(base == null ? unsafe.getShort(displacement) : unsafe.getShort(base, displacement));
1156             case Int:
1157                 return Constant.forInt(base == null ? unsafe.getInt(displacement) : unsafe.getInt(base, displacement));
1158             case Long:
1159                 return Constant.forLong(base == null ? unsafe.getLong(displacement) : unsafe.getLong(base, displacement));
1160             case Float:
1161                 return Constant.forFloat(base == null ? unsafe.getFloat(displacement) : unsafe.getFloat(base, displacement));
1162             case Double:
1163                 return Constant.forDouble(base == null ? unsafe.getDouble(displacement) : unsafe.getDouble(base, displacement));
1164             case Object: {
1165                 Object o = null;
1166                 if (compressedPointer || !this.getGraalRuntime().getRuntime().config.useCompressedOops) {
1167                     o = unsafe.getObject(base, displacement);
1168                 } else {
1169                     o = this.getGraalRuntime().getCompilerToVM().readUnsafeUncompressedPointer(base, displacement);
1170                 }
1171                 return Constant.forObject(o);
1172             }
1173             default:
1174                 throw GraalInternalError.shouldNotReachHere();
1175         }
1176     }
1177 
1178     @Override
1179     public boolean isReexecutable(ForeignCallDescriptor descriptor) {
1180         return foreignCalls.get(descriptor).isReexecutable();
1181     }
1182 
1183     public boolean canDeoptimize(ForeignCallDescriptor descriptor) {
1184         return foreignCalls.get(descriptor).canDeoptimize();
1185     }
1186 
1187     public LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor) {
1188         return foreignCalls.get(descriptor).getKilledLocations();
1189     }
1190 
1191     @Override
1192     public TargetDescription getTarget() {
1193         return graalRuntime.getTarget();
1194     }
1195 
1196     public String disassemble(InstalledCode code) {
1197         if (code.isValid()) {
1198             long codeBlob = ((HotSpotInstalledCode) code).getCodeBlob();
1199             return graalRuntime.getCompilerToVM().disassembleCodeBlob(codeBlob);
1200         }
1201         return null;
1202     }
1203 
1204     public String disassemble(ResolvedJavaMethod method) {
1205         return new BytecodeDisassembler().disassemble(method);
1206     }
1207 
1208     public Suites getDefaultSuites() {
1209         return defaultSuites;
1210     }
1211 
1212     public Suites createSuites() {
1213         Suites ret = Suites.createDefaultSuites();
1214 
1215         if (AOTCompilation.getValue()) {
1216             // lowering introduces class constants, therefore it must be after lowering
1217             ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase());
1218             if (VerifyPhases.getValue()) {
1219                 ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
1220             }
1221         }
1222 
1223         ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase());
1224         if (VerifyPhases.getValue()) {
1225             ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config.useG1GC));
1226         }
1227 
1228         return ret;
1229     }
1230 }