1 /* 2 * Copyright (c) 2012, 2025, 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 package jdk.vm.ci.hotspot; 24 25 import static java.lang.String.format; 26 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; 27 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 28 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; 29 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 30 31 import java.util.Arrays; 32 33 import jdk.internal.misc.Unsafe; 34 import jdk.vm.ci.meta.DeoptimizationReason; 35 import jdk.vm.ci.meta.JavaMethodProfile; 36 import jdk.vm.ci.meta.JavaMethodProfile.ProfiledMethod; 37 import jdk.vm.ci.meta.JavaTypeProfile; 38 import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType; 39 import jdk.vm.ci.meta.ResolvedJavaMethod; 40 import jdk.vm.ci.meta.ResolvedJavaType; 41 import jdk.vm.ci.meta.TriState; 42 43 /** 44 * Access to a HotSpot {@code MethodData} structure (defined in methodData.hpp). 45 */ 46 final class HotSpotMethodData implements MetaspaceObject { 47 48 /** 49 * VM state that can be reset when building an AOT image. 50 */ 51 static final class VMState { 52 final HotSpotVMConfig config = config(); 53 final HotSpotMethodDataAccessor noDataNoExceptionAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.FALSE); 54 final HotSpotMethodDataAccessor noDataExceptionPossiblyNotRecordedAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.UNKNOWN); 55 final int noDataSize = cellIndexToOffset(0); 56 final int bitDataSize = cellIndexToOffset(0); 57 final int bitDataNullSeenFlag = 1 << config.bitDataNullSeenFlag; 58 final int counterDataSize = cellIndexToOffset(1); 59 final int counterDataCountOffset = cellIndexToOffset(config.methodDataCountOffset); 60 final int jumpDataSize = cellIndexToOffset(2); 61 final int takenCountOffset = cellIndexToOffset(config.jumpDataTakenOffset); 62 final int takenDisplacementOffset = cellIndexToOffset(config.jumpDataDisplacementOffset); 63 final int typeDataRowSize = cellsToBytes(config.receiverTypeDataReceiverTypeRowCellCount); 64 65 final int typeDataFirstTypeOffset = cellIndexToOffset(config.receiverTypeDataReceiver0Offset); 66 final int typeDataFirstTypeCountOffset = cellIndexToOffset(config.receiverTypeDataCount0Offset); 67 68 final int typeCheckDataSize = cellIndexToOffset(1) + typeDataRowSize * config.typeProfileWidth; 69 final int virtualCallDataSize = cellIndexToOffset(1) + typeDataRowSize * (config.typeProfileWidth + config.methodProfileWidth); 70 final int virtualCallDataFirstMethodOffset = typeDataFirstTypeOffset + typeDataRowSize * config.typeProfileWidth; 71 final int virtualCallDataFirstMethodCountOffset = typeDataFirstTypeCountOffset + typeDataRowSize * config.typeProfileWidth; 72 73 final int retDataRowSize = cellsToBytes(3); 74 final int retDataSize = cellIndexToOffset(1) + retDataRowSize * config.bciProfileWidth; 75 76 final int branchDataSize = cellIndexToOffset(3); 77 final int notTakenCountOffset = cellIndexToOffset(config.branchDataNotTakenOffset); 78 79 final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset); 80 final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset); 81 82 final int multiBranchDataSize = cellIndexToOffset(1); 83 final int multiBranchDataRowSizeInCells = config.multiBranchDataPerCaseCellCount; 84 final int multiBranchDataRowSize = cellsToBytes(multiBranchDataRowSizeInCells); 85 final int multiBranchDataFirstCountOffset = arrayDataStartOffset + cellsToBytes(0); 86 final int multiBranchDataFirstDisplacementOffset = arrayDataStartOffset + cellsToBytes(1); 87 88 final int argInfoDataSize = cellIndexToOffset(1); 89 90 // sorted by tag 91 // @formatter:off 92 final HotSpotMethodDataAccessor[] profileDataAccessors = { 93 null, 94 new BitData(this, config.dataLayoutBitDataTag), 95 new CounterData(this, config.dataLayoutCounterDataTag), 96 new JumpData(this, config.dataLayoutJumpDataTag), 97 new ReceiverTypeData(this, config.dataLayoutReceiverTypeDataTag), 98 new VirtualCallData(this, config.dataLayoutVirtualCallDataTag), 99 new RetData(this, config.dataLayoutRetDataTag), 100 new BranchData(this, config.dataLayoutBranchDataTag), 101 new MultiBranchData(this, config.dataLayoutMultiBranchDataTag), 102 new ArgInfoData(this, config.dataLayoutArgInfoDataTag), 103 new UnknownProfileData(this, config.dataLayoutCallTypeDataTag), 104 new VirtualCallTypeData(this, config.dataLayoutVirtualCallTypeDataTag), 105 new UnknownProfileData(this, config.dataLayoutParametersTypeDataTag), 106 new UnknownProfileData(this, config.dataLayoutSpeculativeTrapDataTag), 107 new UnknownProfileData(this, config.dataLayoutArrayStoreDataTag), 108 new UnknownProfileData(this, config.dataLayoutArrayLoadDataTag), 109 new UnknownProfileData(this, config.dataLayoutACmpDataTag), 110 }; 111 // @formatter:on 112 113 private boolean checkAccessorTags() { 114 int expectedTag = 0; 115 for (HotSpotMethodDataAccessor accessor : profileDataAccessors) { 116 if (expectedTag == 0) { 117 assert accessor == null; 118 } else { 119 assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor; 120 } 121 expectedTag++; 122 } 123 return true; 124 } 125 126 private VMState() { 127 assert checkAccessorTags(); 128 } 129 130 private static int truncateLongToInt(long value) { 131 return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; 132 } 133 134 private int computeFullOffset(int position, int offsetInBytes) { 135 return config.methodDataOopDataOffset + position + offsetInBytes; 136 } 137 138 private int cellIndexToOffset(int cells) { 139 return config.dataLayoutHeaderSize + cellsToBytes(cells); 140 } 141 142 private int cellsToBytes(int cells) { 143 return cells * config.dataLayoutCellSize; 144 } 145 146 /** 147 * Singleton instance lazily initialized via double-checked locking. 148 */ 149 private static volatile VMState instance; 150 151 static VMState instance() { 152 VMState result = instance; 153 if (result == null) { 154 synchronized (VMState.class) { 155 result = instance; 156 if (result == null) { 157 instance = result = new VMState(); 158 } 159 } 160 } 161 return result; 162 } 163 } 164 165 /** 166 * A {@code MethodData*} value. 167 */ 168 final long methodDataPointer; 169 private final HotSpotResolvedJavaMethodImpl method; 170 private final VMState state; 171 172 HotSpotMethodData(long methodDataPointer, HotSpotResolvedJavaMethodImpl method) { 173 this.methodDataPointer = methodDataPointer; 174 this.method = method; 175 this.state = VMState.instance(); 176 } 177 178 @Override 179 public long getMetaspacePointer() { 180 return methodDataPointer; 181 } 182 183 /** 184 * @return value of the MethodData::_data_size field 185 */ 186 private int normalDataSize() { 187 return UNSAFE.getInt(methodDataPointer + state.config.methodDataDataSize); 188 } 189 190 /** 191 * Returns the size of the extra data records. This method does the same calculation as 192 * MethodData::extra_data_size(). 193 * 194 * @return size of extra data records 195 */ 196 private int extraDataSize() { 197 final int extraDataBase = state.config.methodDataOopDataOffset + normalDataSize(); 198 final int extraDataLimit = UNSAFE.getInt(methodDataPointer + state.config.methodDataSize); 199 return extraDataLimit - extraDataBase; 200 } 201 202 public boolean hasNormalData() { 203 return normalDataSize() > 0; 204 } 205 206 /** 207 * Return true if there is an extra data section and the first tag is non-zero. 208 */ 209 public boolean hasExtraData() { 210 return extraDataSize() > 0 && HotSpotMethodDataAccessor.readTag(state.config, this, getExtraDataBeginOffset()) != 0; 211 } 212 213 private int getExtraDataBeginOffset() { 214 return normalDataSize(); 215 } 216 217 public boolean isWithin(int position) { 218 return position >= 0 && position < normalDataSize(); 219 } 220 221 public int getDeoptimizationCount(DeoptimizationReason reason) { 222 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 223 int reasonIndex = metaAccess.convertDeoptReason(reason); 224 return UNSAFE.getByte(methodDataPointer + state.config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; 225 } 226 227 public int getOSRDeoptimizationCount(DeoptimizationReason reason) { 228 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 229 int reasonIndex = metaAccess.convertDeoptReason(reason); 230 return UNSAFE.getByte(methodDataPointer + state.config.methodDataOopTrapHistoryOffset + state.config.deoptReasonOSROffset + reasonIndex) & 0xFF; 231 } 232 233 public int getDecompileCount() { 234 return UNSAFE.getInt(methodDataPointer + state.config.methodDataDecompiles); 235 } 236 237 public int getOverflowRecompileCount() { 238 return UNSAFE.getInt(methodDataPointer + state.config.methodDataOverflowRecompiles); 239 } 240 241 public int getOverflowTrapCount() { 242 return UNSAFE.getInt(methodDataPointer + state.config.methodDataOverflowTraps); 243 } 244 245 public HotSpotMethodDataAccessor getNormalData(int position) { 246 if (position >= normalDataSize()) { 247 return null; 248 } 249 250 return getData(position); 251 } 252 253 public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { 254 if (exceptionPossiblyNotRecorded) { 255 return VMState.instance().noDataExceptionPossiblyNotRecordedAccessor; 256 } else { 257 return VMState.instance().noDataNoExceptionAccessor; 258 } 259 } 260 261 private HotSpotMethodDataAccessor getData(int position) { 262 assert position >= 0 : "out of bounds"; 263 final int tag = HotSpotMethodDataAccessor.readTag(state.config, this, position); 264 HotSpotMethodDataAccessor accessor = state.profileDataAccessors[tag]; 265 assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; 266 return accessor; 267 } 268 269 int readUnsignedByte(int position, int offsetInBytes) { 270 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 271 return UNSAFE.getByte(methodDataPointer + fullOffsetInBytes) & 0xFF; 272 } 273 274 int readUnsignedShort(int position, int offsetInBytes) { 275 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 276 return UNSAFE.getShort(methodDataPointer + fullOffsetInBytes) & 0xFFFF; 277 } 278 279 /** 280 * Since the values are stored in cells (platform words) this method uses 281 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 282 */ 283 private long readUnsignedInt(int position, int offsetInBytes) { 284 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 285 return UNSAFE.getAddress(methodDataPointer + fullOffsetInBytes) & 0xFFFFFFFFL; 286 } 287 288 private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { 289 long value = readUnsignedInt(position, offsetInBytes); 290 return VMState.truncateLongToInt(value); 291 } 292 293 /** 294 * Since the values are stored in cells (platform words) this method uses 295 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 296 */ 297 private int readInt(int position, int offsetInBytes) { 298 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 299 return (int) UNSAFE.getAddress(methodDataPointer + fullOffsetInBytes); 300 } 301 302 private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) { 303 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 304 return compilerToVM().getResolvedJavaMethod(null, methodDataPointer + fullOffsetInBytes); 305 } 306 307 private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) { 308 long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes); 309 return compilerToVM().getResolvedJavaType(this, fullOffsetInBytes); 310 } 311 312 /** 313 * Returns whether profiling ran long enough that the profile information is mature. Other 314 * informational data will still be valid even if the profile isn't mature. 315 */ 316 public boolean isProfileMature() { 317 return runtime().getCompilerToVM().isMature(methodDataPointer); 318 } 319 320 @Override 321 public String toString() { 322 StringBuilder sb = new StringBuilder(); 323 String nl = System.lineSeparator(); 324 String nlIndent = String.format("%n%38s", ""); 325 sb.append("Raw method data for "); 326 sb.append(method.format("%H.%n(%p)")); 327 sb.append(":"); 328 sb.append(nl); 329 sb.append(String.format("nof_decompiles(%d) nof_overflow_recompiles(%d) nof_overflow_traps(%d)%n", 330 getDecompileCount(), getOverflowRecompileCount(), getOverflowTrapCount())); 331 if (hasNormalData()) { 332 int pos = 0; 333 HotSpotMethodDataAccessor data; 334 while ((data = getNormalData(pos)) != null) { 335 if (pos != 0) { 336 sb.append(nl); 337 } 338 int bci = data.getBCI(this, pos); 339 sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); 340 sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); 341 pos = pos + data.getSize(this, pos); 342 } 343 } 344 345 return sb.toString(); 346 } 347 348 static class NoMethodData extends HotSpotMethodDataAccessor { 349 350 private final TriState exceptionSeen; 351 352 protected NoMethodData(VMState state, int tag, TriState exceptionSeen) { 353 super(state, tag, state.noDataSize); 354 this.exceptionSeen = exceptionSeen; 355 } 356 357 @Override 358 public int getBCI(HotSpotMethodData data, int position) { 359 return -1; 360 } 361 362 @Override 363 public TriState getExceptionSeen(HotSpotMethodData data, int position) { 364 return exceptionSeen; 365 } 366 367 @Override 368 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 369 return sb; 370 } 371 } 372 373 static class BitData extends HotSpotMethodDataAccessor { 374 375 private BitData(VMState state, int tag) { 376 super(state, tag, state.bitDataSize); 377 } 378 379 protected BitData(VMState state, int tag, int staticSize) { 380 super(state, tag, staticSize); 381 } 382 383 @Override 384 public TriState getNullSeen(HotSpotMethodData data, int position) { 385 return TriState.get((getFlags(data, position) & state.bitDataNullSeenFlag) != 0); 386 } 387 388 @Override 389 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 390 return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); 391 } 392 } 393 394 static class CounterData extends BitData { 395 396 CounterData(VMState state, int tag) { 397 super(state, tag, state.counterDataSize); 398 } 399 400 protected CounterData(VMState state, int tag, int staticSize) { 401 super(state, tag, staticSize); 402 } 403 404 @Override 405 public int getExecutionCount(HotSpotMethodData data, int position) { 406 return getCounterValue(data, position); 407 } 408 409 protected int getCounterValue(HotSpotMethodData data, int position) { 410 return data.readUnsignedIntAsSignedInt(position, state.counterDataCountOffset); 411 } 412 413 @Override 414 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 415 return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); 416 } 417 } 418 419 static class JumpData extends HotSpotMethodDataAccessor { 420 421 JumpData(VMState state, int tag) { 422 super(state, tag, state.jumpDataSize); 423 } 424 425 protected JumpData(VMState state, int tag, int staticSize) { 426 super(state, tag, staticSize); 427 } 428 429 @Override 430 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 431 return getExecutionCount(data, position) != 0 ? 1 : 0; 432 } 433 434 @Override 435 public int getExecutionCount(HotSpotMethodData data, int position) { 436 return data.readUnsignedIntAsSignedInt(position, state.takenCountOffset); 437 } 438 439 public int getTakenDisplacement(HotSpotMethodData data, int position) { 440 return data.readInt(position, state.takenDisplacementOffset); 441 } 442 443 @Override 444 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 445 return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); 446 } 447 } 448 449 record RawItemProfile<T>(int entries, T[] items, long[] counts, long totalCount) {} 450 451 abstract static class AbstractTypeData extends CounterData { 452 453 protected AbstractTypeData(VMState state, int tag, int staticSize) { 454 super(state, tag, staticSize); 455 } 456 457 @Override 458 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 459 return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); 460 } 461 462 private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) { 463 int typeProfileWidth = config.typeProfileWidth; 464 465 ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; 466 long[] counts = new long[typeProfileWidth]; 467 long totalCount = 0; 468 int entries = 0; 469 470 outer: for (int i = 0; i < typeProfileWidth; i++) { 471 HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); 472 if (receiverKlass != null) { 473 HotSpotResolvedObjectTypeImpl klass = receiverKlass; 474 long count = data.readUnsignedInt(position, getTypeCountOffset(i)); 475 /* 476 * Because of races in the profile collection machinery it's possible for a 477 * class to appear multiple times so merge them to make the profile look 478 * rational. 479 */ 480 for (int j = 0; j < entries; j++) { 481 if (types[j].equals(klass)) { 482 totalCount += count; 483 counts[j] += count; 484 continue outer; 485 } 486 } 487 types[entries] = klass; 488 totalCount += count; 489 counts[entries] = count; 490 entries++; 491 } 492 } 493 494 totalCount += getCounterValue(data, position); 495 return new RawItemProfile<>(entries, types, counts, totalCount); 496 } 497 498 private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) { 499 if (profile.entries <= 0 || profile.totalCount <= 0) { 500 return null; 501 } 502 503 ProfiledType[] ptypes = new ProfiledType[profile.entries]; 504 double totalProbability = 0.0; 505 for (int i = 0; i < profile.entries; i++) { 506 double p = profile.counts[i]; 507 p = p / profile.totalCount; 508 totalProbability += p; 509 ptypes[i] = new ProfiledType(profile.items[i], p); 510 } 511 512 Arrays.sort(ptypes); 513 514 double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 515 assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; 516 return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); 517 } 518 519 private int getTypeOffset(int row) { 520 return state.typeDataFirstTypeOffset + row * state.typeDataRowSize; 521 } 522 523 protected int getTypeCountOffset(int row) { 524 return state.typeDataFirstTypeCountOffset + row * state.typeDataRowSize; 525 } 526 527 @Override 528 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 529 RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos); 530 TriState nullSeen = getNullSeen(data, pos); 531 TriState exceptionSeen = getExceptionSeen(data, pos); 532 sb.append(format("count(%d) null_seen(%s) exception_seen(%s) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, 533 profile.entries)); 534 for (int i = 0; i < profile.entries; i++) { 535 long count = profile.counts[i]; 536 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); 537 } 538 return sb; 539 } 540 } 541 542 static class ReceiverTypeData extends AbstractTypeData { 543 544 ReceiverTypeData(VMState state, int tag) { 545 super(state, tag, state.typeCheckDataSize); 546 } 547 548 protected ReceiverTypeData(VMState state, int tag, int staticSize) { 549 super(state, tag, staticSize); 550 } 551 552 @Override 553 public int getExecutionCount(HotSpotMethodData data, int position) { 554 return -1; 555 } 556 } 557 558 static class VirtualCallData extends ReceiverTypeData { 559 560 VirtualCallData(VMState state, int tag) { 561 super(state, tag, state.virtualCallDataSize); 562 } 563 564 protected VirtualCallData(VMState state, int tag, int staticSize) { 565 super(state, tag, staticSize); 566 } 567 568 @Override 569 public int getExecutionCount(HotSpotMethodData data, int position) { 570 final int typeProfileWidth = config.typeProfileWidth; 571 572 long total = 0; 573 for (int i = 0; i < typeProfileWidth; i++) { 574 total += data.readUnsignedInt(position, getTypeCountOffset(i)); 575 } 576 577 total += getCounterValue(data, position); 578 return VMState.truncateLongToInt(total); 579 } 580 581 @Override 582 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 583 return createMethodProfile(getRawMethodProfile(data, position)); 584 } 585 586 private RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) { 587 int profileWidth = config.methodProfileWidth; 588 589 ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; 590 long[] counts = new long[profileWidth]; 591 long totalCount = 0; 592 int entries = 0; 593 594 for (int i = 0; i < profileWidth; i++) { 595 HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); 596 if (method != null) { 597 methods[entries] = method; 598 long count = data.readUnsignedInt(position, getMethodCountOffset(i)); 599 totalCount += count; 600 counts[entries] = count; 601 602 entries++; 603 } 604 } 605 606 // Fixup the case of C1's inability to optimize profiling of a statically bindable call 607 // site. If it's a monomorphic call site, attribute all the counts to the first type (if 608 // any is recorded). 609 if (entries == 1) { 610 counts[0] = totalCount; 611 } 612 613 return new RawItemProfile<>(entries, methods, counts, totalCount); 614 } 615 616 private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 617 if (profile.entries <= 0 || profile.totalCount <= 0) { 618 return null; 619 } 620 621 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 622 double totalProbability = 0.0; 623 for (int i = 0; i < profile.entries; i++) { 624 double p = profile.counts[i]; 625 p = p / profile.totalCount; 626 totalProbability += p; 627 pmethods[i] = new ProfiledMethod(profile.items[i], p); 628 } 629 630 Arrays.sort(pmethods); 631 632 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 633 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 634 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 635 } 636 637 private int getMethodOffset(int row) { 638 return state.virtualCallDataFirstMethodOffset + row * state.typeDataRowSize; 639 } 640 641 private int getMethodCountOffset(int row) { 642 return state.virtualCallDataFirstMethodCountOffset + row * state.typeDataRowSize; 643 } 644 645 @Override 646 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 647 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 648 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 649 for (int i = 0; i < profile.entries; i++) { 650 long count = profile.counts[i]; 651 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 652 } 653 return sb; 654 } 655 } 656 657 static class VirtualCallTypeData extends VirtualCallData { 658 659 VirtualCallTypeData(VMState state, int tag) { 660 super(state, tag, 0); 661 } 662 663 @Override 664 protected int getDynamicSize(HotSpotMethodData data, int position) { 665 assert staticSize == 0; 666 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 667 } 668 } 669 670 static class RetData extends CounterData { 671 672 RetData(VMState state, int tag) { 673 super(state, tag, state.retDataSize); 674 } 675 } 676 677 static class BranchData extends JumpData { 678 679 BranchData(VMState state, int tag) { 680 super(state, tag, state.branchDataSize); 681 } 682 683 @Override 684 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 685 long takenCount = data.readUnsignedInt(position, state.takenCountOffset); 686 long notTakenCount = data.readUnsignedInt(position, state.notTakenCountOffset); 687 long total = takenCount + notTakenCount; 688 689 return total <= 0 ? -1 : takenCount / (double) total; 690 } 691 692 @Override 693 public int getExecutionCount(HotSpotMethodData data, int position) { 694 long count = data.readUnsignedInt(position, state.takenCountOffset) + data.readUnsignedInt(position, state.notTakenCountOffset); 695 return VMState.truncateLongToInt(count); 696 } 697 698 @Override 699 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 700 long taken = data.readUnsignedInt(pos, state.takenCountOffset); 701 long notTaken = data.readUnsignedInt(pos, state.notTakenCountOffset); 702 double takenProbability = getBranchTakenProbability(data, pos); 703 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 704 } 705 } 706 707 static class ArrayData extends HotSpotMethodDataAccessor { 708 709 ArrayData(VMState state, int tag, int staticSize) { 710 super(state, tag, staticSize); 711 } 712 713 @Override 714 protected int getDynamicSize(HotSpotMethodData data, int position) { 715 return state.cellsToBytes(getLength(data, position)); 716 } 717 718 protected int getLength(HotSpotMethodData data, int position) { 719 return data.readInt(position, state.arrayDataLengthOffset); 720 } 721 722 @Override 723 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 724 return sb.append(format("length(%d)", getLength(data, pos))); 725 } 726 } 727 728 static class MultiBranchData extends ArrayData { 729 730 MultiBranchData(VMState state, int tag) { 731 super(state, tag, state.multiBranchDataSize); 732 } 733 734 @Override 735 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 736 int arrayLength = getLength(data, position); 737 assert arrayLength > 0 : "switch must have at least the default case"; 738 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 739 740 int length = arrayLength / state.multiBranchDataRowSizeInCells; 741 long totalCount = 0; 742 double[] result = new double[length]; 743 744 // default case is first in HotSpot but last for the compiler 745 long count = readCount(data, position, 0); 746 totalCount += count; 747 result[length - 1] = count; 748 749 for (int i = 1; i < length; i++) { 750 count = readCount(data, position, i); 751 totalCount += count; 752 result[i - 1] = count; 753 } 754 755 if (totalCount <= 0) { 756 return null; 757 } else { 758 for (int i = 0; i < length; i++) { 759 result[i] = result[i] / totalCount; 760 } 761 return result; 762 } 763 } 764 765 private long readCount(HotSpotMethodData data, int position, int i) { 766 int offset; 767 long count; 768 offset = getCountOffset(i); 769 count = data.readUnsignedInt(position, offset); 770 return count; 771 } 772 773 @Override 774 public int getExecutionCount(HotSpotMethodData data, int position) { 775 int arrayLength = getLength(data, position); 776 assert arrayLength > 0 : "switch must have at least the default case"; 777 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 778 779 int length = arrayLength / state.multiBranchDataRowSizeInCells; 780 long totalCount = 0; 781 for (int i = 0; i < length; i++) { 782 int offset = getCountOffset(i); 783 totalCount += data.readUnsignedInt(position, offset); 784 } 785 786 return VMState.truncateLongToInt(totalCount); 787 } 788 789 private int getCountOffset(int index) { 790 return state.multiBranchDataFirstCountOffset + index * state.multiBranchDataRowSize; 791 } 792 793 private int getDisplacementOffset(int index) { 794 return state.multiBranchDataFirstDisplacementOffset + index * state.multiBranchDataRowSize; 795 } 796 797 @Override 798 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 799 int entries = getLength(data, pos) / state.multiBranchDataRowSizeInCells; 800 sb.append(format("entries(%d)", entries)); 801 for (int i = 0; i < entries; i++) { 802 sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); 803 } 804 return sb; 805 } 806 } 807 808 static class ArgInfoData extends ArrayData { 809 810 ArgInfoData(VMState state, int tag) { 811 super(state, tag, state.argInfoDataSize); 812 } 813 } 814 815 static class UnknownProfileData extends HotSpotMethodDataAccessor { 816 UnknownProfileData(VMState state, int tag) { 817 super(state, tag, 0); 818 } 819 820 @Override 821 protected int getDynamicSize(HotSpotMethodData data, int position) { 822 assert staticSize == 0; 823 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 824 } 825 826 @Override 827 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 828 sb.append("unknown profile data with tag: " + tag); 829 return sb; 830 } 831 } 832 833 public void setCompiledIRSize(int size) { 834 UNSAFE.putInt(methodDataPointer + state.config.methodDataIRSizeOffset, size); 835 } 836 837 public int getCompiledIRSize() { 838 return UNSAFE.getInt(methodDataPointer + state.config.methodDataIRSizeOffset); 839 } 840 }