diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 822a04d..2e72e7b 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -470,6 +470,22 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod break; } break; + case gt: + switch( valueType ) { + case i32: + op = I32_GT_S; + break; + case i64: + op = I64_NE; + break; + case f32: + op = F32_NE; + break; + case f64: + op = F64_NE; + break; + } + break; } if( op == 0 ) { throw new Error( valueType + "." + numOp ); @@ -527,6 +543,9 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod codeStream.write( IF ); codeStream.write( 0x40 ); // void; the return type of the block. currently we does not use it break; + case ELSE: + codeStream.write( ELSE ); + break; case END: codeStream.write( END ); break; diff --git a/src/de/inetsoftware/jwebassembly/module/BlockOperator.java b/src/de/inetsoftware/jwebassembly/module/BlockOperator.java index bcc5f86..d4b6fd2 100644 --- a/src/de/inetsoftware/jwebassembly/module/BlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/BlockOperator.java @@ -1,3 +1,19 @@ +/* + Copyright 2018 Volker Berlin (i-net software) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ package de.inetsoftware.jwebassembly.module; /** @@ -8,5 +24,7 @@ package de.inetsoftware.jwebassembly.module; */ public enum BlockOperator { IF, + ELSE, END, + GOTO, } diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManger.java b/src/de/inetsoftware/jwebassembly/module/BranchManger.java index cb03971..6eed244 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -1,7 +1,23 @@ +/* + Copyright 2018 Volker Berlin (i-net software) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ package de.inetsoftware.jwebassembly.module; import java.io.IOException; -import java.util.ArrayDeque; +import java.util.ArrayList; import de.inetsoftware.classparser.CodeInputStream; @@ -13,20 +29,79 @@ import de.inetsoftware.classparser.CodeInputStream; */ class BranchManger { - private final ArrayDeque stack = new ArrayDeque<>(); + private final ArrayList stack = new ArrayList<>(); + + /** + * Remove all branch information. + */ + void reset() { + stack.clear(); + } /** * Start a new block. * * @param op * the start operation - * @param basePosition + * @param startPosition * the byte position of the start position * @param offset * the relative jump position */ - void start( BlockOperator op, int basePosition, int offset ) { - stack.push( new Block( op, basePosition, offset ) ); + void start( BlockOperator op, int startPosition, int offset ) { + stack.add( new Block( op, startPosition, offset ) ); + } + + /** + * Calculate all block operators from the parsed information. + */ + void calculate() { + for( int i = 0; i < stack.size(); i++ ) { + Block block = stack.get( i ); + switch( block.op ) { + case IF: + caculateIf( i, block ); + break; + } + } + } + + /** + * Calculate the ELSE and END position of an IF control structure. + * + * @param i + * the index in the stack + * @param startBlock + * the start block of the if control structure + */ + private void caculateIf( int i, Block startBlock ) { + i++; + int gotoPos = startBlock.endPosition - 3; // 3 - byte size of goto instruction + for( ; i < stack.size(); i++ ) { + Block block = stack.get( i ); + if( block.startPosition == gotoPos && block.op == BlockOperator.GOTO ) { + block.op = BlockOperator.ELSE; + block.startPosition += 3; + startBlock = block; + i++; + break; + } + if( block.startPosition > gotoPos ) { + break; + } + } + + /** + * Search the index in the stack to add the END operator + */ + int endPos = startBlock.endPosition; + for( ; i < stack.size(); i++ ) { + Block block = stack.get( i ); + if( block.startPosition >= endPos ) { + break; + } + } + stack.add( i, new Block( BlockOperator.END, endPos, 0 ) ); } /** @@ -40,13 +115,14 @@ class BranchManger { * if any I/O exception occur */ void handle( CodeInputStream byteCode, ModuleWriter writer ) throws IOException { + if( stack.isEmpty() ) { + return; + } int position = byteCode.getCodePosition(); - Block block = stack.peek(); - if( block != null ) { - if( block.endPosition == position ) { - writer.writeBlockCode( BlockOperator.END ); - stack.pop(); - } + Block block = stack.get( 0 ); + if( block.startPosition == position ) { + writer.writeBlockCode( block.op ); + stack.remove( 0 ); } } @@ -56,14 +132,14 @@ class BranchManger { private static class Block { private BlockOperator op; - private int basePosition; + private int startPosition; private int endPosition; - private Block( BlockOperator op, int basePosition, int offset ) { + private Block( BlockOperator op, int startPosition, int offset ) { this.op = op; - this.basePosition = basePosition; - this.endPosition = basePosition + offset; + this.startPosition = startPosition; + this.endPosition = startPosition + offset; } } } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index c635e5a..39e9399 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Volker Berlin (i-net software) + * Copyright 2017 - 2018 Volker Berlin (i-net software) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,6 @@ import de.inetsoftware.classparser.Code; import de.inetsoftware.classparser.CodeInputStream; import de.inetsoftware.classparser.ConstantPool; import de.inetsoftware.classparser.ConstantRef; -import de.inetsoftware.classparser.LineNumberTable; import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.WasmException; @@ -132,21 +131,15 @@ public abstract class ModuleWriter implements Closeable { writeMethodSignature( method ); locals.clear(); localTable = code.getLocalVariableTable(); - LineNumberTable lineNumberTable = code.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() ? code.getCodeSize() - : lineNumberTable.getStartOffset( i + 1 ); - CodeInputStream byteCode = code.getByteCode( offset, nextOffset - offset ); - writeCodeChunk( byteCode, lineNumber, method.getConstantPool() ); - } - } else { - CodeInputStream byteCode = code.getByteCode(); - writeCodeChunk( byteCode, -1, method.getConstantPool() ); + + branchManager.reset(); + for( CodeInputStream byteCode : code.getByteCodes() ) { + prepareBranchManager( byteCode, byteCode.getLineNumber() ); + } + branchManager.calculate(); + + for( CodeInputStream byteCode : code.getByteCodes() ) { + writeCodeChunk( byteCode, byteCode.getLineNumber(), method.getConstantPool() ); } for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) { locals.remove( 0 ); @@ -290,6 +283,72 @@ public abstract class ModuleWriter implements Closeable { */ protected abstract void writeMethodFinish( List locals ) throws IOException; + /** + * Write a chunk of byte code. + * + * @param byteCode + * a stream of byte code + * @param lineNumber + * the current line number + * @throws WasmException + * if some Java code can't converted + */ + private void prepareBranchManager( CodeInputStream byteCode, int lineNumber ) throws WasmException { + try { + while( byteCode.available() > 0 ) { + int op = byteCode.readUnsignedByte(); + switch( op ) { + case 16: // bipush + case 18: // ldc + case 21: //iload + case 22: //lload + case 23: //fload + case 24: //dload + case 25: //aload + case 54: // istore + case 55: // lstore + case 56: // fstore + case 57: // dstore + case 58: // astore + case 179: // putstatic + case 181: // putfield + byteCode.skip(1); + break; + case 17: // sipush + case 20: // ldc2_w + case 132: // iinc + case 184: // invokestatic + byteCode.skip( 2); + break; + case 153: // ifeq + case 154: // ifne + case 155: // iflt + case 156: // ifge + case 157: // ifgt + case 158: // ifle + case 159: // if_icmpeq + case 160: // if_icmpne + case 161: // if_icmplt + case 162: // if_icmpge + case 163: // if_icmpgt + case 164: // if_icmple + case 165: // if_acmpeq + case 166: // if_acmpne + int startPosition = byteCode.getCodePosition() + 2; + int offset = byteCode.readUnsignedShort(); + branchManager.start( BlockOperator.IF, startPosition, offset - 3 ); + break; + case 167: // goto + startPosition = byteCode.getCodePosition() - 1; + offset = byteCode.readUnsignedShort(); + branchManager.start( BlockOperator.GOTO, startPosition, offset ); + break; + } + } + } catch( Exception ex ) { + throw WasmException.create( ex, sourceFile, lineNumber ); + } + } /** * Write a chunk of byte code. * @@ -502,10 +561,11 @@ public abstract class ModuleWriter implements Closeable { case 154: // ifne opIfCondition( NumericOperator.eq, byteCode ); break; + case 155: // iflt + opIfCondition( NumericOperator.gt, byteCode ); + break; case 167: // goto - int baseCodePosition = byteCode.getCodePosition() - 1; - int offset = byteCode.readUnsignedShort(); - if(true)throw new WasmException( "Unimplemented byte code operation: " + op, sourceFile, lineNumber ); + byteCode.skip(2); break; case 172: // ireturn case 173: // lreturn @@ -541,12 +601,10 @@ public abstract class ModuleWriter implements Closeable { * if any I/O errors occur. */ private void opIfCondition( NumericOperator numOp, CodeInputStream byteCode ) throws IOException { - int baseCodePosition = byteCode.getCodePosition() - 1; - int offset = byteCode.readUnsignedShort(); - branchManager.start( BlockOperator.IF, baseCodePosition, offset ); + byteCode.skip(2); writeConstInt( 0 ); writeNumericOperator( numOp, ValueType.i32 ); - writeBlockCode( BlockOperator.IF ); + //writeBlockCode( BlockOperator.IF ); } /** diff --git a/src/de/inetsoftware/jwebassembly/module/NumericOperator.java b/src/de/inetsoftware/jwebassembly/module/NumericOperator.java index 1102ce8..3126bfe 100644 --- a/src/de/inetsoftware/jwebassembly/module/NumericOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/NumericOperator.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Volker Berlin (i-net software) + * Copyright 2017 - 2018 Volker Berlin (i-net software) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,4 +32,6 @@ public enum NumericOperator { shr_u, eq, ne, + gt, + lt_s, } diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 66da6ab..5e7af56 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Volker Berlin (i-net software) + * Copyright 2017 - 2018 Volker Berlin (i-net software) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -234,6 +234,12 @@ public class TextModuleWriter extends ModuleWriter { methodOutput.append( "if" ); inset++; break; + case ELSE: + inset--; + newline( methodOutput ); + methodOutput.append( "else" ); + inset++; + break; case END: inset--; newline( methodOutput );