diff --git a/src/de/inetsoftware/classparser/Code.java b/src/de/inetsoftware/classparser/Code.java index e05c6b6..f52e76f 100644 --- a/src/de/inetsoftware/classparser/Code.java +++ b/src/de/inetsoftware/classparser/Code.java @@ -18,8 +18,6 @@ package de.inetsoftware.classparser; import java.io.DataInputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; import javax.annotation.Nonnull; 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 - * @throws IOException - * if any I/O error occur + * @return the stream */ - public Collection getByteCodes() throws IOException { - ArrayList list = new ArrayList<>(); - 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 CodeInputStream getByteCode() { + return new CodeInputStream( codeData, 0, codeData.length, this ); } public int getCodeSize(){ diff --git a/src/de/inetsoftware/classparser/CodeInputStream.java b/src/de/inetsoftware/classparser/CodeInputStream.java index f7584c8..c919e1c 100644 --- a/src/de/inetsoftware/classparser/CodeInputStream.java +++ b/src/de/inetsoftware/classparser/CodeInputStream.java @@ -18,6 +18,7 @@ package de.inetsoftware.classparser; import java.io.ByteArrayInputStream; import java.io.DataInputStream; +import java.io.IOException; /** * Extends the DataInputStream with a code position. @@ -26,7 +27,7 @@ import java.io.DataInputStream; */ public class CodeInputStream extends DataInputStream { - private int lineNumber; + private Code code; /** * Create a new instance of CodeInputStream. @@ -37,12 +38,12 @@ public class CodeInputStream extends DataInputStream { * the offset in the array * @param length * the length - * @param lineNumber - * the lineNumber in the source code or -1 if not available + * @param code + * 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.lineNumber = lineNumber; + this.code = code; } private CodeInputStream( ByteCodeArrayInputStream in ) { @@ -64,6 +65,22 @@ public class CodeInputStream extends DataInputStream { * @return the line number */ 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; } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 3a9b1b6..71074d1 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -16,7 +16,6 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; -import java.util.Iterator; import java.util.Map; import java.util.function.Consumer; @@ -149,10 +148,9 @@ public class ModuleGenerator { * if some Java code can't converted */ private void writeMethod( MethodInfo method ) throws WasmException { - int lineNumber = -1; + CodeInputStream byteCode = null; try { 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 FunctionName name = new FunctionName( method ); writeExport( name, method ); @@ -162,19 +160,14 @@ public class ModuleGenerator { localVariables.reset(); stackManager.reset(); branchManager.reset(); - for( CodeInputStream byteCode : code.getByteCodes() ) { - prepareCodeChunk( byteCode, lineNumber = byteCode.getLineNumber(), method.getConstantPool() ); - } + byteCode = code.getByteCode(); + prepareCodeChunk( byteCode, method.getConstantPool() ); branchManager.calculate(); localVariables.calculate(); - CodeInputStream byteCode = null; boolean endWithReturn = false; - Iterator byteCodes = code.getByteCodes().iterator(); - while( byteCodes.hasNext() ) { - byteCode = byteCodes.next(); - endWithReturn = writeCodeChunk( byteCode, lineNumber = byteCode.getLineNumber(), method.getConstantPool() ); - } + byteCode = code.getByteCode(); + endWithReturn = writeCode( byteCode, method.getConstantPool() ); branchManager.handle( byteCode, writer ); // write the last end operators if( !endWithReturn && returnType != null ) { // 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: writer.writeConstDouble( 0 ); break; + default: } writer.writeBlockCode( WasmBlockOperator.RETURN, null ); } writer.writeMethodFinish( localVariables.getLocalTypes( paramCount ) ); } } catch( Exception ioex ) { + int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); throw WasmException.create( ioex, sourceFile, lineNumber ); } } @@ -298,14 +293,12 @@ public class ModuleGenerator { * * @param byteCode * a stream of byte code - * @param lineNumber - * the current line number * @param constantPool * the constant pool of the the current class * @throws WasmException * 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 { while( byteCode.available() > 0 ) { int codePosition = byteCode.getCodePosition(); @@ -466,15 +459,15 @@ public class ModuleGenerator { case 165: // if_acmpeq case 166: // if_acmpne int offset = byteCode.readShort(); - branchManager.start( JavaBlockOperator.IF, codePosition, offset, lineNumber ); + branchManager.start( JavaBlockOperator.IF, codePosition, offset, byteCode.getLineNumber() ); break; case 167: // goto offset = byteCode.readShort(); - branchManager.start( JavaBlockOperator.GOTO, codePosition, offset, lineNumber ); + branchManager.start( JavaBlockOperator.GOTO, codePosition, offset, byteCode.getLineNumber() ); break; case 170: // tableswitch case 171: // lookupswitch - prepareSwitchCode( byteCode, op == 171, lineNumber ); + prepareSwitchCode( byteCode, op == 171, byteCode.getLineNumber() ); break; case 184: // invokestatic ConstantRef method = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); @@ -487,7 +480,7 @@ public class ModuleGenerator { } } } 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 * a stream of byte code - * @param lineNumber - * the current line number * @param constantPool * the constant pool of the the current class * @throws WasmException * if some Java code can't converted * @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; try { while( byteCode.available() > 0 ) { @@ -681,7 +672,7 @@ public class ModuleGenerator { case 94: // dup2_x2 case 95: // swap // 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 writer.writeNumericOperator( NumericOperator.add, ValueType.i32); break; @@ -739,7 +730,7 @@ public class ModuleGenerator { case 114: // frem case 115: // drem //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 writer.writeConstInt( -1 ); writer.writeNumericOperator( NumericOperator.mul, ValueType.i32 ); @@ -922,13 +913,13 @@ public class ModuleGenerator { writer.writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() ); break; 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 ) { throw ex; } catch( Exception ex ) { - throw WasmException.create( ex, sourceFile, lineNumber ); + throw WasmException.create( ex, sourceFile, byteCode.getLineNumber() ); } return endWithReturn; }