1 /* 2 * Copyright (c) 2000, 2013, 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 sun.jvm.hotspot.oops; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.debugger.*; 30 import sun.jvm.hotspot.runtime.*; 31 import sun.jvm.hotspot.types.*; 32 import sun.jvm.hotspot.utilities.*; 33 34 // A MethodData provides interpreter profiling information 35 36 public class MethodData extends Metadata implements MethodDataInterface<Klass,Method> { 37 static int TypeProfileWidth = 2; 38 static int BciProfileWidth = 2; 39 static int CompileThreshold; 40 41 static int Reason_many; // indicates presence of several reasons 42 static int Reason_none; // indicates absence of a relevant deopt. 43 static int Reason_LIMIT; 44 static int Reason_RECORDED_LIMIT; // some are not recorded per bc 45 46 private static String[] trapReasonName; 47 48 static String trapReasonName(int reason) { 49 if (reason == Reason_many) return "many"; 50 if (reason < Reason_LIMIT) 51 return trapReasonName[reason]; 52 return "reason" + reason; 53 } 54 55 56 static int trapStateReason(int trapState) { 57 // This assert provides the link between the width of DataLayout.trapBits 58 // and the encoding of "recorded" reasons. It ensures there are enough 59 // bits to store all needed reasons in the per-BCI MDO profile. 60 // assert(dsReasonMask >= reasonRecordedLimit, "enough bits"); 61 int recompileBit = (trapState & dsRecompileBit); 62 trapState -= recompileBit; 63 if (trapState == dsReasonMask) { 64 return Reason_many; 65 } else { 66 // assert((int)reasonNone == 0, "state=0 => Reason_none"); 67 return trapState; 68 } 69 } 70 71 72 static final int dsReasonMask = DataLayout.trapMask >> 1; 73 static final int dsRecompileBit = DataLayout.trapMask - dsReasonMask; 74 75 static boolean trapStateIsRecompiled(int trapState) { 76 return (trapState & dsRecompileBit) != 0; 77 } 78 79 static boolean reasonIsRecordedPerBytecode(int reason) { 80 return reason > Reason_none && reason < Reason_RECORDED_LIMIT; 81 } 82 static int trapStateAddReason(int trapState, int reason) { 83 // assert(reasonIsRecordedPerBytecode((DeoptReason)reason) || reason == reasonMany, "valid reason"); 84 int recompileBit = (trapState & dsRecompileBit); 85 trapState -= recompileBit; 86 if (trapState == dsReasonMask) { 87 return trapState + recompileBit; // already at state lattice bottom 88 } else if (trapState == reason) { 89 return trapState + recompileBit; // the condition is already true 90 } else if (trapState == 0) { 91 return reason + recompileBit; // no condition has yet been true 92 } else { 93 return dsReasonMask + recompileBit; // fall to state lattice bottom 94 } 95 } 96 static int trapStateSetRecompiled(int trapState, boolean z) { 97 if (z) return trapState | dsRecompileBit; 98 else return trapState & ~dsRecompileBit; 99 } 100 101 static String formatTrapState(int trapState) { 102 int reason = trapStateReason(trapState); 103 boolean recompFlag = trapStateIsRecompiled(trapState); 104 // Re-encode the state from its decoded components. 105 int decodedState = 0; 106 if (reasonIsRecordedPerBytecode(reason) || reason == Reason_many) 107 decodedState = trapStateAddReason(decodedState, reason); 108 if (recompFlag) 109 decodedState = trapStateSetRecompiled(decodedState, recompFlag); 110 // If the state re-encodes properly, format it symbolically. 111 // Because this routine is used for debugging and diagnostics, 112 // be robust even if the state is a strange value. 113 if (decodedState != trapState) { 114 // Random buggy state that doesn't decode?? 115 return "#" + trapState; 116 } else { 117 return trapReasonName(reason) + (recompFlag ? " recompiled" : ""); 118 } 119 } 120 121 122 123 static { 124 VM.registerVMInitializedObserver(new Observer() { 125 public void update(Observable o, Object data) { 126 initialize(VM.getVM().getTypeDataBase()); 127 } 128 }); 129 } 130 131 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { 132 Type type = db.lookupType("MethodData"); 133 baseOffset = type.getSize(); 134 135 size = new CIntField(type.getCIntegerField("_size"), 0); 136 method = new MetadataField(type.getAddressField("_method"), 0); 137 138 VM.Flag[] flags = VM.getVM().getCommandLineFlags(); 139 for (int f = 0; f < flags.length; f++) { 140 VM.Flag flag = flags[f]; 141 if (flag.getName().equals("TypeProfileWidth")) { 142 TypeProfileWidth = (int)flag.getIntx(); 143 } else if (flag.getName().equals("BciProfileWidth")) { 144 BciProfileWidth = (int)flag.getIntx(); 145 } else if (flag.getName().equals("CompileThreshold")) { 146 CompileThreshold = (int)flag.getIntx(); 147 } 148 } 149 150 cellSize = (int)VM.getVM().getAddressSize(); 151 152 dataSize = new CIntField(type.getCIntegerField("_data_size"), 0); 153 data = type.getAddressField("_data[0]"); 154 155 parametersTypeDataDi = new CIntField(type.getCIntegerField("_parameters_type_data_di"), 0); 156 157 sizeofMethodDataOopDesc = (int)type.getSize();; 158 159 Reason_many = db.lookupIntConstant("Deoptimization::Reason_many").intValue(); 160 Reason_none = db.lookupIntConstant("Deoptimization::Reason_none").intValue(); 161 Reason_LIMIT = db.lookupIntConstant("Deoptimization::Reason_LIMIT").intValue(); 162 Reason_RECORDED_LIMIT = db.lookupIntConstant("Deoptimization::Reason_RECORDED_LIMIT").intValue(); 163 164 trapReasonName = new String[Reason_LIMIT]; 165 166 // Find Deopt reasons 167 Iterator i = db.getIntConstants(); 168 String prefix = "Deoptimization::Reason_"; 169 while (i.hasNext()) { 170 String name = (String)i.next(); 171 if (name.startsWith(prefix)) { 172 // Strip prefix 173 if (!name.endsWith("Reason_many") && 174 !name.endsWith("Reason_LIMIT") && 175 !name.endsWith("Reason_RECORDED_LIMIT")) { 176 String trimmed = name.substring(prefix.length()); 177 int value = db.lookupIntConstant(name).intValue(); 178 if (trapReasonName[value] != null) { 179 throw new InternalError("duplicate reasons: " + trapReasonName[value] + " " + trimmed); 180 } 181 trapReasonName[value] = trimmed; 182 } 183 } 184 } 185 for (int index = 0; index < trapReasonName.length; index++) { 186 if (trapReasonName[index] == null) { 187 throw new InternalError("missing reason for " + index); 188 } 189 } 190 } 191 192 public MethodData(Address addr) { 193 super(addr); 194 } 195 196 public Klass getKlassAtAddress(Address addr) { 197 return (Klass)Metadata.instantiateWrapperFor(addr); 198 } 199 200 public Method getMethodAtAddress(Address addr) { 201 return (Method)Metadata.instantiateWrapperFor(addr); 202 } 203 204 public void printKlassValueOn(Klass klass, PrintStream st) { 205 klass.printValueOn(st); 206 } 207 208 public void printMethodValueOn(Method method, PrintStream st) { 209 method.printValueOn(st); 210 } 211 212 public boolean isMethodData() { return true; } 213 214 private static long baseOffset; 215 private static CIntField size; 216 private static MetadataField method; 217 private static CIntField dataSize; 218 private static AddressField data; 219 private static CIntField parametersTypeDataDi; 220 public static int sizeofMethodDataOopDesc; 221 public static int cellSize; 222 223 public Method getMethod() { 224 return (Method) method.getValue(this); 225 } 226 227 public void printValueOn(PrintStream tty) { 228 Method m = getMethod(); 229 tty.print("MethodData for " + m.getName().asString() + m.getSignature().asString()); 230 } 231 232 public void iterateFields(MetadataVisitor visitor) { 233 super.iterateFields(visitor); 234 visitor.doMetadata(method, true); 235 visitor.doCInt(size, true); 236 } 237 238 int dataSize() { 239 if (dataSize == null) { 240 return 0; 241 } else { 242 return (int)dataSize.getValue(getAddress()); 243 } 244 } 245 246 int sizeInBytes() { 247 if (size == null) { 248 return 0; 249 } else { 250 return (int)size.getValue(getAddress()); 251 } 252 } 253 254 int size() { 255 return (int)Oop.alignObjectSize(VM.getVM().alignUp(sizeInBytes(), VM.getVM().getBytesPerWord())/VM.getVM().getBytesPerWord()); 256 } 257 258 ParametersTypeData<Klass,Method> parametersTypeData() { 259 int di = (int)parametersTypeDataDi.getValue(getAddress()); 260 if (di == -1) { 261 return null; 262 } 263 DataLayout dataLayout = new DataLayout(this, di + (int)data.getOffset()); 264 return new ParametersTypeData<Klass,Method>(this, dataLayout); 265 } 266 267 boolean outOfBounds(int dataIndex) { 268 return dataIndex >= dataSize(); 269 } 270 271 ProfileData dataAt(int dataIndex) { 272 if (outOfBounds(dataIndex)) { 273 return null; 274 } 275 DataLayout dataLayout = new DataLayout(this, dataIndex + (int)data.getOffset()); 276 277 switch (dataLayout.tag()) { 278 case DataLayout.noTag: 279 default: 280 throw new InternalError(dataIndex + " " + dataSize() + " " + dataLayout.tag()); 281 case DataLayout.bitDataTag: 282 return new BitData(dataLayout); 283 case DataLayout.counterDataTag: 284 return new CounterData(dataLayout); 285 case DataLayout.jumpDataTag: 286 return new JumpData(dataLayout); 287 case DataLayout.receiverTypeDataTag: 288 return new ReceiverTypeData<Klass,Method>(this, dataLayout); 289 case DataLayout.virtualCallDataTag: 290 return new VirtualCallData<Klass,Method>(this, dataLayout); 291 case DataLayout.retDataTag: 292 return new RetData(dataLayout); 293 case DataLayout.branchDataTag: 294 return new BranchData(dataLayout); 295 case DataLayout.multiBranchDataTag: 296 return new MultiBranchData(dataLayout); 297 case DataLayout.callTypeDataTag: 298 return new CallTypeData<Klass,Method>(this, dataLayout); 299 case DataLayout.virtualCallTypeDataTag: 300 return new VirtualCallTypeData<Klass,Method>(this, dataLayout); 301 case DataLayout.parametersTypeDataTag: 302 return new ParametersTypeData<Klass,Method>(this, dataLayout); 303 } 304 } 305 306 int dpToDi(int dp) { 307 // this in an offset from the base of the MDO, so convert to offset into _data 308 return dp - (int)data.getOffset(); 309 } 310 311 int firstDi() { return 0; } 312 public ProfileData firstData() { return dataAt(firstDi()); } 313 public ProfileData nextData(ProfileData current) { 314 int currentIndex = dpToDi(current.dp()); 315 int nextIndex = currentIndex + current.sizeInBytes(); 316 return dataAt(nextIndex); 317 } 318 boolean isValid(ProfileData current) { return current != null; } 319 320 DataLayout limitDataPosition() { 321 return new DataLayout(this, dataSize() + (int)data.getOffset()); 322 } 323 324 DataLayout extraDataBase() { 325 return limitDataPosition(); 326 } 327 328 DataLayout extraDataLimit() { 329 return new DataLayout(this, sizeInBytes()); 330 } 331 332 static public int extraNbCells(DataLayout dataLayout) { 333 int nbCells = 0; 334 switch(dataLayout.tag()) { 335 case DataLayout.bitDataTag: 336 case DataLayout.noTag: 337 nbCells = BitData.staticCellCount(); 338 break; 339 case DataLayout.speculativeTrapDataTag: 340 nbCells = SpeculativeTrapData.staticCellCount(); 341 break; 342 default: 343 throw new InternalError("unexpected tag " + dataLayout.tag()); 344 } 345 return nbCells; 346 } 347 348 DataLayout nextExtra(DataLayout dataLayout) { 349 return new DataLayout(this, dataLayout.dp() + DataLayout.computeSizeInBytes(extraNbCells(dataLayout))); 350 } 351 352 public void printDataOn(PrintStream st) { 353 if (parametersTypeData() != null) { 354 parametersTypeData().printDataOn(st); 355 } 356 ProfileData data = firstData(); 357 for ( ; isValid(data); data = nextData(data)) { 358 st.print(dpToDi(data.dp())); 359 st.print(" "); 360 // st->fillTo(6); 361 data.printDataOn(st); 362 } 363 st.println("--- Extra data:"); 364 DataLayout dp = extraDataBase(); 365 DataLayout end = extraDataLimit(); 366 for (;; dp = nextExtra(dp)) { 367 switch(dp.tag()) { 368 case DataLayout.noTag: 369 continue; 370 case DataLayout.bitDataTag: 371 data = new BitData(dp); 372 break; 373 case DataLayout.speculativeTrapDataTag: 374 data = new SpeculativeTrapData<Klass,Method>(this, dp); 375 break; 376 case DataLayout.argInfoDataTag: 377 data = new ArgInfoData(dp); 378 dp = end; // ArgInfoData is at the end of extra data section. 379 break; 380 default: 381 throw new InternalError("unexpected tag " + dp.tag()); 382 } 383 st.print(dpToDi(data.dp())); 384 st.print(" "); 385 data.printDataOn(st); 386 if (dp == end) return; 387 } 388 } 389 390 private byte[] fetchDataAt(Address base, long offset, long size) { 391 byte[] result = new byte[(int)size]; 392 for (int i = 0; i < size; i++) { 393 result[i] = base.getJByteAt(offset + i); 394 } 395 return result; 396 } 397 398 public byte[] orig() { 399 // fetch the orig MethodData data between header and dataSize 400 return fetchDataAt(getAddress(), 0, sizeofMethodDataOopDesc); 401 } 402 403 public long[] data() { 404 // Read the data as an array of intptr_t elements 405 Address base = getAddress(); 406 long offset = data.getOffset(); 407 int elements = dataSize() / cellSize; 408 long[] result = new long[elements]; 409 for (int i = 0; i < elements; i++) { 410 Address value = base.getAddressAt(offset + i * MethodData.cellSize); 411 if (value != null) { 412 result[i] = value.minus(null); 413 } 414 } 415 return result; 416 } 417 418 // Get a measure of how much mileage the method has on it. 419 int mileageOf(Method method) { 420 long mileage = 0; 421 int iic = method.interpreterInvocationCount(); 422 if (mileage < iic) mileage = iic; 423 424 long ic = method.getInvocationCount(); 425 long bc = method.getBackedgeCount(); 426 427 long icval = ic >> 3; 428 if ((ic & 4) != 0) icval += CompileThreshold; 429 if (mileage < icval) mileage = icval; 430 long bcval = bc >> 3; 431 if ((bc & 4) != 0) bcval += CompileThreshold; 432 if (mileage < bcval) mileage = bcval; 433 return (int)mileage; 434 } 435 436 public int currentMileage() { 437 return 20000; 438 } 439 440 int dumpReplayDataTypeHelper(PrintStream out, int round, int count, int index, ProfileData pdata, Klass k) { 441 if (k != null) { 442 if (round == 0) count++; 443 else out.print(" " + 444 (dpToDi(pdata.dp() + 445 pdata.cellOffset(index)) / cellSize) + " " + 446 k.getName().asString()); 447 } 448 return count; 449 } 450 451 int dumpReplayDataReceiverTypeHelper(PrintStream out, int round, int count, ReceiverTypeData<Klass,Method> vdata) { 452 for (int i = 0; i < vdata.rowLimit(); i++) { 453 Klass k = vdata.receiver(i); 454 count = dumpReplayDataTypeHelper(out, round, count, vdata.receiverCellIndex(i), vdata, k); 455 } 456 return count; 457 } 458 459 int dumpReplayDataCallTypeHelper(PrintStream out, int round, int count, CallTypeDataInterface<Klass> callTypeData) { 460 if (callTypeData.hasArguments()) { 461 for (int i = 0; i < callTypeData.numberOfArguments(); i++) { 462 count = dumpReplayDataTypeHelper(out, round, count, callTypeData.argumentTypeIndex(i), (ProfileData)callTypeData, callTypeData.argumentType(i)); 463 } 464 } 465 if (callTypeData.hasReturn()) { 466 count = dumpReplayDataTypeHelper(out, round, count, callTypeData.returnTypeIndex(), (ProfileData)callTypeData, callTypeData.returnType()); 467 } 468 return count; 469 } 470 471 int dumpReplayDataExtraDataHelper(PrintStream out, int round, int count) { 472 DataLayout dp = extraDataBase(); 473 DataLayout end = extraDataLimit(); 474 475 for (;dp != end; dp = nextExtra(dp)) { 476 switch(dp.tag()) { 477 case DataLayout.noTag: 478 case DataLayout.argInfoDataTag: 479 return count; 480 case DataLayout.bitDataTag: 481 break; 482 case DataLayout.speculativeTrapDataTag: { 483 SpeculativeTrapData<Klass,Method> data = new SpeculativeTrapData<Klass,Method>(this, dp); 484 Method m = data.method(); 485 if (m != null) { 486 if (round == 0) { 487 count++; 488 } else { 489 out.print(" " + (dpToDi(data.dp() + data.cellOffset(SpeculativeTrapData.methodIndex())) / cellSize) + " " + m.nameAsAscii()); 490 } 491 } 492 break; 493 } 494 default: 495 throw new InternalError("bad tag " + dp.tag()); 496 } 497 } 498 return count; 499 } 500 501 public void dumpReplayData(PrintStream out) { 502 Method method = getMethod(); 503 out.print("ciMethodData " + method.nameAsAscii() 504 + " " + "2" + " " + 505 currentMileage()); 506 byte[] orig = orig(); 507 out.print(" orig " + orig.length); 508 for (int i = 0; i < orig.length; i++) { 509 out.print(" " + (orig[i] & 0xff)); 510 } 511 512 long[] data = data(); 513 out.print(" data " + data.length); 514 for (int i = 0; i < data.length; i++) { 515 out.print(" 0x" + Long.toHexString(data[i])); 516 } 517 int count = 0; 518 ParametersTypeData<Klass,Method> parameters = parametersTypeData(); 519 for (int round = 0; round < 2; round++) { 520 if (round == 1) out.print(" oops " + count); 521 ProfileData pdata = firstData(); 522 for ( ; isValid(pdata); pdata = nextData(pdata)) { 523 if (pdata instanceof ReceiverTypeData) { 524 count = dumpReplayDataReceiverTypeHelper(out, round, count, (ReceiverTypeData<Klass,Method>)pdata); 525 } 526 if (pdata instanceof CallTypeDataInterface) { 527 count = dumpReplayDataCallTypeHelper(out, round, count, (CallTypeDataInterface<Klass>)pdata); 528 } 529 } 530 if (parameters != null) { 531 for (int i = 0; i < parameters.numberOfParameters(); i++) { 532 count = dumpReplayDataTypeHelper(out, round, count, ParametersTypeData.typeIndex(i), parameters, parameters.type(i)); 533 } 534 } 535 } 536 count = 0; 537 for (int round = 0; round < 2; round++) { 538 if (round == 1) out.print(" methods " + count); 539 count = dumpReplayDataExtraDataHelper(out, round, count); 540 } 541 out.println(); 542 } 543 }