2014-10-01 01:00:11 -04:00
package org.jetbrains.java.decompiler.main.collectors ;
2014-10-17 09:02:13 -04:00
import java.util.* ;
2014-10-07 13:03:09 -04:00
import java.util.Map.Entry ;
2014-10-01 01:00:11 -04:00
2014-10-15 00:26:49 -04:00
import org.jetbrains.java.decompiler.main.DecompilerContext ;
import org.jetbrains.java.decompiler.main.TextBuffer ;
2014-10-01 01:00:11 -04:00
public class BytecodeSourceMapper {
private int offset_total ;
2014-10-05 22:27:26 -04:00
2014-10-17 10:52:47 -04:00
private final HashMap < Integer , Integer > myOriginalLinesMapping = new HashMap < Integer , Integer > ( ) ;
2014-10-01 01:00:11 -04:00
// class, method, bytecode offset, source line
2014-10-17 09:02:13 -04:00
private final HashMap < String , HashMap < String , HashMap < Integer , Integer > > > mapping = new LinkedHashMap < String , HashMap < String , HashMap < Integer , Integer > > > ( ) ; // need to preserve order
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
public void addMapping ( String classname , String methodname , int bytecode_offset , int source_line ) {
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
HashMap < String , HashMap < Integer , Integer > > class_mapping = mapping . get ( classname ) ;
if ( class_mapping = = null ) {
2014-10-17 09:02:13 -04:00
mapping . put ( classname , class_mapping = new LinkedHashMap < String , HashMap < Integer , Integer > > ( ) ) ; // need to preserve order
2014-10-01 01:00:11 -04:00
}
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
HashMap < Integer , Integer > method_mapping = class_mapping . get ( methodname ) ;
if ( method_mapping = = null ) {
class_mapping . put ( methodname , method_mapping = new HashMap < Integer , Integer > ( ) ) ;
}
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
// don't overwrite
if ( ! method_mapping . containsKey ( bytecode_offset ) ) {
method_mapping . put ( bytecode_offset , source_line ) ;
}
}
2014-10-05 22:27:26 -04:00
public void addTracer ( String classname , String methodname , BytecodeMappingTracer tracer ) {
for ( Entry < Integer , Integer > entry : tracer . getMapping ( ) . entrySet ( ) ) {
addMapping ( classname , methodname , entry . getKey ( ) , entry . getValue ( ) ) ;
}
2014-10-17 10:52:47 -04:00
myOriginalLinesMapping . putAll ( tracer . getOriginalLinesMapping ( ) ) ;
2014-10-05 22:27:26 -04:00
}
2014-10-15 00:26:49 -04:00
public void dumpMapping ( TextBuffer buffer , boolean offsetsToHex ) {
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
String lineSeparator = DecompilerContext . getNewLineSeparator ( ) ;
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
for ( Entry < String , HashMap < String , HashMap < Integer , Integer > > > class_entry : mapping . entrySet ( ) ) {
HashMap < String , HashMap < Integer , Integer > > class_mapping = class_entry . getValue ( ) ;
buffer . append ( " class " + class_entry . getKey ( ) + " { " + lineSeparator ) ;
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
boolean is_first_method = true ;
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
for ( Entry < String , HashMap < Integer , Integer > > method_entry : class_mapping . entrySet ( ) ) {
HashMap < Integer , Integer > method_mapping = method_entry . getValue ( ) ;
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
if ( ! is_first_method ) {
2014-10-07 13:03:09 -04:00
buffer . appendLineSeparator ( ) ;
2014-10-01 01:00:11 -04:00
}
2014-10-07 13:03:09 -04:00
buffer . appendIndent ( 1 ) . append ( " method " + method_entry . getKey ( ) + " { " + lineSeparator ) ;
2014-10-05 22:27:26 -04:00
2014-10-15 02:35:45 -04:00
List < Integer > lstBytecodeOffsets = new ArrayList < Integer > ( method_mapping . keySet ( ) ) ;
Collections . sort ( lstBytecodeOffsets ) ;
for ( Integer offset : lstBytecodeOffsets ) {
Integer line = method_mapping . get ( offset ) ;
String strOffset = offsetsToHex ? Integer . toHexString ( offset ) : line . toString ( ) ;
buffer . appendIndent ( 2 ) . append ( strOffset ) . appendIndent ( 2 ) . append ( ( line + offset_total ) + lineSeparator ) ;
2014-10-01 01:00:11 -04:00
}
2014-10-07 13:03:09 -04:00
buffer . appendIndent ( 1 ) . append ( " } " ) . appendLineSeparator ( ) ;
2014-10-01 01:00:11 -04:00
is_first_method = false ;
}
2014-10-07 13:03:09 -04:00
buffer . append ( " } " ) . appendLineSeparator ( ) ;
2014-10-01 01:00:11 -04:00
}
2014-10-17 10:52:47 -04:00
// 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 ( ) ;
}
2014-10-01 01:00:11 -04:00
}
2014-10-05 22:27:26 -04:00
2014-10-01 01:00:11 -04:00
public int getTotalOffset ( ) {
return offset_total ;
}
public void setTotalOffset ( int offset_total ) {
this . offset_total = offset_total ;
}
2014-10-05 22:27:26 -04:00
public void addTotalOffset ( int offset_total ) {
this . offset_total + = offset_total ;
}
2014-10-17 10:52:47 -04:00
/ * *
* original to our line mapping
* /
public int [ ] getOriginalLinesMapping ( ) {
int [ ] res = new int [ myOriginalLinesMapping . size ( ) * 2 ] ;
int i = 0 ;
for ( Entry < Integer , Integer > entry : myOriginalLinesMapping . entrySet ( ) ) {
res [ i ] = entry . getKey ( ) ;
res [ i + 1 ] = entry . getValue ( ) + offset_total + 1 ; // make it 1 based
i + = 2 ;
}
return res ;
}
2014-10-01 01:00:11 -04:00
}