decompiler: map all lines according to bytecode information

master
Egor.Ushakov 10 years ago
parent 6d03229b91
commit a182de6271
  1. 47
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  2. 10
      src/org/jetbrains/java/decompiler/main/TextBuffer.java
  3. 4
      src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java

@ -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.struct.gen.generics.*;
import org.jetbrains.java.decompiler.util.InterpreterUtil; import org.jetbrains.java.decompiler.util.InterpreterUtil;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -581,13 +582,9 @@ public class ClassWriter {
boolean isDeprecated = mt.getAttributes().containsKey("Deprecated"); boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
boolean clinit = false, init = false, dinit = false; boolean clinit = false, init = false, dinit = false;
int startLine = -1; StructLineNumberTableAttribute lineNumberTable = null;
if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) { if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) {
StructLineNumberTableAttribute lineNumberTable = lineNumberTable = (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
(StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE);
if (lineNumberTable != null) {
startLine = lineNumberTable.getFirstLine();
}
} }
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
@ -804,8 +801,10 @@ public class ClassWriter {
buffer.append(' '); buffer.append(' ');
} }
//TODO: for now only start line set // We do not have line information for method start, lets have it here for now
buffer.setCurrentLine(startLine-1); if (lineNumberTable != null) {
buffer.setCurrentLine(lineNumberTable.getFirstLine() - 1);
}
buffer.append('{').appendLineSeparator(); buffer.append('{').appendLineSeparator();
RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root; RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
@ -813,11 +812,16 @@ public class ClassWriter {
if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
try { try {
tracer.incrementCurrentSourceLine(buffer.count(lineSeparator, start_index_method)); tracer.incrementCurrentSourceLine(buffer.count(lineSeparator, start_index_method));
int startLine = tracer.getCurrentSourceLine();
TextBuffer code = root.toJava(indent + 1, tracer); TextBuffer code = root.toJava(indent + 1, tracer);
hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;
if (!hideMethod && lineNumberTable != null) {
mapLines(code, lineNumberTable, tracer, startLine);
}
buffer.append(code); buffer.append(code);
} }
catch (Throwable ex) { catch (Throwable ex) {
@ -846,6 +850,33 @@ public class ClassWriter {
return !hideMethod; 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) { private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) {
if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) { if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
return false; return false;

@ -43,9 +43,13 @@ public class TextBuffer {
} }
public void setCurrentLine(int line) { public void setCurrentLine(int line) {
setLineMapping(line, myStringBuilder.length()+1);
}
public void setLineMapping(int line, int offset) {
if (line >= 0) { if (line >= 0) {
checkMapCreated(); checkMapCreated();
myLineToOffsetMapping.put(line, myStringBuilder.length()+1); myLineToOffsetMapping.put(line, offset);
} }
} }
@ -257,4 +261,8 @@ public class TextBuffer {
} }
return res; return res;
} }
public StringBuilder getOriginalText() {
return myStringBuilder;
}
} }

@ -54,11 +54,13 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute {
} }
public int findLineNumber(int pc) { public int findLineNumber(int pc) {
for (int i = 0; i < myLineInfo.length; i += 2) { if (myLineInfo.length >= 2) {
for (int i = myLineInfo.length - 2; i >= 0; i -= 2) {
if (pc >= myLineInfo[i]) { if (pc >= myLineInfo[i]) {
return myLineInfo[i + 1]; return myLineInfo[i + 1];
} }
} }
}
return -1; return -1;
} }
} }

Loading…
Cancel
Save