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