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