mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +01:00
Use a BLOCK with input parameters for SWITCHES so that the start position of the SWITCH value does not have to be determined. #43
This commit is contained in:
parent
3d5543fa38
commit
c392afc76f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 - 2021 Volker Berlin (i-net software)
|
||||
* Copyright 2017 - 2022 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.
|
||||
@ -84,12 +84,8 @@ class WasmOutputStream extends LittleEndianOutputStream {
|
||||
* if an I/O error occurs.
|
||||
*/
|
||||
public void writeValueType( AnyType type ) throws IOException {
|
||||
if( !type.isRefType() && !options.useGC() ) {
|
||||
switch( (ValueType)type ) {
|
||||
case eqref:
|
||||
type = ValueType.externref;
|
||||
break;
|
||||
}
|
||||
if( !options.useGC() && type == ValueType.eqref ) {
|
||||
type = ValueType.externref;
|
||||
}
|
||||
writeVarint( type.getCode() );
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ 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;
|
||||
@ -64,6 +65,7 @@ class BranchManager {
|
||||
|
||||
private final ArrayList<BreakBlock> breakOperations = new ArrayList<>();
|
||||
|
||||
private BlockType switchType;
|
||||
|
||||
/**
|
||||
* Create a branch manager.
|
||||
@ -534,7 +536,7 @@ class BranchManager {
|
||||
// find the code position where the condition values are push on the stack
|
||||
List<WasmInstruction> instructions = this.instructions;
|
||||
int idx = instructions.indexOf( startBlock.instr );
|
||||
startPos = WasmCodeBuilder.findBlockStart( 1, true, instructions, idx + 1 );
|
||||
startPos = WasmCodeBuilder.findBlockStart( 1, instructions, idx + 1 );
|
||||
if( parent.overlapped( startPos ) ) {
|
||||
branch = addMiddleNode( parent, parent.startPos, endPos );
|
||||
} else {
|
||||
@ -853,6 +855,10 @@ class BranchManager {
|
||||
* the not consumed operations in the parent branch
|
||||
*/
|
||||
private void calculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock, List<ParsedBlock> parsedOperations ) {
|
||||
BlockType switchType = this.switchType;
|
||||
if( switchType == null ) {
|
||||
this.switchType = switchType = options.types.blockType( Arrays.asList( ValueType.i32 ), Collections.emptyList() );
|
||||
}
|
||||
int startPosition = ((ParsedBlock)switchBlock).startPosition;
|
||||
int posCount = switchBlock.positions.length;
|
||||
boolean isTable = switchBlock.keys == null;
|
||||
@ -883,7 +889,7 @@ class BranchManager {
|
||||
}
|
||||
lastPosition = currentPosition;
|
||||
blockCount++;
|
||||
BranchNode node = new BranchNode( startPosition, currentPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
|
||||
BranchNode node = new BranchNode( startPosition, currentPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END, switchType );
|
||||
if( blockNode != null ) {
|
||||
node.add( blockNode );
|
||||
}
|
||||
@ -914,7 +920,7 @@ class BranchManager {
|
||||
while( parentNode != null && end > parentNode.endPos ) {
|
||||
parentNode = parentNode.parent;
|
||||
}
|
||||
BranchNode middleNode = new BranchNode( startPosition, end, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
|
||||
BranchNode middleNode = new BranchNode( startPosition, end, WasmBlockOperator.BLOCK, WasmBlockOperator.END, switchType );
|
||||
if( parentNode != null ) {
|
||||
BranchNode child = parentNode.remove( 0 );
|
||||
parentNode.add( middleNode );
|
||||
@ -980,7 +986,7 @@ class BranchManager {
|
||||
}
|
||||
|
||||
// Create the main block around the switch
|
||||
BranchNode switchNode = new BranchNode( startPosition, lastPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
|
||||
BranchNode switchNode = new BranchNode( startPosition, lastPosition, WasmBlockOperator.BLOCK, WasmBlockOperator.END, switchType );
|
||||
switchNode.add( blockNode );
|
||||
parent.add( switchNode );
|
||||
|
||||
@ -1467,7 +1473,8 @@ class BranchManager {
|
||||
* @return the new node
|
||||
*/
|
||||
private BranchNode addMiddleNode( BranchNode parent, int startPos, int endPos ) {
|
||||
BranchNode middleNode = new BranchNode( startPos, endPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END );
|
||||
Object data = parent.data == switchType && parent.startPos == startPos ? switchType : null;
|
||||
BranchNode middleNode = new BranchNode( startPos, endPos, WasmBlockOperator.BLOCK, WasmBlockOperator.END, data );
|
||||
int idx = 0;
|
||||
for( Iterator<BranchNode> it = parent.iterator(); it.hasNext(); ) {
|
||||
BranchNode child = it.next();
|
||||
@ -1510,7 +1517,6 @@ class BranchManager {
|
||||
} while( codePosition < nextCodePosition );
|
||||
}
|
||||
root.handle( byteCode.getCodePosition(), instructions, instructions.size(), byteCode.getLineNumber() );
|
||||
|
||||
root.calculateBlockType( instructions );
|
||||
}
|
||||
|
||||
@ -1725,9 +1731,20 @@ class BranchManager {
|
||||
@Override
|
||||
public boolean add( BranchNode node ) {
|
||||
node.parent = this;
|
||||
assert node.startOp == null || (node.startPos >= startPos && node.endPos <= endPos): "Node outside parent: " + this + " + " + node;
|
||||
assert node.startOp == null || !overlapped( node.startPos ) : "Node on wrong level: " + node + "; parent: " + this + "; last: " + get( size() - 1 );
|
||||
return super.add( node );
|
||||
assert node.startOp == null || (node.startPos >= startPos && node.endPos <= endPos) : "Node outside parent: " + this + " + " + node;
|
||||
|
||||
int size = size();
|
||||
if( size > 0 && node.startOp != null ) {
|
||||
int nodeStartPos = node.startPos;
|
||||
for( int i = size - 1; i >= 0; i-- ) {
|
||||
if( get( i ).endPos <= nodeStartPos ) {
|
||||
super.add( i + 1, node );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.add( 0, node );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1746,7 +1763,16 @@ class BranchManager {
|
||||
* @return true, if the position is already consumed from a child
|
||||
*/
|
||||
boolean overlapped( int startPos ) {
|
||||
return size() > 0 && get( size() - 1 ).endPos > startPos;
|
||||
for( int i = size() - 1; i >= 0; i-- ) {
|
||||
BranchNode node = get( i );
|
||||
if( node.endPos <= startPos ) {
|
||||
return false;
|
||||
}
|
||||
if( node.startPos < startPos ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1801,6 +1827,14 @@ class BranchManager {
|
||||
try {
|
||||
ArrayDeque<AnyType> stack = new ArrayDeque<>();
|
||||
stack.push( ValueType.empty );
|
||||
|
||||
BlockType blockType = startBlock.getData() instanceof BlockType ? (BlockType)startBlock.getData() : null;
|
||||
if( blockType != null ) {
|
||||
for( AnyType param : blockType.getParams() ) {
|
||||
stack.push( param );
|
||||
}
|
||||
}
|
||||
|
||||
INSTRUCTIONS: for( int i = startIdx; i < instructions.size(); i++ ) {
|
||||
WasmInstruction instr = instructions.get( i );
|
||||
if( instr.getType() == Type.Jump ) {
|
||||
@ -1852,7 +1886,13 @@ class BranchManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
startBlock.setData( stack.pop() );
|
||||
|
||||
AnyType result = stack.pop();
|
||||
if( blockType == null ) {
|
||||
startBlock.setData( result );
|
||||
} else if( result != ValueType.empty) {
|
||||
throw new WasmException( "block with parameter has return parameter", startBlock.getLineNumber() );
|
||||
}
|
||||
} catch( Throwable th ) {
|
||||
throw WasmException.create( th, startBlock.getLineNumber() );
|
||||
}
|
||||
|
@ -787,7 +787,6 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
byteCode.skip( 4 - padding );
|
||||
}
|
||||
startPosition--;
|
||||
int switchValuestartPosition = findBlockStartCodePosition( 1 );
|
||||
|
||||
int defaultPosition = startPosition + byteCode.readInt();
|
||||
int[] keys;
|
||||
@ -846,7 +845,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
addNumericInstruction( NumericOperator.sub, ValueType.i32, codePos, lineNumber );
|
||||
}
|
||||
}
|
||||
branchManager.addSwitchOperator( switchValuestartPosition, 0, lineNumber, keys, positions, defaultPosition );
|
||||
branchManager.addSwitchOperator( startPosition, 0, lineNumber, keys, positions, defaultPosition );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,10 +17,12 @@
|
||||
package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||
import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
|
||||
@ -104,7 +106,14 @@ class WasmBlockInstruction extends WasmInstruction {
|
||||
switch( op ) {
|
||||
case IF:
|
||||
case BLOCK:
|
||||
return data != ValueType.empty ? (AnyType)data : null;
|
||||
if( data == ValueType.empty || data == null ) {
|
||||
return null;
|
||||
}
|
||||
if( data instanceof BlockType ) {
|
||||
List<AnyType> results = ((BlockType)data).getResults();
|
||||
return results.isEmpty() ? null : results.get( 0 );
|
||||
}
|
||||
return (AnyType)data;
|
||||
case RETURN:
|
||||
return (AnyType)data;
|
||||
default:
|
||||
@ -125,6 +134,8 @@ class WasmBlockInstruction extends WasmInstruction {
|
||||
case THROW:
|
||||
case RETHROW:
|
||||
return 1;
|
||||
case BLOCK:
|
||||
return data instanceof BlockType ? ((BlockType)data).getParams().size() : 0;
|
||||
case RETURN:
|
||||
return data == null ? 0 : 1;
|
||||
default:
|
||||
@ -146,6 +157,8 @@ class WasmBlockInstruction extends WasmInstruction {
|
||||
case THROW:
|
||||
case RETHROW:
|
||||
return new AnyType[] { ValueType.exnref };
|
||||
case BLOCK:
|
||||
return data instanceof BlockType ? ((BlockType)data).getParams().toArray( new AnyType[0] ) : null;
|
||||
case RETURN:
|
||||
return data == null ? null : new AnyType[] { (AnyType)data };
|
||||
default:
|
||||
|
@ -162,41 +162,13 @@ public abstract class WasmCodeBuilder {
|
||||
*
|
||||
* @param count
|
||||
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
|
||||
* @return the code position that push the last instruction
|
||||
*/
|
||||
int findBlockStartCodePosition( int count ) {
|
||||
return findBlockStart( count, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* We need a value (or several) from the stack inside a block. We need to find the WasmInstruction where the block
|
||||
* can can begin. If it is a function call or a numeric expression, it can be complicated to find the right point.
|
||||
*
|
||||
* @param count
|
||||
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
|
||||
* @param codePosition
|
||||
* true, get the code position; false, get the index in the instructions
|
||||
* @return the code position that push the last instruction
|
||||
*/
|
||||
private int findBlockStart( int count, boolean codePosition ) {
|
||||
return findBlockStart( count, codePosition, instructions, instructions.size() );
|
||||
}
|
||||
|
||||
/**
|
||||
* We need a value (or several) from the stack inside a block. We need to find the WasmInstruction where the block
|
||||
* can can begin. If it is a function call or a numeric expression, it can be complicated to find the right point.
|
||||
*
|
||||
* @param count
|
||||
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
|
||||
* @param codePosition
|
||||
* true, get the code position; false, get the index in the instructions
|
||||
* @param instructions
|
||||
* the instruction list for searching
|
||||
* @param idx
|
||||
* the start index for the search. Between 0 and instructions.size().
|
||||
* @return the code position that push the last instruction
|
||||
*/
|
||||
static int findBlockStart( int count, boolean codePosition, List<WasmInstruction> instructions, int idx ) {
|
||||
static int findBlockStart( int count, List<WasmInstruction> instructions, int idx ) {
|
||||
int valueCount = 0;
|
||||
for( int i = idx - 1; i >= 0; i-- ) {
|
||||
WasmInstruction instr = instructions.get( i );
|
||||
@ -204,12 +176,13 @@ public abstract class WasmCodeBuilder {
|
||||
if( valueType != null ) {
|
||||
valueCount++;
|
||||
}
|
||||
valueCount -= instr.getPopCount();
|
||||
if( valueCount == count ) {
|
||||
int popCount = instr.getPopCount();
|
||||
valueCount -= popCount;
|
||||
if( valueCount == count && popCount == 0 ) {
|
||||
int codePos = instr.getCodePosition();
|
||||
if( i == 0 || instructions.get( i - 1 ).getCodePosition() < codePos ) {
|
||||
// if the same codePos is used from multiple instructions then it is not an atomic operation in Java
|
||||
return codePosition ? codePos : i;
|
||||
return codePos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ public class TextModuleWriter extends ModuleWriter {
|
||||
* if any I/O error occur
|
||||
*/
|
||||
private void writeTypeName( Appendable output, AnyType type ) throws IOException {
|
||||
if( !type.isRefType() ) {
|
||||
if( type instanceof ValueType ) {
|
||||
String name;
|
||||
switch( (ValueType)type ) {
|
||||
case u16:
|
||||
|
Loading…
x
Reference in New Issue
Block a user