1 /* 2 * Copyright (c) 2009, 2018, 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.java; 26 27 import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA; 28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; 29 30 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; 31 import org.graalvm.compiler.core.common.type.Stamp; 32 import org.graalvm.compiler.core.common.type.StampFactory; 33 import org.graalvm.compiler.core.common.type.StampPair; 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.NodeCycles; 38 import org.graalvm.compiler.nodeinfo.NodeInfo; 39 import org.graalvm.compiler.nodes.ConstantNode; 40 import org.graalvm.compiler.nodes.DeoptimizeNode; 41 import org.graalvm.compiler.nodes.FixedGuardNode; 42 import org.graalvm.compiler.nodes.NodeView; 43 import org.graalvm.compiler.nodes.PhiNode; 44 import org.graalvm.compiler.nodes.ValueNode; 45 import org.graalvm.compiler.nodes.ValuePhiNode; 46 import org.graalvm.compiler.nodes.calc.IsNullNode; 47 import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider; 48 import org.graalvm.compiler.nodes.spi.Virtualizable; 49 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 50 import org.graalvm.compiler.nodes.type.StampTool; 51 import org.graalvm.compiler.nodes.util.ConstantFoldUtil; 52 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; 53 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 54 import org.graalvm.compiler.options.OptionValues; 55 56 import jdk.vm.ci.meta.Assumptions; 57 import jdk.vm.ci.meta.ConstantReflectionProvider; 58 import jdk.vm.ci.meta.DeoptimizationAction; 59 import jdk.vm.ci.meta.DeoptimizationReason; 60 import jdk.vm.ci.meta.JavaConstant; 61 import jdk.vm.ci.meta.JavaKind; 62 import jdk.vm.ci.meta.MetaAccessProvider; 63 import jdk.vm.ci.meta.ResolvedJavaField; 64 65 /** 66 * The {@code LoadFieldNode} represents a read of a static or instance field. 67 */ 68 @NodeInfo(nameTemplate = "LoadField#{p#field/s}") 69 public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary<ValueNode>, Virtualizable, UncheckedInterfaceProvider { 70 71 public static final NodeClass<LoadFieldNode> TYPE = NodeClass.create(LoadFieldNode.class); 72 73 private final Stamp uncheckedStamp; 74 LoadFieldNode(StampPair stamp, ValueNode object, ResolvedJavaField field)75 protected LoadFieldNode(StampPair stamp, ValueNode object, ResolvedJavaField field) { 76 this(stamp, object, field, field.isVolatile()); 77 } 78 LoadFieldNode(StampPair stamp, ValueNode object, ResolvedJavaField field, boolean volatileAccess)79 protected LoadFieldNode(StampPair stamp, ValueNode object, ResolvedJavaField field, boolean volatileAccess) { 80 super(TYPE, stamp.getTrustedStamp(), object, field, volatileAccess); 81 this.uncheckedStamp = stamp.getUncheckedStamp(); 82 } 83 create(Assumptions assumptions, ValueNode object, ResolvedJavaField field)84 public static LoadFieldNode create(Assumptions assumptions, ValueNode object, ResolvedJavaField field) { 85 return create(assumptions, object, field, field.isVolatile()); 86 } 87 create(Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean volatileAccess)88 public static LoadFieldNode create(Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean volatileAccess) { 89 return new LoadFieldNode(StampFactory.forDeclaredType(assumptions, field.getType(), false), object, field, volatileAccess); 90 } 91 create(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable)92 public static ValueNode create(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, 93 OptionValues options, Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { 94 return canonical(null, StampFactory.forDeclaredType(assumptions, field.getType(), false), object, 95 field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable); 96 } 97 createOverrideStamp(StampPair stamp, ValueNode object, ResolvedJavaField field)98 public static LoadFieldNode createOverrideStamp(StampPair stamp, ValueNode object, ResolvedJavaField field) { 99 return new LoadFieldNode(stamp, object, field); 100 } 101 createOverrideStamp(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, StampPair stamp, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable)102 public static ValueNode createOverrideStamp(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, 103 OptionValues options, StampPair stamp, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { 104 return canonical(null, stamp, object, field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable); 105 } 106 107 @Override getValue()108 public ValueNode getValue() { 109 return object(); 110 } 111 112 @Override canonical(CanonicalizerTool tool, ValueNode forObject)113 public ValueNode canonical(CanonicalizerTool tool, ValueNode forObject) { 114 NodeView view = NodeView.from(tool); 115 if (tool.allUsagesAvailable() && hasNoUsages() && !isVolatile()) { 116 if (isStatic() || StampTool.isPointerNonNull(forObject.stamp(view))) { 117 return null; 118 } 119 if (graph().getGuardsStage().allowsGuardInsertion()) { 120 return new FixedGuardNode(new IsNullNode(forObject), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile, true, getNodeSourcePosition()); 121 } 122 } 123 return canonical(this, StampPair.create(stamp, uncheckedStamp), forObject, field, tool.getConstantFieldProvider(), 124 tool.getConstantReflection(), tool.getOptions(), tool.getMetaAccess(), tool.canonicalizeReads(), tool.allUsagesAvailable()); 125 } 126 canonical(LoadFieldNode loadFieldNode, StampPair stamp, ValueNode forObject, ResolvedJavaField field, ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, OptionValues options, MetaAccessProvider metaAccess, boolean canonicalizeReads, boolean allUsagesAvailable)127 private static ValueNode canonical(LoadFieldNode loadFieldNode, StampPair stamp, ValueNode forObject, ResolvedJavaField field, 128 ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, 129 OptionValues options, MetaAccessProvider metaAccess, boolean canonicalizeReads, boolean allUsagesAvailable) { 130 LoadFieldNode self = loadFieldNode; 131 if (canonicalizeReads && metaAccess != null) { 132 ConstantNode constant = asConstant(constantFields, constantReflection, metaAccess, options, forObject, field); 133 if (constant != null) { 134 return constant; 135 } 136 if (allUsagesAvailable) { 137 PhiNode phi = asPhi(constantFields, constantReflection, metaAccess, options, forObject, 138 field, stamp.getTrustedStamp()); 139 if (phi != null) { 140 return phi; 141 } 142 } 143 } 144 if (self != null && !field.isStatic() && forObject.isNullConstant()) { 145 return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); 146 } 147 if (self == null) { 148 self = new LoadFieldNode(stamp, forObject, field); 149 } 150 return self; 151 } 152 153 /** 154 * Gets a constant value for this load if possible. 155 */ asConstant(CanonicalizerTool tool, ValueNode forObject)156 public ConstantNode asConstant(CanonicalizerTool tool, ValueNode forObject) { 157 return asConstant(tool.getConstantFieldProvider(), tool.getConstantReflection(), 158 tool.getMetaAccess(), tool.getOptions(), forObject, field); 159 } 160 asConstant(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, ValueNode forObject, ResolvedJavaField field)161 private static ConstantNode asConstant(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, 162 MetaAccessProvider metaAccess, OptionValues options, ValueNode forObject, ResolvedJavaField field) { 163 if (field.isStatic()) { 164 return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, null, options); 165 } else if (forObject.isConstant() && !forObject.isNullConstant()) { 166 return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, forObject.asJavaConstant(), options); 167 } 168 return null; 169 } 170 asConstant(CanonicalizerTool tool, JavaConstant constant)171 public ConstantNode asConstant(CanonicalizerTool tool, JavaConstant constant) { 172 return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, tool.getOptions()); 173 } 174 asPhi(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAcccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, Stamp stamp)175 private static PhiNode asPhi(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, 176 MetaAccessProvider metaAcccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, Stamp stamp) { 177 if (!field.isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) { 178 PhiNode phi = (PhiNode) forObject; 179 ConstantNode[] constantNodes = new ConstantNode[phi.valueCount()]; 180 for (int i = 0; i < phi.valueCount(); i++) { 181 ConstantNode constant = ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAcccess, field, phi.valueAt(i).asJavaConstant(), 182 options); 183 if (constant == null) { 184 return null; 185 } 186 constantNodes[i] = constant; 187 } 188 return new ValuePhiNode(stamp, phi.merge(), constantNodes); 189 } 190 return null; 191 } 192 193 @Override virtualize(VirtualizerTool tool)194 public void virtualize(VirtualizerTool tool) { 195 ValueNode alias = tool.getAlias(object()); 196 if (alias instanceof VirtualObjectNode) { 197 int fieldIndex = ((VirtualInstanceNode) alias).fieldIndex(field()); 198 if (fieldIndex != -1) { 199 ValueNode entry = tool.getEntry((VirtualObjectNode) alias, fieldIndex); 200 if (stamp.isCompatible(entry.stamp(NodeView.DEFAULT))) { 201 tool.replaceWith(entry); 202 } else { 203 assert stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Int && (entry.stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Long || entry.getStackKind() == JavaKind.Double || 204 entry.getStackKind() == JavaKind.Illegal) : "Can only allow different stack kind two slot marker writes on one stot fields."; 205 } 206 } 207 } 208 } 209 210 @Override uncheckedStamp()211 public Stamp uncheckedStamp() { 212 return uncheckedStamp; 213 } 214 setObject(ValueNode newObject)215 public void setObject(ValueNode newObject) { 216 this.updateUsages(object, newObject); 217 this.object = newObject; 218 } 219 220 @Override estimatedNodeCycles()221 public NodeCycles estimatedNodeCycles() { 222 if (isVolatile()) { 223 return CYCLES_2; 224 } 225 return super.estimatedNodeCycles(); 226 } 227 } 228