/*
* Copyright (c) 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.hotthrow;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_HOLDER;
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.S_PARSE_HIR;
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_DEPENDENCY;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_DIRECT_CALL;
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.ATTR_PREALLOCATED;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_KLASS;
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_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_HOT_THROW;
import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_BCI;
import java.util.ArrayList;
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.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.Tag;
import org.adoptopenjdk.jitwatch.model.bytecode.ExceptionTable;
import org.adoptopenjdk.jitwatch.model.bytecode.ExceptionTableEntry;
import org.adoptopenjdk.jitwatch.model.bytecode.MemberBytecode;
import org.adoptopenjdk.jitwatch.util.ParseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class HotThrowFinder extends AbstractCompilationVisitable
{
private Set<HotThrowResult> result;
private IReadOnlyJITDataModel model;
private static final Logger logger = LoggerFactory.getLogger(HotThrowFinder.class);
public HotThrowFinder(IReadOnlyJITDataModel model)
{
this.model = model;
ignoreTags.add(TAG_KLASS);
ignoreTags.add(TAG_TYPE);
ignoreTags.add(TAG_UNCOMMON_TRAP);
ignoreTags.add(TAG_PARSE_DONE);
ignoreTags.add(TAG_BRANCH);
ignoreTags.add(TAG_CAST_UP);
ignoreTags.add(TAG_PARSE);
ignoreTags.add(TAG_INLINE_SUCCESS);
ignoreTags.add(TAG_INLINE_FAIL);
ignoreTags.add(TAG_DIRECT_CALL);
ignoreTags.add(TAG_PREDICTED_CALL);
ignoreTags.add(TAG_DEPENDENCY);
ignoreTags.add(TAG_OBSERVE);
ignoreTags.add(TAG_INTRINSIC);
ignoreTags.add(TAG_ASSERT_NULL);
}
public Set<HotThrowResult> findHotThrows(IMetaMember member)
{
result = new HashSet<>();
if (member != null)
{
try
{
for (Compilation compilation : member.getCompilations())
{
CompilationUtil.visitParseTagsOfCompilation(compilation, this);
}
}
catch (LogParseException e)
{
logger.error("Error while finding hot throws for member {}", member, e);
}
}
return result;
}
@Override
public void visitTag(Tag parseTag, IParseDictionary parseDictionary) throws LogParseException
{
String currentMethod = null;
String holder = null;
String currentBCI = null;
Map<String, String> attrs = parseTag.getAttributes();
String methodID = attrs.get(ATTR_METHOD);
Tag methodTag = parseDictionary.getMethod(methodID);
Map<String, String> methodTagAttributes = methodTag.getAttributes();
currentMethod = methodTagAttributes.get(ATTR_NAME);
holder = methodTagAttributes.get(ATTR_HOLDER);
List<Tag> allChildren = parseTag.getChildren();
for (Tag child : allChildren)
{
String tagName = child.getName();
attrs = child.getAttributes();
switch (tagName)
{
case TAG_METHOD:
{
currentMethod = attrs.get(ATTR_NAME);
holder = attrs.get(ATTR_HOLDER);
break;
}
case TAG_BC:
{
currentBCI = attrs.get(ATTR_BCI);
break;
}
// changes member context
case TAG_CALL:
{
methodID = attrs.get(ATTR_METHOD);
methodTag = parseDictionary.getMethod(methodID);
methodTagAttributes = methodTag.getAttributes();
currentMethod = methodTagAttributes.get(ATTR_NAME);
holder = methodTagAttributes.get(ATTR_HOLDER);
break;
}
case TAG_HOT_THROW:
{
if (holder != null && currentMethod != null)
{
Tag klassTag = parseDictionary.getKlass(holder);
String preallocated = child.getAttributes().get(ATTR_PREALLOCATED);
if (currentBCI != null && klassTag != null)
{
IMetaMember member = ParseUtil.lookupMember(methodID, parseDictionary, model);
if (member != null)
{
MemberBytecode memberBytecode = member.getMemberBytecode();
if (memberBytecode == null)
{
member.getMetaClass().getClassBytecode(model, new ArrayList<String>());
memberBytecode = member.getMemberBytecode();
}
if (memberBytecode != null)
{
ExceptionTable exceptionTable = memberBytecode.getExceptionTable();
if (exceptionTable != null)
{
int bciValue = Integer.valueOf(currentBCI);
ExceptionTableEntry entry = exceptionTable.getEntryForBCI(bciValue);
if (entry != null)
{
HotThrowResult throwResult = new HotThrowResult(member, bciValue, entry.getType(), "1".equals(preallocated));
result.add(throwResult);
}
}
}
}
}
}
holder = null;
currentMethod = null;
break;
}
case TAG_PHASE:
{
String phaseName = attrs.get(ATTR_NAME);
if (S_PARSE_HIR.equals(phaseName))
{
visitTag(child, parseDictionary);
}
else
{
logger.warn("Don't know how to handle phase {}", phaseName);
}
break;
}
case TAG_PARSE: // nested parse from inlining
{
visitTag(child, parseDictionary);
break;
}
default:
handleOther(child);
break;
}
}
}
}