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.graphbuilderconf;
24
25 import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
26 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
27 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
28
29 import org.graalvm.compiler.bytecode.Bytecode;
30 import org.graalvm.compiler.bytecode.BytecodeProvider;
31 import org.graalvm.compiler.core.common.type.ObjectStamp;
32 import org.graalvm.compiler.core.common.type.Stamp;
33 import org.graalvm.compiler.core.common.type.StampFactory;
34 import org.graalvm.compiler.core.common.type.StampPair;
35 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
36 import org.graalvm.compiler.nodes.FixedGuardNode;
37 import org.graalvm.compiler.nodes.LogicNode;
38 import org.graalvm.compiler.nodes.PiNode;
39 import org.graalvm.compiler.nodes.StateSplit;
40 import org.graalvm.compiler.nodes.ValueNode;
41 import org.graalvm.compiler.nodes.calc.IsNullNode;
42 import org.graalvm.compiler.nodes.type.StampTool;
43
44 import jdk.vm.ci.code.BailoutException;
45 import jdk.vm.ci.meta.Assumptions;
46 import jdk.vm.ci.meta.JavaKind;
47 import jdk.vm.ci.meta.JavaType;
48 import jdk.vm.ci.meta.ResolvedJavaMethod;
49
50 /**
51 * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
52 * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
53 */
54 public interface GraphBuilderContext extends GraphBuilderTool {
55
56 /**
57 * Pushes a given value to the frame state stack using an explicit kind. This should be used
58 * when {@code value.getJavaKind()} is different from the kind that the bytecode instruction
59 * currently being parsed pushes to the stack.
60 *
61 * @param kind the kind to use when type checking this operation
62 * @param value the value to push to the stack. The value must already have been
63 * {@linkplain #append(ValueNode) appended}.
64 */
65 void push(JavaKind kind, ValueNode value);
70 *
71 * @param value the value to add to the graph and push to the stack. The
72 * {@code value.getJavaKind()} kind is used when type checking this operation.
73 * @return a node equivalent to {@code value} in the graph
74 */
75 default <T extends ValueNode> T add(T value) {
76 if (value.graph() != null) {
77 assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
78 return value;
79 }
80 T equivalentValue = append(value);
81 if (equivalentValue instanceof StateSplit) {
82 StateSplit stateSplit = (StateSplit) equivalentValue;
83 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
84 setStateAfter(stateSplit);
85 }
86 }
87 return equivalentValue;
88 }
89
90 /**
91 * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
92 * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
93 * frame state is initialized.
94 *
95 * @param kind the kind to use when type checking this operation
96 * @param value the value to add to the graph and push to the stack
97 * @return a node equivalent to {@code value} in the graph
98 */
99 default <T extends ValueNode> T addPush(JavaKind kind, T value) {
100 T equivalentValue = value.graph() != null ? value : append(value);
101 push(kind, equivalentValue);
102 if (equivalentValue instanceof StateSplit) {
103 StateSplit stateSplit = (StateSplit) equivalentValue;
104 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
105 setStateAfter(stateSplit);
106 }
107 }
108 return equivalentValue;
109 }
110
111 /**
112 * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
113 * one for which the plugin was applied). This applies all standard graph builder processing to
114 * the replaced invocation including applying any relevant plugins.
115 *
116 * @param invokeKind the kind of the replacement invocation
117 * @param targetMethod the target of the replacement invocation
118 * @param args the arguments to the replacement invocation
119 * @param forceInlineEverything specifies if all invocations encountered in the scope of
120 * handling the replaced invoke are to be force inlined
121 */
122 void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
123
124 /**
125 * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
126 * substitution method.
127 *
128 * @param bytecodeProvider used to get the bytecodes to parse for the substitution method
129 * @param targetMethod the method being intrinsified
130 * @param substitute the intrinsic implementation
131 * @param receiver the receiver, or null for static methods
132 * @param argsIncludingReceiver the arguments with which to inline the invocation
133 *
134 * @return whether the intrinsification was successful
135 */
136 boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver);
137
138 /**
139 * Creates a snap shot of the current frame state with the BCI of the instruction after the one
140 * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
141 * effect} node.
142 *
143 * @param sideEffect a side effect node just appended to the graph
200 return parent == null ? 0 : 1 + parent.getDepth();
201 }
202
203 /**
204 * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
205 * by an intrinsic.
206 */
207 @Override
208 default boolean parsingIntrinsic() {
209 return getIntrinsic() != null;
210 }
211
212 /**
213 * Gets the intrinsic of the current parsing context or {@code null} if not
214 * {@link #parsingIntrinsic() parsing an intrinsic}.
215 */
216 IntrinsicContext getIntrinsic();
217
218 BailoutException bailout(String string);
219
220 /**
221 * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
222 * non-null} stamp.
223 */
224 default ValueNode nullCheckedValue(ValueNode value) {
225 if (!StampTool.isPointerNonNull(value.stamp())) {
226 LogicNode condition = getGraph().unique(IsNullNode.create(value));
227 ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
228 Stamp stamp = receiverStamp.join(objectNonNull());
229 FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
230 PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp, fixedGuard));
231 // TODO: Propogating the non-null into the frame state would
232 // remove subsequent null-checks on the same value. However,
233 // it currently causes an assertion failure when merging states.
234 //
235 // frameState.replace(value, nonNullReceiver);
236 return nonNullReceiver;
237 }
238 return value;
239 }
240 }
|
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.graphbuilderconf;
24
25 import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile;
26 import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException;
27 import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
28
29 import org.graalvm.compiler.bytecode.Bytecode;
30 import org.graalvm.compiler.bytecode.BytecodeProvider;
31 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
32 import org.graalvm.compiler.core.common.type.ObjectStamp;
33 import org.graalvm.compiler.core.common.type.Stamp;
34 import org.graalvm.compiler.core.common.type.StampFactory;
35 import org.graalvm.compiler.core.common.type.StampPair;
36 import org.graalvm.compiler.nodes.CallTargetNode;
37 import org.graalvm.compiler.nodes.ConstantNode;
38 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
39 import org.graalvm.compiler.nodes.FixedGuardNode;
40 import org.graalvm.compiler.nodes.LogicNode;
41 import org.graalvm.compiler.nodes.PiNode;
42 import org.graalvm.compiler.nodes.StateSplit;
43 import org.graalvm.compiler.nodes.ValueNode;
44 import org.graalvm.compiler.nodes.calc.IsNullNode;
45 import org.graalvm.compiler.nodes.type.StampTool;
46
47 import jdk.vm.ci.code.BailoutException;
48 import jdk.vm.ci.meta.Assumptions;
49 import jdk.vm.ci.meta.DeoptimizationAction;
50 import jdk.vm.ci.meta.DeoptimizationReason;
51 import jdk.vm.ci.meta.JavaKind;
52 import jdk.vm.ci.meta.JavaType;
53 import jdk.vm.ci.meta.ResolvedJavaMethod;
54
55 /**
56 * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
57 * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
58 */
59 public interface GraphBuilderContext extends GraphBuilderTool {
60
61 /**
62 * Pushes a given value to the frame state stack using an explicit kind. This should be used
63 * when {@code value.getJavaKind()} is different from the kind that the bytecode instruction
64 * currently being parsed pushes to the stack.
65 *
66 * @param kind the kind to use when type checking this operation
67 * @param value the value to push to the stack. The value must already have been
68 * {@linkplain #append(ValueNode) appended}.
69 */
70 void push(JavaKind kind, ValueNode value);
75 *
76 * @param value the value to add to the graph and push to the stack. The
77 * {@code value.getJavaKind()} kind is used when type checking this operation.
78 * @return a node equivalent to {@code value} in the graph
79 */
80 default <T extends ValueNode> T add(T value) {
81 if (value.graph() != null) {
82 assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
83 return value;
84 }
85 T equivalentValue = append(value);
86 if (equivalentValue instanceof StateSplit) {
87 StateSplit stateSplit = (StateSplit) equivalentValue;
88 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
89 setStateAfter(stateSplit);
90 }
91 }
92 return equivalentValue;
93 }
94
95 default ValueNode addNonNullCast(ValueNode value) {
96 AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp();
97 if (valueStamp.nonNull()) {
98 return value;
99 } else {
100 LogicNode isNull = add(IsNullNode.create(value));
101 FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true));
102 Stamp newStamp = valueStamp.improveWith(StampFactory.objectNonNull());
103 return add(new PiNode(value, newStamp, fixedGuard));
104 }
105 }
106
107 /**
108 * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
109 * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
110 * frame state is initialized.
111 *
112 * @param kind the kind to use when type checking this operation
113 * @param value the value to add to the graph and push to the stack
114 * @return a node equivalent to {@code value} in the graph
115 */
116 default <T extends ValueNode> T addPush(JavaKind kind, T value) {
117 T equivalentValue = value.graph() != null ? value : append(value);
118 push(kind, equivalentValue);
119 if (equivalentValue instanceof StateSplit) {
120 StateSplit stateSplit = (StateSplit) equivalentValue;
121 if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
122 setStateAfter(stateSplit);
123 }
124 }
125 return equivalentValue;
126 }
127
128 /**
129 * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
130 * one for which the plugin was applied). This applies all standard graph builder processing to
131 * the replaced invocation including applying any relevant plugins.
132 *
133 * @param invokeKind the kind of the replacement invocation
134 * @param targetMethod the target of the replacement invocation
135 * @param args the arguments to the replacement invocation
136 * @param forceInlineEverything specifies if all invocations encountered in the scope of
137 * handling the replaced invoke are to be force inlined
138 */
139 void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
140
141 void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType);
142
143 /**
144 * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
145 * substitution method.
146 *
147 * @param bytecodeProvider used to get the bytecodes to parse for the substitution method
148 * @param targetMethod the method being intrinsified
149 * @param substitute the intrinsic implementation
150 * @param receiver the receiver, or null for static methods
151 * @param argsIncludingReceiver the arguments with which to inline the invocation
152 *
153 * @return whether the intrinsification was successful
154 */
155 boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver);
156
157 /**
158 * Creates a snap shot of the current frame state with the BCI of the instruction after the one
159 * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
160 * effect} node.
161 *
162 * @param sideEffect a side effect node just appended to the graph
219 return parent == null ? 0 : 1 + parent.getDepth();
220 }
221
222 /**
223 * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
224 * by an intrinsic.
225 */
226 @Override
227 default boolean parsingIntrinsic() {
228 return getIntrinsic() != null;
229 }
230
231 /**
232 * Gets the intrinsic of the current parsing context or {@code null} if not
233 * {@link #parsingIntrinsic() parsing an intrinsic}.
234 */
235 IntrinsicContext getIntrinsic();
236
237 BailoutException bailout(String string);
238
239 default ValueNode nullCheckedValue(ValueNode value) {
240 return nullCheckedValue(value, InvalidateReprofile);
241 }
242
243 /**
244 * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
245 * non-null} stamp.
246 */
247 default ValueNode nullCheckedValue(ValueNode value, DeoptimizationAction action) {
248 if (!StampTool.isPointerNonNull(value.stamp())) {
249 LogicNode condition = getGraph().unique(IsNullNode.create(value));
250 ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
251 Stamp stamp = receiverStamp.join(objectNonNull());
252 FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, action, true));
253 PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp, fixedGuard));
254 // TODO: Propogating the non-null into the frame state would
255 // remove subsequent null-checks on the same value. However,
256 // it currently causes an assertion failure when merging states.
257 //
258 // frameState.replace(value, nonNullReceiver);
259 return nonNullReceiver;
260 }
261 return value;
262 }
263
264 @SuppressWarnings("unused")
265 default void notifyReplacedCall(ResolvedJavaMethod targetMethod, ConstantNode node) {
266
267 }
268 }
|