experimental exception handling

This commit is contained in:
Volker Berlin 2018-11-03 18:01:42 +01:00
parent ce3e2d7546
commit f15e9c8341
8 changed files with 79 additions and 9 deletions

View File

@ -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 );
}

View File

@ -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<ParsedBlock> 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.
*/

View File

@ -27,4 +27,5 @@ public enum JavaBlockOperator {
GOTO,
SWITCH,
LOOP,
TRY,
}

View File

@ -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

View File

@ -34,4 +34,6 @@ public enum WasmBlockOperator {
BR_TABLE,
LOOP,
UNREACHABLE,
TRY,
CATCH,
}

View File

@ -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 );
}

View File

@ -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() );
}
/**

View File

@ -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;