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