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