1/*
2 * Copyright (c) 2009, 2015, 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 *
23 */
24
25package com.sun.hotspot.tools.compiler;
26
27import java.io.PrintStream;
28import java.util.ArrayDeque;
29import java.util.ArrayList;
30import java.util.List;
31
32/**
33 * Representation of a compilation scope in a compilation log. This class is a
34 * hybrid: its instances can represent original scopes of methods being
35 * compiled, but are also used to represent call sites in given methods.
36 */
37public class CallSite {
38
39    /**
40     * The index of the call in the caller. This will be 0 if this instance
41     * represents a compilation root.
42     */
43    private int bci;
44
45    /**
46     * The method that is called at this call site. This will be {@code null}
47     * if this instance represents a compilation root.
48     */
49    private Method method;
50
51    /**
52     * The invocation count for this call site.
53     */
54    private int count;
55
56    /**
57     * The receiver type of the call represented by this instance, if known.
58     */
59    private String receiver;
60
61    /**
62     * In case the {@linkplain receiver receiver type} of the call represented
63     * by this instance is known, this is how often the type was encountered.
64     */
65    private int receiver_count;
66
67    /**
68     * The reason for a success or failure of an inlining operation at this
69     * call site.
70     */
71    private String reason;
72
73    /**
74     * A list of all calls in this compilation scope.
75     */
76    private List<CallSite> calls;
77
78    /**
79     * Number of nodes in the graph at the end of parsing this compilation
80     * scope.
81     */
82    private int endNodes;
83
84    /**
85     * Number of live nodes in the graph at the end of parsing this compilation
86     * scope.
87     */
88    private int endLiveNodes;
89
90    /**
91     * Time in seconds since VM startup at which parsing this compilation scope
92     * ended.
93     */
94    private double timeStamp;
95
96    /**
97     * The inline ID in case the call represented by this instance is inlined,
98     * 0 otherwise.
99     */
100    private long inlineId;
101
102    /**
103     * List of uncommon traps in this compilation scope.
104     */
105    private List<UncommonTrap> traps;
106
107    /**
108     * Default constructor: used to create an instance that represents the top
109     * scope of a compilation.
110     */
111    CallSite() {}
112
113    /**
114     * Constructor to create an instance that represents an actual method call.
115     */
116    CallSite(int bci, Method m) {
117        this.bci = bci;
118        this.method = m;
119    }
120
121    /**
122     * Add a call site to the compilation scope represented by this instance.
123     */
124    void add(CallSite site) {
125        if (getCalls() == null) {
126            calls = new ArrayList<>();
127        }
128        getCalls().add(site);
129    }
130
131    /**
132     * Return the last of the {@linkplain #getCalls() call sites} in this
133     * compilation scope.
134     */
135    CallSite last() {
136        return getCalls().get(getCalls().size() - 1);
137    }
138
139    /**
140     * Return the last-but-one of the {@linkplain #getCalls() call sites} in
141     * this compilation scope.
142     */
143    CallSite lastButOne() {
144        return getCalls().get(getCalls().size() - 2);
145    }
146
147    public String toString() {
148        StringBuilder sb = new StringBuilder();
149        if (getReason() == null) {
150            sb.append("  @ " + getBci() + " " + getMethod());
151        } else {
152            sb.append("- @ " + getBci() + " " + getMethod() + " " + getReason());
153        }
154        sb.append("\n");
155        if (getCalls() != null) {
156            for (CallSite site : getCalls()) {
157                sb.append(site);
158                sb.append("\n");
159            }
160        }
161        return sb.toString();
162    }
163
164    public void print(PrintStream stream) {
165        print(stream, 0, true, false);
166    }
167
168    void emit(PrintStream stream, int indent) {
169        for (int i = 0; i < indent; i++) {
170            stream.print(' ');
171        }
172    }
173
174    public void print(PrintStream stream, int indent, boolean printInlining, boolean printUncommonTraps) {
175        emit(stream, indent);
176        String m = getMethod().getHolder() + "::" + getMethod().getName();
177        if (getReason() == null) {
178            stream.print("  @ " + getBci() + " " + m + " (" + getMethod().getBytes() + " bytes)");
179        } else {
180            stream.print("  @ " + getBci() + " " + m + " " + getReason());
181        }
182        stream.printf(" (end time: %6.4f", getTimeStamp());
183        if (getEndNodes() > 0) {
184            stream.printf(" nodes: %d live: %d", getEndNodes(), getEndLiveNodes());
185        }
186        stream.println(")");
187
188        if (getReceiver() != null) {
189            emit(stream, indent + 4);
190            stream.println("type profile " + getMethod().getHolder() + " -> " + getReceiver() + " (" +
191                    (getReceiverCount() * 100 / getCount()) + "%)");
192        }
193        if (printInlining && getCalls() != null) {
194            for (CallSite site : getCalls()) {
195                site.print(stream, indent + 2, printInlining, printUncommonTraps);
196            }
197        }
198        if (printUncommonTraps && getTraps() != null) {
199            for (UncommonTrap site : getTraps()) {
200                site.print(stream, indent + 2);
201            }
202        }
203    }
204
205    public int getBci() {
206        return bci;
207    }
208
209    public void setBci(int bci) {
210        this.bci = bci;
211    }
212
213    public Method getMethod() {
214        return method;
215    }
216
217    public void setMethod(Method method) {
218        this.method = method;
219    }
220
221    public int getCount() {
222        return count;
223    }
224
225    public void setCount(int count) {
226        this.count = count;
227    }
228
229    public String getReceiver() {
230        return receiver;
231    }
232
233    public void setReceiver(String receiver) {
234        this.receiver = receiver;
235    }
236
237    public int getReceiverCount() {
238        return receiver_count;
239    }
240
241    public void setReceiver_count(int receiver_count) {
242        this.receiver_count = receiver_count;
243    }
244
245    public String getReason() {
246        return reason;
247    }
248
249    public void setReason(String reason) {
250        this.reason = reason;
251    }
252
253    public List<CallSite> getCalls() {
254        return calls;
255    }
256
257    public List<UncommonTrap> getTraps() {
258        return traps;
259    }
260
261    void add(UncommonTrap e) {
262        if (traps == null) {
263            traps = new ArrayList<UncommonTrap>();
264        }
265        traps.add(e);
266    }
267
268    void setEndNodes(int n) {
269        endNodes = n;
270    }
271
272    public int getEndNodes() {
273        return endNodes;
274    }
275
276    void setEndLiveNodes(int n) {
277        endLiveNodes = n;
278    }
279
280    public int getEndLiveNodes() {
281        return endLiveNodes;
282    }
283
284    void setTimeStamp(double time) {
285        timeStamp = time;
286    }
287
288    public double getTimeStamp() {
289        return timeStamp;
290    }
291
292    /**
293     * Check whether this call site matches another. Every late inline call
294     * site has a unique inline ID. If the call site we're looking for has one,
295     * then use it; otherwise rely on method name and byte code index.
296     */
297    private boolean matches(CallSite other) {
298        if (other.inlineId != 0) {
299            return inlineId == other.inlineId;
300        }
301        return method.equals(other.method) && bci == other.bci;
302    }
303
304    /**
305     * Locate a late inline call site: find, in this instance's
306     * {@linkplain #calls call sites}, the one furthest down the given call
307     * stack.
308     *
309     * Multiple chains of identical call sites with the same method name / bci
310     * combination are possible, so we have to try them all until we find the
311     * late inline call site that has a matching inline ID.
312     *
313     * @return a matching call site, or {@code null} if none was found.
314     */
315    public CallSite findCallSite(ArrayDeque<CallSite> sites) {
316        if (calls == null) {
317            return null;
318        }
319        CallSite site = sites.pop();
320        for (CallSite c : calls) {
321            if (c.matches(site)) {
322                if (!sites.isEmpty()) {
323                    CallSite res = c.findCallSite(sites);
324                    if (res != null) {
325                        sites.push(site);
326                        return res;
327                    }
328                } else {
329                    sites.push(site);
330                    return c;
331                }
332            }
333        }
334        sites.push(site);
335        return null;
336    }
337
338    /**
339     * Locate a late inline call site in the tree spanned by all this instance's
340     * {@linkplain #calls call sites}, and return the sequence of call sites
341     * (scopes) leading to that late inline call site.
342     */
343    public ArrayDeque<CallSite> findCallSite2(CallSite site) {
344        if (calls == null) {
345            return null;
346        }
347
348        for (CallSite c : calls) {
349            if (c.matches(site)) {
350                ArrayDeque<CallSite> stack = new ArrayDeque<>();
351                stack.push(c);
352                return stack;
353            } else {
354                ArrayDeque<CallSite> stack = c.findCallSite2(site);
355                if (stack != null) {
356                    stack.push(c);
357                    return stack;
358                }
359            }
360        }
361        return null;
362    }
363
364    public long getInlineId() {
365        return inlineId;
366    }
367
368    public void setInlineId(long inlineId) {
369        this.inlineId = inlineId;
370    }
371}
372