1/*
2 * Copyright (c) 2013, 2014, 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.phases.common.inlining.info;
24
25import org.graalvm.compiler.core.common.calc.Condition;
26import org.graalvm.compiler.graph.Node;
27import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
28import org.graalvm.compiler.nodes.ConstantNode;
29import org.graalvm.compiler.nodes.FixedGuardNode;
30import org.graalvm.compiler.nodes.Invoke;
31import org.graalvm.compiler.nodes.LogicNode;
32import org.graalvm.compiler.nodes.StructuredGraph;
33import org.graalvm.compiler.nodes.ValueNode;
34import org.graalvm.compiler.nodes.calc.CompareNode;
35import org.graalvm.compiler.nodes.extended.LoadHubNode;
36import org.graalvm.compiler.phases.common.inlining.InliningUtil;
37import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
38import org.graalvm.compiler.phases.util.Providers;
39import org.graalvm.util.EconomicSet;
40
41import jdk.vm.ci.meta.DeoptimizationAction;
42import jdk.vm.ci.meta.DeoptimizationReason;
43import jdk.vm.ci.meta.ResolvedJavaMethod;
44import jdk.vm.ci.meta.ResolvedJavaType;
45
46/**
47 * Represents an inlining opportunity for which profiling information suggests a monomorphic
48 * receiver, but for which the receiver type cannot be proven. A type check guard will be generated
49 * if this inlining is performed.
50 */
51public class TypeGuardInlineInfo extends AbstractInlineInfo {
52
53    private final ResolvedJavaMethod concrete;
54    private final ResolvedJavaType type;
55    private Inlineable inlineableElement;
56
57    public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
58        super(invoke);
59        this.concrete = concrete;
60        this.type = type;
61        assert type.isArray() || type.isConcrete() : type;
62    }
63
64    @Override
65    public int numberOfMethods() {
66        return 1;
67    }
68
69    @Override
70    public ResolvedJavaMethod methodAt(int index) {
71        assert index == 0;
72        return concrete;
73    }
74
75    @Override
76    public Inlineable inlineableElementAt(int index) {
77        assert index == 0;
78        return inlineableElement;
79    }
80
81    @Override
82    public double probabilityAt(int index) {
83        assert index == 0;
84        return 1.0;
85    }
86
87    @Override
88    public double relevanceAt(int index) {
89        assert index == 0;
90        return 1.0;
91    }
92
93    @Override
94    public void setInlinableElement(int index, Inlineable inlineableElement) {
95        assert index == 0;
96        this.inlineableElement = inlineableElement;
97    }
98
99    @Override
100    public EconomicSet<Node> inline(Providers providers) {
101        createGuard(graph(), providers);
102        return inline(invoke, concrete, inlineableElement, false);
103    }
104
105    @Override
106    public void tryToDevirtualizeInvoke(Providers providers) {
107        createGuard(graph(), providers);
108        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
109    }
110
111    private void createGuard(StructuredGraph graph, Providers providers) {
112        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
113        LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver));
114        ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph);
115
116        LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection());
117        FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
118        assert invoke.predecessor() != null;
119
120        ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
121        invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
122
123        graph.addBeforeFixed(invoke.asNode(), guard);
124    }
125
126    @Override
127    public String toString() {
128        return "type-checked with type " + type.getName() + " and method " + concrete.format("%H.%n(%p):%r");
129    }
130
131    @Override
132    public boolean shouldInline() {
133        return concrete.shouldBeInlined();
134    }
135}
136