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