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 }