blob: 214494f9d1fd6046e81dd6819250e9fb807b207c [file] [log] [blame]
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package sun.jvm.hotspot.debugger.cdbg.basic;
import java.util.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.utilities.AddressOps;
public class BasicLineNumberMapping {
private List infoList;
public BasicLineNumberMapping() {
}
/** Add line number information for the given PC. The end PC may be
a very loose approximation (i.e., the end of the given DLL) if
that information is not available in the debug information.
recomputeEndPCs() will recompute them if needed. */
public void addLineNumberInfo(BasicLineNumberInfo info) {
if (infoList == null) {
infoList = new ArrayList();
}
infoList.add(info);
}
/** Sort the line number information by increasing starting program
counter. This must be done before any queries are made. */
public void sort() {
if (infoList == null) return;
Collections.sort(infoList, new Comparator() {
public int compare(Object o1, Object o2) {
BasicLineNumberInfo l1 = (BasicLineNumberInfo) o1;
BasicLineNumberInfo l2 = (BasicLineNumberInfo) o2;
Address a1 = l1.getStartPC();
Address a2 = l2.getStartPC();
if (AddressOps.lt(a1, a2)) { return -1; }
if (AddressOps.gt(a1, a2)) { return 1; }
return 0;
}
});
}
/** Recomputes the ending PCs of each interval based on the starting
PC of the next one. If this needs to be called, must be called
after sort(). */
public void recomputeEndPCs() {
if (infoList == null) return;
for (int i = 0; i < infoList.size() - 1; i++) {
BasicLineNumberInfo i1 = get(i);
BasicLineNumberInfo i2 = get(i + 1);
i1.setEndPC(i2.getStartPC());
}
}
public BasicLineNumberInfo lineNumberForPC(Address pc) throws DebuggerException {
if (infoList == null) return null;
return searchLineNumbers(pc, 0, infoList.size() - 1);
}
public void iterate(LineNumberVisitor v) {
if (infoList == null) return;
for (int i = 0; i < infoList.size(); i++) {
v.doLineNumber(get(i));
}
}
//----------------------------------------------------------------------
// Internals only below this point
//
private BasicLineNumberInfo get(int i) {
return (BasicLineNumberInfo) infoList.get(i);
}
private BasicLineNumberInfo searchLineNumbers(Address addr, int lowIdx, int highIdx) {
if (highIdx < lowIdx) return null;
if (lowIdx == highIdx) {
// Base case: see whether start PC is less than or equal to addr
if (check(addr, lowIdx)) {
return get(lowIdx);
} else {
return null;
}
} else if (lowIdx == highIdx - 1) {
if (check(addr, lowIdx)) {
return get(lowIdx);
} else if (check(addr, highIdx)) {
return get(highIdx);
} else {
return null;
}
}
int midIdx = (lowIdx + highIdx) >> 1;
BasicLineNumberInfo info = get(midIdx);
if (AddressOps.lt(addr, info.getStartPC())) {
// Always move search down
return searchLineNumbers(addr, lowIdx, midIdx);
} else if (AddressOps.equal(addr, info.getStartPC())) {
return info;
} else {
// Move search up
return searchLineNumbers(addr, midIdx, highIdx);
}
}
private boolean check(Address addr, int idx) {
BasicLineNumberInfo info = get(idx);
if (AddressOps.lte(info.getStartPC(), addr)) {
return true;
} else {
return false;
}
}
}