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