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