/*
* Copyright (c) 2013-2017 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.model.bytecode;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BCI;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BRANCH_COUNT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BRANCH_NOT_TAKEN;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BRANCH_PROB;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BRANCH_TAKEN;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_CODE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_ID;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_KIND;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_METHOD;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_NAME;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_PREALLOCATED;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_REASON;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_TYPE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_NEWLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_BYTECODE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_DOT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_PARSE_HIR;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_SLASH;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_ASSERT_NULL;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_BC;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_BRANCH;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_CALL;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_CAST_UP;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_COMMENT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_DEPENDENCY;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_DIRECT_CALL;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_ELIMINATE_ALLOCATION;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_ELIMINATE_LOCK;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_HOT_THROW;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_INLINE_FAIL;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_INLINE_SUCCESS;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_INTRINSIC;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_JVMS;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_KLASS;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_LATE_INLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_METHOD;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_OBSERVE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PARSE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PARSE_DONE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PHASE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PHASE_DONE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PREDICTED_CALL;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_TYPE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_UNCOMMON_TRAP;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_VIRTUAL_CALL;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.adoptopenjdk.jitwatch.compilation.AbstractCompilationVisitable;
import org.adoptopenjdk.jitwatch.compilation.CompilationUtil;
import org.adoptopenjdk.jitwatch.model.AnnotationException;
import org.adoptopenjdk.jitwatch.model.BCIOpcodeMap;
import org.adoptopenjdk.jitwatch.model.Compilation;
import org.adoptopenjdk.jitwatch.model.IMetaMember;
import org.adoptopenjdk.jitwatch.model.IParseDictionary;
import org.adoptopenjdk.jitwatch.model.IReadOnlyJITDataModel;
import org.adoptopenjdk.jitwatch.model.LogParseException;
import org.adoptopenjdk.jitwatch.model.MetaClass;
import org.adoptopenjdk.jitwatch.model.PackageManager;
import org.adoptopenjdk.jitwatch.model.Tag;
import org.adoptopenjdk.jitwatch.util.ParseUtil;
import org.adoptopenjdk.jitwatch.util.TooltipUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BytecodeAnnotationBuilder extends AbstractCompilationVisitable
{
private static final Logger logger = LoggerFactory.getLogger(BytecodeAnnotationBuilder.class);
private IMetaMember currentMember;
private IReadOnlyJITDataModel model;
private BytecodeAnnotations bcAnnotations = new BytecodeAnnotations();
private boolean verifyBytecodeInstructions;
private boolean processAnnotationsForInlinedMethods;
private EnumSet<BCAnnotationType> allowedAnnotations;
private PackageManager packageManager;
private Set<Tag> unhandledTags = new HashSet<>();
public BytecodeAnnotationBuilder(boolean verifyBytecodeInstructions)
{
this(verifyBytecodeInstructions, false);
}
public BytecodeAnnotationBuilder(boolean verifyBytecodeInstructions, boolean processAnnotationsForInlinedMethods)
{
this.verifyBytecodeInstructions = verifyBytecodeInstructions;
this.processAnnotationsForInlinedMethods = processAnnotationsForInlinedMethods;
ignoreTags.add(TAG_KLASS);
ignoreTags.add(TAG_TYPE);
ignoreTags.add(TAG_DEPENDENCY);
ignoreTags.add(TAG_PHASE);
ignoreTags.add(TAG_PARSE_DONE);
ignoreTags.add(TAG_DIRECT_CALL);
ignoreTags.add(TAG_PARSE);
ignoreTags.add(TAG_PHASE_DONE);
ignoreTags.add(TAG_PREDICTED_CALL);
ignoreTags.add(TAG_OBSERVE);
ignoreTags.add(TAG_ASSERT_NULL);
ignoreTags.add(TAG_CAST_UP);
ignoreTags.add(TAG_COMMENT);
}
public BytecodeAnnotations buildBytecodeAnnotations(final IMetaMember member, int compilationIndex, IReadOnlyJITDataModel model)
throws AnnotationException
{
return buildBytecodeAnnotations(member, compilationIndex, model, EnumSet.allOf(BCAnnotationType.class));
}
public BytecodeAnnotations buildBytecodeAnnotations(final IMetaMember member, int compilationIndex, IReadOnlyJITDataModel model,
EnumSet<BCAnnotationType> allowedAnnotations) throws AnnotationException
{
this.currentMember = member;
this.model = model;
this.allowedAnnotations = allowedAnnotations;
this.packageManager = model.getPackageManager();
bcAnnotations.clear();
String vmVersion = model.getVmVersionRelease();
if (member != null)
{
if (!member.isCompiled())
{
return bcAnnotations;
}
Compilation compilation = member.getCompilation(compilationIndex);
try
{
buildParseTagAnnotations(vmVersion, compilation);
buildEliminationTagAnnotations(vmVersion, compilation);
}
catch (LogParseException e)
{
logger.error("Error building bytecode annotations", e);
Throwable cause = e.getCause();
if (cause != null)
{
logger.error("Cause", cause);
if (cause instanceof AnnotationException)
{
throw (AnnotationException) cause;
}
}
}
}
return bcAnnotations;
}
private void buildParseTagAnnotations(String vmVersion, Compilation compilation) throws LogParseException
{
CompilationUtil.visitParseTagsOfCompilation(compilation, this);
}
private void buildEliminationTagAnnotations(String vmVersion, Compilation compilation) throws LogParseException
{
if (vmVersion != null && vmVersion.startsWith("1.9"))
{
CompilationUtil.visitEliminationTagsOfCompilation(compilation, this);
}
else
{
CompilationUtil.visitOptimizerTagsOfCompilation(compilation, this);
}
}
@Override
public void visitTag(Tag tag, IParseDictionary parseDictionary) throws LogParseException
{
switch (tag.getName())
{
case TAG_PARSE:
visitTagParse(tag, parseDictionary);
break;
case TAG_ELIMINATE_ALLOCATION:
visitTagEliminateAllocation(tag, parseDictionary);
break;
case TAG_ELIMINATE_LOCK:
visitTagEliminateLock(tag, parseDictionary);
break;
default:
handleOther(tag);
break;
}
}
private void visitTagParse(Tag tagParse, IParseDictionary parseDictionary) throws LogParseException
{
String methodID = tagParse.getAttributes().get(ATTR_METHOD);
if (CompilationUtil.memberMatchesMethodID(currentMember, methodID, parseDictionary))
{
try
{
buildParseTagAnnotations(tagParse, bcAnnotations, parseDictionary);
}
catch (Exception e)
{
throw new LogParseException("Could not parse annotations", e);
}
}
else
{
if (!isLateInline(tagParse))
{
logger.warn("Parse tag does not appear to be for member {}", currentMember.getMemberName());
logger.warn("Method ID: {}\nTag was:\n{}", methodID, tagParse.toString(true));
logger.warn("Dictionary:\n{}", parseDictionary.toString());
}
}
}
private boolean isLateInline(Tag parseTag)
{
boolean result = false;
if (parseTag != null)
{
Tag parent = parseTag.getParent();
if (parent != null)
{
String parseTagMethod = parseTag.getAttributes().get(ATTR_METHOD);
List<Tag> lateInlines = parent.getNamedChildren(TAG_LATE_INLINE);
for (Tag lateInline : lateInlines)
{
String method = lateInline.getAttributes().get(ATTR_METHOD);
if (method != null && method.equals(parseTagMethod))
{
result = true;
break;
}
}
}
}
return result;
}
private void visitTagEliminateAllocation(Tag tagEliminateAllocation, IParseDictionary parseDictionary)
{
List<Tag> childrenJVMS = tagEliminateAllocation.getNamedChildren(TAG_JVMS);
String typeID = tagEliminateAllocation.getAttributes().get(ATTR_TYPE);
String typeOrKlassName = null;
if (typeID != null)
{
typeOrKlassName = ParseUtil.lookupType(typeID, parseDictionary);
if (typeOrKlassName != null)
{
for (Tag tagJVMS : childrenJVMS)
{
Map<String, String> tagJVMSAttributes = tagJVMS.getAttributes();
String attrBCI = tagJVMSAttributes.get(ATTR_BCI);
int bciValue = 0;
if (attrBCI != null)
{
try
{
bciValue = Integer.parseInt(attrBCI);
}
catch (NumberFormatException nfe)
{
logger.error("Couldn't parse bci attribute {} tag {}", attrBCI, tagJVMS.toString(true));
continue;
}
}
else
{
logger.error("Missing bci attribute on tag {}", tagJVMS.toString(true));
}
String methodID = tagJVMSAttributes.get(ATTR_METHOD);
BCIOpcodeMap bciOpcodeMap = parseDictionary.getBCIOpcodeMap(methodID);
//logger.info("method {} {} {}", methodID, parseDictionary.getParseMethod(), bciOpcodeMap.entrySet());
if (CompilationUtil.memberMatchesMethodID(currentMember, methodID, parseDictionary))
{
storeEliminatedAllocation(currentMember, bciValue, typeOrKlassName, bciOpcodeMap);
}
else if (processAnnotationsForInlinedMethods)
{
IMetaMember inlinedMember = findMemberForInlinedMethod(tagJVMS, parseDictionary);
if (inlinedMember != null)
{
storeEliminatedAllocation(inlinedMember, bciValue, typeOrKlassName, bciOpcodeMap);
}
else
{
unhandledTags.add(tagJVMS);
}
}
}
}
else
{
logger.error("Unknown type attribute {} on tag {}", typeID, tagEliminateAllocation.toString(true));
}
}
else
{
logger.error("Missing type attribute on tag {}", tagEliminateAllocation.toString(true));
}
}
private void storeEliminatedAllocation(IMetaMember member, int bciValue, String typeOrKlassName, BCIOpcodeMap bciOpcodeMap)
{
Object referencedObject = null;
MetaClass eliminatedMetaClass = packageManager.getMetaClass(typeOrKlassName);
if (eliminatedMetaClass != null)
{
referencedObject = eliminatedMetaClass;
}
else
{
referencedObject = typeOrKlassName;
}
Opcode opcode = bciOpcodeMap.get(bciValue);
boolean isInlined = (opcode != null && opcode.isInvoke());
String annotation = buildEliminatedAllocationAnnotation(typeOrKlassName, isInlined);
putAnnotation(member, bciValue, new LineAnnotation(annotation, BCAnnotationType.ELIMINATED_ALLOCATION, referencedObject));
}
private IMetaMember findMemberForInlinedMethod(Tag tagJVMS, IParseDictionary parseDictionary)
{
IMetaMember member = null;
String methodID = tagJVMS.getAttributes().get(ATTR_METHOD);
if (methodID != null)
{
member = ParseUtil.lookupMember(methodID, parseDictionary, model);
}
return member;
}
private void putAnnotation(IMetaMember member, int bci, LineAnnotation annotation)
{
if (allowedAnnotations.contains(annotation.getType()))
{
bcAnnotations.addAnnotation(member, bci, annotation);
}
}
private void visitTagEliminateLock(Tag tagEliminateLock, IParseDictionary parseDictionary)
{
String kind = tagEliminateLock.getAttributes().get(ATTR_KIND);
List<Tag> childrenJVMS = tagEliminateLock.getNamedChildren(TAG_JVMS);
if (childrenJVMS.size() > 0)
{
for (Tag tagJVMS : childrenJVMS)
{
Map<String, String> tagJVMSAttributes = tagJVMS.getAttributes();
String attrBCI = tagJVMSAttributes.get(ATTR_BCI);
int bciValue = 0;
if (attrBCI != null)
{
try
{
bciValue = Integer.parseInt(attrBCI);
}
catch (NumberFormatException nfe)
{
logger.error("Couldn't parse bci attribute {} tag {}", attrBCI, tagJVMS.toString(true));
continue;
}
}
else
{
logger.error("Missing bci attribute on tag {}", tagJVMS.toString(true));
}
String methodID = tagJVMSAttributes.get(ATTR_METHOD);
BCIOpcodeMap bciOpcodeMap = parseDictionary.getBCIOpcodeMap(methodID);
//logger.info("current {} methodID {} parseMethod {}", currentMember.toStringUnqualifiedMethodName(true, true), methodID, parseDictionary.getParseMethod());
if (CompilationUtil.memberMatchesMethodID(currentMember, methodID, parseDictionary))
{
storeElidedLock(currentMember, bciValue, kind, bciOpcodeMap);
}
else if (processAnnotationsForInlinedMethods)
{
IMetaMember inlinedMember = findMemberForInlinedMethod(tagJVMS, parseDictionary);
if (inlinedMember != null)
{
storeElidedLock(inlinedMember, bciValue, kind, bciOpcodeMap);
}
else
{
unhandledTags.add(tagJVMS);
}
}
} // end for
}
}
private void storeElidedLock(IMetaMember member, int bciValue, String kind, BCIOpcodeMap bciOpcodeMap)
{
Opcode opcode = bciOpcodeMap.get(bciValue);
boolean isInlined = (opcode != null && opcode.isInvoke());
String annotation = buildElidedLockAnnotation(isInlined);
putAnnotation(member, bciValue, new LineAnnotation(annotation, BCAnnotationType.LOCK_ELISION, kind));
}
private String buildElidedLockAnnotation(boolean isInlined)
{
StringBuilder builder = new StringBuilder();
if (isInlined)
{
builder.append("A lock was eliminated due to inlining at this bci");
}
else
{
builder.append("A lock was eliminated at this bci");
}
return builder.toString();
}
private void visitTagUncommonTrap(Tag tag)
{
UncommonTrap trap = UncommonTrap.parse(tag);
if (trap != null)
{
putAnnotation(currentMember, trap.getBCI(), new LineAnnotation(trap.toString(), BCAnnotationType.UNCOMMON_TRAP));
}
}
private void buildParseTagAnnotations(Tag parseTag, BytecodeAnnotations annotations, IParseDictionary parseDictionary)
throws AnnotationException
{
// Only interested in annotating the current method so
// do not recurse into method or parse tags
if (DEBUG_LOGGING)
{
logger.debug("Building parse tag annotations");
}
List<Tag> children = parseTag.getChildren();
int currentBytecode = -1;
Map<String, Map<String, String>> methodAttrs = new HashMap<>();
Map<String, String> callAttrs = new HashMap<>();
Map<String, String> lastMethodAttrs = new HashMap<>();
String currentMethodID = parseTag.getAttributes().get(ATTR_METHOD);
BytecodeInstruction currentInstruction = null;
for (Tag child : children)
{
String name = child.getName();
Map<String, String> tagAttrs = child.getAttributes();
if (DEBUG_LOGGING_BYTECODE)
{
logger.debug("Examining child tag {}", child);
}
switch (name)
{
case TAG_BC:
{
String bciAttr = tagAttrs.get(ATTR_BCI);
String codeAttr = tagAttrs.get(ATTR_CODE);
currentBytecode = Integer.parseInt(bciAttr);
int code = Integer.parseInt(codeAttr);
callAttrs.clear();
if (DEBUG_LOGGING_BYTECODE)
{
logger.debug("BC Tag {} {}", currentBytecode, code);
}
currentInstruction = getInstructionAtIndex(currentBytecode);
if (DEBUG_LOGGING_BYTECODE)
{
logger.debug("Instruction at {} is {}", currentBytecode, currentInstruction);
}
break;
}
case TAG_CALL:
{
callAttrs.clear();
callAttrs.putAll(tagAttrs);
lastMethodAttrs.clear();
String calleeId = tagAttrs.get("method");
if (calleeId != null)
{
Map<String, String> calleeAttrs = methodAttrs.get(calleeId);
if (calleeAttrs != null)
{
lastMethodAttrs.putAll(calleeAttrs);
}
}
break;
}
case TAG_METHOD:
{
String methodId = tagAttrs.get("id");
if (methodId != null)
{
methodAttrs.put(methodId, tagAttrs);
}
break;
}
case TAG_INLINE_SUCCESS:
{
if (!sanityCheckInline(currentInstruction))
{
throw new AnnotationException("Expected an invoke instruction (in INLINE_SUCCESS)", currentBytecode,
currentInstruction);
}
String reason = tagAttrs.get(ATTR_REASON);
String annotationText = buildInlineAnnotation(parseDictionary, lastMethodAttrs, callAttrs, reason, true);
IMetaMember inlinedMember = ParseUtil.lookupMember(lastMethodAttrs.get(ATTR_ID), parseDictionary, model);
LineAnnotation lineAnnotation = new LineAnnotation(annotationText, BCAnnotationType.INLINE_SUCCESS, inlinedMember);
putAnnotation(currentMember, currentBytecode, lineAnnotation);
break;
}
case TAG_INLINE_FAIL:
{
if (!sanityCheckInline(currentInstruction))
{
throw new AnnotationException("Expected an invoke instruction (in INLINE_FAIL)", currentBytecode,
currentInstruction);
}
String reason = tagAttrs.get(ATTR_REASON);
String annotationText = buildInlineAnnotation(parseDictionary, lastMethodAttrs, callAttrs, reason, false);
IMetaMember inlinedMember = ParseUtil.lookupMember(lastMethodAttrs.get(ATTR_ID), parseDictionary, model);
LineAnnotation lineAnnotation = new LineAnnotation(annotationText, BCAnnotationType.INLINE_FAIL, inlinedMember);
putAnnotation(currentMember, currentBytecode, lineAnnotation);
break;
}
case TAG_BRANCH:
{
if (!sanityCheckBranch(currentInstruction))
{
throw new AnnotationException("Expected a branch instruction (BRANCH)", currentBytecode, currentInstruction);
}
String branchAnnotation = buildBranchAnnotation(tagAttrs);
putAnnotation(currentMember, currentBytecode, new LineAnnotation(branchAnnotation, BCAnnotationType.BRANCH));
break;
}
case TAG_INTRINSIC:
{
if (!sanityCheckIntrinsic(currentInstruction))
{
throw new AnnotationException("Expected an invoke instruction (INTRINSIC)", currentBytecode,
currentInstruction);
}
StringBuilder reason = new StringBuilder();
reason.append("Intrinsic: ").append(tagAttrs.get(ATTR_ID));
putAnnotation(currentMember, currentBytecode,
new LineAnnotation(reason.toString(), BCAnnotationType.INTRINSIC_USED));
break;
}
case TAG_UNCOMMON_TRAP:
{
String trapMethod = child.getAttributes().get(ATTR_METHOD);
if (trapMethod == null || currentMethodID.equals(trapMethod))
{
visitTagUncommonTrap(child);
}
break;
}
case TAG_PHASE:
{
String phaseName = tagAttrs.get(ATTR_NAME);
if (S_PARSE_HIR.equals(phaseName))
{
buildParseTagAnnotations(child, annotations, parseDictionary);
}
else
{
logger.warn("Don't know how to handle phase {}", phaseName);
}
break;
}
case TAG_VIRTUAL_CALL:
putAnnotation(currentMember, currentBytecode,
new LineAnnotation("Virtual call, not inlined", BCAnnotationType.VIRTUAL_CALL));
break;
case TAG_HOT_THROW:
{
MemberBytecode memberBytecode = currentMember.getMemberBytecode();
if (memberBytecode != null)
{
ExceptionTable exceptionTable = memberBytecode.getExceptionTable();
if (exceptionTable != null)
{
ExceptionTableEntry entry = exceptionTable.getEntryForBCI(currentBytecode);
if (entry != null)
{
int exceptionBCI = entry.getTarget();
String exceptionType = entry.getType();
String preallocated = child.getAttributes().get(ATTR_PREALLOCATED);
StringBuilder reason = new StringBuilder();
reason.append(exceptionType.replaceAll(S_SLASH, S_DOT)).append(" thrown by this operation");
BCAnnotationType annotationType;
if (preallocated != null && "1".equals(preallocated))
{
reason.append(" has been pre-allocated.");
annotationType = BCAnnotationType.HOT_THROW_PREALLOCATED;
}
else
{
reason.append(" was not pre-allocated.");
annotationType = BCAnnotationType.HOT_THROW_NOT_PREALLOCATED;
}
putAnnotation(currentMember, exceptionBCI, new LineAnnotation(reason.toString(), annotationType));
}
}
else
{
logger.warn("No ExceptionTable found for {}", currentMember);
}
}
else
{
logger.warn("No MemberBytecode found for {}", currentMember);
}
break;
}
default:
handleOther(child);
break;
}
}
}
private String buildInlineAnnotation(IParseDictionary parseDictionary, Map<String, String> methodAttrs,
Map<String, String> callAttrs, String reason, boolean inlined)
{
return TooltipUtil.buildInlineAnnotationText(inlined, reason, callAttrs, methodAttrs, parseDictionary);
}
private String buildEliminatedAllocationAnnotation(String typeOrKlassName, boolean isInlined)
{
StringBuilder builder = new StringBuilder();
if (isInlined)
{
builder.append("Heap allocation");
if (typeOrKlassName != null)
{
builder.append(" of type ").append(typeOrKlassName);
}
builder.append(S_NEWLINE).append("was eliminated due to inlining at this bci");
}
else
{
builder.append("Object");
if (typeOrKlassName != null)
{
builder.append(" of type ").append(typeOrKlassName);
}
builder.append(" does not escape method.\n");
builder.append("Heap allocation has been eliminated.\n");
}
return builder.toString();
}
private String buildBranchAnnotation(Map<String, String> tagAttrs)
{
String count = tagAttrs.get(ATTR_BRANCH_COUNT);
String taken = tagAttrs.get(ATTR_BRANCH_TAKEN);
String notTaken = tagAttrs.get(ATTR_BRANCH_NOT_TAKEN);
String prob = tagAttrs.get(ATTR_BRANCH_PROB);
StringBuilder reason = new StringBuilder();
if (count != null)
{
reason.append("Count: ").append(count).append(C_NEWLINE);
}
reason.append("Branch taken: ").append(taken).append(C_NEWLINE).append("Branch not taken: ").append(notTaken);
if (prob != null)
{
reason.append(C_NEWLINE).append("Taken Probability: ").append(prob);
}
return reason.toString();
}
// used to detect if class file matches log file
// only these bytecode instruction should be at the offset
// for an inlining log statement
public boolean sanityCheckInline(BytecodeInstruction instr)
{
return verifyBytecodeInstructions ? sanityCheckInvoke(instr) : true;
}
public boolean sanityCheckIntrinsic(BytecodeInstruction instr)
{
return verifyBytecodeInstructions ? sanityCheckInvoke(instr) : true;
}
private boolean sanityCheckInvoke(BytecodeInstruction instr)
{
boolean sane = false;
if (instr != null)
{
sane = instr.getOpcode().isInvoke();
}
return sane;
}
public boolean sanityCheckBranch(BytecodeInstruction instr)
{
boolean sane = false;
if (instr != null)
{
sane = instr.getOpcode().getMnemonic().startsWith("if");
}
return verifyBytecodeInstructions ? sane : true;
}
private BytecodeInstruction getInstructionAtIndex(int index)
{
BytecodeInstruction found = null;
for (BytecodeInstruction instruction : currentMember.getInstructions())
{
if (instruction.getOffset() == index)
{
found = instruction;
break;
}
}
return found;
}
public Set<Tag> getUnhandledTags()
{
return unhandledTags;
}
}