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