001/* 002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot; 024 025import static java.lang.String.*; 026import static jdk.internal.jvmci.common.UnsafeAccess.*; 027import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; 028 029import java.util.*; 030 031import jdk.internal.jvmci.hotspot.HotSpotMethodDataAccessor.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.meta.JavaMethodProfile.*; 034import jdk.internal.jvmci.meta.JavaTypeProfile.*; 035import sun.misc.*; 036 037/** 038 * Access to a HotSpot MethodData structure (defined in methodData.hpp). 039 */ 040public final class HotSpotMethodData { 041 042 private static final HotSpotVMConfig config = runtime().getConfig(); 043 private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(TriState.FALSE); 044 private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR = new NoMethodData(TriState.UNKNOWN); 045 046 // sorted by tag 047 // @formatter:off 048 private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { 049 null, 050 new BitData(), 051 new CounterData(), 052 new JumpData(), 053 new TypeCheckData(), 054 new VirtualCallData(), 055 new RetData(), 056 new BranchData(), 057 new MultiBranchData(), 058 new ArgInfoData(), 059 null, // call_type_data_tag 060 null, // virtual_call_type_data_tag 061 null, // parameters_type_data_tag 062 null, // speculative_trap_data_tag 063 }; 064 // @formatter:on 065 066 /** 067 * Reference to the C++ MethodData object. 068 */ 069 private final long metaspaceMethodData; 070 071 public HotSpotMethodData(long metaspaceMethodData) { 072 this.metaspaceMethodData = metaspaceMethodData; 073 } 074 075 /** 076 * @return value of the MethodData::_data_size field 077 */ 078 private int normalDataSize() { 079 return unsafe.getInt(metaspaceMethodData + config.methodDataDataSize); 080 } 081 082 /** 083 * Returns the size of the extra data records. This method does the same calculation as 084 * MethodData::extra_data_size(). 085 * 086 * @return size of extra data records 087 */ 088 private int extraDataSize() { 089 final int extraDataBase = config.methodDataOopDataOffset + normalDataSize(); 090 final int extraDataLimit = unsafe.getInt(metaspaceMethodData + config.methodDataSize); 091 return extraDataLimit - extraDataBase; 092 } 093 094 public boolean hasNormalData() { 095 return normalDataSize() > 0; 096 } 097 098 public boolean hasExtraData() { 099 return extraDataSize() > 0; 100 } 101 102 public int getExtraDataBeginOffset() { 103 return normalDataSize(); 104 } 105 106 public boolean isWithin(int position) { 107 return position >= 0 && position < normalDataSize() + extraDataSize(); 108 } 109 110 public int getDeoptimizationCount(DeoptimizationReason reason) { 111 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 112 int reasonIndex = metaAccess.convertDeoptReason(reason); 113 return unsafe.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF; 114 } 115 116 public int getOSRDeoptimizationCount(DeoptimizationReason reason) { 117 HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess(); 118 int reasonIndex = metaAccess.convertDeoptReason(reason); 119 return unsafe.getByte(metaspaceMethodData + config.methodDataOopTrapHistoryOffset + config.deoptReasonOSROffset + reasonIndex) & 0xFF; 120 } 121 122 public HotSpotMethodDataAccessor getNormalData(int position) { 123 if (position >= normalDataSize()) { 124 return null; 125 } 126 127 HotSpotMethodDataAccessor result = getData(position); 128 assert result != null : "NO_DATA tag is not allowed"; 129 return result; 130 } 131 132 public HotSpotMethodDataAccessor getExtraData(int position) { 133 if (position >= normalDataSize() + extraDataSize()) { 134 return null; 135 } 136 HotSpotMethodDataAccessor data = getData(position); 137 if (data != null) { 138 return data; 139 } 140 return data; 141 } 142 143 public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) { 144 if (exceptionPossiblyNotRecorded) { 145 return NO_DATA_EXCEPTION_POSSIBLY_NOT_RECORDED_ACCESSOR; 146 } else { 147 return NO_DATA_NO_EXCEPTION_ACCESSOR; 148 } 149 } 150 151 private HotSpotMethodDataAccessor getData(int position) { 152 assert position >= 0 : "out of bounds"; 153 final Tag tag = AbstractMethodData.readTag(this, position); 154 HotSpotMethodDataAccessor accessor = PROFILE_DATA_ACCESSORS[tag.getValue()]; 155 assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag; 156 return accessor; 157 } 158 159 private int readUnsignedByte(int position, int offsetInBytes) { 160 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 161 return unsafe.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF; 162 } 163 164 private int readUnsignedShort(int position, int offsetInBytes) { 165 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 166 return unsafe.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF; 167 } 168 169 /** 170 * Since the values are stored in cells (platform words) this method uses 171 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 172 */ 173 private long readUnsignedInt(int position, int offsetInBytes) { 174 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 175 return unsafe.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL; 176 } 177 178 private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) { 179 long value = readUnsignedInt(position, offsetInBytes); 180 return truncateLongToInt(value); 181 } 182 183 /** 184 * Since the values are stored in cells (platform words) this method uses 185 * {@link Unsafe#getAddress} to read the right value on both little and big endian machines. 186 */ 187 private int readInt(int position, int offsetInBytes) { 188 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 189 return (int) unsafe.getAddress(metaspaceMethodData + fullOffsetInBytes); 190 } 191 192 private long readWord(int position, int offsetInBytes) { 193 long fullOffsetInBytes = computeFullOffset(position, offsetInBytes); 194 return unsafe.getAddress(metaspaceMethodData + fullOffsetInBytes); 195 } 196 197 private static int truncateLongToInt(long value) { 198 return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value; 199 } 200 201 private static int computeFullOffset(int position, int offsetInBytes) { 202 return config.methodDataOopDataOffset + position + offsetInBytes; 203 } 204 205 private static int cellIndexToOffset(int cells) { 206 return config.dataLayoutHeaderSize + cellsToBytes(cells); 207 } 208 209 private static int cellsToBytes(int cells) { 210 return cells * config.dataLayoutCellSize; 211 } 212 213 /** 214 * Returns whether profiling ran long enough that the profile information is mature. Other 215 * informational data will still be valid even if the profile isn't mature. 216 */ 217 public boolean isProfileMature() { 218 return runtime().getCompilerToVM().isMature(metaspaceMethodData); 219 } 220 221 @Override 222 public String toString() { 223 StringBuilder sb = new StringBuilder(); 224 String nl = String.format("%n"); 225 String nlIndent = String.format("%n%38s", ""); 226 if (hasNormalData()) { 227 int pos = 0; 228 HotSpotMethodDataAccessor data; 229 while ((data = getNormalData(pos)) != null) { 230 if (pos != 0) { 231 sb.append(nl); 232 } 233 int bci = data.getBCI(this, pos); 234 sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); 235 sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); 236 pos = pos + data.getSize(this, pos); 237 } 238 } 239 240 if (hasExtraData()) { 241 int pos = getExtraDataBeginOffset(); 242 HotSpotMethodDataAccessor data; 243 while ((data = getExtraData(pos)) != null) { 244 if (pos == getExtraDataBeginOffset()) { 245 sb.append(nl).append("--- Extra data:"); 246 } 247 int bci = data.getBCI(this, pos); 248 sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName())); 249 sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent)); 250 pos = pos + data.getSize(this, pos); 251 } 252 253 } 254 return sb.toString(); 255 } 256 257 private abstract static class AbstractMethodData implements HotSpotMethodDataAccessor { 258 259 /** 260 * Corresponds to {@code exception_seen_flag}. 261 */ 262 private static final int EXCEPTIONS_MASK = 0x2; 263 264 private final Tag tag; 265 private final int staticSize; 266 267 protected AbstractMethodData(Tag tag, int staticSize) { 268 this.tag = tag; 269 this.staticSize = staticSize; 270 } 271 272 public Tag getTag() { 273 return tag; 274 } 275 276 public static Tag readTag(HotSpotMethodData data, int position) { 277 final int tag = data.readUnsignedByte(position, config.dataLayoutTagOffset); 278 return Tag.getEnum(tag); 279 } 280 281 @Override 282 public int getBCI(HotSpotMethodData data, int position) { 283 return data.readUnsignedShort(position, config.dataLayoutBCIOffset); 284 } 285 286 @Override 287 public int getSize(HotSpotMethodData data, int position) { 288 return staticSize + getDynamicSize(data, position); 289 } 290 291 @Override 292 public TriState getExceptionSeen(HotSpotMethodData data, int position) { 293 return TriState.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); 294 } 295 296 @Override 297 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 298 return null; 299 } 300 301 @Override 302 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 303 return null; 304 } 305 306 @Override 307 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 308 return -1; 309 } 310 311 @Override 312 public double[] getSwitchProbabilities(HotSpotMethodData data, int position) { 313 return null; 314 } 315 316 @Override 317 public int getExecutionCount(HotSpotMethodData data, int position) { 318 return -1; 319 } 320 321 @Override 322 public TriState getNullSeen(HotSpotMethodData data, int position) { 323 return TriState.UNKNOWN; 324 } 325 326 protected int getFlags(HotSpotMethodData data, int position) { 327 return data.readUnsignedByte(position, config.dataLayoutFlagsOffset); 328 } 329 330 /** 331 * @param data 332 * @param position 333 */ 334 protected int getDynamicSize(HotSpotMethodData data, int position) { 335 return 0; 336 } 337 338 public abstract StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos); 339 } 340 341 private static class NoMethodData extends AbstractMethodData { 342 343 private static final int NO_DATA_SIZE = cellIndexToOffset(0); 344 345 private final TriState exceptionSeen; 346 347 protected NoMethodData(TriState exceptionSeen) { 348 super(Tag.No, NO_DATA_SIZE); 349 this.exceptionSeen = exceptionSeen; 350 } 351 352 @Override 353 public int getBCI(HotSpotMethodData data, int position) { 354 return -1; 355 } 356 357 @Override 358 public TriState getExceptionSeen(HotSpotMethodData data, int position) { 359 return exceptionSeen; 360 } 361 362 @Override 363 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 364 return sb; 365 } 366 } 367 368 private static class BitData extends AbstractMethodData { 369 370 private static final int BIT_DATA_SIZE = cellIndexToOffset(0); 371 private static final int BIT_DATA_NULL_SEEN_FLAG = 0x01; 372 373 private BitData() { 374 super(Tag.BitData, BIT_DATA_SIZE); 375 } 376 377 protected BitData(Tag tag, int staticSize) { 378 super(tag, staticSize); 379 } 380 381 @Override 382 public TriState getNullSeen(HotSpotMethodData data, int position) { 383 return TriState.get((getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0); 384 } 385 386 @Override 387 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 388 return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos))); 389 } 390 } 391 392 private static class CounterData extends BitData { 393 394 private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1); 395 private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(0); 396 397 public CounterData() { 398 super(Tag.CounterData, COUNTER_DATA_SIZE); 399 } 400 401 protected CounterData(Tag tag, int staticSize) { 402 super(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, COUNTER_DATA_COUNT_OFFSET); 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 private static class JumpData extends AbstractMethodData { 421 422 private static final int JUMP_DATA_SIZE = cellIndexToOffset(2); 423 protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(0); 424 protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(1); 425 426 public JumpData() { 427 super(Tag.JumpData, JUMP_DATA_SIZE); 428 } 429 430 protected JumpData(Tag tag, int staticSize) { 431 super(tag, staticSize); 432 } 433 434 @Override 435 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 436 return getExecutionCount(data, position) != 0 ? 1 : 0; 437 } 438 439 @Override 440 public int getExecutionCount(HotSpotMethodData data, int position) { 441 return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET); 442 } 443 444 public int getTakenDisplacement(HotSpotMethodData data, int position) { 445 return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET); 446 } 447 448 @Override 449 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 450 return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos))); 451 } 452 } 453 454 static class RawItemProfile<T> { 455 final int entries; 456 final T[] items; 457 final long[] counts; 458 final long totalCount; 459 460 public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) { 461 this.entries = entries; 462 this.items = items; 463 this.counts = counts; 464 this.totalCount = totalCount; 465 } 466 } 467 468 private abstract static class AbstractTypeData extends CounterData { 469 470 protected static final int TYPE_DATA_ROW_SIZE = cellsToBytes(2); 471 472 protected static final int NONPROFILED_COUNT_OFFSET = cellIndexToOffset(1); 473 protected static final int TYPE_DATA_FIRST_TYPE_OFFSET = cellIndexToOffset(2); 474 protected static final int TYPE_DATA_FIRST_TYPE_COUNT_OFFSET = cellIndexToOffset(3); 475 476 protected AbstractTypeData(Tag tag, int staticSize) { 477 super(tag, staticSize); 478 } 479 480 @Override 481 public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) { 482 return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position)); 483 } 484 485 private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) { 486 int typeProfileWidth = config.typeProfileWidth; 487 488 ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth]; 489 long[] counts = new long[typeProfileWidth]; 490 long totalCount = 0; 491 int entries = 0; 492 493 outer: for (int i = 0; i < typeProfileWidth; i++) { 494 long receiverKlass = data.readWord(position, getTypeOffset(i)); 495 if (receiverKlass != 0) { 496 HotSpotResolvedObjectTypeImpl klass = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(receiverKlass); 497 long count = data.readUnsignedInt(position, getTypeCountOffset(i)); 498 /* 499 * Because of races in the profile collection machinery it's possible for a 500 * class to appear multiple times so merge them to make the profile look 501 * rational. 502 */ 503 for (int j = 0; j < entries; j++) { 504 if (types[j].equals(klass)) { 505 totalCount += count; 506 counts[j] += count; 507 continue outer; 508 } 509 } 510 types[entries] = klass; 511 totalCount += count; 512 counts[entries] = count; 513 entries++; 514 } 515 } 516 517 totalCount += getTypesNotRecordedExecutionCount(data, position); 518 return new RawItemProfile<>(entries, types, counts, totalCount); 519 } 520 521 protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); 522 523 private static JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) { 524 if (profile.entries <= 0 || profile.totalCount <= 0) { 525 return null; 526 } 527 528 ProfiledType[] ptypes = new ProfiledType[profile.entries]; 529 double totalProbability = 0.0; 530 for (int i = 0; i < profile.entries; i++) { 531 double p = profile.counts[i]; 532 p = p / profile.totalCount; 533 totalProbability += p; 534 ptypes[i] = new ProfiledType(profile.items[i], p); 535 } 536 537 Arrays.sort(ptypes); 538 539 double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 540 assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth; 541 return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes); 542 } 543 544 private static int getTypeOffset(int row) { 545 return TYPE_DATA_FIRST_TYPE_OFFSET + row * TYPE_DATA_ROW_SIZE; 546 } 547 548 protected static int getTypeCountOffset(int row) { 549 return TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; 550 } 551 552 @Override 553 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 554 RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos); 555 TriState nullSeen = getNullSeen(data, pos); 556 TriState exceptionSeen = getExceptionSeen(data, pos); 557 sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, 558 getTypesNotRecordedExecutionCount(data, pos), profile.entries)); 559 for (int i = 0; i < profile.entries; i++) { 560 long count = profile.counts[i]; 561 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount)); 562 } 563 return sb; 564 } 565 } 566 567 private static class TypeCheckData extends AbstractTypeData { 568 569 private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 570 571 public TypeCheckData() { 572 super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE); 573 } 574 575 @Override 576 public int getExecutionCount(HotSpotMethodData data, int position) { 577 return -1; 578 } 579 580 @Override 581 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 582 return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); 583 } 584 } 585 586 private static class VirtualCallData extends AbstractTypeData { 587 588 private static final int VIRTUAL_CALL_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * (config.typeProfileWidth + config.methodProfileWidth); 589 private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 590 private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth; 591 592 public VirtualCallData() { 593 super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE); 594 } 595 596 @Override 597 public int getExecutionCount(HotSpotMethodData data, int position) { 598 final int typeProfileWidth = config.typeProfileWidth; 599 600 long total = 0; 601 for (int i = 0; i < typeProfileWidth; i++) { 602 total += data.readUnsignedInt(position, getTypeCountOffset(i)); 603 } 604 605 total += getCounterValue(data, position); 606 return truncateLongToInt(total); 607 } 608 609 @Override 610 protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { 611 return getCounterValue(data, position); 612 } 613 614 private static long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) { 615 return data.readUnsignedIntAsSignedInt(position, NONPROFILED_COUNT_OFFSET); 616 } 617 618 @Override 619 public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) { 620 return createMethodProfile(getRawMethodProfile(data, position)); 621 } 622 623 private static RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) { 624 int profileWidth = config.methodProfileWidth; 625 626 ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth]; 627 long[] counts = new long[profileWidth]; 628 long totalCount = 0; 629 int entries = 0; 630 631 for (int i = 0; i < profileWidth; i++) { 632 long method = data.readWord(position, getMethodOffset(i)); 633 if (method != 0) { 634 methods[entries] = HotSpotResolvedJavaMethodImpl.fromMetaspace(method); 635 long count = data.readUnsignedInt(position, getMethodCountOffset(i)); 636 totalCount += count; 637 counts[entries] = count; 638 639 entries++; 640 } 641 } 642 643 totalCount += getMethodsNotRecordedExecutionCount(data, position); 644 return new RawItemProfile<>(entries, methods, counts, totalCount); 645 } 646 647 private static JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) { 648 if (profile.entries <= 0 || profile.totalCount <= 0) { 649 return null; 650 } 651 652 ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries]; 653 double totalProbability = 0.0; 654 for (int i = 0; i < profile.entries; i++) { 655 double p = profile.counts[i]; 656 p = p / profile.totalCount; 657 totalProbability += p; 658 pmethods[i] = new ProfiledMethod(profile.items[i], p); 659 } 660 661 Arrays.sort(pmethods); 662 663 double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability)); 664 assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth; 665 return new JavaMethodProfile(notRecordedMethodProbability, pmethods); 666 } 667 668 private static int getMethodOffset(int row) { 669 return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE; 670 } 671 672 private static int getMethodCountOffset(int row) { 673 return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE; 674 } 675 676 @Override 677 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 678 RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos); 679 super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries)); 680 for (int i = 0; i < profile.entries; i++) { 681 long count = profile.counts[i]; 682 sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount)); 683 } 684 return sb; 685 } 686 } 687 688 private static class RetData extends CounterData { 689 690 private static final int RET_DATA_ROW_SIZE = cellsToBytes(3); 691 private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth; 692 693 public RetData() { 694 super(Tag.RetData, RET_DATA_SIZE); 695 } 696 } 697 698 private static class BranchData extends JumpData { 699 700 private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3); 701 private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(2); 702 703 public BranchData() { 704 super(Tag.BranchData, BRANCH_DATA_SIZE); 705 } 706 707 @Override 708 public double getBranchTakenProbability(HotSpotMethodData data, int position) { 709 long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET); 710 long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 711 long total = takenCount + notTakenCount; 712 713 return total <= 0 ? -1 : takenCount / (double) total; 714 } 715 716 @Override 717 public int getExecutionCount(HotSpotMethodData data, int position) { 718 long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET); 719 return truncateLongToInt(count); 720 } 721 722 @Override 723 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 724 long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET); 725 long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET); 726 double takenProbability = getBranchTakenProbability(data, pos); 727 return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos))); 728 } 729 } 730 731 private static class ArrayData extends AbstractMethodData { 732 733 private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(0); 734 protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(1); 735 736 public ArrayData(Tag tag, int staticSize) { 737 super(tag, staticSize); 738 } 739 740 @Override 741 protected int getDynamicSize(HotSpotMethodData data, int position) { 742 return cellsToBytes(getLength(data, position)); 743 } 744 745 protected static int getLength(HotSpotMethodData data, int position) { 746 return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET); 747 } 748 749 @Override 750 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 751 return sb.append(format("length(%d)", getLength(data, pos))); 752 } 753 } 754 755 private static class MultiBranchData extends ArrayData { 756 757 private static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1); 758 private static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = 2; 759 private static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS); 760 private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0); 761 private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1); 762 763 public MultiBranchData() { 764 super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE); 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 % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 772 773 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 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 static 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 % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows"; 811 812 int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 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 truncateLongToInt(totalCount); 820 } 821 822 private static int getCountOffset(int index) { 823 return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 824 } 825 826 private static int getDisplacementOffset(int index) { 827 return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE; 828 } 829 830 @Override 831 public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { 832 int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS; 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 private static class ArgInfoData extends ArrayData { 842 843 private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1); 844 845 public ArgInfoData() { 846 super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE); 847 } 848 } 849 850 public void setCompiledIRSize(int size) { 851 unsafe.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size); 852 } 853 854 public int getCompiledIRSize() { 855 return unsafe.getInt(metaspaceMethodData + config.methodDataIRSizeOffset); 856 } 857}