Merge remote-tracking branch 'origin/master'

This commit is contained in:
Ilya.Kazakevich
2014-10-16 00:47:59 +04:00
8 changed files with 161 additions and 88 deletions
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
import com.intellij.util.PairFunction;
import com.intellij.util.containers.ContainerUtil;
@@ -26,6 +27,7 @@ import com.intellij.util.containers.FilteringIterator;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.containers.Queue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -35,11 +37,13 @@ import java.util.*;
public class LiveVariablesAnalyzer {
private final DfaValueFactory myFactory;
private final Instruction[] myInstructions;
private final MultiMap<Instruction, Instruction> myForwardMap;
private final MultiMap<Instruction, Instruction> myBackwardMap;
public LiveVariablesAnalyzer(ControlFlow flow, DfaValueFactory factory) {
myFactory = factory;
myInstructions = flow.getInstructions();
myForwardMap = calcForwardMap();
myBackwardMap = calcBackwardMap();
}
@@ -64,17 +68,49 @@ public class LiveVariablesAnalyzer {
private MultiMap<Instruction, Instruction> calcBackwardMap() {
MultiMap<Instruction, Instruction> result = MultiMap.create();
for (Instruction instruction : myInstructions) {
for (Instruction next : getSuccessors(instruction)) {
for (Instruction next : myForwardMap.get(instruction)) {
result.putValue(next, instruction);
}
}
return result;
}
private MultiMap<Instruction, Instruction> calcForwardMap() {
MultiMap<Instruction, Instruction> result = MultiMap.create();
for (Instruction instruction : myInstructions) {
if (isInterestingInstruction(instruction)) {
for (Instruction next : getSuccessors(instruction)) {
while (true) {
if (isInterestingInstruction(next)) {
result.putValue(instruction, next);
break;
}
if (next.getIndex() + 1 >= myInstructions.length) {
break;
}
next = myInstructions[next.getIndex() + 1];
}
}
}
}
return result;
}
private boolean isInterestingInstruction(Instruction instruction) {
if (instruction == myInstructions[0]) return true;
if (instruction instanceof PushInstruction) return ((PushInstruction)instruction).getValue() instanceof DfaVariableValue;
return instruction instanceof FinishElementInstruction ||
instruction instanceof FlushVariableInstruction ||
instruction instanceof GotoInstruction ||
instruction instanceof ConditionalGotoInstruction ||
instruction instanceof ReturnInstruction;
}
@Nullable
private Map<FinishElementInstruction, BitSet> findLiveVars() {
final Map<FinishElementInstruction, BitSet> result = ContainerUtil.newHashMap();
runDfa(false, new PairFunction<Instruction, BitSet, BitSet>() {
boolean ok = runDfa(false, new PairFunction<Instruction, BitSet, BitSet>() {
@Override
public BitSet fun(Instruction instruction, BitSet liveVars) {
if (instruction instanceof FinishElementInstruction) {
@@ -115,13 +151,16 @@ public class LiveVariablesAnalyzer {
return liveVars;
}
});
return result;
return ok ? result : null;
}
void flushDeadVariablesOnStatementFinish() {
final Map<FinishElementInstruction, BitSet> liveVars = findLiveVars();
if (liveVars == null) return;
runDfa(true, new PairFunction<Instruction, BitSet, BitSet>() {
final MultiMap<FinishElementInstruction, DfaVariableValue> toFlush = MultiMap.createSet();
boolean ok = runDfa(true, new PairFunction<Instruction, BitSet, BitSet>() {
@Override
@NotNull
public BitSet fun(Instruction instruction, @NotNull BitSet prevLiveVars) {
@@ -135,7 +174,7 @@ public class LiveVariablesAnalyzer {
int setBit = prevLiveVars.nextSetBit(index);
if (setBit < 0) break;
if (!currentlyLive.get(setBit)) {
((FinishElementInstruction)instruction).getVarsToFlush().add((DfaVariableValue)myFactory.getValue(setBit));
toFlush.putValue((FinishElementInstruction)instruction, (DfaVariableValue)myFactory.getValue(setBit));
}
index = setBit + 1;
}
@@ -145,9 +184,18 @@ public class LiveVariablesAnalyzer {
return prevLiveVars;
}
});
if (ok) {
for (FinishElementInstruction instruction : toFlush.keySet()) {
instruction.getVarsToFlush().addAll(toFlush.get(instruction));
}
}
}
private void runDfa(boolean forward, PairFunction<Instruction, BitSet, BitSet> handleState) {
/**
* @return true if completed, false if "too complex"
*/
private boolean runDfa(boolean forward, PairFunction<Instruction, BitSet, BitSet> handleState) {
Set<Instruction> entryPoints = ContainerUtil.newHashSet();
if (forward) {
entryPoints.add(myInstructions[0]);
@@ -160,25 +208,28 @@ public class LiveVariablesAnalyzer {
queue.addLast(new InstructionState(i, new BitSet()));
}
int steps = 0;
int limit = myForwardMap.size() * 20;
Set<InstructionState> processed = ContainerUtil.newHashSet();
while (!queue.isEmpty()) {
steps++;
int steps = processed.size();
if (steps > limit) {
return false;
}
if (steps % 1024 == 0) {
ProgressManager.checkCanceled();
}
InstructionState state = queue.pullFirst();
Instruction instruction = state.first;
Collection<Instruction> nextInstructions = forward ? getSuccessors(instruction) : myBackwardMap.get(instruction);
boolean branching = nextInstructions.size() > 1 || !forward && instruction.getIndex() == 0;
Collection<Instruction> nextInstructions = forward ? myForwardMap.get(instruction) : myBackwardMap.get(instruction);
BitSet nextVars = handleState.fun(instruction, state.second);
for (Instruction next : nextInstructions) {
InstructionState nextState = new InstructionState(next, nextVars);
if (!branching || processed.add(nextState)) {
if (processed.add(nextState)) {
queue.addLast(nextState);
}
}
}
if (steps > 10000) {
int a = 1;
}
return true;
}
private static class InstructionState extends Pair<Instruction, BitSet> {
@@ -117,6 +117,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
}
};
myTree.setEditable(true);
myTree.setShowsRootHandles(root.getChildCount() > 1);
MyTreeCellEditor treeCellEditor = new MyTreeCellEditor();
myTree.setCellEditor(treeCellEditor);
treeCellEditor.addCellEditorListener(new CellEditorListener() {
@@ -71,7 +71,6 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
public void render(@NotNull ColoredTreeCellRenderer renderer) {
int repoFixedWidth = 120;
int borderHOffset = myRepositoryPanel.getHBorderOffset(renderer);
int borderVOffset = myRepositoryPanel.getVBorderOffset(renderer);
if (myLoading.get()) {
renderer.setIcon(myLoadingIcon);
renderer.setIconOnTheRight(false);
@@ -81,27 +80,31 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
renderer.append("");
renderer.appendFixedTextFragmentWidth(checkBoxWidth + renderer.getIconTextGap() + borderHOffset);
}
if (myCheckBoxVGap > 0) {
int shiftV = myCheckBoxVGap - borderVOffset;
renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0));
}
}
else {
if (myCheckBoxHGap <= 0) {
renderer.append("");
renderer.appendFixedTextFragmentWidth(myRepositoryPanel.calculateRendererShiftH(renderer));
}
if (myCheckBoxVGap <= 0) {
int shiftV = -myCheckBoxVGap + borderVOffset;
renderer.setBorder(new EmptyBorder(shiftV / 2, 0, shiftV / 2, 0));
}
}
renderer.append(getRepoName(renderer, repoFixedWidth), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
renderer.append(getRepoName(renderer, repoFixedWidth),
isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
renderer.appendFixedTextFragmentWidth(repoFixedWidth);
renderer.append(myRepositoryPanel.getSourceName(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
renderer.append(myRepositoryPanel.getSourceName(),
isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
renderer
.append(myRepositoryPanel.getArrow(), isChecked() ? SimpleTextAttributes.REGULAR_ATTRIBUTES : SimpleTextAttributes.GRAY_ATTRIBUTES);
PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
pushTargetPanel.render(renderer);
int maxSize = Math.max(myRepositoryPanel.getCheckBoxHeight(), myLoadingIcon.getIconHeight());
int rendererHeight = renderer.getPreferredSize().height;
if (maxSize > rendererHeight) {
if (myCheckBoxVGap > 0 && isLoading() || myCheckBoxVGap < 0 && !isLoading()) {
int vShift = maxSize - rendererHeight;
renderer.setBorder(new EmptyBorder((vShift + 1) / 2, 0, (vShift) / 2, 0));
}
}
}
@NotNull
@@ -52,6 +52,7 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
private final int myCheckBoxLoadingIconGapV;
private final LoadingIcon myLoadingIcon;
private final int myCheckBoxWidth;
private final int myCheckBoxHeight;
public RepositoryWithBranchPanel(@NotNull final Project project, @NotNull String repoName,
@@ -102,6 +103,7 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
emptyBorderCheckBox.setBorder(null);
Dimension size = emptyBorderCheckBox.getPreferredSize();
myCheckBoxWidth = size.width;
myCheckBoxHeight = size.height;
myLoadingIcon = LoadingIcon.create(myCheckBoxWidth, size.height);
myCheckBoxLoadingIconGapH = myCheckBoxWidth - myLoadingIcon.getIconWidth();
myCheckBoxLoadingIconGapV = size.height - myLoadingIcon.getIconHeight();
@@ -223,6 +225,10 @@ public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePa
Border border = coloredRenderer.getMyBorder();
return border != null ? border.getBorderInsets(coloredRenderer).top : 0;
}
public int getCheckBoxHeight() {
return myCheckBoxHeight;
}
}
@@ -26,7 +26,6 @@ import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBLoadingPanel;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.ui.components.JBTextField;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.DateFormatUtil;
@@ -69,10 +68,9 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
@NotNull private final VcsLogGraphTable myGraphTable;
@NotNull private final RefsPanel myRefsPanel;
@NotNull private final DataPanel myHashAuthorPanel;
@NotNull private final DataPanel myMessageDataPanel;
@NotNull private final ContainingBranchesPanel myContainingBranchesPanel;
@NotNull private final MessagePanel myMessagePanel;
@NotNull private final JLabel myMessageLabel;
@NotNull private final JBLoadingPanel myLoadingPanel;
@NotNull private VisiblePack myDataPack;
@@ -84,7 +82,6 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
myDataPack = initialDataPack;
myRefsPanel = new RefsPanel(colorManager);
myHashAuthorPanel = new DataPanel(logDataHolder.getProject(), false);
final JScrollPane scrollPane = new JBScrollPane() {
@Override
@@ -92,7 +89,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
return getVerticalScrollBar().isVisible() ? super.getBorder() : null;
}
};
myMessageDataPanel = new DataPanel(logDataHolder.getProject(), true) {
myMessageDataPanel = new DataPanel(logDataHolder.getProject()) {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
@@ -105,20 +102,20 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
scrollPane.setViewportView(myMessageDataPanel);
myContainingBranchesPanel = new ContainingBranchesPanel();
myMessagePanel = new MessagePanel();
myMessageLabel = new JLabel();
myMessageLabel.setForeground(UIUtil.getInactiveTextColor());
myMessageLabel.setHorizontalAlignment(SwingConstants.CENTER);
myMessageLabel.setVerticalAlignment(SwingConstants.CENTER);
myLoadingPanel = new JBLoadingPanel(new BorderLayout(), logDataHolder, ProgressWindow.DEFAULT_PROGRESS_DIALOG_POSTPONE_TIME_MILLIS);
JPanel header = new NonOpaquePanel(new BorderLayout());
header.add(myRefsPanel, BorderLayout.NORTH);
header.add(myHashAuthorPanel, BorderLayout.SOUTH);
myLoadingPanel.add(header, BorderLayout.NORTH);
myLoadingPanel.add(myRefsPanel, BorderLayout.NORTH);
myLoadingPanel.add(scrollPane, BorderLayout.CENTER);
myLoadingPanel.add(myContainingBranchesPanel, BorderLayout.SOUTH);
myLoadingPanel.setOpaque(false);
setLayout(new CardLayout());
add(myLoadingPanel, STANDARD_LAYER);
add(myMessagePanel, MESSAGE_LAYER);
add(myMessageLabel, MESSAGE_LAYER);
setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
showMessage("No commits selected");
@@ -154,13 +151,11 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
}
if (commitData instanceof LoadingDetails) {
myLoadingPanel.startLoading();
myHashAuthorPanel.setData(null);
myMessageDataPanel.setData(null);
myRefsPanel.setRefs(Collections.<VcsRef>emptyList());
}
else {
myLoadingPanel.stopLoading();
myHashAuthorPanel.setData(commitData);
myMessageDataPanel.setData(commitData);
myRefsPanel.setRefs(sortRefs(hash, commitData.getRoot()));
}
@@ -176,7 +171,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
private void showMessage(String text) {
myLoadingPanel.stopLoading();
((CardLayout)getLayout()).show(this, MESSAGE_LAYER);
myMessagePanel.setText(text);
myMessageLabel.setText(text);
}
@NotNull
@@ -188,11 +183,9 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
private static class DataPanel extends JEditorPane {
@NotNull private final Project myProject;
private final boolean myMessageMode;
DataPanel(@NotNull Project project, boolean messageMode) {
DataPanel(@NotNull Project project) {
super(UIUtil.HTML_MIME, "");
myMessageMode = messageMode;
setEditable(false);
myProject = project;
addHyperlinkListener(BrowserHyperlinkListener.INSTANCE);
@@ -205,12 +198,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
setText("");
}
else {
String body;
if (myMessageMode) {
body = getMessageText(commit);
} else {
body = commit.getId().asString() + "<br/>" + getAuthorText(commit);
}
String body = commit.getId().toShortString() + " " + getAuthorText(commit) + "<br>" + getMessageText(commit);
setText("<html><head>" + UIUtil.getCssFontDeclaration(UIUtil.getLabelFont()) + "</head><body>" + body + "</body></html>");
setCaretPosition(0);
}
@@ -221,8 +209,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
@Override
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
int h = getFontMetrics(getFont()).getHeight();
size.height = Math.max(size.height, myMessageMode ? 5 * h : 2 * h);
size.height = Math.max(size.height, 7 * getFontMetrics(getFont()).getHeight());
return size;
}
@@ -257,7 +244,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
private static class ContainingBranchesPanel extends JPanel {
private final JComponent myLoadingComponent;
private final JTextField myBranchesList;
private final JTextArea myBranchesText;
ContainingBranchesPanel() {
JLabel label = new JBLabel("Contained in branches: ") {
@@ -269,7 +256,7 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
myLoadingComponent = new NonOpaquePanel(new BorderLayout());
myLoadingComponent.add(new AsyncProcessIcon("Loading..."), BorderLayout.WEST);
myLoadingComponent.add(Box.createHorizontalGlue(), BorderLayout.CENTER);
myBranchesList = new JBTextField("") {
myBranchesText = new JTextArea("") {
private final Border gtkBorder = new LineBorder(UIUtil.getTextFieldBackground(), 3) {
@Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
@@ -286,8 +273,10 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
return UIUtil.isUnderGTKLookAndFeel() ? gtkBorder : emptyBorder;
}
};
myBranchesList.setOpaque(false);
myBranchesList.setEditable(false);
myBranchesText.setOpaque(false);
myBranchesText.setEditable(false);
myBranchesText.setWrapStyleWord(true);
myBranchesText.setLineWrap(true);
setOpaque(false);
setLayout(new BorderLayout());
add(label, BorderLayout.WEST);
@@ -296,13 +285,13 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
void setBranches(@Nullable List<String> branches) {
if (branches == null) {
remove(myBranchesList);
remove(myBranchesText);
add(myLoadingComponent, BorderLayout.CENTER);
}
else {
remove(myLoadingComponent);
myBranchesList.setText(StringUtil.join(branches, ", "));
add(myBranchesList, BorderLayout.CENTER);
myBranchesText.setText(StringUtil.join(branches, ", "));
add(myBranchesText, BorderLayout.CENTER);
}
revalidate();
repaint();
@@ -333,22 +322,4 @@ class DetailsPanel extends JPanel implements ListSelectionListener {
repaint();
}
}
private static class MessagePanel extends NonOpaquePanel {
private final JLabel myLabel;
MessagePanel() {
super(new BorderLayout());
myLabel = new JLabel();
myLabel.setForeground(UIUtil.getInactiveTextColor());
myLabel.setHorizontalAlignment(SwingConstants.CENTER);
myLabel.setVerticalAlignment(SwingConstants.CENTER);
add(myLabel);
}
void setText(String text) {
myLabel.setText(text);
}
}
}
@@ -43,6 +43,7 @@ import org.jetbrains.java.decompiler.struct.gen.VarType;
import org.jetbrains.java.decompiler.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -581,13 +582,9 @@ public class ClassWriter {
boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
boolean clinit = false, init = false, dinit = false;
int startLine = -1;
StructLineNumberTableAttribute lineNumberTable = null;
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) {
StructLineNumberTableAttribute lineNumberTable =
(StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
if (lineNumberTable != null) {
startLine = lineNumberTable.getFirstLine();
}
lineNumberTable = (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
}
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
@@ -804,8 +801,10 @@ public class ClassWriter {
buffer.append(' ');
}
//TODO: for now only start line set
buffer.setCurrentLine(startLine-1);
// We do not have line information for method start, lets have it here for now
if (lineNumberTable != null) {
buffer.setCurrentLine(lineNumberTable.getFirstLine() - 1);
}
buffer.append('{').appendLineSeparator();
RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
@@ -813,11 +812,16 @@ public class ClassWriter {
if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
try {
tracer.incrementCurrentSourceLine(buffer.count(lineSeparator, start_index_method));
int startLine = tracer.getCurrentSourceLine();
TextBuffer code = root.toJava(indent + 1, tracer);
hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;
if (!hideMethod && lineNumberTable != null) {
mapLines(code, lineNumberTable, tracer, startLine);
}
buffer.append(code);
}
catch (Throwable ex) {
@@ -846,6 +850,33 @@ public class ClassWriter {
return !hideMethod;
}
private void mapLines(TextBuffer code, StructLineNumberTableAttribute table, BytecodeMappingTracer tracer, int startLine) {
// build line start offsets map
HashMap<Integer, Integer> lineStartOffsets = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : tracer.getMapping().entrySet()) {
Integer lineNumber = entry.getValue() - startLine;
Integer curr = lineStartOffsets.get(lineNumber);
if (curr == null || curr > entry.getKey()) {
lineStartOffsets.put(lineNumber, entry.getKey());
}
}
String lineSeparator = DecompilerContext.getNewLineSeparator();
StringBuilder text = code.getOriginalText();
int pos = text.indexOf(lineSeparator);
int lineNumber = 0;
while (pos != -1) {
Integer startOffset = lineStartOffsets.get(lineNumber);
if (startOffset != null) {
int number = table.findLineNumber(startOffset);
if (number >= 0) {
code.setLineMapping(number, pos);
}
}
pos = text.indexOf(lineSeparator, pos+1);
lineNumber++;
}
}
private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) {
if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
return false;
@@ -43,9 +43,13 @@ public class TextBuffer {
}
public void setCurrentLine(int line) {
setLineMapping(line, myStringBuilder.length()+1);
}
public void setLineMapping(int line, int offset) {
if (line >= 0) {
checkMapCreated();
myLineToOffsetMapping.put(line, myStringBuilder.length()+1);
myLineToOffsetMapping.put(line, offset);
}
}
@@ -257,4 +261,8 @@ public class TextBuffer {
}
return res;
}
public StringBuilder getOriginalText() {
return myStringBuilder;
}
}
@@ -54,9 +54,11 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute {
}
public int findLineNumber(int pc) {
for (int i = 0; i < myLineInfo.length; i += 2) {
if (pc >= myLineInfo[i]) {
return myLineInfo[i + 1];
if (myLineInfo.length >= 2) {
for (int i = myLineInfo.length - 2; i >= 0; i -= 2) {
if (pc >= myLineInfo[i]) {
return myLineInfo[i + 1];
}
}
}
return -1;