/* * 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.chain; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.ATTR_ID; 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_REASON; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.S_PARSE_HIR; 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_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_KLASS; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_METHOD; 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_INTRINSIC; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_OBSERVE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_HOT_THROW; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_VIRTUAL_CALL; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.TAG_CAST_UP; import java.util.HashMap; import java.util.Map; import org.adoptopenjdk.jitwatch.compilation.AbstractCompilationVisitable; import org.adoptopenjdk.jitwatch.compilation.CompilationUtil; import org.adoptopenjdk.jitwatch.model.Compilation; 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.util.TooltipUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CompileChainWalker extends AbstractCompilationVisitable { private static final Logger logger = LoggerFactory.getLogger(CompileChainWalker.class); private IReadOnlyJITDataModel model; private CompileNode root = null; private Compilation compilation; public CompileChainWalker(IReadOnlyJITDataModel model) { this.model = model; ignoreTags.add(TAG_DIRECT_CALL); ignoreTags.add(TAG_KLASS); ignoreTags.add(TAG_TYPE); ignoreTags.add(TAG_DEPENDENCY); ignoreTags.add(TAG_PREDICTED_CALL); ignoreTags.add(TAG_PARSE_DONE); ignoreTags.add(TAG_PHASE_DONE); ignoreTags.add(TAG_BRANCH); ignoreTags.add(TAG_UNCOMMON_TRAP); ignoreTags.add(TAG_INTRINSIC); ignoreTags.add(TAG_OBSERVE); ignoreTags.add(TAG_HOT_THROW); ignoreTags.add(TAG_CAST_UP); ignoreTags.add(TAG_HOT_THROW); } public CompileNode buildCallTree(Compilation compilation) { this.root = null; this.compilation = compilation; try { CompilationUtil.visitParseTagsOfCompilation(compilation, this); } catch (LogParseException lpe) { logger.error("Could not build compile tree", lpe); } return root; } private void processParseTag(Tag parseTag, CompileNode parentNode, IParseDictionary parseDictionary) { String methodID = null; CompileNode lastNode = null; Map<String, String> methodAttrs = new HashMap<>(); Map<String, String> callAttrs = new HashMap<>(); for (Tag child : parseTag.getChildren()) { String tagName = child.getName(); Map<String, String> tagAttrs = child.getAttributes(); switch (tagName) { case TAG_BC: { callAttrs.clear(); break; } case TAG_METHOD: { methodID = tagAttrs.get(ATTR_ID); methodAttrs.clear(); methodAttrs.putAll(tagAttrs); break; } case TAG_CALL: { methodID = tagAttrs.get(ATTR_METHOD); callAttrs.clear(); callAttrs.putAll(tagAttrs); break; } case TAG_INLINE_FAIL: { createChildNode(parentNode, methodID, parseDictionary, false, false, methodAttrs, callAttrs, tagAttrs); methodID = null; lastNode = null; break; } case TAG_INLINE_SUCCESS: { lastNode = createChildNode(parentNode, methodID, parseDictionary, true, false, methodAttrs, callAttrs, tagAttrs); break; } case TAG_PARSE: // call depth { String childMethodID = tagAttrs.get(ATTR_METHOD); CompileNode nextParent = parentNode; if (lastNode != null) { nextParent = lastNode; } else if (child.getNamedChildren(TAG_PARSE).size() > 0) { CompileNode childNode = new CompileNode(childMethodID); parentNode.addChild(childNode); nextParent = childNode; } processParseTag(child, nextParent, parseDictionary); break; } case TAG_PHASE: { String phaseName = tagAttrs.get(ATTR_NAME); if (S_PARSE_HIR.equals(phaseName)) { processParseTag(child, parentNode, parseDictionary); } else { logger.warn("Don't know how to handle phase {}", phaseName); } break; } case TAG_VIRTUAL_CALL: lastNode = createChildNode(parentNode, methodID, parseDictionary, false, true, methodAttrs, callAttrs, tagAttrs); break; default: handleOther(child); break; } } } private CompileNode createChildNode(CompileNode parentNode, String methodID, IParseDictionary parseDictionary, boolean inlined, boolean virtualCall, Map<String, String> methodAttrs, Map<String, String> callAttrs, Map<String, String> tagAttrs) { CompileNode childNode = new CompileNode(methodID); parentNode.addChild(childNode); String reason = tagAttrs.get(ATTR_REASON); String tooltip = TooltipUtil.buildInlineAnnotationText(inlined, reason, callAttrs, methodAttrs, parseDictionary); childNode.setInlined(inlined); childNode.setVirtualCall(virtualCall); childNode.setTooltipText(tooltip); return childNode; } @Override public void visitTag(Tag parseTag, IParseDictionary parseDictionary) throws LogParseException { String methodID = parseTag.getAttributes().get(ATTR_METHOD); // only initialise on first parse tag. // there may be multiple if late_inline // is detected if (root == null) { root = CompileNode.createRootNode(compilation, methodID, parseDictionary, model); } processParseTag(parseTag, root, parseDictionary); } }