diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 3b813c7..bc10d1c 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -847,7 +847,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod break; case BLOCK: codeStream.writeOpCode( BLOCK ); - codeStream.writeValueType( ValueType.empty ); // void; the return type of the block. currently we does not use it + codeStream.writeValueType( data == null ? ValueType.empty : (ValueType)data ); // void; the return type of the block. break; case BR: codeStream.writeOpCode( BR ); @@ -879,6 +879,18 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod case CATCH: codeStream.writeOpCode( CATCH ); break; + case THROW: + codeStream.writeOpCode( THROW ); + codeStream.writeVaruint32( 0 ); // event/exception ever 0 because currently there is only one with signature anyref + break; + case RETHROW: + codeStream.writeOpCode( RETHROW ); + break; + case BR_ON_EXN: + codeStream.writeOpCode( BR_ON_EXN ); + codeStream.writeVaruint32( (Integer)data ); // break depth + codeStream.writeVaruint32( 0 ); // event/exception ever 0 because currently there is only one with signature anyref + break; default: throw new Error( "Unknown block: " + op ); } diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManger.java b/src/de/inetsoftware/jwebassembly/module/BranchManger.java index 3bbbbdf..0d119ec 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -48,7 +48,9 @@ class BranchManger { private final HashMap loops = new HashMap<>(); - private final List instructions; + private final List instructions; + + private TryCatchFinally[] exceptionTable; /** * Create a branch manager. @@ -71,7 +73,7 @@ class BranchManger { root.clear(); loops.clear(); root.endPos = code.getCodeSize(); - TryCatchFinally[] exceptionTable = code.getExceptionTable(); + exceptionTable = code.getExceptionTable(); for( TryCatchFinally ex : exceptionTable ) { allParsedOperations.add( new TryCatchParsedBlock( ex ) ); } @@ -588,6 +590,36 @@ class BranchManger { /** * Calculate the needed nodes for try/catch + * Sample: The follow Java code: + * + *
+     * try {
+     *   code1
+     * catch(Exception ex)
+     *   code2
+     * }
+     * code3
+     * 
+ * + * Should be converted to the follow Wasm code for tableswitch: + * + *
+     * block
+     *   block (result anyref)
+     *     try
+     *       code1
+     *     catch
+     *       br_on_exn 1 0
+     *       rethrow
+     *     end
+     *     br 1
+     *   end
+     *   local.set x
+     *   code2
+     * end
+     * code3
+     * 
+ * * @param parent * the parent branch * @param tryBlock @@ -595,14 +627,14 @@ class BranchManger { * @param parsedOperations * the not consumed operations in the parent branch */ - private void calculateTry ( BranchNode parent, TryCatchParsedBlock tryBlock, List parsedOperations ) { + private void calculateTry( BranchNode parent, TryCatchParsedBlock tryBlock, List parsedOperations ) { TryCatchFinally tryCatch = tryBlock.tryCatch; int gotoPos = tryCatch.getEnd(); // alternativ we can use tryCatch.getHandler()-3 int endPos = parent.endPos; for( int i = 0; i < parsedOperations.size(); i++ ) { ParsedBlock parsedBlock = parsedOperations.get( i ); - if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition) { + if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO && parsedBlock.startPosition < parsedBlock.endPosition ) { parsedOperations.remove( i ); endPos = parsedBlock.endPosition; break; @@ -611,8 +643,40 @@ class BranchManger { break; } } - parent.add( new BranchNode( tryBlock.startPosition, tryCatch.getHandler(), WasmBlockOperator.TRY, null ) ); - parent.add( new BranchNode( tryCatch.getHandler(), endPos, WasmBlockOperator.CATCH, WasmBlockOperator.END ) ); + int startPos = tryBlock.startPosition; + int catchPos = tryCatch.getHandler(); + BranchNode node = new BranchNode( startPos, endPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END ); + parent.add( node ); + parent = node; + + node = new BranchNode( startPos, catchPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, ValueType.anyref ); + parent.add( node ); + parent = node; + + parent.add( new BranchNode( startPos, catchPos, WasmBlockOperator.TRY, null ) ); + BranchNode catchNode = new BranchNode( catchPos, catchPos, WasmBlockOperator.CATCH, WasmBlockOperator.END ); + parent.add( catchNode ); + + catchNode.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.BR_ON_EXN, null, 1 ) ); + catchNode.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.RETHROW, null ) ); + + parent.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.BR, null, 1 ) ); + } + + /** + * Check if there are a start of a catch block on the code position. + * + * @param codePosition + * the code position + * @return true, if there is a catch block + */ + boolean isCatch( int codePosition ) { + for( TryCatchFinally tryCatch : exceptionTable ) { + if( tryCatch.getHandler() == codePosition ) { + return true; + } + } + return false; } /** diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index 688af4a..f2c7300 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -241,7 +241,11 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { case 76: // astore_1 case 77: // astore_2 case 78: // astore_3 - storeType = findPreviousPushInstructionPushValueType(); + if( branchManager.isCatch( codePos ) ) { + storeType = ValueType.anyref; // for the catch there are no previous instructions + } else { + storeType = findPreviousPushInstructionPushValueType(); + } addLoadStoreInstruction( storeType, false, op - 75, codePos ); break; case 79: // iastore @@ -556,7 +560,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { ref = (ConstantRef)constantPool.get( byteCode.readUnsignedShort() ); addStructInstruction( StructOperator.SET, ref.getClassName(), ref.getName(), codePos ); break; - //TODO case 182: // invokevirtual + case 182: // invokevirtual case 183: // invokespecial, invoke a constructor case 184: // invokestatic idx = byteCode.readUnsignedShort(); @@ -603,7 +607,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { case 190: // arraylength addArrayInstruction( ArrayOperator.LENGTH, ValueType.i32, codePos ); break; - //TODO case 191: // athrow + case 191: // athrow + addBlockInstruction( WasmBlockOperator.THROW, null, codePos ); + break; //TODO case 192: // checkcast //TODO case 193: // instanceof //TODO case 194: // monitorenter diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 3c34910..5a0d039 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -389,6 +389,9 @@ public class TextModuleWriter extends ModuleWriter { break; case BLOCK: name = "block"; + if( data != null ) { + name += " (result " + data + ")"; + } insetAfter++; break; case BR: @@ -420,6 +423,15 @@ public class TextModuleWriter extends ModuleWriter { name = "catch"; insetAfter++; break; + case THROW: + name = "throw 0"; // currently there is only one event/exception with anyref + break; + case RETHROW: + name = "rethrow"; + break; + case BR_ON_EXN: + name = "br_on_exn " + data + " 0"; // br_on_exn, break depth, event; // currently there is only one event/exception with anyref + break; default: throw new Error( "Unknown block: " + op ); } diff --git a/src/de/inetsoftware/jwebassembly/wasm/WasmBlockOperator.java b/src/de/inetsoftware/jwebassembly/wasm/WasmBlockOperator.java index 0571054..c0de666 100644 --- a/src/de/inetsoftware/jwebassembly/wasm/WasmBlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/wasm/WasmBlockOperator.java @@ -1,5 +1,5 @@ /* - Copyright 2018 Volker Berlin (i-net software) + Copyright 2018 - 2019 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. @@ -36,4 +36,7 @@ public enum WasmBlockOperator { UNREACHABLE, TRY, CATCH, + THROW, + RETHROW, + BR_ON_EXN, }