mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +01:00
Add support for complex block types
This commit is contained in:
parent
27199c53db
commit
cf7e66901d
@ -32,6 +32,7 @@ import javax.annotation.Nullable;
|
||||
import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.module.FunctionName;
|
||||
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructTypeKind;
|
||||
import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
|
||||
@ -525,6 +526,18 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
||||
return typeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected int writeBlockType( BlockType type ) throws IOException {
|
||||
FunctionTypeEntry entry = new FunctionTypeEntry();
|
||||
entry.params.addAll( type.getParams() );
|
||||
entry.results.addAll( type.getResults() );
|
||||
functionTypes.add( entry );
|
||||
return functionTypes.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -532,19 +545,13 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
||||
protected void writeException() throws IOException {
|
||||
if( exceptionSignatureIndex <= 0 ) {
|
||||
FunctionTypeEntry type = new FunctionTypeEntry();
|
||||
type.params.add( ValueType.externref );
|
||||
AnyType eventType = options.useGC() ? options.types.valueOf( "java/lang/Throwable" ) : ValueType.externref;
|
||||
type.params.add( eventType );
|
||||
exceptionSignatureIndex = functionTypes.indexOf( type );
|
||||
if( exceptionSignatureIndex < 0 ) {
|
||||
exceptionSignatureIndex = functionTypes.size();
|
||||
functionTypes.add( type );
|
||||
}
|
||||
|
||||
// result type of catch block for unboxing
|
||||
type = new FunctionTypeEntry();
|
||||
type.params.add( ValueType.exnref );
|
||||
type.results.add( ValueType.externref );
|
||||
options.setCatchType( functionTypes.size() );
|
||||
functionTypes.add( type );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,11 +25,14 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.classparser.Code;
|
||||
import de.inetsoftware.classparser.CodeInputStream;
|
||||
import de.inetsoftware.classparser.ConstantClass;
|
||||
import de.inetsoftware.classparser.TryCatchFinally;
|
||||
import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
@ -1015,10 +1018,10 @@ class BranchManger {
|
||||
// occur with a RETURN in a finally block
|
||||
// We does not need to unbox if the value will be drop
|
||||
} else {
|
||||
addUnboxExnref( catchNode );
|
||||
addUnboxExnref( catchNode, tryCatch );
|
||||
}
|
||||
} else {
|
||||
addUnboxExnref( catchNode );
|
||||
addUnboxExnref( catchNode, tryCatch );
|
||||
|
||||
// add a "if $exception instanceof type" check to the WASM code
|
||||
int instrPos = findIdxOfCodePos( catchPos ) + 1;
|
||||
@ -1083,8 +1086,10 @@ class BranchManger {
|
||||
*
|
||||
* @param catchNode
|
||||
* the catch node
|
||||
* @param tryCatch
|
||||
* the catch or finally block
|
||||
*/
|
||||
private void addUnboxExnref( BranchNode catchNode ) {
|
||||
private void addUnboxExnref( BranchNode catchNode, TryCatchFinally tryCatch ) {
|
||||
// unboxing the exnref on the stack to a reference of the exception
|
||||
int catchPos = catchNode.startPos;
|
||||
if( !options.useEH() ) {
|
||||
@ -1092,7 +1097,9 @@ class BranchManger {
|
||||
catchNode.add( 0, unBoxing );
|
||||
return;
|
||||
}
|
||||
BranchNode unBoxing = new BranchNode( catchPos, catchPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, options.getCatchType() );
|
||||
AnyType excepType = getCatchType( tryCatch );
|
||||
BlockType blockType = options.types.blockType( Arrays.asList( ValueType.exnref ), Arrays.asList( excepType ) );
|
||||
BranchNode unBoxing = new BranchNode( catchPos, catchPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, blockType );
|
||||
catchNode.add( 0, unBoxing );
|
||||
|
||||
//TODO localVariables.getTempVariable( ValueType.exnref, catchPos, endPos ); https://github.com/WebAssembly/wabt/issues/1388
|
||||
@ -1100,20 +1107,30 @@ class BranchManger {
|
||||
unBoxing.add( new BranchNode( catchPos, catchPos, WasmBlockOperator.RETHROW, null ) );
|
||||
}
|
||||
|
||||
private AnyType getCatchType( TryCatchFinally tryCatch ) {
|
||||
if( options.useGC() ) {
|
||||
ConstantClass excepClass = tryCatch.getType();
|
||||
String excepName = excepClass != null ? excepClass.getName() : "java/lang/Throwable";
|
||||
return options.types.valueOf( excepName );
|
||||
}
|
||||
return ValueType.externref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are a start of a catch block on the code position.
|
||||
* Get the catch type 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
|
||||
* @return the type or null
|
||||
*/
|
||||
boolean isCatch( int codePosition ) {
|
||||
@Nullable
|
||||
AnyType getCatchType( int codePosition ) {
|
||||
for( TryCatchFinally tryCatch : exceptionTable ) {
|
||||
if( tryCatch.getHandler() == codePosition ) {
|
||||
return true;
|
||||
return getCatchType( tryCatch );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -234,9 +234,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
addLoadStoreInstruction( ValueType.f64, false, byteCode.readUnsignedIndex( wide ), codePos, lineNumber );
|
||||
break;
|
||||
case 58: // astore
|
||||
if( branchManager.isCatch( codePos ) ) {
|
||||
addJumpPlaceholder( codePos, 0, ValueType.externref, codePos, lineNumber );
|
||||
storeType = ValueType.externref; // for the catch there are no previous instructions
|
||||
storeType = branchManager.getCatchType( codePos );
|
||||
if( storeType != null ) {
|
||||
// for the catch there are no previous instructions
|
||||
addJumpPlaceholder( codePos, 0, storeType, codePos, lineNumber );
|
||||
} else {
|
||||
storeType = findValueTypeFromStack( 1, codePos );
|
||||
}
|
||||
@ -270,9 +271,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
case 76: // astore_1
|
||||
case 77: // astore_2
|
||||
case 78: // astore_3
|
||||
if( branchManager.isCatch( codePos ) ) {
|
||||
addJumpPlaceholder( codePos, 0, ValueType.externref, codePos, lineNumber );
|
||||
storeType = ValueType.externref; // for the catch there are no previous instructions
|
||||
storeType = branchManager.getCatchType( codePos );
|
||||
if( storeType != null ) {
|
||||
// for the catch there are no previous instructions
|
||||
addJumpPlaceholder( codePos, 0, storeType, codePos, lineNumber );
|
||||
} else {
|
||||
storeType = findValueTypeFromStack( 1, codePos );
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 - 2020 Volker Berlin (i-net software)
|
||||
* Copyright 2017 - 2021 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.
|
||||
@ -23,6 +23,7 @@ import javax.annotation.Nonnegative;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
|
||||
@ -78,7 +79,18 @@ public abstract class ModuleWriter implements Closeable {
|
||||
* @throws IOException
|
||||
* if any I/O error occur
|
||||
*/
|
||||
protected abstract int writeStructType( StructType type ) throws IOException;
|
||||
protected abstract int writeStructType( @Nonnull StructType type ) throws IOException;
|
||||
|
||||
/**
|
||||
* Write a block type.
|
||||
*
|
||||
* @param type
|
||||
* the type
|
||||
* @return type ID
|
||||
* @throws IOException
|
||||
* if any I/O error occur
|
||||
*/
|
||||
protected abstract int writeBlockType( @Nonnull BlockType type ) throws IOException;
|
||||
|
||||
/**
|
||||
* Mark to write exceptions
|
||||
|
@ -19,6 +19,7 @@ package de.inetsoftware.jwebassembly.module;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
@ -146,7 +147,9 @@ public class TypeManager {
|
||||
*/
|
||||
private static final String[] PRIMITIVE_CLASSES = { "boolean", "byte", "char", "double", "float", "int", "long", "short", "void" };
|
||||
|
||||
private Map<Object, StructType> structTypes = new LinkedHashMap<>();
|
||||
private final Map<Object, StructType> structTypes = new LinkedHashMap<>();
|
||||
|
||||
private final Map<BlockType, BlockType> blockTypes = new LinkedHashMap<>();
|
||||
|
||||
private int typeIndexCounter;
|
||||
|
||||
@ -211,7 +214,11 @@ public class TypeManager {
|
||||
void prepareFinish( ModuleWriter writer, ClassFileLoader classFileLoader ) throws IOException {
|
||||
isFinish = true;
|
||||
for( StructType type : structTypes.values() ) {
|
||||
type.writeStructType( writer, options.functions, this, classFileLoader );
|
||||
type.writeStructType( writer );
|
||||
}
|
||||
|
||||
for( BlockType type : blockTypes.values() ) {
|
||||
type.code = writer.writeBlockType( type );
|
||||
}
|
||||
|
||||
// write type table
|
||||
@ -380,6 +387,26 @@ public class TypeManager {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create block type
|
||||
*
|
||||
* @param params
|
||||
* the parameters
|
||||
* @param results
|
||||
* the results
|
||||
* @return the type
|
||||
*/
|
||||
@Nonnull
|
||||
BlockType blockType( List<AnyType> params, List<AnyType> results ) {
|
||||
BlockType blockType = new BlockType( params, results );
|
||||
BlockType type = blockTypes.get( blockType );
|
||||
if( type != null ) {
|
||||
return type;
|
||||
}
|
||||
blockTypes.put( blockType, blockType );
|
||||
return blockType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the FunctionName for a virtual call. The function has 2 parameters (THIS,
|
||||
* virtualfunctionIndex) and returns the index of the function.
|
||||
@ -648,16 +675,10 @@ public class TypeManager {
|
||||
*
|
||||
* @param writer
|
||||
* the targets for the types
|
||||
* @param functions
|
||||
* the used functions for the vtables of the types
|
||||
* @param types
|
||||
* for types of fields
|
||||
* @param classFileLoader
|
||||
* for loading the class files
|
||||
* @throws IOException
|
||||
* if any I/O error occur on loading or writing
|
||||
*/
|
||||
private void writeStructType( ModuleWriter writer, FunctionManager functions, TypeManager types, ClassFileLoader classFileLoader ) throws IOException {
|
||||
private void writeStructType( ModuleWriter writer ) throws IOException {
|
||||
JWebAssembly.LOGGER.fine( "write type: " + name );
|
||||
code = writer.writeStructType( this );
|
||||
}
|
||||
@ -1121,4 +1142,96 @@ public class TypeManager {
|
||||
return interfaceMethodName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that can use for a block
|
||||
*/
|
||||
public static class BlockType implements AnyType {
|
||||
|
||||
@Nonnull
|
||||
private final List<AnyType> params;
|
||||
@Nonnull
|
||||
private final List<AnyType> results;
|
||||
private int code;
|
||||
private String name;
|
||||
|
||||
public BlockType(List<AnyType> params, List<AnyType> results) {
|
||||
this.params = params;
|
||||
this.results = results;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isRefType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isSubTypeOf( AnyType type ) {
|
||||
return type == this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return params.hashCode() + results.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals( Object obj ) {
|
||||
if( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
BlockType other = (BlockType)obj;
|
||||
return params.equals( other.params ) && results.equals( other.results );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if( name != null ) {
|
||||
return name;
|
||||
}
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
public List<AnyType> getParams() {
|
||||
return Collections.unmodifiableList( params );
|
||||
}
|
||||
|
||||
public List<AnyType> getResults() {
|
||||
return Collections.unmodifiableList( results );
|
||||
}
|
||||
|
||||
public void setName( String name ) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 - 2020 Volker Berlin (i-net software)
|
||||
* Copyright 2017 - 2021 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.
|
||||
@ -21,7 +21,6 @@ import javax.annotation.Nonnull;
|
||||
|
||||
import de.inetsoftware.jwebassembly.JWebAssembly;
|
||||
import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||
|
||||
/**
|
||||
@ -63,30 +62,6 @@ public class WasmOptions {
|
||||
|
||||
private SyntheticFunctionName 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
|
||||
*
|
||||
@ -223,23 +198,4 @@ 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;
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import javax.annotation.Nullable;
|
||||
import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.module.FunctionName;
|
||||
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructTypeKind;
|
||||
import de.inetsoftware.jwebassembly.module.ValueTypeConvertion;
|
||||
@ -247,6 +248,24 @@ public class TextModuleWriter extends ModuleWriter {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected int writeBlockType( BlockType type ) throws IOException {
|
||||
StringBuilder output = new StringBuilder();
|
||||
for( AnyType valueType : type.getParams() ) {
|
||||
writeParam( output, "param", valueType, null );
|
||||
}
|
||||
for( AnyType valueType : type.getResults() ) {
|
||||
writeParam( output, "result", valueType, null );
|
||||
}
|
||||
String name = output.toString();
|
||||
type.setName( name );
|
||||
types.add( name );
|
||||
return types.size() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -257,11 +276,12 @@ public class TextModuleWriter extends ModuleWriter {
|
||||
int oldInset = inset;
|
||||
inset = 1;
|
||||
newline( output );
|
||||
output.append( "(event (param externref))" );
|
||||
if( options.useGC() ) {
|
||||
output.append( "(event (param (ref null $java/lang/Throwable)))" );
|
||||
} else {
|
||||
output.append( "(event (param externref))" );
|
||||
}
|
||||
inset = oldInset;
|
||||
|
||||
options.setCatchType( types.size() );
|
||||
types.add( options.getCatchType().toString() );
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,19 +403,37 @@ public class TextModuleWriter extends ModuleWriter {
|
||||
if( methodOutput == null ) {
|
||||
return;
|
||||
}
|
||||
newline( methodOutput );
|
||||
methodOutput.append( " (" ).append( kind );
|
||||
if( options.debugNames() ) {
|
||||
writeParam( methodOutput, kind, valueType, name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a parameter to the given output
|
||||
*
|
||||
* @param output
|
||||
* the traget
|
||||
* @param kind
|
||||
* "param", "result" or "local"
|
||||
* @param valueType
|
||||
* the data type of the parameter
|
||||
* @param name
|
||||
* optional name of the parameter
|
||||
* @throws IOException
|
||||
* if any I/O error occur
|
||||
*/
|
||||
private void writeParam( StringBuilder output, String kind, AnyType valueType, @Nullable String name ) throws IOException {
|
||||
newline( output );
|
||||
output.append( " (" ).append( kind );
|
||||
if( options.debugNames() ) {
|
||||
if( name != null ) {
|
||||
methodOutput.append( " $" ).append( name );
|
||||
output.append( " $" ).append( name );
|
||||
}
|
||||
if( kind != "result" ) {
|
||||
methodParamNames.add( name );
|
||||
}
|
||||
}
|
||||
methodOutput.append( ' ' );
|
||||
writeTypeName( methodOutput, valueType );
|
||||
methodOutput.append( ')' );
|
||||
output.append( ' ' );
|
||||
writeTypeName( output, valueType );
|
||||
output.append( ')' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user