Use a single CoeInputStream pro method instead chucks pro line number

This commit is contained in:
Volker Berlin 2018-06-03 11:54:45 +02:00
parent 0c83869a81
commit ecd61dcde7
3 changed files with 44 additions and 54 deletions

View File

@ -18,8 +18,6 @@ package de.inetsoftware.classparser;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -128,28 +126,12 @@ public class Code {
} }
/** /**
* Get a list of CodeInputStream separated by source code line number. * Get the stream of Java Byte code instruction of this method.
* *
* @return the list * @return the stream
* @throws IOException
* if any I/O error occur
*/ */
public Collection<CodeInputStream> getByteCodes() throws IOException { public CodeInputStream getByteCode() {
ArrayList<CodeInputStream> list = new ArrayList<>(); return new CodeInputStream( codeData, 0, codeData.length, this );
LineNumberTable lineNumberTable = getLineNumberTable();
if( lineNumberTable != null ) {
int lineNumber;
for( int i = 0; i < lineNumberTable.size(); i++ ) {
lineNumber = lineNumberTable.getLineNumber( i );
int offset = lineNumberTable.getStartOffset( i );
int nextOffset = i + 1 == lineNumberTable.size() ? getCodeSize()
: lineNumberTable.getStartOffset( i + 1 );
list.add( new CodeInputStream( codeData, offset, nextOffset - offset, lineNumber ) );
}
} else {
list.add( new CodeInputStream( codeData, 0, codeData.length, -1 ) );
}
return list;
} }
public int getCodeSize(){ public int getCodeSize(){

View File

@ -18,6 +18,7 @@ package de.inetsoftware.classparser;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.IOException;
/** /**
* Extends the DataInputStream with a code position. * Extends the DataInputStream with a code position.
@ -26,7 +27,7 @@ import java.io.DataInputStream;
*/ */
public class CodeInputStream extends DataInputStream { public class CodeInputStream extends DataInputStream {
private int lineNumber; private Code code;
/** /**
* Create a new instance of CodeInputStream. * Create a new instance of CodeInputStream.
@ -37,12 +38,12 @@ public class CodeInputStream extends DataInputStream {
* the offset in the array * the offset in the array
* @param length * @param length
* the length * the length
* @param lineNumber * @param code
* the lineNumber in the source code or -1 if not available * the calling code to get the line numbers
*/ */
CodeInputStream( byte[] buf, int offset, int length, int lineNumber ) { CodeInputStream( byte[] buf, int offset, int length, Code code ) {
this( new ByteCodeArrayInputStream( buf, offset, length ) ); this( new ByteCodeArrayInputStream( buf, offset, length ) );
this.lineNumber = lineNumber; this.code = code;
} }
private CodeInputStream( ByteCodeArrayInputStream in ) { private CodeInputStream( ByteCodeArrayInputStream in ) {
@ -64,6 +65,22 @@ public class CodeInputStream extends DataInputStream {
* @return the line number * @return the line number
*/ */
public int getLineNumber() { public int getLineNumber() {
int lineNumber = -1;
try {
LineNumberTable lineNumberTable = code.getLineNumberTable();
if( lineNumberTable != null ) {
int codePos = getCodePosition();
for( int i = 0; i < lineNumberTable.size(); i++ ) {
int offset = lineNumberTable.getStartOffset( i );
if( offset > codePos ) {
break;
}
lineNumber = lineNumberTable.getLineNumber( i );
}
}
} catch( IOException e ) {
// ignore, line naumber are only needed for debug information
}
return lineNumber; return lineNumber;
} }

View File

@ -16,7 +16,6 @@
package de.inetsoftware.jwebassembly.module; package de.inetsoftware.jwebassembly.module;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -149,10 +148,9 @@ public class ModuleGenerator {
* if some Java code can't converted * if some Java code can't converted
*/ */
private void writeMethod( MethodInfo method ) throws WasmException { private void writeMethod( MethodInfo method ) throws WasmException {
int lineNumber = -1; CodeInputStream byteCode = null;
try { try {
Code code = method.getCode(); Code code = method.getCode();
lineNumber = code.getFirstLineNr();
if( code != null && method.getAnnotation( "org.webassembly.annotation.Import" ) == null ) { // abstract methods and interface methods does not have code if( code != null && method.getAnnotation( "org.webassembly.annotation.Import" ) == null ) { // abstract methods and interface methods does not have code
FunctionName name = new FunctionName( method ); FunctionName name = new FunctionName( method );
writeExport( name, method ); writeExport( name, method );
@ -162,19 +160,14 @@ public class ModuleGenerator {
localVariables.reset(); localVariables.reset();
stackManager.reset(); stackManager.reset();
branchManager.reset(); branchManager.reset();
for( CodeInputStream byteCode : code.getByteCodes() ) { byteCode = code.getByteCode();
prepareCodeChunk( byteCode, lineNumber = byteCode.getLineNumber(), method.getConstantPool() ); prepareCodeChunk( byteCode, method.getConstantPool() );
}
branchManager.calculate(); branchManager.calculate();
localVariables.calculate(); localVariables.calculate();
CodeInputStream byteCode = null;
boolean endWithReturn = false; boolean endWithReturn = false;
Iterator<CodeInputStream> byteCodes = code.getByteCodes().iterator(); byteCode = code.getByteCode();
while( byteCodes.hasNext() ) { endWithReturn = writeCode( byteCode, method.getConstantPool() );
byteCode = byteCodes.next();
endWithReturn = writeCodeChunk( byteCode, lineNumber = byteCode.getLineNumber(), method.getConstantPool() );
}
branchManager.handle( byteCode, writer ); // write the last end operators branchManager.handle( byteCode, writer ); // write the last end operators
if( !endWithReturn && returnType != null ) { if( !endWithReturn && returnType != null ) {
// if a method ends with a loop without a break then code after the loop is no reachable // if a method ends with a loop without a break then code after the loop is no reachable
@ -193,12 +186,14 @@ public class ModuleGenerator {
case f64: case f64:
writer.writeConstDouble( 0 ); writer.writeConstDouble( 0 );
break; break;
default:
} }
writer.writeBlockCode( WasmBlockOperator.RETURN, null ); writer.writeBlockCode( WasmBlockOperator.RETURN, null );
} }
writer.writeMethodFinish( localVariables.getLocalTypes( paramCount ) ); writer.writeMethodFinish( localVariables.getLocalTypes( paramCount ) );
} }
} catch( Exception ioex ) { } catch( Exception ioex ) {
int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber();
throw WasmException.create( ioex, sourceFile, lineNumber ); throw WasmException.create( ioex, sourceFile, lineNumber );
} }
} }
@ -298,14 +293,12 @@ public class ModuleGenerator {
* *
* @param byteCode * @param byteCode
* a stream of byte code * a stream of byte code
* @param lineNumber
* the current line number
* @param constantPool * @param constantPool
* the constant pool of the the current class * the constant pool of the the current class
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
*/ */
private void prepareCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool ) throws WasmException { private void prepareCodeChunk( CodeInputStream byteCode, ConstantPool constantPool ) throws WasmException {
try { try {
while( byteCode.available() > 0 ) { while( byteCode.available() > 0 ) {
int codePosition = byteCode.getCodePosition(); int codePosition = byteCode.getCodePosition();
@ -466,15 +459,15 @@ public class ModuleGenerator {
case 165: // if_acmpeq case 165: // if_acmpeq
case 166: // if_acmpne case 166: // if_acmpne
int offset = byteCode.readShort(); int offset = byteCode.readShort();
branchManager.start( JavaBlockOperator.IF, codePosition, offset, lineNumber ); branchManager.start( JavaBlockOperator.IF, codePosition, offset, byteCode.getLineNumber() );
break; break;
case 167: // goto case 167: // goto
offset = byteCode.readShort(); offset = byteCode.readShort();
branchManager.start( JavaBlockOperator.GOTO, codePosition, offset, lineNumber ); branchManager.start( JavaBlockOperator.GOTO, codePosition, offset, byteCode.getLineNumber() );
break; break;
case 170: // tableswitch case 170: // tableswitch
case 171: // lookupswitch case 171: // lookupswitch
prepareSwitchCode( byteCode, op == 171, lineNumber ); prepareSwitchCode( byteCode, op == 171, byteCode.getLineNumber() );
break; break;
case 184: // invokestatic case 184: // invokestatic
ConstantRef method = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); ConstantRef method = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() );
@ -487,7 +480,7 @@ public class ModuleGenerator {
} }
} }
} catch( Exception ex ) { } catch( Exception ex ) {
throw WasmException.create( ex, sourceFile, lineNumber ); throw WasmException.create( ex, sourceFile, byteCode.getLineNumber() );
} }
} }
@ -537,19 +530,17 @@ public class ModuleGenerator {
} }
/** /**
* Write a chunk of byte code. * Write the byte code of a method.
* *
* @param byteCode * @param byteCode
* a stream of byte code * a stream of byte code
* @param lineNumber
* the current line number
* @param constantPool * @param constantPool
* the constant pool of the the current class * the constant pool of the the current class
* @throws WasmException * @throws WasmException
* if some Java code can't converted * if some Java code can't converted
* @return true, if the last operation was a return * @return true, if the last operation was a return
*/ */
private boolean writeCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool ) throws WasmException { private boolean writeCode( CodeInputStream byteCode, ConstantPool constantPool ) throws WasmException {
boolean endWithReturn = false; boolean endWithReturn = false;
try { try {
while( byteCode.available() > 0 ) { while( byteCode.available() > 0 ) {
@ -681,7 +672,7 @@ public class ModuleGenerator {
case 94: // dup2_x2 case 94: // dup2_x2
case 95: // swap case 95: // swap
// can be do with functions with more as one return value in future WASM standard // can be do with functions with more as one return value in future WASM standard
throw new WasmException( "Stack duplicate is not supported in current WASM. try to save immediate values in a local variable: " + op, sourceFile, lineNumber ); throw new WasmException( "Stack duplicate is not supported in current WASM. try to save immediate values in a local variable: " + op, sourceFile, byteCode.getLineNumber() );
case 96: // iadd case 96: // iadd
writer.writeNumericOperator( NumericOperator.add, ValueType.i32); writer.writeNumericOperator( NumericOperator.add, ValueType.i32);
break; break;
@ -739,7 +730,7 @@ public class ModuleGenerator {
case 114: // frem case 114: // frem
case 115: // drem case 115: // drem
//TODO can be implemented with a helper function like: (a - (long)(a / b) * (double)b) //TODO can be implemented with a helper function like: (a - (long)(a / b) * (double)b)
throw new WasmException( "Modulo/Remainder for floating numbers is not supported in WASM. Use int or long data types." + op, sourceFile, lineNumber ); throw new WasmException( "Modulo/Remainder for floating numbers is not supported in WASM. Use int or long data types." + op, sourceFile, byteCode.getLineNumber() );
case 116: // ineg case 116: // ineg
writer.writeConstInt( -1 ); writer.writeConstInt( -1 );
writer.writeNumericOperator( NumericOperator.mul, ValueType.i32 ); writer.writeNumericOperator( NumericOperator.mul, ValueType.i32 );
@ -922,13 +913,13 @@ public class ModuleGenerator {
writer.writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() ); writer.writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() );
break; break;
default: default:
throw new WasmException( "Unimplemented Java byte code operation: " + op, sourceFile, lineNumber ); throw new WasmException( "Unimplemented Java byte code operation: " + op, sourceFile, byteCode.getLineNumber() );
} }
} }
} catch( WasmException ex ) { } catch( WasmException ex ) {
throw ex; throw ex;
} catch( Exception ex ) { } catch( Exception ex ) {
throw WasmException.create( ex, sourceFile, lineNumber ); throw WasmException.create( ex, sourceFile, byteCode.getLineNumber() );
} }
return endWithReturn; return endWithReturn;
} }