/* * Copyright (c) 2013-2015 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.C_NEWLINE; import static org.adoptopenjdk.jitwatch.core.JITWatchConstants.DEBUG_LOGGING_BYTECODE; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LineTable { private List<LineTableEntry> lineTableEntries = new ArrayList<>(); private static final Logger logger = LoggerFactory.getLogger(LineTable.class); private MemberBytecode memberBytecode; public LineTable(MemberBytecode memberBytecode) { this.memberBytecode = memberBytecode; } public MemberBytecode getMemberBytecode() { return memberBytecode; } public void add(LineTableEntry entry) { lineTableEntries.add(entry); sort(); } public void add(LineTable lineTable) { if (lineTable != null) { lineTableEntries.addAll(lineTable.lineTableEntries); sort(); } } public int getLastSourceLine() { return lineTableEntries.get(lineTableEntries.size() - 1).getSourceOffset(); } public boolean sourceLineInRange(int sourceLine) { boolean result = false; if (lineTableEntries.size() > 0) { int maxIndex = lineTableEntries.size() - 1; int minSourceLine = lineTableEntries.get(0).getSourceOffset(); int maxSourceLine = lineTableEntries.get(maxIndex).getSourceOffset(); result = (sourceLine >= minSourceLine) && (sourceLine <= maxSourceLine); if (DEBUG_LOGGING_BYTECODE) { logger.debug("{} in range {}-{} : {}", sourceLine, minSourceLine, maxSourceLine, result); } } return result; } private void sort() { Collections.sort(lineTableEntries, new Comparator<LineTableEntry>() { @Override public int compare(LineTableEntry o1, LineTableEntry o2) { return Integer.compare(o1.getSourceOffset(), o2.getSourceOffset()); } }); } public LineTableEntry getEntryForSourceLine(int sourceLine) { LineTableEntry result = null; for (LineTableEntry entry : lineTableEntries) { if (entry.getSourceOffset() == sourceLine) { result = entry; break; } } return result; } public List<LineTableEntry> getEntries() { return Collections.unmodifiableList(lineTableEntries); } public int findSourceLineForBytecodeOffset(int searchBCI) { int sourceAtClosestBCI = -1; int distanceToClosestBCI = Integer.MAX_VALUE; for (LineTableEntry entry : lineTableEntries) { int entryBCI = entry.getBytecodeOffset(); int distance = searchBCI - entryBCI; if (distance >= 0) { if (distance == 0) { sourceAtClosestBCI = entry.getSourceOffset(); break; } else if (distance < distanceToClosestBCI) { distanceToClosestBCI = distance; sourceAtClosestBCI = entry.getSourceOffset(); } } } return sourceAtClosestBCI; } public int size() { return lineTableEntries.size(); } @Override public String toString() { StringBuilder builder = new StringBuilder(); for (LineTableEntry entry : lineTableEntries) { builder.append(entry).append(C_NEWLINE); } return builder.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((lineTableEntries == null) ? 0 : lineTableEntries.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } LineTable other = (LineTable) obj; if (lineTableEntries == null) { if (other.lineTableEntries != null) { return false; } } else if (!lineTableEntries.equals(other.lineTableEntries)) { return false; } return true; } }