001/*
002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.graphbuilderconf;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.meta.*;
027import static com.oracle.graal.compiler.common.type.StampFactory.*;
028import static jdk.internal.jvmci.meta.DeoptimizationAction.*;
029import static jdk.internal.jvmci.meta.DeoptimizationReason.*;
030
031import com.oracle.graal.compiler.common.type.*;
032import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.calc.*;
035import com.oracle.graal.nodes.spi.*;
036import com.oracle.graal.nodes.type.*;
037
038/**
039 * Used by a {@link GraphBuilderPlugin} to interface with an object that parses the bytecode of a
040 * single {@linkplain #getMethod() method} as part of building a {@linkplain #getGraph() graph} .
041 */
042public interface GraphBuilderContext {
043
044    /**
045     * Raw operation for adding a node to the graph when neither {@link #add} nor
046     * {@link #addPush(Kind, ValueNode)} can be used.
047     *
048     * @return either the node added or an equivalent node
049     */
050    <T extends ValueNode> T append(T value);
051
052    /**
053     * Adds the given node to the graph and also adds recursively all referenced inputs.
054     *
055     * @param value the node to be added to the graph
056     * @return either the node added or an equivalent node
057     */
058    <T extends ValueNode> T recursiveAppend(T value);
059
060    /**
061     * Pushes a given value to the frame state stack using an explicit kind. This should be used
062     * when {@code value.getKind()} is different from the kind that the bytecode instruction
063     * currently being parsed pushes to the stack.
064     *
065     * @param kind the kind to use when type checking this operation
066     * @param value the value to push to the stack. The value must already have been
067     *            {@linkplain #append(ValueNode) appended}.
068     */
069    void push(Kind kind, ValueNode value);
070
071    /**
072     * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null
073     * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized.
074     *
075     * @param value the value to add to the graph and push to the stack. The {@code value.getKind()}
076     *            kind is used when type checking this operation.
077     * @return a node equivalent to {@code value} in the graph
078     */
079    default <T extends ValueNode> T add(T value) {
080        if (value.graph() != null) {
081            assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null;
082            return value;
083        }
084        T equivalentValue = append(value);
085        if (equivalentValue instanceof StateSplit) {
086            StateSplit stateSplit = (StateSplit) equivalentValue;
087            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
088                setStateAfter(stateSplit);
089            }
090        }
091        return equivalentValue;
092    }
093
094    /**
095     * Adds a node with a non-void kind to the graph, pushes it to the stack. If the returned node
096     * is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the
097     * frame state is initialized.
098     *
099     * @param kind the kind to use when type checking this operation
100     * @param value the value to add to the graph and push to the stack
101     * @return a node equivalent to {@code value} in the graph
102     */
103    default <T extends ValueNode> T addPush(Kind kind, T value) {
104        T equivalentValue = value.graph() != null ? value : append(value);
105        push(kind, equivalentValue);
106        if (equivalentValue instanceof StateSplit) {
107            StateSplit stateSplit = (StateSplit) equivalentValue;
108            if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) {
109                setStateAfter(stateSplit);
110            }
111        }
112        return equivalentValue;
113    }
114
115    /**
116     * Handles an invocation that a plugin determines can replace the original invocation (i.e., the
117     * one for which the plugin was applied). This applies all standard graph builder processing to
118     * the replaced invocation including applying any relevant plugins.
119     *
120     * @param invokeKind the kind of the replacement invocation
121     * @param targetMethod the target of the replacement invocation
122     * @param args the arguments to the replacement invocation
123     * @param forceInlineEverything specifies if all invocations encountered in the scope of
124     *            handling the replaced invoke are to be force inlined
125     */
126    void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything);
127
128    /**
129     * Intrinsifies an invocation of a given method by inlining the bytecodes of a given
130     * substitution method.
131     *
132     * @param targetMethod the method being intrinsified
133     * @param substitute the intrinsic implementation
134     * @param args the arguments with which to inline the invocation
135     */
136    void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args);
137
138    StampProvider getStampProvider();
139
140    MetaAccessProvider getMetaAccess();
141
142    default Assumptions getAssumptions() {
143        return getGraph().getAssumptions();
144    }
145
146    ConstantReflectionProvider getConstantReflection();
147
148    /**
149     * Gets the graph being constructed.
150     */
151    StructuredGraph getGraph();
152
153    /**
154     * Creates a snap shot of the current frame state with the BCI of the instruction after the one
155     * currently being parsed and assigns it to a given {@linkplain StateSplit#hasSideEffect() side
156     * effect} node.
157     *
158     * @param sideEffect a side effect node just appended to the graph
159     */
160    void setStateAfter(StateSplit sideEffect);
161
162    /**
163     * Gets the parsing context for the method that inlines the method being parsed by this context.
164     */
165    GraphBuilderContext getParent();
166
167    /**
168     * Gets the first ancestor parsing context that is not parsing a
169     * {@linkplain #parsingIntrinsic() intrinsic}.
170     */
171    default GraphBuilderContext getNonIntrinsicAncestor() {
172        GraphBuilderContext ancestor = getParent();
173        while (ancestor != null && ancestor.parsingIntrinsic()) {
174            ancestor = ancestor.getParent();
175        }
176        return ancestor;
177    }
178
179    /**
180     * Gets the method being parsed by this context.
181     */
182    ResolvedJavaMethod getMethod();
183
184    /**
185     * Gets the index of the bytecode instruction currently being parsed.
186     */
187    int bci();
188
189    /**
190     * Gets the kind of invocation currently being parsed.
191     */
192    InvokeKind getInvokeKind();
193
194    /**
195     * Gets the return type of the invocation currently being parsed.
196     */
197    JavaType getInvokeReturnType();
198
199    default Stamp getInvokeReturnStamp() {
200        JavaType returnType = getInvokeReturnType();
201        if (returnType.getKind() == Kind.Object && returnType instanceof ResolvedJavaType) {
202            return StampFactory.declared((ResolvedJavaType) returnType);
203        } else {
204            return StampFactory.forKind(returnType.getKind());
205        }
206    }
207
208    /**
209     * Gets the inline depth of this context. A return value of 0 implies that this is the context
210     * for the parse root.
211     */
212    default int getDepth() {
213        GraphBuilderContext parent = getParent();
214        return parent == null ? 0 : 1 + parent.getDepth();
215    }
216
217    /**
218     * Determines if this parsing context is within the bytecode of an intrinsic or a method inlined
219     * by an intrinsic.
220     */
221    default boolean parsingIntrinsic() {
222        return getIntrinsic() != null;
223    }
224
225    /**
226     * Gets the intrinsic of the current parsing context or {@code null} if not
227     * {@link #parsingIntrinsic() parsing an intrinsic}.
228     */
229    IntrinsicContext getIntrinsic();
230
231    BailoutException bailout(String string);
232
233    /**
234     * Gets a version of a given value that has a {@linkplain StampTool#isPointerNonNull(ValueNode)
235     * non-null} stamp.
236     */
237    default ValueNode nullCheckedValue(ValueNode value) {
238        if (!StampTool.isPointerNonNull(value.stamp())) {
239            IsNullNode condition = getGraph().unique(new IsNullNode(value));
240            ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
241            Stamp stamp = receiverStamp.join(objectNonNull());
242            FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
243            PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp));
244            nonNullReceiver.setGuard(fixedGuard);
245            // TODO: Propogating the non-null into the frame state would
246            // remove subsequent null-checks on the same value. However,
247            // it currently causes an assertion failure when merging states.
248            //
249            // frameState.replace(value, nonNullReceiver);
250            return nonNullReceiver;
251        }
252        return value;
253    }
254}