improve the compiling of exceptions

This commit is contained in:
Volker Berlin 2019-03-02 21:54:27 +01:00
parent b9bbb1c56d
commit cd2f07733d
5 changed files with 108 additions and 11 deletions

View File

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

View File

@ -48,7 +48,9 @@ class BranchManger {
private final HashMap<Integer, ParsedBlock> loops = new HashMap<>();
private final List<WasmInstruction> instructions;
private final List<WasmInstruction> 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:
*
* <pre>
* try {
* code1
* catch(Exception ex)
* code2
* }
* code3
* </pre>
*
* Should be converted to the follow Wasm code for tableswitch:
*
* <pre>
* block
* block (result anyref)
* try
* code1
* catch
* br_on_exn 1 0
* rethrow
* end
* br 1
* end
* local.set x
* code2
* end
* code3
* </pre>
*
* @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<ParsedBlock> parsedOperations ) {
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) {
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;
}
/**

View File

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

View File

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

View File

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