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