package jdk.vm.ci.hotspot;
import static java.lang.String.format;
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
import java.util.Arrays;
import jdk.vm.ci.common.NativeImageReinitialize;
import jdk.internal.misc.Unsafe;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaMethodProfile;
import jdk.vm.ci.meta.JavaMethodProfile.ProfiledMethod;
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.JavaTypeProfile.ProfiledType;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.TriState;
final class HotSpotMethodData {
static final class VMState {
final HotSpotVMConfig config = config();
final HotSpotMethodDataAccessor noDataNoExceptionAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.FALSE);
final HotSpotMethodDataAccessor noDataExceptionPossiblyNotRecordedAccessor = new NoMethodData(this, config.dataLayoutNoTag, TriState.UNKNOWN);
final int noDataSize = cellIndexToOffset(0);
final int bitDataSize = cellIndexToOffset(0);
final int bitDataNullSeenFlag = 1 << config.bitDataNullSeenFlag;
final int counterDataSize = cellIndexToOffset(1);
final int counterDataCountOffset = cellIndexToOffset(config.methodDataCountOffset);
final int jumpDataSize = cellIndexToOffset(2);
final int takenCountOffset = cellIndexToOffset(config.jumpDataTakenOffset);
final int takenDisplacementOffset = cellIndexToOffset(config.jumpDataDisplacementOffset);
final int typeDataRowSize = cellsToBytes(config.receiverTypeDataReceiverTypeRowCellCount);
final int nonprofiledCountOffset = cellIndexToOffset(config.receiverTypeDataNonprofiledCountOffset);
final int typeDataFirstTypeOffset = cellIndexToOffset(config.receiverTypeDataReceiver0Offset);
final int typeDataFirstTypeCountOffset = cellIndexToOffset(config.receiverTypeDataCount0Offset);
final int typeCheckDataSize = cellIndexToOffset(2) + typeDataRowSize * config.typeProfileWidth;
final int virtualCallDataSize = cellIndexToOffset(2) + typeDataRowSize * (config.typeProfileWidth + config.methodProfileWidth);
final int virtualCallDataFirstMethodOffset = typeDataFirstTypeOffset + typeDataRowSize * config.typeProfileWidth;
final int virtualCallDataFirstMethodCountOffset = typeDataFirstTypeCountOffset + typeDataRowSize * config.typeProfileWidth;
final int retDataRowSize = cellsToBytes(3);
final int retDataSize = cellIndexToOffset(1) + retDataRowSize * config.bciProfileWidth;
final int branchDataSize = cellIndexToOffset(3);
final int notTakenCountOffset = cellIndexToOffset(config.branchDataNotTakenOffset);
final int arrayDataLengthOffset = cellIndexToOffset(config.arrayDataArrayLenOffset);
final int arrayDataStartOffset = cellIndexToOffset(config.arrayDataArrayStartOffset);
final int multiBranchDataSize = cellIndexToOffset(1);
final int multiBranchDataRowSizeInCells = config.multiBranchDataPerCaseCellCount;
final int multiBranchDataRowSize = cellsToBytes(multiBranchDataRowSizeInCells);
final int multiBranchDataFirstCountOffset = arrayDataStartOffset + cellsToBytes(0);
final int multiBranchDataFirstDisplacementOffset = arrayDataStartOffset + cellsToBytes(1);
final int argInfoDataSize = cellIndexToOffset(1);
final HotSpotMethodDataAccessor[] profileDataAccessors = {
null,
new BitData(this, config.dataLayoutBitDataTag),
new CounterData(this, config.dataLayoutCounterDataTag),
new JumpData(this, config.dataLayoutJumpDataTag),
new ReceiverTypeData(this, config.dataLayoutReceiverTypeDataTag),
new VirtualCallData(this, config.dataLayoutVirtualCallDataTag),
new RetData(this, config.dataLayoutRetDataTag),
new BranchData(this, config.dataLayoutBranchDataTag),
new MultiBranchData(this, config.dataLayoutMultiBranchDataTag),
new ArgInfoData(this, config.dataLayoutArgInfoDataTag),
new UnknownProfileData(this, config.dataLayoutCallTypeDataTag),
new VirtualCallTypeData(this, config.dataLayoutVirtualCallTypeDataTag),
new UnknownProfileData(this, config.dataLayoutParametersTypeDataTag),
new UnknownProfileData(this, config.dataLayoutSpeculativeTrapDataTag),
};
private boolean checkAccessorTags() {
int expectedTag = 0;
for (HotSpotMethodDataAccessor accessor : profileDataAccessors) {
if (expectedTag == 0) {
assert accessor == null;
} else {
assert accessor.tag == expectedTag : expectedTag + " != " + accessor.tag + " " + accessor;
}
expectedTag++;
}
return true;
}
private VMState() {
assert checkAccessorTags();
}
private static int truncateLongToInt(long value) {
return value > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) value;
}
private int computeFullOffset(int position, int offsetInBytes) {
return config.methodDataOopDataOffset + position + offsetInBytes;
}
private int cellIndexToOffset(int cells) {
return config.dataLayoutHeaderSize + cellsToBytes(cells);
}
private int cellsToBytes(int cells) {
return cells * config.dataLayoutCellSize;
}
@NativeImageReinitialize private static volatile VMState instance;
static VMState instance() {
VMState result = instance;
if (result == null) {
synchronized (VMState.class) {
result = instance;
if (result == null) {
instance = result = new VMState();
}
}
}
return result;
}
}
final long metaspaceMethodData;
private final HotSpotResolvedJavaMethodImpl method;
private final VMState state;
HotSpotMethodData(long metaspaceMethodData, HotSpotResolvedJavaMethodImpl method) {
this.metaspaceMethodData = metaspaceMethodData;
this.method = method;
this.state = VMState.instance();
}
private int normalDataSize() {
return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataDataSize);
}
private int () {
final int extraDataBase = state.config.methodDataOopDataOffset + normalDataSize();
final int extraDataLimit = UNSAFE.getInt(metaspaceMethodData + state.config.methodDataSize);
return extraDataLimit - extraDataBase;
}
public boolean hasNormalData() {
return normalDataSize() > 0;
}
public boolean () {
return extraDataSize() > 0;
}
public int () {
return normalDataSize();
}
public boolean isWithin(int position) {
return position >= 0 && position < normalDataSize() + extraDataSize();
}
public int getDeoptimizationCount(DeoptimizationReason reason) {
HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess();
int reasonIndex = metaAccess.convertDeoptReason(reason);
return UNSAFE.getByte(metaspaceMethodData + state.config.methodDataOopTrapHistoryOffset + reasonIndex) & 0xFF;
}
public int getOSRDeoptimizationCount(DeoptimizationReason reason) {
HotSpotMetaAccessProvider metaAccess = (HotSpotMetaAccessProvider) runtime().getHostJVMCIBackend().getMetaAccess();
int reasonIndex = metaAccess.convertDeoptReason(reason);
return UNSAFE.getByte(metaspaceMethodData + state.config.methodDataOopTrapHistoryOffset + state.config.deoptReasonOSROffset + reasonIndex) & 0xFF;
}
public int getDecompileCount() {
return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataDecompiles);
}
public int getOverflowRecompileCount() {
return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataOverflowRecompiles);
}
public int getOverflowTrapCount() {
return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataOverflowTraps);
}
public HotSpotMethodDataAccessor getNormalData(int position) {
if (position >= normalDataSize()) {
return null;
}
return getData(position);
}
public HotSpotMethodDataAccessor (int position) {
if (position >= normalDataSize() + extraDataSize()) {
return null;
}
HotSpotMethodDataAccessor data = getData(position);
if (data != null) {
return data;
}
return data;
}
public static HotSpotMethodDataAccessor getNoDataAccessor(boolean exceptionPossiblyNotRecorded) {
if (exceptionPossiblyNotRecorded) {
return VMState.instance().noDataExceptionPossiblyNotRecordedAccessor;
} else {
return VMState.instance().noDataNoExceptionAccessor;
}
}
private HotSpotMethodDataAccessor getData(int position) {
assert position >= 0 : "out of bounds";
final int tag = HotSpotMethodDataAccessor.readTag(state.config, this, position);
HotSpotMethodDataAccessor accessor = state.profileDataAccessors[tag];
assert accessor == null || accessor.getTag() == tag : "wrong data accessor " + accessor + " for tag " + tag;
return accessor;
}
int readUnsignedByte(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return UNSAFE.getByte(metaspaceMethodData + fullOffsetInBytes) & 0xFF;
}
int readUnsignedShort(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return UNSAFE.getShort(metaspaceMethodData + fullOffsetInBytes) & 0xFFFF;
}
private long readUnsignedInt(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes) & 0xFFFFFFFFL;
}
private int readUnsignedIntAsSignedInt(int position, int offsetInBytes) {
long value = readUnsignedInt(position, offsetInBytes);
return VMState.truncateLongToInt(value);
}
private int readInt(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return (int) UNSAFE.getAddress(metaspaceMethodData + fullOffsetInBytes);
}
private HotSpotResolvedJavaMethod readMethod(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return compilerToVM().getResolvedJavaMethod(null, metaspaceMethodData + fullOffsetInBytes);
}
private HotSpotResolvedObjectTypeImpl readKlass(int position, int offsetInBytes) {
long fullOffsetInBytes = state.computeFullOffset(position, offsetInBytes);
return compilerToVM().getResolvedJavaType(metaspaceMethodData + fullOffsetInBytes, false);
}
public boolean isProfileMature() {
return runtime().getCompilerToVM().isMature(metaspaceMethodData);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
String nl = String.format("%n");
String nlIndent = String.format("%n%38s", "");
sb.append("Raw method data for ");
sb.append(method.format("%H.%n(%p)"));
sb.append(":");
sb.append(nl);
sb.append(String.format("nof_decompiles(%d) nof_overflow_recompiles(%d) nof_overflow_traps(%d)%n",
getDecompileCount(), getOverflowRecompileCount(), getOverflowTrapCount()));
if (hasNormalData()) {
int pos = 0;
HotSpotMethodDataAccessor data;
while ((data = getNormalData(pos)) != null) {
if (pos != 0) {
sb.append(nl);
}
int bci = data.getBCI(this, pos);
sb.append(String.format("%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName()));
sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent));
pos = pos + data.getSize(this, pos);
}
}
if (hasExtraData()) {
int pos = getExtraDataBeginOffset();
HotSpotMethodDataAccessor data;
while ((data = getExtraData(pos)) != null) {
if (pos == getExtraDataBeginOffset()) {
sb.append(nl).append("--- Extra data:");
}
int bci = data.getBCI(this, pos);
sb.append(String.format("%n%-6d bci: %-6d%-20s", pos, bci, data.getClass().getSimpleName()));
sb.append(data.appendTo(new StringBuilder(), this, pos).toString().replace(nl, nlIndent));
pos = pos + data.getSize(this, pos);
}
}
return sb.toString();
}
static class NoMethodData extends HotSpotMethodDataAccessor {
private final TriState exceptionSeen;
protected NoMethodData(VMState state, int tag, TriState exceptionSeen) {
super(state, tag, state.noDataSize);
this.exceptionSeen = exceptionSeen;
}
@Override
public int getBCI(HotSpotMethodData data, int position) {
return -1;
}
@Override
public TriState getExceptionSeen(HotSpotMethodData data, int position) {
return exceptionSeen;
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
return sb;
}
}
static class BitData extends HotSpotMethodDataAccessor {
private BitData(VMState state, int tag) {
super(state, tag, state.bitDataSize);
}
protected BitData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public TriState getNullSeen(HotSpotMethodData data, int position) {
return TriState.get((getFlags(data, position) & state.bitDataNullSeenFlag) != 0);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
return sb.append(format("exception_seen(%s)", getExceptionSeen(data, pos)));
}
}
static class CounterData extends BitData {
CounterData(VMState state, int tag) {
super(state, tag, state.counterDataSize);
}
protected CounterData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
return getCounterValue(data, position);
}
protected int getCounterValue(HotSpotMethodData data, int position) {
return data.readUnsignedIntAsSignedInt(position, state.counterDataCountOffset);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos)));
}
}
static class JumpData extends HotSpotMethodDataAccessor {
JumpData(VMState state, int tag) {
super(state, tag, state.jumpDataSize);
}
protected JumpData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public double getBranchTakenProbability(HotSpotMethodData data, int position) {
return getExecutionCount(data, position) != 0 ? 1 : 0;
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
return data.readUnsignedIntAsSignedInt(position, state.takenCountOffset);
}
public int getTakenDisplacement(HotSpotMethodData data, int position) {
return data.readInt(position, state.takenDisplacementOffset);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
return sb.append(format("taken(%d) displacement(%d)", getExecutionCount(data, pos), getTakenDisplacement(data, pos)));
}
}
static class RawItemProfile<T> {
final int entries;
final T[] items;
final long[] counts;
final long totalCount;
RawItemProfile(int entries, T[] items, long[] counts, long totalCount) {
this.entries = entries;
this.items = items;
this.counts = counts;
this.totalCount = totalCount;
}
}
abstract static class AbstractTypeData extends CounterData {
protected AbstractTypeData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public JavaTypeProfile getTypeProfile(HotSpotMethodData data, int position) {
return createTypeProfile(getNullSeen(data, position), getRawTypeProfile(data, position));
}
private RawItemProfile<ResolvedJavaType> getRawTypeProfile(HotSpotMethodData data, int position) {
int typeProfileWidth = config.typeProfileWidth;
ResolvedJavaType[] types = new ResolvedJavaType[typeProfileWidth];
long[] counts = new long[typeProfileWidth];
long totalCount = 0;
int entries = 0;
outer: for (int i = 0; i < typeProfileWidth; i++) {
HotSpotResolvedObjectTypeImpl receiverKlass = data.readKlass(position, getTypeOffset(i));
if (receiverKlass != null) {
HotSpotResolvedObjectTypeImpl klass = receiverKlass;
long count = data.readUnsignedInt(position, getTypeCountOffset(i));
for (int j = 0; j < entries; j++) {
if (types[j].equals(klass)) {
totalCount += count;
counts[j] += count;
continue outer;
}
}
types[entries] = klass;
totalCount += count;
counts[entries] = count;
entries++;
}
}
totalCount += getTypesNotRecordedExecutionCount(data, position);
return new RawItemProfile<>(entries, types, counts, totalCount);
}
protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position);
public int getNonprofiledCount(HotSpotMethodData data, int position) {
return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset);
}
private JavaTypeProfile createTypeProfile(TriState nullSeen, RawItemProfile<ResolvedJavaType> profile) {
if (profile.entries <= 0 || profile.totalCount <= 0) {
return null;
}
ProfiledType[] ptypes = new ProfiledType[profile.entries];
double totalProbability = 0.0;
for (int i = 0; i < profile.entries; i++) {
double p = profile.counts[i];
p = p / profile.totalCount;
totalProbability += p;
ptypes[i] = new ProfiledType(profile.items[i], p);
}
Arrays.sort(ptypes);
double notRecordedTypeProbability = profile.entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
assert notRecordedTypeProbability == 0 || profile.entries == config.typeProfileWidth;
return new JavaTypeProfile(nullSeen, notRecordedTypeProbability, ptypes);
}
private int getTypeOffset(int row) {
return state.typeDataFirstTypeOffset + row * state.typeDataRowSize;
}
protected int getTypeCountOffset(int row) {
return state.typeDataFirstTypeCountOffset + row * state.typeDataRowSize;
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
RawItemProfile<ResolvedJavaType> profile = getRawTypeProfile(data, pos);
TriState nullSeen = getNullSeen(data, pos);
TriState exceptionSeen = getExceptionSeen(data, pos);
sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen,
getNonprofiledCount(data, pos), profile.entries));
for (int i = 0; i < profile.entries; i++) {
long count = profile.counts[i];
sb.append(format("%n %s (%d, %4.2f)", profile.items[i].toJavaName(), count, (double) count / profile.totalCount));
}
return sb;
}
}
static class ReceiverTypeData extends AbstractTypeData {
ReceiverTypeData(VMState state, int tag) {
super(state, tag, state.typeCheckDataSize);
}
protected ReceiverTypeData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
return -1;
}
@Override
protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
return getNonprofiledCount(data, position);
}
}
static class VirtualCallData extends ReceiverTypeData {
VirtualCallData(VMState state, int tag) {
super(state, tag, state.virtualCallDataSize);
}
protected VirtualCallData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
final int typeProfileWidth = config.typeProfileWidth;
long total = 0;
for (int i = 0; i < typeProfileWidth; i++) {
total += data.readUnsignedInt(position, getTypeCountOffset(i));
}
total += getCounterValue(data, position);
return VMState.truncateLongToInt(total);
}
@Override
protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) {
return getCounterValue(data, position);
}
private long getMethodsNotRecordedExecutionCount(HotSpotMethodData data, int position) {
return data.readUnsignedIntAsSignedInt(position, state.nonprofiledCountOffset);
}
@Override
public JavaMethodProfile getMethodProfile(HotSpotMethodData data, int position) {
return createMethodProfile(getRawMethodProfile(data, position));
}
private RawItemProfile<ResolvedJavaMethod> getRawMethodProfile(HotSpotMethodData data, int position) {
int profileWidth = config.methodProfileWidth;
ResolvedJavaMethod[] methods = new ResolvedJavaMethod[profileWidth];
long[] counts = new long[profileWidth];
long totalCount = 0;
int entries = 0;
for (int i = 0; i < profileWidth; i++) {
HotSpotResolvedJavaMethod method = data.readMethod(position, getMethodOffset(i));
if (method != null) {
methods[entries] = method;
long count = data.readUnsignedInt(position, getMethodCountOffset(i));
totalCount += count;
counts[entries] = count;
entries++;
}
}
totalCount += getMethodsNotRecordedExecutionCount(data, position);
if (entries == 1) {
counts[0] = totalCount;
}
return new RawItemProfile<>(entries, methods, counts, totalCount);
}
private JavaMethodProfile createMethodProfile(RawItemProfile<ResolvedJavaMethod> profile) {
if (profile.entries <= 0 || profile.totalCount <= 0) {
return null;
}
ProfiledMethod[] pmethods = new ProfiledMethod[profile.entries];
double totalProbability = 0.0;
for (int i = 0; i < profile.entries; i++) {
double p = profile.counts[i];
p = p / profile.totalCount;
totalProbability += p;
pmethods[i] = new ProfiledMethod(profile.items[i], p);
}
Arrays.sort(pmethods);
double notRecordedMethodProbability = profile.entries < config.methodProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
assert notRecordedMethodProbability == 0 || profile.entries == config.methodProfileWidth;
return new JavaMethodProfile(notRecordedMethodProbability, pmethods);
}
private int getMethodOffset(int row) {
return state.virtualCallDataFirstMethodOffset + row * state.typeDataRowSize;
}
private int getMethodCountOffset(int row) {
return state.virtualCallDataFirstMethodCountOffset + row * state.typeDataRowSize;
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
RawItemProfile<ResolvedJavaMethod> profile = getRawMethodProfile(data, pos);
super.appendTo(sb.append(format("exception_seen(%s) ", getExceptionSeen(data, pos))), data, pos).append(format("%nmethod_entries(%d)", profile.entries));
for (int i = 0; i < profile.entries; i++) {
long count = profile.counts[i];
sb.append(format("%n %s (%d, %4.2f)", profile.items[i].format("%H.%n(%p)"), count, (double) count / profile.totalCount));
}
return sb;
}
}
static class VirtualCallTypeData extends VirtualCallData {
VirtualCallTypeData(VMState state, int tag) {
super(state, tag, 0);
}
@Override
protected int getDynamicSize(HotSpotMethodData data, int position) {
assert staticSize == 0;
return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position);
}
}
static class RetData extends CounterData {
RetData(VMState state, int tag) {
super(state, tag, state.retDataSize);
}
}
static class BranchData extends JumpData {
BranchData(VMState state, int tag) {
super(state, tag, state.branchDataSize);
}
@Override
public double getBranchTakenProbability(HotSpotMethodData data, int position) {
long takenCount = data.readUnsignedInt(position, state.takenCountOffset);
long notTakenCount = data.readUnsignedInt(position, state.notTakenCountOffset);
long total = takenCount + notTakenCount;
return total <= 0 ? -1 : takenCount / (double) total;
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
long count = data.readUnsignedInt(position, state.takenCountOffset) + data.readUnsignedInt(position, state.notTakenCountOffset);
return VMState.truncateLongToInt(count);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
long taken = data.readUnsignedInt(pos, state.takenCountOffset);
long notTaken = data.readUnsignedInt(pos, state.notTakenCountOffset);
double takenProbability = getBranchTakenProbability(data, pos);
return sb.append(format("taken(%d, %4.2f) not_taken(%d, %4.2f) displacement(%d)", taken, takenProbability, notTaken, 1.0D - takenProbability, getTakenDisplacement(data, pos)));
}
}
static class ArrayData extends HotSpotMethodDataAccessor {
ArrayData(VMState state, int tag, int staticSize) {
super(state, tag, staticSize);
}
@Override
protected int getDynamicSize(HotSpotMethodData data, int position) {
return state.cellsToBytes(getLength(data, position));
}
protected int getLength(HotSpotMethodData data, int position) {
return data.readInt(position, state.arrayDataLengthOffset);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
return sb.append(format("length(%d)", getLength(data, pos)));
}
}
static class MultiBranchData extends ArrayData {
MultiBranchData(VMState state, int tag) {
super(state, tag, state.multiBranchDataSize);
}
@Override
public double[] getSwitchProbabilities(HotSpotMethodData data, int position) {
int arrayLength = getLength(data, position);
assert arrayLength > 0 : "switch must have at least the default case";
assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows";
int length = arrayLength / state.multiBranchDataRowSizeInCells;
long totalCount = 0;
double[] result = new double[length];
long count = readCount(data, position, 0);
totalCount += count;
result[length - 1] = count;
for (int i = 1; i < length; i++) {
count = readCount(data, position, i);
totalCount += count;
result[i - 1] = count;
}
if (totalCount <= 0) {
return null;
} else {
for (int i = 0; i < length; i++) {
result[i] = result[i] / totalCount;
}
return result;
}
}
private long readCount(HotSpotMethodData data, int position, int i) {
int offset;
long count;
offset = getCountOffset(i);
count = data.readUnsignedInt(position, offset);
return count;
}
@Override
public int getExecutionCount(HotSpotMethodData data, int position) {
int arrayLength = getLength(data, position);
assert arrayLength > 0 : "switch must have at least the default case";
assert arrayLength % state.multiBranchDataRowSizeInCells == 0 : "array must have full rows";
int length = arrayLength / state.multiBranchDataRowSizeInCells;
long totalCount = 0;
for (int i = 0; i < length; i++) {
int offset = getCountOffset(i);
totalCount += data.readUnsignedInt(position, offset);
}
return VMState.truncateLongToInt(totalCount);
}
private int getCountOffset(int index) {
return state.multiBranchDataFirstCountOffset + index * state.multiBranchDataRowSize;
}
private int getDisplacementOffset(int index) {
return state.multiBranchDataFirstDisplacementOffset + index * state.multiBranchDataRowSize;
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
int entries = getLength(data, pos) / state.multiBranchDataRowSizeInCells;
sb.append(format("entries(%d)", entries));
for (int i = 0; i < entries; i++) {
sb.append(format("%n %d: count(%d) displacement(%d)", i, data.readUnsignedInt(pos, getCountOffset(i)), data.readUnsignedInt(pos, getDisplacementOffset(i))));
}
return sb;
}
}
static class ArgInfoData extends ArrayData {
ArgInfoData(VMState state, int tag) {
super(state, tag, state.argInfoDataSize);
}
}
static class UnknownProfileData extends HotSpotMethodDataAccessor {
UnknownProfileData(VMState state, int tag) {
super(state, tag, 0);
}
@Override
protected int getDynamicSize(HotSpotMethodData data, int position) {
assert staticSize == 0;
return HotSpotJVMCIRuntime.runtime().compilerToVm.methodDataProfileDataSize(data.metaspaceMethodData, position);
}
@Override
public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) {
sb.append("unknown profile data with tag: " + tag);
return sb;
}
}
public void setCompiledIRSize(int size) {
UNSAFE.putInt(metaspaceMethodData + state.config.methodDataIRSizeOffset, size);
}
public int getCompiledIRSize() {
return UNSAFE.getInt(metaspaceMethodData + state.config.methodDataIRSizeOffset);
}
}