1 /*
   2  * Copyright (c) 2011, 2016, 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 org.graalvm.compiler.replacements;
  24 
  25 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ;
  26 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE;
  27 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ;
  28 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE;
  29 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
  30 import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException;
  31 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
  32 import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION;
  33 import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
  34 import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull;
  35 
  36 import java.util.ArrayList;
  37 import java.util.BitSet;
  38 import java.util.List;
  39 
  40 import org.graalvm.compiler.api.directives.GraalDirectives;
  41 import org.graalvm.compiler.api.replacements.Snippet;
  42 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  43 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  44 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  45 import org.graalvm.compiler.core.common.type.IntegerStamp;
  46 import org.graalvm.compiler.core.common.type.Stamp;
  47 import org.graalvm.compiler.core.common.type.StampFactory;
  48 import org.graalvm.compiler.core.common.type.TypeReference;
  49 import org.graalvm.compiler.debug.DebugHandlersFactory;
  50 import org.graalvm.compiler.debug.GraalError;
  51 import org.graalvm.compiler.graph.Node;
  52 import org.graalvm.compiler.nodeinfo.InputType;
  53 import org.graalvm.compiler.nodes.ConstantNode;
  54 import org.graalvm.compiler.nodes.FieldLocationIdentity;
  55 import org.graalvm.compiler.nodes.FixedNode;
  56 import org.graalvm.compiler.nodes.LogicNode;
  57 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  58 import org.graalvm.compiler.nodes.PiNode;
  59 import org.graalvm.compiler.nodes.StructuredGraph;
  60 import org.graalvm.compiler.nodes.ValueNode;
  61 import org.graalvm.compiler.nodes.calc.AddNode;
  62 import org.graalvm.compiler.nodes.calc.ConditionalNode;
  63 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
  64 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  65 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
  66 import org.graalvm.compiler.nodes.calc.IsNullNode;
  67 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  68 import org.graalvm.compiler.nodes.calc.NarrowNode;
  69 import org.graalvm.compiler.nodes.calc.RightShiftNode;
  70 import org.graalvm.compiler.nodes.calc.SignExtendNode;
  71 import org.graalvm.compiler.nodes.calc.SubNode;
  72 import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
  73 import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
  74 import org.graalvm.compiler.nodes.extended.BoxNode;
  75 import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
  76 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  77 import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
  78 import org.graalvm.compiler.nodes.extended.GuardingNode;
  79 import org.graalvm.compiler.nodes.extended.JavaReadNode;
  80 import org.graalvm.compiler.nodes.extended.JavaWriteNode;
  81 import org.graalvm.compiler.nodes.extended.LoadHubNode;
  82 import org.graalvm.compiler.nodes.extended.MembarNode;
  83 import org.graalvm.compiler.nodes.extended.RawLoadNode;
  84 import org.graalvm.compiler.nodes.extended.RawStoreNode;
  85 import org.graalvm.compiler.nodes.extended.UnboxNode;
  86 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode;
  87 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode;
  88 import org.graalvm.compiler.nodes.java.AbstractNewObjectNode;
  89 import org.graalvm.compiler.nodes.java.AccessIndexedNode;
  90 import org.graalvm.compiler.nodes.java.ArrayLengthNode;
  91 import org.graalvm.compiler.nodes.java.AtomicReadAndWriteNode;
  92 import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode;
  93 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
  94 import org.graalvm.compiler.nodes.java.InstanceOfNode;
  95 import org.graalvm.compiler.nodes.java.LoadFieldNode;
  96 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
  97 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
  98 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
  99 import org.graalvm.compiler.nodes.java.MonitorEnterNode;
 100 import org.graalvm.compiler.nodes.java.MonitorIdNode;
 101 import org.graalvm.compiler.nodes.java.NewArrayNode;
 102 import org.graalvm.compiler.nodes.java.NewInstanceNode;
 103 import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
 104 import org.graalvm.compiler.nodes.java.StoreFieldNode;
 105 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
 106 import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
 107 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
 108 import org.graalvm.compiler.nodes.memory.ReadNode;
 109 import org.graalvm.compiler.nodes.memory.WriteNode;
 110 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 111 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 112 import org.graalvm.compiler.nodes.memory.address.RawAddressNode;
 113 import org.graalvm.compiler.nodes.spi.Lowerable;
 114 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 115 import org.graalvm.compiler.nodes.spi.LoweringTool;
 116 import org.graalvm.compiler.nodes.type.StampTool;
 117 import org.graalvm.compiler.nodes.util.GraphUtil;
 118 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
 119 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
 120 import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
 121 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
 122 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 123 import org.graalvm.compiler.options.OptionValues;
 124 import org.graalvm.compiler.phases.util.Providers;
 125 import org.graalvm.compiler.replacements.SnippetLowerableMemoryNode.SnippetLowering;
 126 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
 127 import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.BinaryOperation;
 128 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
 129 import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
 130 import org.graalvm.word.LocationIdentity;
 131 
 132 import jdk.vm.ci.code.CodeUtil;
 133 import jdk.vm.ci.code.MemoryBarriers;
 134 import jdk.vm.ci.code.TargetDescription;
 135 import jdk.vm.ci.meta.DeoptimizationAction;
 136 import jdk.vm.ci.meta.DeoptimizationReason;
 137 import jdk.vm.ci.meta.JavaConstant;
 138 import jdk.vm.ci.meta.JavaKind;
 139 import jdk.vm.ci.meta.MetaAccessProvider;
 140 import jdk.vm.ci.meta.ResolvedJavaField;
 141 import jdk.vm.ci.meta.ResolvedJavaMethod;
 142 import jdk.vm.ci.meta.ResolvedJavaType;
 143 
 144 /**
 145  * VM-independent lowerings for standard Java nodes. VM-specific methods are abstract and must be
 146  * implemented by VM-specific subclasses.
 147  */
 148 public abstract class DefaultJavaLoweringProvider implements LoweringProvider {
 149 
 150     protected final MetaAccessProvider metaAccess;
 151     protected final ForeignCallsProvider foreignCalls;
 152     protected final TargetDescription target;
 153 
 154     private BoxingSnippets.Templates boxingSnippets;
 155     private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
 156 
 157     public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target) {
 158         this.metaAccess = metaAccess;
 159         this.foreignCalls = foreignCalls;
 160         this.target = target;
 161     }
 162 
 163     public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
 164         boxingSnippets = new BoxingSnippets.Templates(options, factories, factory, providers, snippetReflection, target);
 165         indexOfSnippets = new ConstantStringIndexOfSnippets.Templates(options, factories, providers, snippetReflection, target);
 166         providers.getReplacements().registerSnippetTemplateCache(new SnippetCounterNode.SnippetCounterSnippets.Templates(options, factories, providers, snippetReflection, target));
 167     }
 168 
 169     public final TargetDescription getTarget() {
 170         return target;
 171     }
 172 
 173     @Override
 174     public void lower(Node n, LoweringTool tool) {
 175         assert n instanceof Lowerable;
 176         StructuredGraph graph = (StructuredGraph) n.graph();
 177         if (n instanceof LoadFieldNode) {
 178             lowerLoadFieldNode((LoadFieldNode) n, tool);
 179         } else if (n instanceof StoreFieldNode) {
 180             lowerStoreFieldNode((StoreFieldNode) n, tool);
 181         } else if (n instanceof LoadIndexedNode) {
 182             lowerLoadIndexedNode((LoadIndexedNode) n, tool);
 183         } else if (n instanceof StoreIndexedNode) {
 184             lowerStoreIndexedNode((StoreIndexedNode) n, tool);
 185         } else if (n instanceof ArrayLengthNode) {
 186             lowerArrayLengthNode((ArrayLengthNode) n, tool);
 187         } else if (n instanceof LoadHubNode) {
 188             lowerLoadHubNode((LoadHubNode) n, tool);
 189         } else if (n instanceof MonitorEnterNode) {
 190             lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
 191         } else if (n instanceof UnsafeCompareAndSwapNode) {
 192             lowerCompareAndSwapNode((UnsafeCompareAndSwapNode) n);
 193         } else if (n instanceof AtomicReadAndWriteNode) {
 194             lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
 195         } else if (n instanceof RawLoadNode) {
 196             lowerUnsafeLoadNode((RawLoadNode) n, tool);
 197         } else if (n instanceof UnsafeMemoryLoadNode) {
 198             lowerUnsafeMemoryLoadNode((UnsafeMemoryLoadNode) n);
 199         } else if (n instanceof RawStoreNode) {
 200             lowerUnsafeStoreNode((RawStoreNode) n);
 201         } else if (n instanceof UnsafeMemoryStoreNode) {
 202             lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
 203         } else if (n instanceof JavaReadNode) {
 204             lowerJavaReadNode((JavaReadNode) n);
 205         } else if (n instanceof JavaWriteNode) {
 206             lowerJavaWriteNode((JavaWriteNode) n);
 207         } else if (n instanceof CommitAllocationNode) {
 208             lowerCommitAllocationNode((CommitAllocationNode) n, tool);
 209         } else if (n instanceof BoxNode) {
 210             boxingSnippets.lower((BoxNode) n, tool);
 211         } else if (n instanceof UnboxNode) {
 212             boxingSnippets.lower((UnboxNode) n, tool);
 213         } else if (n instanceof VerifyHeapNode) {
 214             lowerVerifyHeap((VerifyHeapNode) n);
 215         } else if (n instanceof UnaryMathIntrinsicNode) {
 216             lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
 217         } else if (n instanceof BinaryMathIntrinsicNode) {
 218             lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
 219         } else if (n instanceof StringIndexOfNode) {
 220             lowerIndexOf((StringIndexOfNode) n);
 221         } else {
 222             throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
 223         }
 224     }
 225 
 226     private void lowerIndexOf(StringIndexOfNode n) {
 227         if (n.getArgument(3).isConstant()) {
 228             SnippetLowering lowering = new SnippetLowering() {
 229                 @Override
 230                 public void lower(SnippetLowerableMemoryNode node, LoweringTool tool) {
 231                     if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
 232                         return;
 233                     }
 234                     indexOfSnippets.lower(node, tool);
 235                 }
 236             };
 237             SnippetLowerableMemoryNode snippetLower = new SnippetLowerableMemoryNode(lowering, NamedLocationIdentity.getArrayLocation(JavaKind.Char), n.stamp(), n.toArgumentArray());
 238             n.graph().add(snippetLower);
 239             n.graph().replaceFixedWithFixed(n, snippetLower);
 240         }
 241     }
 242 
 243     private void lowerBinaryMath(BinaryMathIntrinsicNode math, LoweringTool tool) {
 244         if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
 245             return;
 246         }
 247         ResolvedJavaMethod method = math.graph().method();
 248         if (method != null) {
 249             if (method.getAnnotation(Snippet.class) != null) {
 250                 /*
 251                  * In the context of the snippet use the LIR lowering instead of the Node lowering.
 252                  */
 253                 return;
 254             }
 255             if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
 256                 /*
 257                  * A root compilation of the intrinsic method should emit the full assembly
 258                  * implementation.
 259                  */
 260                 return;
 261             }
 262 
 263         }
 264         ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
 265         if (foreignCall != null) {
 266             StructuredGraph graph = math.graph();
 267             ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, toForeignCall(math.getOperation()), math.getX(), math.getY()));
 268             graph.addAfterFixed(tool.lastFixedNode(), call);
 269             math.replaceAtUsages(call);
 270         }
 271     }
 272 
 273     private void lowerUnaryMath(UnaryMathIntrinsicNode math, LoweringTool tool) {
 274         if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.HIGH_TIER) {
 275             return;
 276         }
 277         ResolvedJavaMethod method = math.graph().method();
 278         if (method != null) {
 279             if (method.getAnnotation(Snippet.class) != null) {
 280                 /*
 281                  * In the context of the snippet use the LIR lowering instead of the Node lowering.
 282                  */
 283                 return;
 284             }
 285             if (method.getName().equalsIgnoreCase(math.getOperation().name()) && tool.getMetaAccess().lookupJavaType(Math.class).equals(method.getDeclaringClass())) {
 286                 /*
 287                  * A root compilation of the intrinsic method should emit the full assembly
 288                  * implementation.
 289                  */
 290                 return;
 291             }
 292 
 293         }
 294         ForeignCallDescriptor foreignCall = toForeignCall(math.getOperation());
 295         if (foreignCall != null) {
 296             StructuredGraph graph = math.graph();
 297             ForeignCallNode call = math.graph().add(new ForeignCallNode(foreignCalls, foreignCall, math.getValue()));
 298             graph.addAfterFixed(tool.lastFixedNode(), call);
 299             math.replaceAtUsages(call);
 300         }
 301     }
 302 
 303     protected ForeignCallDescriptor toForeignCall(UnaryOperation operation) {
 304         return operation.foreignCallDescriptor;
 305     }
 306 
 307     protected ForeignCallDescriptor toForeignCall(BinaryOperation operation) {
 308         return operation.foreignCallDescriptor;
 309     }
 310 
 311     protected void lowerVerifyHeap(VerifyHeapNode n) {
 312         GraphUtil.removeFixedWithUnusedInputs(n);
 313     }
 314 
 315     protected AddressNode createOffsetAddress(StructuredGraph graph, ValueNode object, long offset) {
 316         ValueNode o = ConstantNode.forIntegerKind(target.wordJavaKind, offset, graph);
 317         return graph.unique(new OffsetAddressNode(object, o));
 318     }
 319 
 320     protected AddressNode createFieldAddress(StructuredGraph graph, ValueNode object, ResolvedJavaField field) {
 321         int offset = fieldOffset(field);
 322         if (offset >= 0) {
 323             return createOffsetAddress(graph, object, offset);
 324         } else {
 325             return null;
 326         }
 327     }
 328 
 329     protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
 330         assert loadField.getStackKind() != JavaKind.Illegal;
 331         StructuredGraph graph = loadField.graph();
 332         ResolvedJavaField field = loadField.field();
 333         ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
 334         object = createNullCheckedValue(object, loadField, tool);
 335         Stamp loadStamp = loadStamp(loadField.stamp(), field.getJavaKind());
 336 
 337         AddressNode address = createFieldAddress(graph, object, field);
 338         assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
 339 
 340         ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
 341         ValueNode readValue = implicitLoadConvert(graph, field.getJavaKind(), memoryRead);
 342         loadField.replaceAtUsages(readValue);
 343         graph.replaceFixed(loadField, memoryRead);
 344 
 345         if (loadField.isVolatile()) {
 346             MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
 347             graph.addBeforeFixed(memoryRead, preMembar);
 348             MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_READ));
 349             graph.addAfterFixed(memoryRead, postMembar);
 350         }
 351     }
 352 
 353     protected void lowerStoreFieldNode(StoreFieldNode storeField, LoweringTool tool) {
 354         StructuredGraph graph = storeField.graph();
 355         ResolvedJavaField field = storeField.field();
 356         ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
 357         object = createNullCheckedValue(object, storeField, tool);
 358         ValueNode value = implicitStoreConvert(graph, storeField.field().getJavaKind(), storeField.value());
 359         AddressNode address = createFieldAddress(graph, object, field);
 360         assert address != null;
 361 
 362         WriteNode memoryWrite = graph.add(new WriteNode(address, fieldLocationIdentity(field), value, fieldStoreBarrierType(storeField.field())));
 363         memoryWrite.setStateAfter(storeField.stateAfter());
 364         graph.replaceFixedWithFixed(storeField, memoryWrite);
 365 
 366         if (storeField.isVolatile()) {
 367             MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_WRITE));
 368             graph.addBeforeFixed(memoryWrite, preMembar);
 369             MembarNode postMembar = graph.add(new MembarNode(JMM_POST_VOLATILE_WRITE));
 370             graph.addAfterFixed(memoryWrite, postMembar);
 371         }
 372     }
 373 
 374     /**
 375      * Create a PiNode on the index proving that the index is positive. On some platforms this is
 376      * important to allow the index to be used as an int in the address mode.
 377      */
 378     public AddressNode createArrayIndexAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index, GuardingNode boundsCheck) {
 379         IntegerStamp indexStamp = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1);
 380         ValueNode positiveIndex = graph.maybeAddOrUnique(PiNode.create(index, indexStamp, boundsCheck != null ? boundsCheck.asNode() : null));
 381         return createArrayAddress(graph, array, elementKind, positiveIndex);
 382     }
 383 
 384     public AddressNode createArrayAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index) {
 385         ValueNode wordIndex;
 386         if (target.wordSize > 4) {
 387             wordIndex = graph.unique(new SignExtendNode(index, target.wordSize * 8));
 388         } else {
 389             assert target.wordSize == 4 : "unsupported word size";
 390             wordIndex = index;
 391         }
 392 
 393         int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
 394         ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph)));
 395 
 396         int base = arrayBaseOffset(elementKind);
 397         ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordJavaKind, base, graph)));
 398 
 399         return graph.unique(new OffsetAddressNode(array, offset));
 400     }
 401 
 402     protected void lowerLoadIndexedNode(LoadIndexedNode loadIndexed, LoweringTool tool) {
 403         StructuredGraph graph = loadIndexed.graph();
 404         ValueNode array = loadIndexed.array();
 405         array = createNullCheckedValue(array, loadIndexed, tool);
 406         JavaKind elementKind = loadIndexed.elementKind();
 407         Stamp loadStamp = loadStamp(loadIndexed.stamp(), elementKind);
 408 
 409         GuardingNode boundsCheck = getBoundsCheck(loadIndexed, array, tool);
 410         AddressNode address = createArrayIndexAddress(graph, array, elementKind, loadIndexed.index(), boundsCheck);
 411         ReadNode memoryRead = graph.add(new ReadNode(address, NamedLocationIdentity.getArrayLocation(elementKind), loadStamp, BarrierType.NONE));
 412         memoryRead.setGuard(boundsCheck);
 413         ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead);
 414 
 415         loadIndexed.replaceAtUsages(readValue);
 416         graph.replaceFixed(loadIndexed, memoryRead);
 417     }
 418 
 419     protected void lowerStoreIndexedNode(StoreIndexedNode storeIndexed, LoweringTool tool) {
 420         StructuredGraph graph = storeIndexed.graph();
 421 
 422         ValueNode value = storeIndexed.value();
 423         ValueNode array = storeIndexed.array();
 424 
 425         array = this.createNullCheckedValue(array, storeIndexed, tool);
 426 
 427         GuardingNode boundsCheck = getBoundsCheck(storeIndexed, array, tool);
 428 
 429         JavaKind elementKind = storeIndexed.elementKind();
 430 
 431         LogicNode condition = null;
 432         if (elementKind == JavaKind.Object && !StampTool.isPointerAlwaysNull(value)) {
 433             /* Array store check. */
 434             TypeReference arrayType = StampTool.typeReferenceOrNull(array);
 435             if (arrayType != null && arrayType.isExact()) {
 436                 ResolvedJavaType elementType = arrayType.getType().getComponentType();
 437                 if (!elementType.isJavaLangObject()) {
 438                     TypeReference typeReference = TypeReference.createTrusted(storeIndexed.graph().getAssumptions(), elementType);
 439                     LogicNode typeTest = graph.addOrUniqueWithInputs(InstanceOfNode.create(typeReference, value));
 440                     condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
 441                 }
 442             } else {
 443                 /*
 444                  * The guard on the read hub should be the null check of the array that was
 445                  * introduced earlier.
 446                  */
 447                 ValueNode arrayClass = createReadHub(graph, array, tool);
 448                 ValueNode componentHub = createReadArrayComponentHub(graph, arrayClass, storeIndexed);
 449                 LogicNode typeTest = graph.unique(InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), componentHub, value, false));
 450                 condition = LogicNode.or(graph.unique(IsNullNode.create(value)), typeTest, GraalDirectives.UNLIKELY_PROBABILITY);
 451             }
 452         }
 453 
 454         AddressNode address = createArrayIndexAddress(graph, array, elementKind, storeIndexed.index(), boundsCheck);
 455         WriteNode memoryWrite = graph.add(new WriteNode(address, NamedLocationIdentity.getArrayLocation(elementKind), implicitStoreConvert(graph, elementKind, value),
 456                         arrayStoreBarrierType(storeIndexed.elementKind())));
 457         memoryWrite.setGuard(boundsCheck);
 458         if (condition != null) {
 459             tool.createGuard(storeIndexed, condition, DeoptimizationReason.ArrayStoreException, DeoptimizationAction.InvalidateReprofile);
 460         }
 461         memoryWrite.setStateAfter(storeIndexed.stateAfter());
 462         graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 463     }
 464 
 465     protected void lowerArrayLengthNode(ArrayLengthNode arrayLengthNode, LoweringTool tool) {
 466         arrayLengthNode.replaceAtUsages(createReadArrayLength(arrayLengthNode.array(), arrayLengthNode, tool));
 467         StructuredGraph graph = arrayLengthNode.graph();
 468         graph.removeFixed(arrayLengthNode);
 469     }
 470 
 471     /**
 472      * Creates a read node that read the array length and is guarded by a null-check.
 473      *
 474      * The created node is placed before {@code before} in the CFG.
 475      */
 476     protected ReadNode createReadArrayLength(ValueNode array, FixedNode before, LoweringTool tool) {
 477         StructuredGraph graph = array.graph();
 478         ValueNode canonicalArray = this.createNullCheckedValue(skipPiWhileNonNull(array), before, tool);
 479         AddressNode address = createOffsetAddress(graph, canonicalArray, arrayLengthOffset());
 480         ReadNode readArrayLength = graph.add(new ReadNode(address, ARRAY_LENGTH_LOCATION, StampFactory.positiveInt(), BarrierType.NONE));
 481         graph.addBeforeFixed(before, readArrayLength);
 482         return readArrayLength;
 483     }
 484 
 485     protected void lowerLoadHubNode(LoadHubNode loadHub, LoweringTool tool) {
 486         StructuredGraph graph = loadHub.graph();
 487         if (tool.getLoweringStage() != LoweringTool.StandardLoweringStage.LOW_TIER) {
 488             return;
 489         }
 490         if (graph.getGuardsStage().allowsFloatingGuards()) {
 491             return;
 492         }
 493         ValueNode hub = createReadHub(graph, loadHub.getValue(), tool);
 494         loadHub.replaceAtUsagesAndDelete(hub);
 495     }
 496 
 497     protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
 498         ValueNode object = createNullCheckedValue(monitorEnter.object(), monitorEnter, tool);
 499         ValueNode hub = graph.addOrUnique(LoadHubNode.create(object, tool.getStampProvider(), tool.getMetaAccess(), tool.getConstantReflection()));
 500         RawMonitorEnterNode rawMonitorEnter = graph.add(new RawMonitorEnterNode(object, hub, monitorEnter.getMonitorId()));
 501         rawMonitorEnter.setStateBefore(monitorEnter.stateBefore());
 502         rawMonitorEnter.setStateAfter(monitorEnter.stateAfter());
 503         graph.replaceFixedWithFixed(monitorEnter, rawMonitorEnter);
 504     }
 505 
 506     protected void lowerCompareAndSwapNode(UnsafeCompareAndSwapNode cas) {
 507         StructuredGraph graph = cas.graph();
 508         JavaKind valueKind = cas.getValueKind();
 509 
 510         ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
 511         ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
 512 
 513         AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
 514         LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, compareAndSwapBarrierType(cas)));
 515         atomicNode.setStateAfter(cas.stateAfter());
 516         graph.replaceFixedWithFixed(cas, atomicNode);
 517     }
 518 
 519     protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
 520         StructuredGraph graph = n.graph();
 521         JavaKind valueKind = n.getValueKind();
 522 
 523         ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
 524 
 525         AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
 526         LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, atomicReadAndWriteBarrierType(n)));
 527         memoryRead.setStateAfter(n.stateAfter());
 528 
 529         ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
 530         n.stateAfter().replaceFirstInput(n, memoryRead);
 531         n.replaceAtUsages(readValue);
 532         graph.replaceFixedWithFixed(n, memoryRead);
 533     }
 534 
 535     /**
 536      * @param tool utility for performing the lowering
 537      */
 538     protected void lowerUnsafeLoadNode(RawLoadNode load, LoweringTool tool) {
 539         StructuredGraph graph = load.graph();
 540         if (load instanceof GuardedUnsafeLoadNode) {
 541             GuardedUnsafeLoadNode guardedLoad = (GuardedUnsafeLoadNode) load;
 542             GuardingNode guard = guardedLoad.getGuard();
 543             if (guard == null) {
 544                 // can float freely if the guard folded away
 545                 ReadNode memoryRead = createUnsafeRead(graph, load, null);
 546                 memoryRead.setForceFixed(false);
 547                 graph.replaceFixedWithFixed(load, memoryRead);
 548             } else {
 549                 // must be guarded, but flows below the guard
 550                 ReadNode memoryRead = createUnsafeRead(graph, load, guard);
 551                 graph.replaceFixedWithFixed(load, memoryRead);
 552             }
 553         } else {
 554             // never had a guarding condition so it must be fixed, creation of the read will force
 555             // it to be fixed
 556             ReadNode memoryRead = createUnsafeRead(graph, load, null);
 557             graph.replaceFixedWithFixed(load, memoryRead);
 558         }
 559     }
 560 
 561     protected AddressNode createUnsafeAddress(StructuredGraph graph, ValueNode object, ValueNode offset) {
 562         if (object.isConstant() && object.asConstant().isDefaultForKind()) {
 563             return graph.unique(new RawAddressNode(offset));
 564         } else {
 565             return graph.unique(new OffsetAddressNode(object, offset));
 566         }
 567     }
 568 
 569     protected ReadNode createUnsafeRead(StructuredGraph graph, RawLoadNode load, GuardingNode guard) {
 570         boolean compressible = load.accessKind() == JavaKind.Object;
 571         JavaKind readKind = load.accessKind();
 572         Stamp loadStamp = loadStamp(load.stamp(), readKind, compressible);
 573         AddressNode address = createUnsafeAddress(graph, load.object(), load.offset());
 574         ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
 575         if (guard == null) {
 576             // An unsafe read must not float otherwise it may float above
 577             // a test guaranteeing the read is safe.
 578             memoryRead.setForceFixed(true);
 579         } else {
 580             memoryRead.setGuard(guard);
 581         }
 582         ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, compressible), readKind);
 583         load.replaceAtUsages(readValue);
 584         return memoryRead;
 585     }
 586 
 587     protected void lowerUnsafeMemoryLoadNode(UnsafeMemoryLoadNode load) {
 588         StructuredGraph graph = load.graph();
 589         JavaKind readKind = load.getKind();
 590         assert readKind != JavaKind.Object;
 591         Stamp loadStamp = loadStamp(load.stamp(), readKind, false);
 592         AddressNode address = graph.unique(new RawAddressNode(load.getAddress()));
 593         ReadNode memoryRead = graph.add(new ReadNode(address, load.getLocationIdentity(), loadStamp, BarrierType.NONE));
 594         // An unsafe read must not float otherwise it may float above
 595         // a test guaranteeing the read is safe.
 596         memoryRead.setForceFixed(true);
 597         ValueNode readValue = performBooleanCoercionIfNecessary(implicitLoadConvert(graph, readKind, memoryRead, false), readKind);
 598         load.replaceAtUsages(readValue);
 599         graph.replaceFixedWithFixed(load, memoryRead);
 600     }
 601 
 602     private static ValueNode performBooleanCoercionIfNecessary(ValueNode readValue, JavaKind readKind) {
 603         if (readKind == JavaKind.Boolean) {
 604             StructuredGraph graph = readValue.graph();
 605             IntegerEqualsNode eq = graph.addOrUnique(new IntegerEqualsNode(readValue, ConstantNode.forInt(0, graph)));
 606             return graph.addOrUnique(new ConditionalNode(eq, ConstantNode.forBoolean(false, graph), ConstantNode.forBoolean(true, graph)));
 607         }
 608         return readValue;
 609     }
 610 
 611     protected void lowerUnsafeStoreNode(RawStoreNode store) {
 612         StructuredGraph graph = store.graph();
 613         boolean compressible = store.value().getStackKind() == JavaKind.Object;
 614         JavaKind valueKind = store.accessKind();
 615         ValueNode value = implicitStoreConvert(graph, valueKind, store.value(), compressible);
 616         AddressNode address = createUnsafeAddress(graph, store.object(), store.offset());
 617         WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, unsafeStoreBarrierType(store)));
 618         write.setStateAfter(store.stateAfter());
 619         graph.replaceFixedWithFixed(store, write);
 620     }
 621 
 622     protected void lowerUnsafeMemoryStoreNode(UnsafeMemoryStoreNode store) {
 623         StructuredGraph graph = store.graph();
 624         assert store.getValue().getStackKind() != JavaKind.Object;
 625         JavaKind valueKind = store.getKind();
 626         ValueNode value = implicitStoreConvert(graph, valueKind, store.getValue(), false);
 627         AddressNode address = graph.unique(new RawAddressNode(store.getAddress()));
 628         WriteNode write = graph.add(new WriteNode(address, store.getLocationIdentity(), value, BarrierType.NONE));
 629         write.setStateAfter(store.stateAfter());
 630         graph.replaceFixedWithFixed(store, write);
 631     }
 632 
 633     protected void lowerJavaReadNode(JavaReadNode read) {
 634         StructuredGraph graph = read.graph();
 635         JavaKind valueKind = read.getReadKind();
 636         Stamp loadStamp = loadStamp(read.stamp(), valueKind, read.isCompressible());
 637 
 638         ReadNode memoryRead = graph.add(new ReadNode(read.getAddress(), read.getLocationIdentity(), loadStamp, read.getBarrierType()));
 639         GuardingNode guard = read.getGuard();
 640         ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead, read.isCompressible());
 641         if (guard == null) {
 642             // An unsafe read must not float otherwise it may float above
 643             // a test guaranteeing the read is safe.
 644             memoryRead.setForceFixed(true);
 645         } else {
 646             memoryRead.setGuard(guard);
 647         }
 648         read.replaceAtUsages(readValue);
 649         graph.replaceFixed(read, memoryRead);
 650     }
 651 
 652     protected void lowerJavaWriteNode(JavaWriteNode write) {
 653         StructuredGraph graph = write.graph();
 654         JavaKind valueKind = write.getWriteKind();
 655         ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
 656 
 657         WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType()));
 658         memoryWrite.setStateAfter(write.stateAfter());
 659         graph.replaceFixedWithFixed(write, memoryWrite);
 660         memoryWrite.setGuard(write.getGuard());
 661     }
 662 
 663     protected void lowerCommitAllocationNode(CommitAllocationNode commit, LoweringTool tool) {
 664         StructuredGraph graph = commit.graph();
 665         if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
 666             List<AbstractNewObjectNode> recursiveLowerings = new ArrayList<>();
 667 
 668             ValueNode[] allocations = new ValueNode[commit.getVirtualObjects().size()];
 669             BitSet omittedValues = new BitSet();
 670             int valuePos = 0;
 671             for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 672                 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
 673                 int entryCount = virtual.entryCount();
 674                 AbstractNewObjectNode newObject;
 675                 if (virtual instanceof VirtualInstanceNode) {
 676                     newObject = graph.add(createNewInstanceFromVirtual(virtual));
 677                 } else {
 678                     newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph)));
 679                 }
 680                 recursiveLowerings.add(newObject);
 681                 graph.addBeforeFixed(commit, newObject);
 682                 allocations[objIndex] = newObject;
 683                 for (int i = 0; i < entryCount; i++) {
 684                     ValueNode value = commit.getValues().get(valuePos);
 685                     if (value instanceof VirtualObjectNode) {
 686                         value = allocations[commit.getVirtualObjects().indexOf(value)];
 687                     }
 688                     if (value == null) {
 689                         omittedValues.set(valuePos);
 690                     } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
 691                         // Constant.illegal is always the defaultForKind, so it is skipped
 692                         JavaKind valueKind = value.getStackKind();
 693                         JavaKind entryKind = virtual.entryKind(i);
 694 
 695                         // Truffle requires some leniency in terms of what can be put where:
 696                         assert valueKind.getStackKind() == entryKind.getStackKind() ||
 697                                         (valueKind == JavaKind.Long || valueKind == JavaKind.Double || (valueKind == JavaKind.Int && virtual instanceof VirtualArrayNode));
 698                         AddressNode address = null;
 699                         BarrierType barrierType = null;
 700                         if (virtual instanceof VirtualInstanceNode) {
 701                             ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
 702                             long offset = fieldOffset(field);
 703                             if (offset >= 0) {
 704                                 address = createOffsetAddress(graph, newObject, offset);
 705                                 barrierType = fieldInitializationBarrier(entryKind);
 706                             }
 707                         } else {
 708                             address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
 709                             barrierType = arrayInitializationBarrier(entryKind);
 710                         }
 711                         if (address != null) {
 712                             WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
 713                             graph.addAfterFixed(newObject, graph.add(write));
 714                         }
 715                     }
 716                     valuePos++;
 717 
 718                 }
 719             }
 720             valuePos = 0;
 721 
 722             for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 723                 VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
 724                 int entryCount = virtual.entryCount();
 725                 ValueNode newObject = allocations[objIndex];
 726                 for (int i = 0; i < entryCount; i++) {
 727                     if (omittedValues.get(valuePos)) {
 728                         ValueNode value = commit.getValues().get(valuePos);
 729                         assert value instanceof VirtualObjectNode;
 730                         ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
 731                         if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
 732                             assert virtual.entryKind(i) == JavaKind.Object && allocValue.getStackKind() == JavaKind.Object;
 733                             AddressNode address;
 734                             BarrierType barrierType;
 735                             if (virtual instanceof VirtualInstanceNode) {
 736                                 VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
 737                                 address = createFieldAddress(graph, newObject, virtualInstance.field(i));
 738                                 barrierType = BarrierType.IMPRECISE;
 739                             } else {
 740                                 address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
 741                                 barrierType = BarrierType.PRECISE;
 742                             }
 743                             if (address != null) {
 744                                 WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
 745                                 graph.addBeforeFixed(commit, graph.add(write));
 746                             }
 747                         }
 748                     }
 749                     valuePos++;
 750                 }
 751             }
 752 
 753             finishAllocatedObjects(tool, commit, allocations);
 754             graph.removeFixed(commit);
 755 
 756             for (AbstractNewObjectNode recursiveLowering : recursiveLowerings) {
 757                 recursiveLowering.lower(tool);
 758             }
 759         }
 760     }
 761 
 762     public NewInstanceNode createNewInstanceFromVirtual(VirtualObjectNode virtual) {
 763         return new NewInstanceNode(virtual.type(), true);
 764     }
 765 
 766     protected NewArrayNode createNewArrayFromVirtual(VirtualObjectNode virtual, ValueNode length) {
 767         return new NewArrayNode(((VirtualArrayNode) virtual).componentType(), length, true);
 768     }
 769 
 770     public void finishAllocatedObjects(LoweringTool tool, CommitAllocationNode commit, ValueNode[] allocations) {
 771         StructuredGraph graph = commit.graph();
 772         for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 773             FixedValueAnchorNode anchor = graph.add(new FixedValueAnchorNode(allocations[objIndex]));
 774             allocations[objIndex] = anchor;
 775             graph.addBeforeFixed(commit, anchor);
 776         }
 777         /*
 778          * Note that the FrameState that is assigned to these MonitorEnterNodes isn't the correct
 779          * state. It will be the state from before the allocation occurred instead of a valid state
 780          * after the locking is performed. In practice this should be fine since these are newly
 781          * allocated objects. The bytecodes themselves permit allocating an object, doing a
 782          * monitorenter and then dropping all references to the object which would produce the same
 783          * state, though that would normally produce an IllegalMonitorStateException. In HotSpot
 784          * some form of fast path locking should always occur so the FrameState should never
 785          * actually be used.
 786          */
 787         ArrayList<MonitorEnterNode> enters = null;
 788         for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
 789             List<MonitorIdNode> locks = commit.getLocks(objIndex);
 790             if (locks.size() > 1) {
 791                 // Ensure that the lock operations are performed in lock depth order
 792                 ArrayList<MonitorIdNode> newList = new ArrayList<>(locks);
 793                 newList.sort((a, b) -> Integer.compare(a.getLockDepth(), b.getLockDepth()));
 794                 locks = newList;
 795             }
 796             int lastDepth = -1;
 797             for (MonitorIdNode monitorId : locks) {
 798                 assert lastDepth < monitorId.getLockDepth();
 799                 lastDepth = monitorId.getLockDepth();
 800                 MonitorEnterNode enter = graph.add(new MonitorEnterNode(allocations[objIndex], monitorId));
 801                 graph.addBeforeFixed(commit, enter);
 802                 if (enters == null) {
 803                     enters = new ArrayList<>();
 804                 }
 805                 enters.add(enter);
 806             }
 807         }
 808         for (Node usage : commit.usages().snapshot()) {
 809             if (usage instanceof AllocatedObjectNode) {
 810                 AllocatedObjectNode addObject = (AllocatedObjectNode) usage;
 811                 int index = commit.getVirtualObjects().indexOf(addObject.getVirtualObject());
 812                 addObject.replaceAtUsagesAndDelete(allocations[index]);
 813             } else {
 814                 assert enters != null;
 815                 commit.replaceAtUsages(InputType.Memory, enters.get(enters.size() - 1));
 816             }
 817         }
 818         if (enters != null) {
 819             for (MonitorEnterNode enter : enters) {
 820                 enter.lower(tool);
 821             }
 822         }
 823         assert commit.hasNoUsages();
 824         insertAllocationBarrier(commit, graph);
 825     }
 826 
 827     /**
 828      * Insert the required {@link MemoryBarriers#STORE_STORE} barrier for an allocation and also
 829      * include the {@link MemoryBarriers#LOAD_STORE} required for final fields if any final fields
 830      * are being written, as if {@link FinalFieldBarrierNode} were emitted.
 831      */
 832     private static void insertAllocationBarrier(CommitAllocationNode commit, StructuredGraph graph) {
 833         int barrier = MemoryBarriers.STORE_STORE;
 834         outer: for (VirtualObjectNode vobj : commit.getVirtualObjects()) {
 835             for (ResolvedJavaField field : vobj.type().getInstanceFields(true)) {
 836                 if (field.isFinal()) {
 837                     barrier = barrier | MemoryBarriers.LOAD_STORE;
 838                     break outer;
 839                 }
 840             }
 841         }
 842         graph.addAfterFixed(commit, graph.add(new MembarNode(barrier, LocationIdentity.init())));
 843     }
 844 
 845     /**
 846      * @param field the field whose barrier type should be returned
 847      */
 848     protected BarrierType fieldLoadBarrierType(ResolvedJavaField field) {
 849         return BarrierType.NONE;
 850     }
 851 
 852     protected BarrierType fieldStoreBarrierType(ResolvedJavaField field) {
 853         if (field.getJavaKind() == JavaKind.Object) {
 854             return BarrierType.IMPRECISE;
 855         }
 856         return BarrierType.NONE;
 857     }
 858 
 859     protected BarrierType arrayStoreBarrierType(JavaKind elementKind) {
 860         if (elementKind == JavaKind.Object) {
 861             return BarrierType.PRECISE;
 862         }
 863         return BarrierType.NONE;
 864     }
 865 
 866     public BarrierType fieldInitializationBarrier(JavaKind entryKind) {
 867         return entryKind == JavaKind.Object ? BarrierType.IMPRECISE : BarrierType.NONE;
 868     }
 869 
 870     public BarrierType arrayInitializationBarrier(JavaKind entryKind) {
 871         return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE;
 872     }
 873 
 874     protected BarrierType unsafeStoreBarrierType(RawStoreNode store) {
 875         if (!store.needsBarrier()) {
 876             return BarrierType.NONE;
 877         }
 878         return storeBarrierType(store.object(), store.value());
 879     }
 880 
 881     protected BarrierType compareAndSwapBarrierType(UnsafeCompareAndSwapNode cas) {
 882         return storeBarrierType(cas.object(), cas.expected());
 883     }
 884 
 885     protected BarrierType atomicReadAndWriteBarrierType(AtomicReadAndWriteNode n) {
 886         return storeBarrierType(n.object(), n.newValue());
 887     }
 888 
 889     protected BarrierType storeBarrierType(ValueNode object, ValueNode value) {
 890         if (value.getStackKind() == JavaKind.Object) {
 891             ResolvedJavaType type = StampTool.typeOrNull(object);
 892             if (type != null && !type.isArray()) {
 893                 return BarrierType.IMPRECISE;
 894             } else {
 895                 return BarrierType.PRECISE;
 896             }
 897         }
 898         return BarrierType.NONE;
 899     }
 900 
 901     public abstract int fieldOffset(ResolvedJavaField field);
 902 
 903     public FieldLocationIdentity fieldLocationIdentity(ResolvedJavaField field) {
 904         return new FieldLocationIdentity(field);
 905     }
 906 
 907     public abstract ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField field);
 908 
 909     public abstract int arrayLengthOffset();
 910 
 911     public abstract int arrayBaseOffset(JavaKind elementKind);
 912 
 913     public int arrayScalingFactor(JavaKind elementKind) {
 914         return target.arch.getPlatformKind(elementKind).getSizeInBytes();
 915     }
 916 
 917     public Stamp loadStamp(Stamp stamp, JavaKind kind) {
 918         return loadStamp(stamp, kind, true);
 919     }
 920 
 921     /**
 922      * @param compressible whether the stamp should be compressible
 923      */
 924     protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
 925         switch (kind) {
 926             case Boolean:
 927             case Byte:
 928                 return IntegerStamp.OPS.getNarrow().foldStamp(32, 8, stamp);
 929             case Char:
 930             case Short:
 931                 return IntegerStamp.OPS.getNarrow().foldStamp(32, 16, stamp);
 932         }
 933         return stamp;
 934     }
 935 
 936     public final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
 937         return implicitLoadConvert(graph, kind, value, true);
 938     }
 939 
 940     public ValueNode implicitLoadConvert(JavaKind kind, ValueNode value) {
 941         return implicitLoadConvert(kind, value, true);
 942     }
 943 
 944     protected final ValueNode implicitLoadConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
 945         ValueNode ret = implicitLoadConvert(kind, value, compressible);
 946         if (!ret.isAlive()) {
 947             ret = graph.addOrUnique(ret);
 948         }
 949         return ret;
 950     }
 951 
 952     /**
 953      * @param compressible whether the covert should be compressible
 954      */
 955     protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
 956         switch (kind) {
 957             case Byte:
 958             case Short:
 959                 return new SignExtendNode(value, 32);
 960             case Boolean:
 961             case Char:
 962                 return new ZeroExtendNode(value, 32);
 963         }
 964         return value;
 965     }
 966 
 967     public final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value) {
 968         return implicitStoreConvert(graph, kind, value, true);
 969     }
 970 
 971     public ValueNode implicitStoreConvert(JavaKind kind, ValueNode value) {
 972         return implicitStoreConvert(kind, value, true);
 973     }
 974 
 975     protected final ValueNode implicitStoreConvert(StructuredGraph graph, JavaKind kind, ValueNode value, boolean compressible) {
 976         ValueNode ret = implicitStoreConvert(kind, value, compressible);
 977         if (!ret.isAlive()) {
 978             ret = graph.addOrUnique(ret);
 979         }
 980         return ret;
 981     }
 982 
 983     /**
 984      * @param compressible whether the covert should be compressible
 985      */
 986     protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
 987         switch (kind) {
 988             case Boolean:
 989             case Byte:
 990                 return new NarrowNode(value, 8);
 991             case Char:
 992             case Short:
 993                 return new NarrowNode(value, 16);
 994         }
 995         return value;
 996     }
 997 
 998     protected abstract ValueNode createReadHub(StructuredGraph graph, ValueNode object, LoweringTool tool);
 999 
1000     protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
1001 
1002     protected GuardingNode getBoundsCheck(AccessIndexedNode n, ValueNode array, LoweringTool tool) {
1003         StructuredGraph graph = n.graph();
1004         ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
1005         if (arrayLength == null) {
1006             arrayLength = createReadArrayLength(array, n, tool);
1007         } else {
1008             arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength);
1009         }
1010 
1011         LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength);
1012         if (boundsCheck.isTautology()) {
1013             return null;
1014         } else {
1015             return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile);
1016         }
1017     }
1018 
1019     protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
1020         if (StampTool.isPointerNonNull(object)) {
1021             return null;
1022         }
1023         return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true);
1024     }
1025 
1026     protected ValueNode createNullCheckedValue(ValueNode object, FixedNode before, LoweringTool tool) {
1027         GuardingNode nullCheck = createNullCheck(object, before, tool);
1028         if (nullCheck == null) {
1029             return object;
1030         } else {
1031             return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck));
1032         }
1033     }
1034 
1035     @Override
1036     public ValueNode reconstructArrayIndex(JavaKind elementKind, AddressNode address) {
1037         StructuredGraph graph = address.graph();
1038         ValueNode offset = ((OffsetAddressNode) address).getOffset();
1039 
1040         int base = arrayBaseOffset(elementKind);
1041         ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(), base, graph)));
1042 
1043         int shift = CodeUtil.log2(arrayScalingFactor(elementKind));
1044         ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph)));
1045         return IntegerConvertNode.convert(ret, StampFactory.forKind(JavaKind.Int), graph);
1046     }
1047 }