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