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