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