1 /* 2 * Copyright (c) 2012, 2019, 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 nonprofiledCountOffset = cellIndexToOffset(config.receiverTypeDataNonprofiledCountOffset); 67 final int typeDataFirstTypeOffset = cellIndexToOffset(config.receiverTypeDataReceiver0Offset); 68 final int typeDataFirstTypeCountOffset = cellIndexToOffset(config.receiverTypeDataCount0Offset); 69 70 final int typeCheckDataSize = cellIndexToOffset(2) + typeDataRowSize * config.typeProfileWidth; 71 final int virtualCallDataSize = cellIndexToOffset(2) + typeDataRowSize * (config.typeProfileWidth + config.methodProfileWidth); 72 final int virtualCallDataFirstMethodOffset = typeDataFirstTypeOffset + typeDataRowSize * config.typeProfileWidth; 73 final int virtualCallDataFirstMethodCountOffset = typeDataFirstTypeCountOffset + typeDataRowSize * config.typeProfileWidth; 74 75 final int retDataRowSize = cellsToBytes(3); 76 final int retDataSize = cellIndexToOffset(1) + retDataRowSize * config.bciProfileWidth; 77 78 final int branchDataSize = cellIndexToOffset(3); 79 final int notTakenCountOffset = cellIndexToOffset(config.branchDataNotTakenOffset); 80 81 final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset); 82 final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset); 83 84 final int multiBranchDataSize = cellIndexToOffset(1); 85 final int multiBranchDataRowSizeInCells = config.multiBranchDataPerCaseCellCount; 86 final int multiBranchDataRowSize = cellsToBytes(multiBranchDataRowSizeInCells); 87 final int multiBranchDataFirstCountOffset = arrayDataStartOffset + cellsToBytes(0); 88 final int multiBranchDataFirstDisplacementOffset = arrayDataStartOffset + cellsToBytes(1); 89 90 final int argInfoDataSize = cellIndexToOffset(1); 91 92 // sorted by tag 93 // @formatter:off 94 final HotSpotMethodDataAccessor[] profileDataAccessors = { 95 null, 96 new BitData(this, config.dataLayoutBitDataTag), 97 new CounterData(this, config.dataLayoutCounterDataTag), 98 new JumpData(this, config.dataLayoutJumpDataTag), 99 new ReceiverTypeData(this, config.dataLayoutReceiverTypeDataTag), 100 new VirtualCallData(this, config.dataLayoutVirtualCallDataTag), 101 new RetData(this, config.dataLayoutRetDataTag), 102 new BranchData(this, config.dataLayoutBranchDataTag), 103 new MultiBranchData(this, config.dataLayoutMultiBranchDataTag), 104 new ArgInfoData(this, config.dataLayoutArgInfoDataTag), 105 new UnknownProfileData(this, config.dataLayoutCallTypeDataTag), 106 new VirtualCallTypeData(this, config.dataLayoutVirtualCallTypeDataTag), 107 new UnknownProfileData(this, config.dataLayoutParametersTypeDataTag), 108 new UnknownProfileData(this, config.dataLayoutSpeculativeTrapDataTag), 109 new UnknownProfileData(this, config.dataLayoutArrayLoadStoreDataTag), 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 = String.format("%n"); 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 += getTypesNotRecordedExecutionCount(data, position); 508 return new RawItemProfile<>(entries, types, counts, totalCount); 509 } 510 511 protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); 512 513 public int getNonprofiledCount(HotSpotMethodData data, int position) { 514 return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset); 515 } 516 517 private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) { 518 if (profile.entries <= 0 || profile.totalCount <= 0) { 519 return null; 520 } 521 522 ProfiledType[] ptypes = new ProfiledType[profile.entries]; 523 double totalProbability = 0.0; 524 for (int i = 0; i < profile.entries; i++) { 525 double p = profile.counts[i]; 526 p = p / profile.totalCount; 527 totalProbability += p; 528 ptypes[i] = new ProfiledType(profile.items[i], p); 529 } 530 531 Arrays.sort(ptypes); 532 533 double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 534 assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; 535 return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); 536 } 537 538 private int getTypeOffset(int row) { 539 return state.typeDataFirstTypeOffset + row * state.typeDataRowSize; 540 } 541 542 protected int getTypeCountOffset(int row) { 543 return state.typeDataFirstTypeCountOffset + row * state.typeDataRowSize; 544 } 545 546 @Override 547 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 548 RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos); 549 TriState nullSeen = getNullSeen(data, pos); 550 TriState exceptionSeen = getExceptionSeen(data, pos); 551 sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, 552 getNonprofiledCount(data, pos), profile.entries)); 553 for (int i = 0; i < profile.entries; i++) { 554 long count = profile.counts[i]; 555 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); 556 } 557 return sb; 558 } 559 } 560 561 static class ReceiverTypeData extends AbstractTypeData { 562 563 ReceiverTypeData(VMState state, int tag) { 564 super(state, tag, state.typeCheckDataSize); 565 } 566 567 protected ReceiverTypeData(VMState state, int tag, int staticSize) { 568 super(state, tag, staticSize); 569 } 570 571 @Override 572 public int getExecutionCount(HotSpotMethodData data, int position) { 573 return -1; 574 } 575 576 @Override 577 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 578 return getNonprofiledCount(data, position); 579 } 580 } 581 582 static class VirtualCallData extends ReceiverTypeData { 583 584 VirtualCallData(VMState state, int tag) { 585 super(state, tag, state.virtualCallDataSize); 586 } 587 588 protected VirtualCallData(VMState state, int tag, int staticSize) { 589 super(state, tag, staticSize); 590 } 591 592 @Override 593 public int getExecutionCount(HotSpotMethodData data, int position) { 594 final int typeProfileWidth = config.typeProfileWidth; 595 596 long total = 0; 597 for (int i = 0; i < typeProfileWidth; i++) { 598 total += data.readUnsignedInt(position, getTypeCountOffset(i)); 599 } 600 601 total += getCounterValue(data, position); 602 return VMState.truncateLongToInt(total); 603 } 604 605 @Override 606 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 607 return getCounterValue(data, position); 608 } 609 610 private long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { 611 return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset); 612 } 613 614 @Override 615 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 616 return createMethodProfile(getRawMethodProfile(data, position)); 617 } 618 619 private RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) { 620 int profileWidth = config.methodProfileWidth; 621 622 ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; 623 long[] counts = new long[profileWidth]; 624 long totalCount = 0; 625 int entries = 0; 626 627 for (int i = 0; i < profileWidth; i++) { 628 HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i)); 629 if (method != null) { 630 methods[entries] = method; 631 long count = data.readUnsignedInt(position, getMethodCountOffset(i)); 632 totalCount += count; 633 counts[entries] = count; 634 635 entries++; 636 } 637 } 638 639 totalCount += getMethodsNotRecordedExecutionCount(data, position); 640 641 // Fixup the case of C1's inability to optimize profiling of a statically bindable call 642 // site. If it's a monomorphic call site, attribute all the counts to the first type (if 643 // any is recorded). 644 if (entries == 1) { 645 counts[0] = totalCount; 646 } 647 648 return new RawItemProfile<>(entries, methods, counts, totalCount); 649 } 650 651 private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 652 if (profile.entries <= 0 || profile.totalCount <= 0) { 653 return null; 654 } 655 656 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 657 double totalProbability = 0.0; 658 for (int i = 0; i < profile.entries; i++) { 659 double p = profile.counts[i]; 660 p = p / profile.totalCount; 661 totalProbability += p; 662 pmethods[i] = new ProfiledMethod(profile.items[i], p); 663 } 664 665 Arrays.sort(pmethods); 666 667 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 668 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 669 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 670 } 671 672 private int getMethodOffset(int row) { 673 return state.virtualCallDataFirstMethodOffset + row * state.typeDataRowSize; 674 } 675 676 private int getMethodCountOffset(int row) { 677 return state.virtualCallDataFirstMethodCountOffset + row * state.typeDataRowSize; 678 } 679 680 @Override 681 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 682 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 683 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 684 for (int i = 0; i < profile.entries; i++) { 685 long count = profile.counts[i]; 686 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 687 } 688 return sb; 689 } 690 } 691 692 static class VirtualCallTypeData extends VirtualCallData { 693 694 VirtualCallTypeData(VMState state, int tag) { 695 super(state, tag, 0); 696 } 697 698 @Override 699 protected int getDynamicSize(HotSpotMethodData data, int position) { 700 assert staticSize == 0; 701 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 702 } 703 } 704 705 static class RetData extends CounterData { 706 707 RetData(VMState state, int tag) { 708 super(state, tag, state.retDataSize); 709 } 710 } 711 712 static class BranchData extends JumpData { 713 714 BranchData(VMState state, int tag) { 715 super(state, tag, state.branchDataSize); 716 } 717 718 @Override 719 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 720 long takenCount = data.readUnsignedInt(position, state.takenCountOffset); 721 long notTakenCount = data.readUnsignedInt(position, state.notTakenCountOffset); 722 long total = takenCount + notTakenCount; 723 724 return total <= 0 ? -1 : takenCount / (double) total; 725 } 726 727 @Override 728 public int getExecutionCount(HotSpotMethodData data, int position) { 729 long count = data.readUnsignedInt(position, state.takenCountOffset) + data.readUnsignedInt(position, state.notTakenCountOffset); 730 return VMState.truncateLongToInt(count); 731 } 732 733 @Override 734 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 735 long taken = data.readUnsignedInt(pos, state.takenCountOffset); 736 long notTaken = data.readUnsignedInt(pos, state.notTakenCountOffset); 737 double takenProbability = getBranchTakenProbability(data, pos); 738 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 739 } 740 } 741 742 static class ArrayData extends HotSpotMethodDataAccessor { 743 744 ArrayData(VMState state, int tag, int staticSize) { 745 super(state, tag, staticSize); 746 } 747 748 @Override 749 protected int getDynamicSize(HotSpotMethodData data, int position) { 750 return state.cellsToBytes(getLength(data, position)); 751 } 752 753 protected int getLength(HotSpotMethodData data, int position) { 754 return data.readInt(position, state.arrayDataLengthOffset); 755 } 756 757 @Override 758 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 759 return sb.append(format("length(%d)", getLength(data, pos))); 760 } 761 } 762 763 static class MultiBranchData extends ArrayData { 764 765 MultiBranchData(VMState state, int tag) { 766 super(state, tag, state.multiBranchDataSize); 767 } 768 769 @Override 770 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 771 int arrayLength = getLength(data, position); 772 assert arrayLength > 0 : "switch must have at least the default case"; 773 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 774 775 int length = arrayLength / state.multiBranchDataRowSizeInCells; 776 long totalCount = 0; 777 double[] result = new double[length]; 778 779 // default case is first in HotSpot but last for the compiler 780 long count = readCount(data, position, 0); 781 totalCount += count; 782 result[length - 1] = count; 783 784 for (int i = 1; i < length; i++) { 785 count = readCount(data, position, i); 786 totalCount += count; 787 result[i - 1] = count; 788 } 789 790 if (totalCount <= 0) { 791 return null; 792 } else { 793 for (int i = 0; i < length; i++) { 794 result[i] = result[i] / totalCount; 795 } 796 return result; 797 } 798 } 799 800 private long readCount(HotSpotMethodData data, int position, int i) { 801 int offset; 802 long count; 803 offset = getCountOffset(i); 804 count = data.readUnsignedInt(position, offset); 805 return count; 806 } 807 808 @Override 809 public int getExecutionCount(HotSpotMethodData data, int position) { 810 int arrayLength = getLength(data, position); 811 assert arrayLength > 0 : "switch must have at least the default case"; 812 assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows"; 813 814 int length = arrayLength / state.multiBranchDataRowSizeInCells; 815 long totalCount = 0; 816 for (int i = 0; i < length; i++) { 817 int offset = getCountOffset(i); 818 totalCount += data.readUnsignedInt(position, offset); 819 } 820 821 return VMState.truncateLongToInt(totalCount); 822 } 823 824 private int getCountOffset(int index) { 825 return state.multiBranchDataFirstCountOffset + index * state.multiBranchDataRowSize; 826 } 827 828 private int getDisplacementOffset(int index) { 829 return state.multiBranchDataFirstDisplacementOffset + index * state.multiBranchDataRowSize; 830 } 831 832 @Override 833 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 834 int entries = getLength(data, pos) / state.multiBranchDataRowSizeInCells; 835 sb.append(format("entries(%d)", entries)); 836 for (int i = 0; i < entries; i++) { 837 sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i)))); 838 } 839 return sb; 840 } 841 } 842 843 static class ArgInfoData extends ArrayData { 844 845 ArgInfoData(VMState state, int tag) { 846 super(state, tag, state.argInfoDataSize); 847 } 848 } 849 850 static class UnknownProfileData extends HotSpotMethodDataAccessor { 851 UnknownProfileData(VMState state, int tag) { 852 super(state, tag, 0); 853 } 854 855 @Override 856 protected int getDynamicSize(HotSpotMethodData data, int position) { 857 assert staticSize == 0; 858 return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.methodDataPointer, position); 859 } 860 861 @Override 862 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 863 sb.append("unknown profile data with tag: " + tag); 864 return sb; 865 } 866 } 867 868 public void setCompiledIRSize(int size) { 869 UNSAFE.putInt(methodDataPointer + state.config.methodDataIRSizeOffset, size); 870 } 871 872 public int getCompiledIRSize() { 873 return UNSAFE.getInt(methodDataPointer + state.config.methodDataIRSizeOffset); 874 } 875 }