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 25 package com.sun.hotspot.tools.compiler; 26 27 import java.io.PrintStream; 28 import java.util.ArrayDeque; 29 import java.util.ArrayList; 30 import 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 */ 37 public 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 }