Simplify the try/catch structure

This commit is contained in:
Volker Berlin 2020-04-18 13:09:11 +02:00
parent 5a665b7c11
commit 87359fb497
10 changed files with 184 additions and 75 deletions

View File

@ -66,7 +66,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
private final boolean createSourceMap;
private WasmOutputStream codeStream = new WasmOutputStream();
private WasmOutputStream codeStream = new WasmOutputStream( options );
private List<TypeEntry> functionTypes = new ArrayList<>();
@ -116,7 +116,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
*/
@Override
public void close() throws IOException {
wasm = new WasmOutputStream( target.getWasmOutput() );
wasm = new WasmOutputStream( options, target.getWasmOutput() );
wasm.write( WASM_BINARY_MAGIC );
wasm.writeInt32( WASM_BINARY_VERSION );
@ -152,7 +152,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
private void writeSection( SectionType type, Collection<? extends SectionEntry> entries ) throws IOException {
int count = entries.size();
if( count > 0 ) {
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( count );
for( SectionEntry entry : entries ) {
entry.writeSectionEntry( stream );
@ -174,7 +174,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
return;
}
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
int count = 1;
if( stringCount > 0 ) {
count++;
@ -217,7 +217,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
private void writeMemorySection() throws IOException {
int dataSize = dataStream.size();
if( dataSize > 0 ) {
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
int pages = (dataSize + 0xFFFF) / 0x10000; // a page is defined with a size of 64KiB
int count = 1;
stream.writeVaruint32( count );
@ -238,7 +238,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
*/
private void writeEventSection() throws IOException {
if( exceptionSignatureIndex >= 0 ) {
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( 1 );
// event declaration
@ -260,7 +260,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
return;
}
int id = getFunction( startFunction ).id;
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( id );
wasm.writeSection( SectionType.Start, stream );
}
@ -277,7 +277,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
}
int elemCount = imports.size() + functions.size();
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( 1 ); // count of element segments to follow
// element_segment
@ -305,7 +305,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
}
int start = wasm.size();
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( size );
for( Entry<String, Function> entry : functions.entrySet() ) {
try {
@ -345,7 +345,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
return;
}
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeVaruint32( 1 ); // count, we use one large segment
// one data segment
@ -368,12 +368,12 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
if( !options.debugNames() ) {
return;
}
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeString( "name" ); // Custom Section name "name", content is part of the section length
// write function names
stream.write( 1 ); // 1 - Function name
WasmOutputStream section = new WasmOutputStream();
WasmOutputStream section = new WasmOutputStream( options );
section.writeVaruint32( imports.size() + functions.size() );
writeDebugFunctionNames( imports.entrySet(), section );
writeDebugFunctionNames( functions.entrySet(), section );
@ -449,7 +449,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
if( url == null ) {
return;
}
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeString( "sourceMappingURL" ); // Custom Section name "sourceMappingURL", content is part of the section length
stream.writeString( url );
wasm.writeSection( SectionType.Custom, stream );
@ -465,7 +465,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
Package pack = getClass().getPackage();
String version = pack == null ? null : pack.getImplementationVersion();
WasmOutputStream stream = new WasmOutputStream();
WasmOutputStream stream = new WasmOutputStream( options );
stream.writeString( "producers" ); // Custom Section name "producers", content is part of the section length
stream.writeVaruint32( 2 ); // field_count; number of fields that follow (language and processed-by)
@ -511,13 +511,20 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
@Override
protected void writeException() throws IOException {
if( exceptionSignatureIndex <= 0 ) {
FunctionTypeEntry exceptionType = new FunctionTypeEntry();
exceptionType.params.add( ValueType.anyref );
exceptionSignatureIndex = functionTypes.indexOf( exceptionType );
FunctionTypeEntry type = new FunctionTypeEntry();
type.params.add( ValueType.anyref );
exceptionSignatureIndex = functionTypes.indexOf( type );
if( exceptionSignatureIndex < 0 ) {
exceptionSignatureIndex = functionTypes.size();
functionTypes.add( exceptionType );
functionTypes.add( type );
}
// result type of catch block for unboxing
type = new FunctionTypeEntry();
type.params.add( ValueType.exnref );
type.results.add( ValueType.anyref );
options.setCatchType( functionTypes.size() );
functionTypes.add( type );
}
}
@ -639,7 +646,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
@Override
protected void writeMethodFinish() throws IOException {
@SuppressWarnings( "resource" )
WasmOutputStream localsTypeStream = new WasmOutputStream();
WasmOutputStream localsTypeStream = new WasmOutputStream( options );
int localEntryCount = 0; // number of local entries in output
int varCount = locals.size();
for( int i = 0; i < varCount; ) {
@ -655,10 +662,10 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
}
@SuppressWarnings( "resource" )
WasmOutputStream localsStream = new WasmOutputStream();
WasmOutputStream localsStream = new WasmOutputStream( options );
localsStream.writeVaruint32( localEntryCount );
WasmOutputStream functionsStream = function.functionsStream = new WasmOutputStream();
WasmOutputStream functionsStream = function.functionsStream = new WasmOutputStream( options );
functionsStream.writeVaruint32( localsStream.size() + localsTypeStream.size() + codeStream.size() + 1 );
localsStream.writeTo( functionsStream );
localsTypeStream.writeTo( functionsStream );

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 - 2019 Volker Berlin (i-net software)
* Copyright 2017 - 2020 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.
@ -24,6 +24,7 @@ import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.module.WasmOptions;
import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.LittleEndianOutputStream;
import de.inetsoftware.jwebassembly.wasm.ValueType;
@ -33,11 +34,17 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
*/
class WasmOutputStream extends LittleEndianOutputStream {
private final WasmOptions options;
/**
* Create a in memory stream.
*
* @param options
* compiler properties
*/
WasmOutputStream() {
WasmOutputStream( WasmOptions options ) {
super();
this.options = options;
}
/**
@ -45,9 +52,12 @@ class WasmOutputStream extends LittleEndianOutputStream {
*
* @param output
* the target of data
* @param options
* compiler properties
*/
WasmOutputStream( OutputStream output ) {
WasmOutputStream( WasmOptions options, OutputStream output ) {
super( output );
this.options = options;
}
/**
@ -86,8 +96,12 @@ class WasmOutputStream extends LittleEndianOutputStream {
* if an I/O error occurs.
*/
public void writeRefValueType( AnyType type ) throws IOException {
if( type.getCode() >= 0 ) {
writeValueType( ValueType.ref_type );
if( type.isRefType() ) {
if( options.useGC() ) {
writeValueType( ValueType.ref_type );
} else {
type = ValueType.anyref;
}
}
writeValueType( type );
}
@ -192,7 +206,7 @@ class WasmOutputStream extends LittleEndianOutputStream {
* if an I/O error occurs.
*/
void writeDouble( double value ) throws IOException {
long l = Double.doubleToLongBits(value);
long l = Double.doubleToLongBits( value );
writeInt32( (int)l );
writeInt32( (int)(l >>> 32) );
}

View File

@ -860,17 +860,21 @@ class BranchManger {
* Should be converted to the follow Wasm code for try/catch:
*
* <pre>
* block
* block (result anyref)
* try
* code1
* catch
* br_on_exn 1 0
* rethrow
* end
* br 1
* try
* code1
* catch
* block (param exnref)(result anyref)
* br_on_exn 0 0
* rethrow
* end
* local.tee $ex
* i32.const classIndex(Exception)
* call $.instanceof
* i32.eqz
* if
* local.get $ex
* throw 0
* end
* local.set x
* code2
* end
* code3
@ -910,25 +914,24 @@ class BranchManger {
}
int startPos = tryBlock.startPosition;
int catchPos = tryCatch.getHandler();
BranchNode outerBlock = new BranchNode( startPos, endPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
parent.add( outerBlock );
BranchNode innerBlock = new BranchNode( startPos, catchPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, ValueType.anyref );
outerBlock.add( innerBlock );
BranchNode tryNode = new BranchNode( startPos, catchPos, WasmBlockOperator.TRY, null );
innerBlock.add( tryNode );
parent.add( tryNode );
calculate( tryNode, parsedOperations.subList( 0, idx ) );
BranchNode catchNode = new BranchNode( catchPos, catchPos, WasmBlockOperator.CATCH, WasmBlockOperator.END );
innerBlock.add( catchNode );
BranchNode catchNode = new BranchNode( catchPos, endPos, WasmBlockOperator.CATCH, WasmBlockOperator.END );
parent.add( catchNode );
if( tryCatch.isFinally() ) {
catchNode.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.DROP, null ) );
} else {
// unboxing the exnref on the stack to a reference of the exception
BranchNode unBoxing = new BranchNode( catchPos, catchPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, options.getCatchType() );
catchNode.add( unBoxing );
//TODO localVariables.getTempVariable( ValueType.exnref, catchPos, endPos ); https://github.com/WebAssembly/wabt/issues/1388
catchNode.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.BR_ON_EXN, null, 1 ) );
catchNode.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.RETHROW, null ) );
unBoxing.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.BR_ON_EXN, null, 0 ) );
unBoxing.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.RETHROW, null ) );
// add a "if $exception instanceof type" check to the WASM code
StructType type = options.types.valueOf( tryCatch.getType().getName() );
@ -946,8 +949,6 @@ class BranchManger {
instructions.add( ++instrPos, new WasmBlockInstruction( WasmBlockOperator.THROW, null, catchPos, lineNumber ) );
instructions.add( ++instrPos, new WasmBlockInstruction( WasmBlockOperator.END, null, catchPos, lineNumber ) );
}
innerBlock.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.BR, null, 1 ) );
}
/**

View File

@ -506,6 +506,14 @@ public class TypeManager {
return code;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRefType() {
return true;
}
/**
* {@inheritDoc}
*/

View File

@ -21,11 +21,7 @@ import javax.annotation.Nonnull;
import de.inetsoftware.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName;
import de.inetsoftware.jwebassembly.module.CodeOptimizer;
import de.inetsoftware.jwebassembly.module.FunctionManager;
import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.StringManager;
import de.inetsoftware.jwebassembly.module.TypeManager;
import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ValueType;
/**
@ -65,6 +61,30 @@ public class WasmOptions {
private FunctionName cast;
private int catchTypeCode;
private AnyType catchType = new AnyType() {
@Override
public int getCode() {
return catchTypeCode;
}
@Override
public boolean isRefType() {
return false;
}
@Override
public boolean isSubTypeOf( AnyType type ) {
return type == this;
}
@Override
public String toString() {
return "(param exnref)(result anyref)";
}
};
/**
* Create a new instance of options
*
@ -184,4 +204,23 @@ public class WasmOptions {
}
return name;
}
/**
* The type for a catch block to unboxing the exnref into a anyref
*
* @return the type
*/
public AnyType getCatchType() {
return catchType;
}
/**
* Set the dynamic type id for the catch type
*
* @param catchTypeCode
* the positive id
*/
public void setCatchType( int catchTypeCode ) {
this.catchTypeCode = catchTypeCode;
}
}

View File

@ -232,6 +232,9 @@ public class TextModuleWriter extends ModuleWriter {
newline( output );
output.append( "(event (param anyref))" );
inset = oldInset;
options.setCatchType( types.size() );
types.add( options.getCatchType().toString() );
}
}
@ -310,7 +313,7 @@ public class TextModuleWriter extends ModuleWriter {
* if any I/O error occur
*/
private void writeTypeName( Appendable output, AnyType type ) throws IOException {
if( type instanceof ValueType ) {
if( !type.isRefType() ) {
output.append( type.toString() );
} else if( options.useGC() ) {
output.append( "(optref " ).append( normalizeName( type.toString() ) ).append( ')' );
@ -714,14 +717,7 @@ public class TextModuleWriter extends ModuleWriter {
name = "return";
break;
case IF:
if( data == ValueType.empty ) {
name = "if";
} else {
StringBuilder builder = new StringBuilder("if (result ");
writeTypeName( builder, (AnyType)data );
builder.append( ")" );
name = builder;
}
name = blockWithResult( "if", (AnyType)data );
insetAfter++;
break;
case ELSE:
@ -737,14 +733,7 @@ public class TextModuleWriter extends ModuleWriter {
name = "drop";
break;
case BLOCK:
if( data == null ) {
name = "block";
} else {
StringBuilder builder = new StringBuilder("block (result ");
writeTypeName( builder, (AnyType)data );
builder.append( ")" );
name = builder;
}
name = blockWithResult( "block", (AnyType)data );
insetAfter++;
break;
case BR:
@ -797,6 +786,34 @@ public class TextModuleWriter extends ModuleWriter {
inset += insetAfter;
}
/**
* Create a the result type for a block instruction
*
* @param blockName
* the name of the block for example "if" or "block"
* @param result
* the result type of the block
* @return the block with result type
* @throws IOException
* if any I/O error occur
*/
@Nonnull
private CharSequence blockWithResult( String blockName, AnyType result ) throws IOException {
if( result == null || result == ValueType.empty ) {
return blockName;
} else {
StringBuilder builder = new StringBuilder( blockName );
if( result.toString().contains( "(" ) ) {
builder.append( result );
} else {
builder.append( "(result " );
writeTypeName( builder, result );
builder.append( ")" );
}
return builder;
}
}
/**
* {@inheritDoc}
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2018 - 2019 Volker Berlin (i-net software)
* Copyright 2018 - 2020 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.
@ -39,6 +39,13 @@ public interface AnyType {
*/
public int getCode();
/**
* If the type is a reference type. A GC reference to the heap.
*
* @return true, is GC type
*/
public boolean isRefType();
/**
* Check if this is a sub type of given type.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 Volker Berlin (i-net software)
* Copyright 2019 - 2020 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.
@ -50,6 +50,14 @@ public class ArrayType implements AnyType {
return ValueType.anyref.getCode();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRefType() {
return true;
}
/**
* {@inheritDoc}
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 - 2019 Volker Berlin (i-net software)
* Copyright 2017 - 2020 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.
@ -58,6 +58,14 @@ public enum ValueType implements AnyType {
return code;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isRefType() {
return false;
}
/**
* {@inheritDoc}
*/

View File

@ -336,7 +336,7 @@ public class WatParserTest {
@Test
public void ifElseEndI32() throws IOException {
test( "if (result i32) else end" );
test( "if(result i32) else end" );
}
@Test