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