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