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 24 25 package org.graalvm.compiler.nodes.extended; 26 27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; 28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; 29 30 import org.graalvm.compiler.core.common.type.PrimitiveStamp; 31 import org.graalvm.compiler.core.common.type.Stamp; 32 import org.graalvm.compiler.core.common.type.StampFactory; 33 import org.graalvm.compiler.graph.Node; 34 import org.graalvm.compiler.graph.NodeClass; 35 import org.graalvm.compiler.graph.spi.Canonicalizable; 36 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 37 import org.graalvm.compiler.nodeinfo.NodeInfo; 38 import org.graalvm.compiler.nodes.ConstantNode; 39 import org.graalvm.compiler.nodes.NodeView; 40 import org.graalvm.compiler.nodes.ValueNode; 41 import org.graalvm.compiler.nodes.calc.ReinterpretNode; 42 import org.graalvm.compiler.nodes.java.LoadFieldNode; 43 import org.graalvm.compiler.nodes.spi.Lowerable; 44 import org.graalvm.compiler.nodes.spi.LoweringTool; 45 import org.graalvm.compiler.nodes.spi.Virtualizable; 46 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 47 import org.graalvm.compiler.nodes.type.StampTool; 48 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 49 import jdk.internal.vm.compiler.word.LocationIdentity; 50 51 import jdk.vm.ci.meta.Assumptions; 52 import jdk.vm.ci.meta.Constant; 53 import jdk.vm.ci.meta.JavaConstant; 54 import jdk.vm.ci.meta.JavaKind; 55 import jdk.vm.ci.meta.ResolvedJavaField; 56 import jdk.vm.ci.meta.ResolvedJavaType; 57 58 /** 59 * Load of a value from a location specified as an offset relative to an object. No null check is 60 * performed before the load. 61 */ 62 @NodeInfo(cycles = CYCLES_2, size = SIZE_1) 63 public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable, Canonicalizable { 64 public static final NodeClass<RawLoadNode> TYPE = NodeClass.create(RawLoadNode.class); 65 66 /** 67 * This constructor exists for node intrinsics that need a stamp based on {@code accessKind}. 68 */ 69 public RawLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) { 70 this(object, offset, accessKind, locationIdentity, false); 71 } 72 73 public RawLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity, boolean forceAnyLocation) { 74 super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, forceAnyLocation); 75 } 76 77 /** 78 * This constructor exists for node intrinsics that need a stamp based on the return type of the 79 * {@link org.graalvm.compiler.graph.Node.NodeIntrinsic} annotated method. 80 */ 81 public RawLoadNode(@InjectedNodeParameter Stamp stamp, ValueNode object, ValueNode offset, LocationIdentity locationIdentity, JavaKind accessKind) { 82 super(TYPE, stamp, object, offset, accessKind, locationIdentity, false); 83 } 84 85 protected RawLoadNode(NodeClass<? extends RawLoadNode> c, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) { 86 super(c, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, false); 87 } 88 89 @Override 90 public void lower(LoweringTool tool) { 91 tool.getLowerer().lower(this, tool); 92 } 93 94 @Override 95 public void virtualize(VirtualizerTool tool) { 96 ValueNode alias = tool.getAlias(object()); 97 if (alias instanceof VirtualObjectNode) { 98 VirtualObjectNode virtual = (VirtualObjectNode) alias; 99 ValueNode offsetValue = tool.getAlias(offset()); 100 if (offsetValue.isConstant()) { 101 long off = offsetValue.asJavaConstant().asLong(); 102 int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind()); 103 104 if (entryIndex != -1) { 105 ValueNode entry = tool.getEntry(virtual, entryIndex); 106 JavaKind entryKind = virtual.entryKind(entryIndex); 107 if (entry.getStackKind() == getStackKind() || entryKind == accessKind()) { 108 109 if (!(entry.stamp(NodeView.DEFAULT).isCompatible(stamp(NodeView.DEFAULT)))) { 110 if (entry.stamp(NodeView.DEFAULT) instanceof PrimitiveStamp && stamp instanceof PrimitiveStamp) { 111 PrimitiveStamp p1 = (PrimitiveStamp) stamp; 112 PrimitiveStamp p2 = (PrimitiveStamp) entry.stamp(NodeView.DEFAULT); 113 int width1 = p1.getBits(); 114 int width2 = p2.getBits(); 115 if (width1 == width2) { 116 Node replacement = ReinterpretNode.create(p2, entry, NodeView.DEFAULT); 117 tool.replaceWith((ValueNode) replacement); 118 return; 119 } else { 120 // different bit width 121 return; 122 } 123 } else { 124 // cannot reinterpret for arbitrary objects 125 return; 126 } 127 } 128 tool.replaceWith(entry); 129 } 130 } 131 } 132 } 133 } 134 135 @Override 136 public Node canonical(CanonicalizerTool tool) { 137 if (!isAnyLocationForced() && getLocationIdentity().isAny()) { 138 ValueNode targetObject = object(); 139 if (offset().isConstant() && targetObject.isConstant() && !targetObject.isNullConstant()) { 140 ConstantNode objectConstant = (ConstantNode) targetObject; 141 ResolvedJavaType type = StampTool.typeOrNull(objectConstant); 142 if (type != null && type.isArray()) { 143 JavaConstant arrayConstant = objectConstant.asJavaConstant(); 144 if (arrayConstant != null) { 145 int stableDimension = objectConstant.getStableDimension(); 146 if (stableDimension > 0) { 147 NodeView view = NodeView.from(tool); 148 long constantOffset = offset().asJavaConstant().asLong(); 149 Constant constant = stamp(view).readConstant(tool.getConstantReflection().getMemoryAccessProvider(), arrayConstant, constantOffset); 150 boolean isDefaultStable = objectConstant.isDefaultStable(); 151 if (constant != null && (isDefaultStable || !constant.isDefaultForKind())) { 152 return ConstantNode.forConstant(stamp(view), constant, stableDimension - 1, isDefaultStable, tool.getMetaAccess()); 153 } 154 } 155 } 156 } 157 } 158 } 159 return super.canonical(tool); 160 } 161 162 @Override 163 protected ValueNode cloneAsFieldAccess(Assumptions assumptions, ResolvedJavaField field, boolean volatileAccess) { 164 return LoadFieldNode.create(assumptions, object(), field, volatileAccess); 165 } 166 167 @Override 168 protected ValueNode cloneAsArrayAccess(ValueNode location, LocationIdentity identity) { 169 return new RawLoadNode(object(), location, accessKind(), identity); 170 } 171 172 @NodeIntrinsic 173 public static native Object load(Object object, long offset, @ConstantNodeParameter JavaKind kind, @ConstantNodeParameter LocationIdentity locationIdentity); 174 }