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