org.adoptopenjdk.jitwatch.model.assembly.AssemblyInstruction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jitwatch-jarscan-maven-plugin Show documentation
Show all versions of jitwatch-jarscan-maven-plugin Show documentation
A Maven plugin that scans the project artifact and its dependencies for methods that cannot be inlined by the JIT
compiler. It uses the JarScan utility from the JITWatch project to do that.
See https://github.com/AdoptOpenJDK/jitwatch .
/*
* Copyright (c) 2013, 2014 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.assembly;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_COLON;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SPACE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_ASSEMBLY;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_ASSEMBLY_ADDRESS;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_COMMA;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_DOUBLE_SPACE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_OPTIMIZED_VIRTUAL_CALL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.adoptopenjdk.jitwatch.optimizedvcall.VirtualCallSite;
import org.adoptopenjdk.jitwatch.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AssemblyInstruction
{
private String annotation;
private long address;
private String modifier;
private String mnemonic;
private List operands = new ArrayList<>();
private List commentLines = new ArrayList<>();
private final AssemblyLabels labels;
private static final Pattern PATTERN_ASSEMBLY_CALL_SIG = Pattern.compile("^; - (.*)::(.*)@(.*)\\s\\(line\\s(.*)\\)");
private static final Logger logger = LoggerFactory.getLogger(AssemblyInstruction.class);
public AssemblyInstruction(String annotation, long address, String modifier, String mnemonic, List operands,
String firstComment, AssemblyLabels labels)
{
this.annotation = annotation;
this.address = address;
this.modifier = modifier;
this.mnemonic = mnemonic;
this.operands = operands;
this.labels = labels;
if (firstComment != null)
{
this.commentLines.add(firstComment.trim());
}
}
public String getAnnotation()
{
return annotation;
}
public long getAddress()
{
return address;
}
public String getModifier()
{
return modifier;
}
public String getMnemonic()
{
return mnemonic;
}
public List getOperands()
{
return operands;
}
public String getComment()
{
StringBuilder builder = new StringBuilder();
if (commentLines.size() > 0)
{
for (String line : commentLines)
{
builder.append(line).append(S_NEWLINE);
}
builder.deleteCharAt(builder.length() - 1);
}
return builder.toString();
}
public List getCommentLines()
{
return commentLines;
}
public void addCommentLine(String comment)
{
if (comment != null)
{
commentLines.add(comment);
}
}
public void appendToLastCommentLine(String comment)
{
if (comment != null)
{
String lastCommentLine = commentLines.get(commentLines.size() - 1);
commentLines.set(commentLines.size() - 1, lastCommentLine + comment);
}
}
public boolean isOptimizedVCall()
{
boolean result = false;
int commentLineCount = commentLines.size();
if (commentLineCount > 1)
{
String lastLine = commentLines.get(commentLineCount - 1);
if (lastLine.contains(S_OPTIMIZED_VIRTUAL_CALL))
{
result = true;
}
}
return result;
}
public VirtualCallSite getOptimizedVirtualCallSiteOrNull()
{
VirtualCallSite result = null;
if (isOptimizedVCall())
{
// Oop comment
// *invoke comment
// callsite comment+
// optimized virtual_call
String callSiteCommentLine = commentLines.get(2);
Matcher matcher = PATTERN_ASSEMBLY_CALL_SIG.matcher(callSiteCommentLine);
if (matcher.find())
{
String className = matcher.group(1);
String methodName = matcher.group(2);
String bytecodeOffset = matcher.group(3);
String lineNumber = matcher.group(4);
try
{
result = new VirtualCallSite(className, methodName, Integer.parseInt(bytecodeOffset),
Integer.parseInt(lineNumber));
}
catch (NumberFormatException nfe)
{
if (DEBUG_LOGGING_ASSEMBLY)
{
logger.warn("Could not parse CallSite from line: {}", callSiteCommentLine);
}
}
}
}
return result;
}
@Override
public String toString()
{
return toString(0, false);
}
public String toString(int annoWidth, boolean useLocalLabels)
{
StringBuilder builder = new StringBuilder();
builder.append(StringUtil.alignLeft(annotation, annoWidth));
if (useLocalLabels)
{
labels.formatAddress(address, builder);
}
else
{
builder.append(S_ASSEMBLY_ADDRESS).append(StringUtil.pad(Long.toHexString(address), 16, '0', true));
}
builder.append(C_COLON).append(C_SPACE);
if (modifier != null)
{
builder.append(modifier);
builder.append(C_SPACE);
}
builder.append(mnemonic);
if (useLocalLabels)
{
labels.formatOperands(this, builder);
}
else
{
if (operands.size() > 0)
{
builder.append(C_SPACE);
for (String op : operands)
{
builder.append(op).append(S_COMMA);
}
builder.deleteCharAt(builder.length() - 1);
}
}
int lineLength = builder.length();
if (commentLines.size() > 0)
{
boolean first = true;
for (String commentLine : commentLines)
{
if (first)
{
builder.append(S_DOUBLE_SPACE).append(commentLine).append(S_NEWLINE);
first = false;
}
else
{
builder.append(StringUtil.repeat(C_SPACE, lineLength + 2));
builder.append(commentLine).append(S_NEWLINE);
}
}
}
else
{
builder.append(S_NEWLINE);
}
return StringUtil.rtrim(builder.toString());
}
// Allow splitting an instruction with a multi-line comment across multiple
// labels which all contain the instruction
public String toString(int annoWidth, int line, boolean useLocalLabels)
{
StringBuilder builder = new StringBuilder();
builder.append(StringUtil.alignLeft(annotation, annoWidth));
if (useLocalLabels)
{
labels.formatAddress(address, builder);
}
else
{
builder.append(S_ASSEMBLY_ADDRESS).append(StringUtil.pad(Long.toHexString(address), 16, '0', true));
}
builder.append(C_COLON).append(C_SPACE);
if (modifier != null)
{
builder.append(modifier);
builder.append(C_SPACE);
}
builder.append(mnemonic);
if (useLocalLabels)
{
labels.formatOperands(this, builder);
}
else
{
if (operands.size() > 0)
{
builder.append(C_SPACE);
for (String op : operands)
{
builder.append(op).append(S_COMMA);
}
builder.deleteCharAt(builder.length() - 1);
}
}
int lineLength = builder.length();
if (commentLines.size() > 0)
{
if (line == 0)
{
// first comment on same line as instruction
builder.append(S_DOUBLE_SPACE).append(commentLines.get(0)).append(S_NEWLINE);
}
else
{
// later comments on own line
builder.delete(0, builder.length());
builder.append(StringUtil.repeat(C_SPACE, lineLength + 2));
builder.append(commentLines.get(line)).append(S_NEWLINE);
}
}
else
{
builder.append(S_NEWLINE);
}
return StringUtil.rtrim(builder.toString());
}
}