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 record RawItemProfile<T>(int entries, T[] items, long[] counts, long totalCount) {} 447 448 abstract static class AbstractTypeData extends CounterData { 449 450 protected AbstractTypeData(VMState state, int tag, int staticSize) { 451 super(state, tag, staticSize); 452 } 453 454 @Override 455 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 456 return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); 457 } 458 459 private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) { 460 int typeProfileWidth = config.typeProfileWidth; 461 462 ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; 463 long[] counts = new long[typeProfileWidth]; 464 long totalCount = 0; 465 int entries = 0; 466 467 outer: for (int i = 0; i < typeProfileWidth; i++) { 468 HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i)); 469 if (receiverKlass != null) { 470 HotSpotResolvedObjectTypeImpl klass = receiverKlass; 471 long count = data.readUnsignedInt(position, getTypeCountOffset(i)); 472 /* 473 * Because of races in the profile collection machinery it's possible for a 474 * class to appear multiple times so merge them to make the profile look 475 * rational. 476 */ 477 for (int j = 0; j < entries; j++) { 478 if (types[j].equals(klass)) { 479 totalCount += count; 480 counts[j] += count; 481 continue outer; 482 } 483 } 484 types[entries] = klass; 485 totalCount += count; 486 counts[entries] = count; 487 entries++; 488 } 489 } 490 491 totalCount += getCounterValue(data, position); 492 return new RawItemProfile<>(entries, types, counts, totalCount); 493 } 494 495 private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) { 496 if (profile.entries <= 0 || profile.totalCount <= 0) { 497 return null; 498 } 499 500 ProfiledType[] ptypes = new ProfiledType[profile.entries]; 501 double totalProbability = 0.0; 502 for (int i = 0; i < profile.entries; i++) { 503 double p = profile.counts[i]; 504 p = p / profile.totalCount; 505 totalProbability += p; 506 ptypes[i] = new ProfiledType(profile.items[i], p); 507 } 508 509 Arrays.sort(ptypes); 510 511 double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 512 assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; 513 return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); 514 } 515 516 private int getTypeOffset(int row) { 517 return state.typeDataFirstTypeOffset + row * state.typeDataRowSize; 518 } 519 520 protected int getTypeCountOffset(int row) { 521 return state.typeDataFirstTypeCountOffset + row * state.typeDataRowSize; 522 } 523 524 @Override 525 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 526 RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos); 527 TriState nullSeen = getNullSeen(data, pos); 528 TriState exceptionSeen = getExceptionSeen(data, pos); 529 sb.append(format("count(%d) null_seen(%s) exception_seen(%s) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, 530 profile.entries)); 531 for (int i = 0; i < profile.entries; i++) { 532 long count = profile.counts[i]; 533 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); 534 } 535 return sb; 536 } 537 } 538 539 static class ReceiverTypeData extends AbstractTypeData { 540 541 ReceiverTypeData(VMState state, int tag) { 542 super(state, tag, state.typeCheckDataSize); 543 } 544 545 protected ReceiverTypeData(VMState state, int tag, int staticSize) { 546 super(state, tag, staticSize); 547 } 548 549 @Override 550 public int getExecutionCount(HotSpotMethodData data, int position) { 551 return -1; 552 } 553 } 554 555 static class VirtualCallData extends ReceiverTypeData { 556 557 VirtualCallData(VMState state, int tag) { 558 super(state, tag, state.virtualCallDataSize); 559 } 560 561 protected VirtualCallData(VMState state, int tag, int staticSize) { 562 super(state, tag, staticSize); 563 } 564 565 @Override 566 public int getExecutionCount(HotSpotMethodData data, int position) { 567 final int typeProfileWidth = config.typeProfileWidth; 568 569 long total = 0; 570 for (int i = 0; i < typeProfileWidth; i++) { 571 total += data.readUnsignedInt(position, getTypeCountOffset(i)); 572 } 573 574 total += getCounterValue(data, position); 575 return VMState.truncateLongToInt(total); 576 } 577 578 @Override 579 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 580 return createMethodProfile(getRawMethodProfile(data, position)); 581 } 582 583 private RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) { 584 int profileWidth = config.methodProfileWidth; 585 586 ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; 587 long[] counts = new long[profileWidth]; 588 long totalCount = 0; 589 int entries = 0; 590 591 for (int i = 0; i < profileWidth; i++) { 592 HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); 593 if (method != null) { 594 methods[entries] = method; 595 long count = data.readUnsignedInt(position, getMethodCountOffset(i)); 596 totalCount += count; 597 counts[entries] = count; 598 599 entries++; 600 } 601 } 602 603 // Fixup the case of C1's inability to optimize profiling of a statically bindable call 604 // site. If it's a monomorphic call site, attribute all the counts to the first type (if 605 // any is recorded). 606 if (entries == 1) { 607 counts[0] = totalCount; 608 } 609 610 return new RawItemProfile<>(entries, methods, counts, totalCount); 611 } 612 613 private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 614 if (profile.entries <= 0 || profile.totalCount <= 0) { 615 return null; 616 } 617 618 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 619 double totalProbability = 0.0; 620 for (int i = 0; i < profile.entries; i++) { 621 double p = profile.counts[i]; 622 p = p / profile.totalCount; 623 totalProbability += p; 624 pmethods[i] = new ProfiledMethod(profile.items[i], p); 625 } 626 627 Arrays.sort(pmethods); 628 629 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 630 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 631 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 632 } 633 634 private int getMethodOffset(int row) { 635 return state.virtualCallDataFirstMethodOffset + row * state.typeDataRowSize; 636 } 637 638 private int getMethodCountOffset(int row) { 639 return state.virtualCallDataFirstMethodCountOffset + row * state.typeDataRowSize; 640 } 641 642 @Override 643 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 644 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 645 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 646 for (int i = 0; i < profile.entries; i++) { 647 long count = profile.counts[i]; 648 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 649 } 650 return sb; 651 } 652 } 653 654 static class VirtualCallTypeData extends VirtualCallData { 655 656 VirtualCallTypeData(VMState state, int tag) { 657 super(state, tag, 0); 658 } 659 660 @Override 661 protected int getDynamicSize(HotSpotMethodData data, int position) { 662 assert staticSize == 0; 663 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 664 } 665 } 666 667 static class RetData extends CounterData { 668 669 RetData(VMState state, int tag) { 670 super(state, tag, state.retDataSize); 671 } 672 } 673 674 static class BranchData extends JumpData { 675 676 BranchData(VMState state, int tag) { 677 super(state, tag, state.branchDataSize); 678 } 679 680 @Override 681 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 682 long takenCount = data.readUnsignedInt(position, state.takenCountOffset); 683 long notTakenCount = data.readUnsignedInt(position, state.notTakenCountOffset); 684 long total = takenCount + notTakenCount; 685 686 return total <= 0 ? -1 : takenCount / (double) total; 687 } 688 689 @Override 690 public int getExecutionCount(HotSpotMethodData data, int position) { 691 long count = data.readUnsignedInt(position, state.takenCountOffset) + data.readUnsignedInt(position, state.notTakenCountOffset); 692 return VMState.truncateLongToInt(count); 693 } 694 695 @Override 696 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 697 long taken = data.readUnsignedInt(pos, state.takenCountOffset); 698 long notTaken = data.readUnsignedInt(pos, state.notTakenCountOffset); 699 double takenProbability = getBranchTakenProbability(data, pos); 700 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 701 } 702 } 703 704 static class ArrayData extends HotSpotMethodDataAccessor { 705 706 ArrayData(VMState state, int tag, int staticSize) { 707 super(state, tag, staticSize); 708 } 709 710 @Override 711 protected int getDynamicSize(HotSpotMethodData data, int position) { 712 return state.cellsToBytes(getLength(data, position)); 713 } 714 715 protected int getLength(HotSpotMethodData data, int position) { 716 return data.readInt(position, state.arrayDataLengthOffset); 717 } 718 719 @Override 720 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 721 return sb.append(format("length(%d)", getLength(data, pos))); 722 } 723 } 724 725 static class MultiBranchData extends ArrayData { 726 727 MultiBranchData(VMState state, int tag) { 728 super(state, tag, state.multiBranchDataSize); 729 } 730 731 @Override 732 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 733 int arrayLength = getLength(data, position); 734 assert arrayLength > 0 : "switch must have at least the default case"; 735 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 736 737 int length = arrayLength / state.multiBranchDataRowSizeInCells; 738 long totalCount = 0; 739 double[] result = new double[length]; 740 741 // default case is first in HotSpot but last for the compiler 742 long count = readCount(data, position, 0); 743 totalCount += count; 744 result[length - 1] = count; 745 746 for (int i = 1; i < length; i++) { 747 count = readCount(data, position, i); 748 totalCount += count; 749 result[i - 1] = count; 750 } 751 752 if (totalCount <= 0) { 753 return null; 754 } else { 755 for (int i = 0; i < length; i++) { 756 result[i] = result[i] / totalCount; 757 } 758 return result; 759 } 760 } 761 762 private long readCount(HotSpotMethodData data, int position, int i) { 763 int offset; 764 long count; 765 offset = getCountOffset(i); 766 count = data.readUnsignedInt(position, offset); 767 return count; 768 } 769 770 @Override 771 public int getExecutionCount(HotSpotMethodData data, int position) { 772 int arrayLength = getLength(data, position); 773 assert arrayLength > 0 : "switch must have at least the default case"; 774 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 775 776 int length = arrayLength / state.multiBranchDataRowSizeInCells; 777 long totalCount = 0; 778 for (int i = 0; i < length; i++) { 779 int offset = getCountOffset(i); 780 totalCount += data.readUnsignedInt(position, offset); 781 } 782 783 return VMState.truncateLongToInt(totalCount); 784 } 785 786 private int getCountOffset(int index) { 787 return state.multiBranchDataFirstCountOffset + index * state.multiBranchDataRowSize; 788 } 789 790 private int getDisplacementOffset(int index) { 791 return state.multiBranchDataFirstDisplacementOffset + index * state.multiBranchDataRowSize; 792 } 793 794 @Override 795 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 796 int entries = getLength(data, pos) / state.multiBranchDataRowSizeInCells; 797 sb.append(format("entries(%d)", entries)); 798 for (int i = 0; i < entries; i++) { 799 sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); 800 } 801 return sb; 802 } 803 } 804 805 static class ArgInfoData extends ArrayData { 806 807 ArgInfoData(VMState state, int tag) { 808 super(state, tag, state.argInfoDataSize); 809 } 810 } 811 812 static class UnknownProfileData extends HotSpotMethodDataAccessor { 813 UnknownProfileData(VMState state, int tag) { 814 super(state, tag, 0); 815 } 816 817 @Override 818 protected int getDynamicSize(HotSpotMethodData data, int position) { 819 assert staticSize == 0; 820 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 821 } 822 823 @Override 824 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 825 sb.append("unknown profile data with tag: " + tag); 826 return sb; 827 } 828 } 829 830 public void setCompiledIRSize(int size) { 831 UNSAFE.putInt(methodDataPointer + state.config.methodDataIRSizeOffset, size); 832 } 833 834 public int getCompiledIRSize() { 835 return UNSAFE.getInt(methodDataPointer + state.config.methodDataIRSizeOffset); 836 } 837 }