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