From f15e9c834128f4309e0bffe1ac3281e855b0d4df Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sat, 3 Nov 2018 18:01:42 +0100 Subject: [PATCH] experimental exception handling --- .../binary/BinaryModuleWriter.java | 7 +++ .../jwebassembly/module/BranchManger.java | 50 ++++++++++++++++++- .../module/JavaBlockOperator.java | 1 + .../jwebassembly/module/ModuleGenerator.java | 12 +++-- .../module/WasmBlockOperator.java | 2 + .../jwebassembly/text/TextModuleWriter.java | 9 ++++ .../inetsoftware/jwebassembly/WasmRule.java | 5 +- test/de/inetsoftware/jwebassembly/WatTest.js | 2 +- 8 files changed, 79 insertions(+), 9 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index a9983e4..886de1a 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -749,6 +749,13 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod case UNREACHABLE: codeStream.writeOpCode( UNREACHABLE ); break; + case TRY: + codeStream.writeOpCode( TRY ); + codeStream.write( ValueType.empty.getCode() ); // void; the return type of the try. currently we does not use it + break; + case CATCH: + codeStream.writeOpCode( CATCH ); + 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 8dffff1..963031a 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -26,6 +26,7 @@ import java.util.List; import javax.annotation.Nonnull; import de.inetsoftware.classparser.CodeInputStream; +import de.inetsoftware.classparser.TryCatchFinally; import de.inetsoftware.jwebassembly.WasmException; /** @@ -57,10 +58,13 @@ class BranchManger { /** * Remove all branch information for reusing the manager. */ - void reset() { + void reset( TryCatchFinally[] exceptionTable ) { allParsedOperations.clear(); root.clear(); loops.clear(); + for( TryCatchFinally ex : exceptionTable ) { + allParsedOperations.add( new TryCatchParsedBlock( ex ) ); + } } /** @@ -224,6 +228,9 @@ class BranchManger { case LOOP: calculateLoop( parent, parsedBlock, parsedOperations ); break; + case TRY: + calculateTry( parent, (TryCatchParsedBlock)parsedBlock, parsedOperations ); + break; default: throw new WasmException( "Unimplemented block code operation: " + parsedBlock.op, null, null, parsedBlock.lineNumber ); } @@ -569,6 +576,35 @@ class BranchManger { // loopNode.add( new BranchNode( loopBlock.endPosition, loopBlock.endPosition, WasmBlockOperator.BR, null, 0 ) ); // continue to the start of the loop } + /** + * Calculate the needed nodes for try/catch + * @param parent + * the parent branch + * @param tryBlock + * the virtual TRY operation + * @param parsedOperations + * the not consumed operations in the parent branch + */ + 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) { + parsedOperations.remove( i ); + endPos = parsedBlock.endPosition; + break; + } + if( parsedBlock.startPosition > gotoPos ) { + break; + } + } + parent.add( new BranchNode( tryBlock.startPosition, tryCatch.getHandler(), WasmBlockOperator.TRY, null ) ); + parent.add( new BranchNode( tryCatch.getHandler(), endPos, WasmBlockOperator.CATCH, WasmBlockOperator.END ) ); + } + /** * Check on every instruction position if there any branch is ending * @@ -682,6 +718,18 @@ class BranchManger { } } + /** + * Description of a parsed try-Catch structure. + */ + private static class TryCatchParsedBlock extends ParsedBlock { + private final TryCatchFinally tryCatch; + + TryCatchParsedBlock( TryCatchFinally tryCatch ) { + super( JavaBlockOperator.TRY, tryCatch.getStart(), 0, -1 ); + this.tryCatch = tryCatch; + } + } + /** * Described a code branch/block node in a tree structure. */ diff --git a/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java index 4431775..dfd1184 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java @@ -27,4 +27,5 @@ public enum JavaBlockOperator { GOTO, SWITCH, LOOP, + TRY, } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index f1bfa3f..123df9a 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -159,7 +159,7 @@ public class ModuleGenerator { writer.writeMethodStart( name ); localVariables.reset(); - branchManager.reset(); + branchManager.reset( code.getExceptionTable() ); byteCode = code.getByteCode(); writeCode( byteCode, method.getConstantPool() ); @@ -388,10 +388,12 @@ public class ModuleGenerator { case 74: // dstore_3 instr = loadStore( ValueType.f64, false, op - 71, codePos ); break; - //TODO case 75: // astore_0 - //TODO case 76: // astore_1 - //TODO case 77: // astore_2 - //TODO case 78: // astore_3 + case 75: // astore_0 + case 76: // astore_1 + case 77: // astore_2 + case 78: // astore_3 + instr = loadStore( ValueType.anyref, false, op - 75, codePos ); + break; //TODO case 79: // iastore //TODO case 80: // lastore //TODO case 81: // fastore diff --git a/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java b/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java index 60fc2ba..c07cd85 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java @@ -34,4 +34,6 @@ public enum WasmBlockOperator { BR_TABLE, LOOP, UNREACHABLE, + TRY, + CATCH, } diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index ad72457..c020e65 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -345,6 +345,15 @@ public class TextModuleWriter extends ModuleWriter { case UNREACHABLE: name = "unreachable"; break; + case TRY: + name = "try"; + insetAfter++; + break; + case CATCH: + inset--; + name = "catch"; + insetAfter++; + break; default: throw new Error( "Unknown block: " + op ); } diff --git a/test/de/inetsoftware/jwebassembly/WasmRule.java b/test/de/inetsoftware/jwebassembly/WasmRule.java index 40c981f..48d86ff 100644 --- a/test/de/inetsoftware/jwebassembly/WasmRule.java +++ b/test/de/inetsoftware/jwebassembly/WasmRule.java @@ -291,7 +291,7 @@ public class WasmRule extends TemporaryFolder { * if the download failed */ private ProcessBuilder spiderMonkeyCommand() throws IOException { - return new ProcessBuilder( spiderMonkey.getCommand(), spiderMonkeyScript.getAbsolutePath() ); + return new ProcessBuilder( spiderMonkey.getCommand(), "--wasm-gc", spiderMonkeyScript.getAbsolutePath() ); } /** @@ -312,7 +312,8 @@ public class WasmRule extends TemporaryFolder { command += "/bin/node"; } } - return new ProcessBuilder( command, "--experimental-wasm-se", "--experimental-wasm-sat-f2i-conversions", script.getAbsolutePath() ); + // details see with command: node --v8-options + return new ProcessBuilder( command, "--experimental-wasm-se", "--experimental-wasm-sat-f2i-conversions", "--experimental-wasm-eh", "--experimental-wasm-anyref", script.getAbsolutePath() ); } /** diff --git a/test/de/inetsoftware/jwebassembly/WatTest.js b/test/de/inetsoftware/jwebassembly/WatTest.js index 38aad7c..cfe1ca8 100644 --- a/test/de/inetsoftware/jwebassembly/WatTest.js +++ b/test/de/inetsoftware/jwebassembly/WatTest.js @@ -6,7 +6,7 @@ var wabt = require("wabt")(); var filename = '{test.wat}'; var text = nodeFS['readFileSync'](filename, "utf8"); -var features = {'sat_float_to_int':true, 'sign_extension':true}; +var features = {'sat_float_to_int':true, 'sign_extension':true, 'exceptions':true}; var ret = wabt.parseWat(filename, text, features); ret = ret.toBinary({}).buffer;