1/*
2 * Copyright (c) 2011, 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 */
23package org.graalvm.compiler.replacements;
24
25import org.graalvm.compiler.bytecode.Bytecode;
26import org.graalvm.compiler.bytecode.BytecodeProvider;
27import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
28import org.graalvm.compiler.core.common.type.Stamp;
29import org.graalvm.compiler.core.common.type.StampFactory;
30import org.graalvm.compiler.core.common.type.StampPair;
31import org.graalvm.compiler.core.common.type.TypeReference;
32import org.graalvm.compiler.debug.DebugContext;
33import org.graalvm.compiler.debug.GraalError;
34import org.graalvm.compiler.nodes.CallTargetNode;
35import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
36import org.graalvm.compiler.nodes.FixedNode;
37import org.graalvm.compiler.nodes.FixedWithNextNode;
38import org.graalvm.compiler.nodes.FrameState;
39import org.graalvm.compiler.nodes.ParameterNode;
40import org.graalvm.compiler.nodes.ReturnNode;
41import org.graalvm.compiler.nodes.StateSplit;
42import org.graalvm.compiler.nodes.StructuredGraph;
43import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
44import org.graalvm.compiler.nodes.ValueNode;
45import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
46import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
47import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
48import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
49import org.graalvm.compiler.nodes.spi.StampProvider;
50import org.graalvm.compiler.options.OptionValues;
51
52import jdk.vm.ci.code.BailoutException;
53import jdk.vm.ci.code.BytecodeFrame;
54import jdk.vm.ci.meta.ConstantReflectionProvider;
55import jdk.vm.ci.meta.JavaKind;
56import jdk.vm.ci.meta.JavaType;
57import jdk.vm.ci.meta.MetaAccessProvider;
58import jdk.vm.ci.meta.ResolvedJavaMethod;
59import jdk.vm.ci.meta.ResolvedJavaType;
60import jdk.vm.ci.meta.Signature;
61
62/**
63 * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
64 * {@link InvocationPlugin} for the method.
65 */
66public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
67
68    protected final MetaAccessProvider metaAccess;
69    protected final ConstantReflectionProvider constantReflection;
70    protected final ConstantFieldProvider constantFieldProvider;
71    protected final StampProvider stampProvider;
72    protected final StructuredGraph graph;
73    protected final Bytecode code;
74    protected final ResolvedJavaMethod method;
75    protected final int invokeBci;
76    protected FixedWithNextNode lastInstr;
77    protected ValueNode[] arguments;
78    protected ValueNode returnValue;
79
80    public IntrinsicGraphBuilder(OptionValues options, DebugContext debug, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
81                    StampProvider stampProvider, Bytecode code, int invokeBci) {
82        this(options, debug, metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci, AllowAssumptions.YES);
83    }
84
85    protected IntrinsicGraphBuilder(OptionValues options, DebugContext debug, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
86                    StampProvider stampProvider, Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
87        this.metaAccess = metaAccess;
88        this.constantReflection = constantReflection;
89        this.constantFieldProvider = constantFieldProvider;
90        this.stampProvider = stampProvider;
91        this.code = code;
92        this.method = code.getMethod();
93        this.graph = new StructuredGraph.Builder(options, debug, allowAssumptions).method(method).build();
94        this.invokeBci = invokeBci;
95        this.lastInstr = graph.start();
96
97        Signature sig = method.getSignature();
98        int max = sig.getParameterCount(false);
99        this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
100
101        int javaIndex = 0;
102        int index = 0;
103        if (!method.isStatic()) {
104            // add the receiver
105            Stamp receiverStamp = StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(method.getDeclaringClass()));
106            ValueNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, StampPair.createSingle(receiverStamp)));
107            arguments[index] = receiver;
108            javaIndex = 1;
109            index = 1;
110        }
111        ResolvedJavaType accessingClass = method.getDeclaringClass();
112        for (int i = 0; i < max; i++) {
113            JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
114            JavaKind kind = type.getJavaKind();
115            Stamp stamp;
116            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
117                stamp = StampFactory.object(TypeReference.createWithoutAssumptions((ResolvedJavaType) type));
118            } else {
119                stamp = StampFactory.forKind(kind);
120            }
121            ValueNode param = graph.addWithoutUnique(new ParameterNode(index, StampPair.createSingle(stamp)));
122            arguments[index] = param;
123            javaIndex += kind.getSlotCount();
124            index++;
125        }
126    }
127
128    private <T extends ValueNode> void updateLastInstruction(T v) {
129        if (v instanceof FixedNode) {
130            FixedNode fixedNode = (FixedNode) v;
131            lastInstr.setNext(fixedNode);
132            if (fixedNode instanceof FixedWithNextNode) {
133                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
134                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
135                lastInstr = fixedWithNextNode;
136            } else {
137                lastInstr = null;
138            }
139        }
140    }
141
142    @Override
143    public <T extends ValueNode> T append(T v) {
144        if (v.graph() != null) {
145            return v;
146        }
147        T added = graph.addOrUniqueWithInputs(v);
148        if (added == v) {
149            updateLastInstruction(v);
150        }
151        return added;
152    }
153
154    @Override
155    public void push(JavaKind kind, ValueNode value) {
156        assert kind != JavaKind.Void;
157        assert returnValue == null;
158        returnValue = value;
159    }
160
161    @Override
162    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
163        throw GraalError.shouldNotReachHere();
164    }
165
166    @Override
167    public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
168        throw GraalError.shouldNotReachHere();
169    }
170
171    @Override
172    public StampProvider getStampProvider() {
173        return stampProvider;
174    }
175
176    @Override
177    public MetaAccessProvider getMetaAccess() {
178        return metaAccess;
179    }
180
181    @Override
182    public ConstantReflectionProvider getConstantReflection() {
183        return constantReflection;
184    }
185
186    @Override
187    public ConstantFieldProvider getConstantFieldProvider() {
188        return constantFieldProvider;
189    }
190
191    @Override
192    public StructuredGraph getGraph() {
193        return graph;
194    }
195
196    @Override
197    public void setStateAfter(StateSplit sideEffect) {
198        assert sideEffect.hasSideEffect();
199        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
200        sideEffect.setStateAfter(stateAfter);
201    }
202
203    @Override
204    public GraphBuilderContext getParent() {
205        return null;
206    }
207
208    @Override
209    public Bytecode getCode() {
210        return code;
211    }
212
213    @Override
214    public ResolvedJavaMethod getMethod() {
215        return method;
216    }
217
218    @Override
219    public int bci() {
220        return invokeBci;
221    }
222
223    @Override
224    public InvokeKind getInvokeKind() {
225        return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
226    }
227
228    @Override
229    public JavaType getInvokeReturnType() {
230        return method.getSignature().getReturnType(method.getDeclaringClass());
231    }
232
233    @Override
234    public int getDepth() {
235        return 0;
236    }
237
238    @Override
239    public boolean parsingIntrinsic() {
240        return true;
241    }
242
243    @Override
244    public IntrinsicContext getIntrinsic() {
245        throw GraalError.shouldNotReachHere();
246    }
247
248    @Override
249    public BailoutException bailout(String string) {
250        throw GraalError.shouldNotReachHere();
251    }
252
253    @Override
254    public ValueNode get(boolean performNullCheck) {
255        return arguments[0];
256    }
257
258    public StructuredGraph buildGraph(InvocationPlugin plugin) {
259        Receiver receiver = method.isStatic() ? null : this;
260        if (plugin.execute(this, method, receiver, arguments)) {
261            assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
262            append(new ReturnNode(returnValue));
263            return graph;
264        }
265        return null;
266    }
267
268    @Override
269    public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
270        throw GraalError.shouldNotReachHere();
271    }
272
273    @Override
274    public String toString() {
275        return String.format("%s:intrinsic", method.format("%H.%n(%p)"));
276    }
277}
278