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