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
 583             // site. If it's a monomorphic call site, attribute all the counts to the first type (if
 584             // any is recorded).
 585             if (entries == 1) {
 586                 counts[0] = totalCount;
 587             }
 588 
 589             return new RawItemProfile<>(entries, methods, counts, totalCount);
 590         }
 591 
 592         private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) {
 593             if (profile.entries <= 0 || profile.totalCount <= 0) {
 594                 return null;
 595             }
 596 
 597             ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries];
 598             double totalProbability = 0.0;
 599             for (int i = 0; i < profile.entries; i++) {
 600                 double p = profile.counts[i];
 601                 p = p / profile.totalCount;
 602                 totalProbability += p;
 603                 pmethods[i] = new ProfiledMethod(profile.items[i], p);
 604             }
 605 
 606             Arrays.sort(pmethods);
 607 
 608             double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
 609             assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth;
 610             return new JavaMethodProfile(notRecordedMethodProbability, pmethods);
 611         }
 612 
 613         private static int getMethodOffset(int row) {
 614             return VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET + row * TYPE_DATA_ROW_SIZE;
 615         }
 616 
 617         private static int getMethodCountOffset(int row) {
 618             return VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET + row * TYPE_DATA_ROW_SIZE;
 619         }
 620 
 621         @Override
 622         public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
 623             RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos);
 624             super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries));
 625             for (int i = 0; i < profile.entries; i++) {
 626                 long count = profile.counts[i];
 627                 sb.append(format("%n  %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount));
 628             }
 629             return sb;
 630         }
 631     }
 632 
 633     static class VirtualCallTypeData extends VirtualCallData {
 634 
 635         VirtualCallTypeData(HotSpotVMConfig config, int tag) {
 636             super(config, tag, 0);
 637         }
 638 
 639         @Override
 640         protected int getDynamicSize(HotSpotMethodData data, int position) {
 641             assert staticSize == 0;
 642             return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position);
 643         }
 644     }
 645 
 646     static final int RET_DATA_ROW_SIZE = cellsToBytes(3);
 647     static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth;
 648 
 649     static class RetData extends CounterData {
 650 
 651         RetData(HotSpotVMConfig config, int tag) {
 652             super(config, tag, RET_DATA_SIZE);
 653         }
 654     }
 655 
 656     static final int BRANCH_DATA_SIZE = cellIndexToOffset(3);
 657     static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(config.branchDataNotTakenOffset);
 658 
 659     static class BranchData extends JumpData {
 660 
 661         BranchData(HotSpotVMConfig config, int tag) {
 662             super(config, tag, BRANCH_DATA_SIZE);
 663         }
 664 
 665         @Override
 666         public double getBranchTakenProbability(HotSpotMethodData data, int position) {
 667             long takenCount = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET);
 668             long notTakenCount = data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
 669             long total = takenCount + notTakenCount;
 670 
 671             return total <= 0 ? -1 : takenCount / (double) total;
 672         }
 673 
 674         @Override
 675         public int getExecutionCount(HotSpotMethodData data, int position) {
 676             long count = data.readUnsignedInt(position, TAKEN_COUNT_OFFSET) + data.readUnsignedInt(position, NOT_TAKEN_COUNT_OFFSET);
 677             return truncateLongToInt(count);
 678         }
 679 
 680         @Override
 681         public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
 682             long taken = data.readUnsignedInt(pos, TAKEN_COUNT_OFFSET);
 683             long notTaken = data.readUnsignedInt(pos, NOT_TAKEN_COUNT_OFFSET);
 684             double takenProbability = getBranchTakenProbability(data, pos);
 685             return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos)));
 686         }
 687     }
 688 
 689     static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(config.arrayDataArrayLenOffset);
 690     static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(config.arrayDataArrayStartOffset);
 691 
 692     static class ArrayData extends HotSpotMethodDataAccessor {
 693 
 694         ArrayData(HotSpotVMConfig config, int tag, int staticSize) {
 695             super(config, tag, staticSize);
 696         }
 697 
 698         @Override
 699         protected int getDynamicSize(HotSpotMethodData data, int position) {
 700             return cellsToBytes(getLength(data, position));
 701         }
 702 
 703         protected static int getLength(HotSpotMethodData data, int position) {
 704             return data.readInt(position, ARRAY_DATA_LENGTH_OFFSET);
 705         }
 706 
 707         @Override
 708         public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
 709             return sb.append(format("length(%d)", getLength(data, pos)));
 710         }
 711     }
 712 
 713     static final int MULTI_BRANCH_DATA_SIZE = cellIndexToOffset(1);
 714     static final int MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS = config.multiBranchDataPerCaseCellCount;
 715     static final int MULTI_BRANCH_DATA_ROW_SIZE = cellsToBytes(MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS);
 716     static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0);
 717     static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1);
 718 
 719     static class MultiBranchData extends ArrayData {
 720 
 721         MultiBranchData(HotSpotVMConfig config, int tag) {
 722             super(config, tag, MULTI_BRANCH_DATA_SIZE);
 723         }
 724 
 725         @Override
 726         public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
 727             int arrayLength = getLength(data, position);
 728             assert arrayLength > 0 : "switch must have at least the default case";
 729             assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows";
 730 
 731             int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
 732             long totalCount = 0;
 733             double[] result = new double[length];
 734 
 735             // default case is first in HotSpot but last for the compiler
 736             long count = readCount(data, position, 0);
 737             totalCount += count;
 738             result[length - 1] = count;
 739 
 740             for (int i = 1; i < length; i++) {
 741                 count = readCount(data, position, i);
 742                 totalCount += count;
 743                 result[i - 1] = count;
 744             }
 745 
 746             if (totalCount <= 0) {
 747                 return null;
 748             } else {
 749                 for (int i = 0; i < length; i++) {
 750                     result[i] = result[i] / totalCount;
 751                 }
 752                 return result;
 753             }
 754         }
 755 
 756         private static long readCount(HotSpotMethodData data, int position, int i) {
 757             int offset;
 758             long count;
 759             offset = getCountOffset(i);
 760             count = data.readUnsignedInt(position, offset);
 761             return count;
 762         }
 763 
 764         @Override
 765         public int getExecutionCount(HotSpotMethodData data, int position) {
 766             int arrayLength = getLength(data, position);
 767             assert arrayLength > 0 : "switch must have at least the default case";
 768             assert arrayLength % MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS == 0 : "array must have full rows";
 769 
 770             int length = arrayLength / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
 771             long totalCount = 0;
 772             for (int i = 0; i < length; i++) {
 773                 int offset = getCountOffset(i);
 774                 totalCount += data.readUnsignedInt(position, offset);
 775             }
 776 
 777             return truncateLongToInt(totalCount);
 778         }
 779 
 780         private static int getCountOffset(int index) {
 781             return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
 782         }
 783 
 784         private static int getDisplacementOffset(int index) {
 785             return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
 786         }
 787 
 788         @Override
 789         public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
 790             int entries = getLength(data, pos) / MULTI_BRANCH_DATA_ROW_SIZE_IN_CELLS;
 791             sb.append(format("entries(%d)", entries));
 792             for (int i = 0; i < entries; i++) {
 793                 sb.append(format("%n  %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i))));
 794             }
 795             return sb;
 796         }
 797     }
 798 
 799     static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1);
 800 
 801     static class ArgInfoData extends ArrayData {
 802 
 803         ArgInfoData(HotSpotVMConfig config, int tag) {
 804             super(config, tag, ARG_INFO_DATA_SIZE);
 805         }
 806     }
 807 
 808     static class UnknownProfileData extends HotSpotMethodDataAccessor {
 809         UnknownProfileData(HotSpotVMConfig config, int tag) {
 810             super(config, tag, 0);
 811         }
 812 
 813         @Override
 814         protected int getDynamicSize(HotSpotMethodData data, int position) {
 815             assert staticSize == 0;
 816             return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position);
 817         }
 818 
 819         @Override
 820         public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
 821             sb.append("unknown profile data with tag: " + tag);
 822             return sb;
 823         }
 824     }
 825 
 826     public void setCompiledIRSize(int size) {
 827         UNSAFE.putInt(metaspaceMethodData + config.methodDataIRSizeOffset, size);
 828     }
 829 
 830     public int getCompiledIRSize() {
 831         return UNSAFE.getInt(metaspaceMethodData + config.methodDataIRSizeOffset);
 832     }
 833 
 834     // sorted by tag
 835     // @formatter:off
 836     static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = {
 837         null,
 838         new BitData(config, config.dataLayoutBitDataTag),
 839         new CounterData(config, config.dataLayoutCounterDataTag),
 840         new JumpData(config, config.dataLayoutJumpDataTag),
 841         new ReceiverTypeData(config, config.dataLayoutReceiverTypeDataTag),
 842         new VirtualCallData(config, config.dataLayoutVirtualCallDataTag),
 843         new RetData(config, config.dataLayoutRetDataTag),
 844         new BranchData(config, config.dataLayoutBranchDataTag),
 845         new MultiBranchData(config, config.dataLayoutMultiBranchDataTag),
 846         new ArgInfoData(config, config.dataLayoutArgInfoDataTag),
 847         new UnknownProfileData(config, config.dataLayoutCallTypeDataTag),
 848         new VirtualCallTypeData(config, config.dataLayoutVirtualCallTypeDataTag),
 849         new UnknownProfileData(config, config.dataLayoutParametersTypeDataTag),
 850         new UnknownProfileData(config, config.dataLayoutSpeculativeTrapDataTag),
 851     };
 852 
 853     private static boolean checkAccessorTags() {
 854         int expectedTag = 0;
 855         for (HotSpotMethodDataAccessor accessor : PROFILE_DATA_ACCESSORS) {
 856             if (expectedTag == 0) {
 857                 assert accessor == null;
 858             } else {
 859                 assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor;
 860             }
 861             expectedTag++;
 862         }
 863         return true;
 864     }
 865 
 866     static {
 867         assert checkAccessorTags();
 868     }
 869     // @formatter:on
 870 }