001/*
002 * Copyright (c) 2013, 2014, 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.phases.common.inlining.info;
024
025import java.util.*;
026
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.compiler.common.calc.*;
030import com.oracle.graal.graph.*;
031import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
032import com.oracle.graal.nodes.*;
033import com.oracle.graal.nodes.calc.*;
034import com.oracle.graal.nodes.extended.*;
035import com.oracle.graal.phases.common.inlining.*;
036import com.oracle.graal.phases.common.inlining.info.elem.*;
037import com.oracle.graal.phases.util.*;
038
039/**
040 * Represents an inlining opportunity for which profiling information suggests a monomorphic
041 * receiver, but for which the receiver type cannot be proven. A type check guard will be generated
042 * if this inlining is performed.
043 */
044public class TypeGuardInlineInfo extends AbstractInlineInfo {
045
046    private final ResolvedJavaMethod concrete;
047    private final ResolvedJavaType type;
048    private Inlineable inlineableElement;
049
050    public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
051        super(invoke);
052        this.concrete = concrete;
053        this.type = type;
054        assert type.isArray() || type.isConcrete() : type;
055    }
056
057    @Override
058    public int numberOfMethods() {
059        return 1;
060    }
061
062    @Override
063    public ResolvedJavaMethod methodAt(int index) {
064        assert index == 0;
065        return concrete;
066    }
067
068    @Override
069    public Inlineable inlineableElementAt(int index) {
070        assert index == 0;
071        return inlineableElement;
072    }
073
074    @Override
075    public double probabilityAt(int index) {
076        assert index == 0;
077        return 1.0;
078    }
079
080    @Override
081    public double relevanceAt(int index) {
082        assert index == 0;
083        return 1.0;
084    }
085
086    @Override
087    public void setInlinableElement(int index, Inlineable inlineableElement) {
088        assert index == 0;
089        this.inlineableElement = inlineableElement;
090    }
091
092    @Override
093    public Collection<Node> inline(Providers providers) {
094        createGuard(graph(), providers);
095        return inline(invoke, concrete, inlineableElement, false);
096    }
097
098    @Override
099    public void tryToDevirtualizeInvoke(Providers providers) {
100        createGuard(graph(), providers);
101        InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
102    }
103
104    private void createGuard(StructuredGraph graph, Providers providers) {
105        ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
106        LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver));
107        ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(), type.getObjectHub(), providers.getMetaAccess(), graph);
108
109        LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection());
110        FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
111        assert invoke.predecessor() != null;
112
113        ValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
114        invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
115
116        graph.addBeforeFixed(invoke.asNode(), guard);
117    }
118
119    @Override
120    public String toString() {
121        return "type-checked with type " + type.getName() + " and method " + concrete.format("%H.%n(%p):%r");
122    }
123
124    public boolean shouldInline() {
125        return concrete.shouldBeInlined();
126    }
127}