/*
* Copyright (c) 2013-2016 Chris Newland.
* Licensed under https://github.com/AdoptOpenJDK/jitwatch/blob/master/LICENSE-BSD
* Instructions: https://github.com/AdoptOpenJDK/jitwatch/wiki
*/
package org.adoptopenjdk.jitwatch.compilation;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BUILDIR;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_COMPILE_KIND;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_HOLDER;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_NAME;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_PARSE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C2N;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_DOT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.C_SLASH;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_CONSTRUCTOR_INIT;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_OPTIMIZER;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_ELIMINATE_ALLOCATION;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_NMETHOD;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PARSE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_PHASE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_FAILURE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_REASON;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_REASON_STALE_TASK;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_NEWLINE;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_METHOD_ID_MATCH;
import java.util.List;
import java.util.Map;
import org.adoptopenjdk.jitwatch.model.Compilation;
import org.adoptopenjdk.jitwatch.model.IMetaMember;
import org.adoptopenjdk.jitwatch.model.IParseDictionary;
import org.adoptopenjdk.jitwatch.model.LogParseException;
import org.adoptopenjdk.jitwatch.model.Tag;
import org.adoptopenjdk.jitwatch.model.Task;
import org.adoptopenjdk.jitwatch.util.ParseUtil;
import org.adoptopenjdk.jitwatch.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class CompilationUtil
{
private static final Logger logger = LoggerFactory.getLogger(CompilationUtil.class);
private static int unhandledTagCount = 0;
private CompilationUtil()
{
}
public static void visitParseTagsOfCompilation(Compilation compilation, ICompilationVisitable visitable)
throws LogParseException
{
if (compilation != null)
{
Task tagTask = compilation.getTagTask();
if (tagTask == null)
{
if (!compilation.isC2N())
{
logger.warn("No Task found in Compilation {}", compilation.getCompileID());
}
}
else
{
IParseDictionary parseDictionary = tagTask.getParseDictionary();
Tag parsePhase = getParsePhase(tagTask);
if (parsePhase != null)
{
List<Tag> parseTags = parsePhase.getNamedChildren(TAG_PARSE);
if (DEBUG_LOGGING)
{
logger.debug("About to visit {} parse tags of <task>", parseTags.size());
}
for (Tag parseTag : parseTags)
{
visitable.visitTag(parseTag, parseDictionary);
}
}
}
}
else
{
logger.warn("Compilation is null");
}
}
public static void visitOptimizerTagsOfCompilation(Compilation compilation, ICompilationVisitable visitable)
throws LogParseException
{
if (compilation != null)
{
Task tagTask = compilation.getTagTask();
if (tagTask == null)
{
if (!compilation.isC2N())
{
logger.warn("No Task found in Compilation {}", compilation.getCompileID());
}
}
else
{
IParseDictionary parseDictionary = tagTask.getParseDictionary();
Tag optimizerPhase = getOptimizerPhase(tagTask);
if (optimizerPhase != null)
{
for (Tag child : optimizerPhase.getChildren())
{
visitable.visitTag(child, parseDictionary);
}
}
}
}
else
{
logger.warn("Compilation is null");
}
}
public static void visitEliminationTagsOfCompilation(Compilation compilation, ICompilationVisitable visitable)
throws LogParseException
{
if (compilation != null)
{
Task tagTask = compilation.getTagTask();
if (tagTask == null)
{
if (!compilation.isC2N())
{
logger.warn("No Task found in Compilation {}", compilation.getCompileID());
}
}
else
{
IParseDictionary parseDictionary = tagTask.getParseDictionary();
for (Tag child : tagTask.getNamedChildren(TAG_ELIMINATE_ALLOCATION))
{
visitable.visitTag(child, parseDictionary);
}
}
}
else
{
logger.warn("Compilation is null");
}
}
// private Map<Integer, Integer> getBytecodeMap
public static boolean isJournalForCompile2NativeMember(Tag tag)
{
boolean result = false;
if (tag != null)
{
String tagName = tag.getName();
if (TAG_NMETHOD.equals(tagName))
{
if (C2N.equals(tag.getAttributes().get(ATTR_COMPILE_KIND)))
{
result = true;
}
}
}
return result;
}
public static boolean memberMatchesKlassID(IMetaMember member, String klassID, IParseDictionary parseDictionary)
{
boolean result = false;
String klassName = ParseUtil.lookupType(klassID, parseDictionary);
String memberClassName = member.getMetaClass().getFullyQualifiedName();
result = memberClassName.equals(klassName);
return result;
}
public static boolean memberMatchesMethodID(IMetaMember member, String methodID, IParseDictionary parseDictionary)
{
boolean result = false;
Tag methodTag = parseDictionary.getMethod(methodID);
StringBuilder builder = null;
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder = new StringBuilder();
builder.append(
String.format("methodID: %s methodTag: %s", methodID, methodTag != null ? methodTag.toString(true) : "null"))
.append(S_NEWLINE);
builder.append(String.format("member: %s ", member.toString())).append(S_NEWLINE);
}
if (methodTag != null)
{
Map<String, String> methodTagAttributes = methodTag.getAttributes();
String klassID = methodTagAttributes.get(ATTR_HOLDER);
Tag klassTag = parseDictionary.getKlass(klassID);
if (klassTag != null)
{
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder.append(String.format("klass tag: %s", klassTag.toString(false))).append(S_NEWLINE);
}
String klassAttrName = klassTag.getAttributes().get(ATTR_NAME);
String methodAttrName = StringUtil.replaceXMLEntities(methodTagAttributes.get(ATTR_NAME));
if (klassAttrName != null)
{
klassAttrName = klassAttrName.replace(C_SLASH, C_DOT);
}
String returnType = ParseUtil.getMethodTagReturn(methodTag, parseDictionary);
List<String> paramTypes = ParseUtil.getMethodTagArguments(methodTag, parseDictionary);
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder.append(String.format("memberName: %s/%s", member.getMemberName(), methodAttrName)).append(S_NEWLINE);
builder.append(String.format("metaClass : %s/%s", member.getMetaClass().getFullyQualifiedName(), klassAttrName))
.append(S_NEWLINE);
builder.append(String.format("return : %s/%s", member.getReturnTypeName(), returnType)).append(S_NEWLINE);
builder.append(String.format("params : %s/%s", StringUtil.arrayToString(member.getParamTypeNames()),
StringUtil.listToString(paramTypes))).append(S_NEWLINE);
}
boolean nameMatches;
if (S_CONSTRUCTOR_INIT.equals(methodAttrName))
{
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder.append(
String.format("Looks like a constructor. Checking %s vs %s", member.getMemberName(), klassAttrName))
.append(S_NEWLINE);
}
String unqualifiedClassName = StringUtil.getUnqualifiedClassName(klassAttrName);
nameMatches = member.getMemberName().equals(unqualifiedClassName);
}
else
{
nameMatches = member.getMemberName().equals(methodAttrName);
}
boolean klassMatches = member.getMetaClass().getFullyQualifiedName().equals(klassAttrName);
boolean returnMatches = member.getReturnTypeName().equals(returnType);
boolean paramsMatch = true;
if (member.getParamTypeNames().length == paramTypes.size())
{
for (int pos = 0; pos < member.getParamTypeNames().length; pos++)
{
String memberParamType = member.getParamTypeNames()[pos];
String tagParamType = paramTypes.get(pos);
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder.append(String.format("checking: %s/%s", memberParamType, tagParamType)).append(S_NEWLINE);
}
if (!memberParamType.equals(tagParamType))
{
paramsMatch = false;
break;
}
}
}
else
{
paramsMatch = false;
}
result = nameMatches && klassMatches && returnMatches && paramsMatch;
if (DEBUG_LOGGING_METHOD_ID_MATCH)
{
builder.append(String.format("Matched name: %s klass: %s return: %s params: %s", nameMatches, klassMatches,
returnMatches, paramsMatch)).append(S_NEWLINE);
builder.append(String.format("Matches member:%s = %s", member, result)).append(S_NEWLINE);
if (!result)
{
logger.error(builder.toString());
}
}
}
}
return result;
}
public static Tag getParsePhase(Task task)
{
Tag parsePhase = null;
if (task != null)
{
// for C1 look for <phase name='buildIR' stamp='18.121'>
// for C2 look for <phase name='parse' nodes='3' live='3'
// stamp='11.237'>
List<Tag> phasesBuildIR = task.getNamedChildrenWithAttribute(TAG_PHASE, ATTR_NAME, ATTR_BUILDIR);
if (phasesBuildIR.size() == 1)
{
parsePhase = phasesBuildIR.get(0);
}
else
{
List<Tag> phasesParse = task.getNamedChildrenWithAttribute(TAG_PHASE, ATTR_NAME, ATTR_PARSE);
if (phasesParse.size() == 1)
{
parsePhase = phasesParse.get(0);
}
else
{
if (!isStaleTask(task))
{
logger.warn("Unexpected parse phase count: buildIR({}), parse({})", phasesBuildIR.size(),
phasesParse.size());
if (DEBUG_LOGGING)
{
logger.debug("Task {}", task);
}
// possible JDK9 new format with no wrapping tag so
// return
// the whole task tag
parsePhase = task;
}
}
}
}
return parsePhase;
}
public static boolean isStaleTask(Task task)
{
List<Tag> failureChildren = task.getNamedChildren(TAG_FAILURE);
boolean stale = false;
for (Tag failure : failureChildren)
{
String reason = failure.getAttributes().get(ATTR_REASON);
if (S_REASON_STALE_TASK.equals(reason))
{
stale = true;
break;
}
}
return stale;
}
private static Tag getOptimizerPhase(Task lastTask)
{
Tag optimizerPhase = null;
if (lastTask != null)
{
List<Tag> parsePhases = lastTask.getNamedChildrenWithAttribute(TAG_PHASE, ATTR_NAME, S_OPTIMIZER);
int count = parsePhases.size();
if (count > 1)
{
logger.warn("Unexpected optimizer phase count: {}", count);
}
else if (count == 1)
{
optimizerPhase = parsePhases.get(0);
}
}
return optimizerPhase;
}
public static void unhandledTag(ICompilationVisitable visitable, Tag child)
{
unhandledTagCount++;
logger.warn("{} did not handle {}", visitable.getClass().getName(), child.toString(false));
}
public static int getUnhandledTagCount()
{
return unhandledTagCount;
}
}