comparison jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java @ 22672:1bbd4a7c274b

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