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