From 1a183952b45decb5c1d68c434b9807ab11c37f1d Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Fri, 17 Oct 2014 18:52:47 +0400 Subject: [PATCH] decompiler: build original lines mapping --- .../java/decompiler/main/ClassWriter.java | 11 +++---- .../java/decompiler/main/TextBuffer.java | 5 +++ .../collectors/BytecodeMappingTracer.java | 32 +++++++++++++++++++ .../main/collectors/BytecodeSourceMapper.java | 24 +++++++++++++- .../attr/StructLineNumberTableAttribute.java | 4 +++ .../TestClassSimpleBytecodeMapping.dec | 10 ++++++ 6 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/src/org/jetbrains/java/decompiler/main/ClassWriter.java index 9fcf4bb..db7d6d6 100644 --- a/src/org/jetbrains/java/decompiler/main/ClassWriter.java +++ b/src/org/jetbrains/java/decompiler/main/ClassWriter.java @@ -577,10 +577,9 @@ public class ClassWriter { boolean isDeprecated = mt.getAttributes().containsKey("Deprecated"); boolean clinit = false, init = false, dinit = false; - StructLineNumberTableAttribute lineNumberTable = null; - if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) { - lineNumberTable = (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); - } + StructLineNumberTableAttribute lineNumberTable = + (StructLineNumberTableAttribute)mt.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_LINE_NUMBER_TABLE); + tracer.setLineNumberTable(lineNumberTable); MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor()); @@ -797,7 +796,7 @@ public class ClassWriter { } // We do not have line information for method start, lets have it here for now - if (lineNumberTable != null) { + if (lineNumberTable != null && DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) { buffer.setCurrentLine(lineNumberTable.getFirstLine() - 1); } buffer.append('{').appendLineSeparator(); @@ -813,7 +812,7 @@ public class ClassWriter { hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0; - if (!hideMethod && lineNumberTable != null) { + if (!hideMethod && lineNumberTable != null && DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_LINE_NUMBERS)) { mapLines(code, lineNumberTable, tracer, startLine); } diff --git a/src/org/jetbrains/java/decompiler/main/TextBuffer.java b/src/org/jetbrains/java/decompiler/main/TextBuffer.java index b952811..4e51e6f 100644 --- a/src/org/jetbrains/java/decompiler/main/TextBuffer.java +++ b/src/org/jetbrains/java/decompiler/main/TextBuffer.java @@ -63,6 +63,11 @@ public class TextBuffer { return this; } + public TextBuffer append(int i) { + myStringBuilder.append(i); + return this; + } + public TextBuffer appendLineSeparator() { myStringBuilder.append(myLineSeparator); return this; diff --git a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java index 20af427..7a26300 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeMappingTracer.java @@ -1,6 +1,10 @@ package org.jetbrains.java.decompiler.main.collectors; +import org.jetbrains.java.decompiler.struct.attr.StructLineNumberTableAttribute; + +import java.util.Collections; import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -8,6 +12,8 @@ public class BytecodeMappingTracer { private int current_sourceline; + private StructLineNumberTableAttribute myLineNumberTable = null; + // bytecode offset, source line private HashMap mapping = new HashMap(); @@ -67,4 +73,30 @@ public class BytecodeMappingTracer { this.current_sourceline = current_sourceline; } + public void setLineNumberTable(StructLineNumberTableAttribute lineNumberTable) { + myLineNumberTable = lineNumberTable; + } + + public Map getOriginalLinesMapping() { + if (myLineNumberTable == null) { + return Collections.emptyMap(); + } + HashMap res = new HashMap(); + int[] data = myLineNumberTable.getRawData(); + for (int i = 0; i < data.length; i+=2) { + int originalOffset = data[i]; + int originalLine = data[i+1]; + Integer newLine = mapping.get(originalOffset); + if (newLine != null) { + res.put(originalLine, newLine); + } + } + for (Entry entry : mapping.entrySet()) { + int originalLine = myLineNumberTable.findLineNumber(entry.getKey()); + if (originalLine > -1) { + res.put(originalLine, entry.getValue()); + } + } + return res; + } } diff --git a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java index 0f1bb4d..20de771 100644 --- a/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java +++ b/src/org/jetbrains/java/decompiler/main/collectors/BytecodeSourceMapper.java @@ -10,6 +10,8 @@ public class BytecodeSourceMapper { private int offset_total; + private final HashMap myOriginalLinesMapping = new HashMap(); + // class, method, bytecode offset, source line private final HashMap>> mapping = new LinkedHashMap>>(); // need to preserve order @@ -35,6 +37,7 @@ public class BytecodeSourceMapper { for(Entry entry : tracer.getMapping().entrySet()) { addMapping(classname, methodname, entry.getKey(), entry.getValue()); } + myOriginalLinesMapping.putAll(tracer.getOriginalLinesMapping()); } public void dumpMapping(TextBuffer buffer, boolean offsetsToHex) { @@ -69,6 +72,13 @@ public class BytecodeSourceMapper { } buffer.append("}").appendLineSeparator(); } + + // lines mapping + buffer.append("Lines mapping:").appendLineSeparator(); + int[] mapping = getOriginalLinesMapping(); + for (int i = 0; i < mapping.length; i+=2) { + buffer.append(mapping[i]).append(" <-> ").append(mapping[i+1]).appendLineSeparator(); + } } public int getTotalOffset() { @@ -83,5 +93,17 @@ public class BytecodeSourceMapper { this.offset_total += offset_total; } - + /** + * original to our line mapping + */ + public int[] getOriginalLinesMapping() { + int[] res = new int[myOriginalLinesMapping.size()*2]; + int i = 0; + for (Entry entry : myOriginalLinesMapping.entrySet()) { + res[i] = entry.getKey(); + res[i+1] = entry.getValue() + offset_total + 1; // make it 1 based + i+=2; + } + return res; + } } diff --git a/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java b/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java index 7149485..3cd757b 100644 --- a/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java +++ b/src/org/jetbrains/java/decompiler/struct/attr/StructLineNumberTableAttribute.java @@ -63,4 +63,8 @@ public class StructLineNumberTableAttribute extends StructGeneralAttribute { } return -1; } + + public int[] getRawData() { + return myLineInfo; + } } diff --git a/testData/results/TestClassSimpleBytecodeMapping.dec b/testData/results/TestClassSimpleBytecodeMapping.dec index 3742f96..ce9cc0c 100644 --- a/testData/results/TestClassSimpleBytecodeMapping.dec +++ b/testData/results/TestClassSimpleBytecodeMapping.dec @@ -55,3 +55,13 @@ class pkg/TestClassSimpleBytecodeMapping{ 1 20 } } +Lines mapping: +17 <-> 8 +21 <-> 11 +22 <-> 12 +23 <-> 13 +25 <-> 15 +26 <-> 16 +12 <-> 5 +14 <-> 6 +31 <-> 21