mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.
|
* if an I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public void writeValueType( AnyType type ) throws IOException {
|
public void writeValueType( AnyType type ) throws IOException {
|
||||||
if( !type.isRefType() && !options.useGC() ) {
|
if( !options.useGC() && type == ValueType.eqref ) {
|
||||||
switch( (ValueType)type ) {
|
type = ValueType.externref;
|
||||||
case eqref:
|
|
||||||
type = ValueType.externref;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
writeVarint( type.getCode() );
|
writeVarint( type.getCode() );
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import de.inetsoftware.classparser.CodeInputStream;
|
|||||||
import de.inetsoftware.classparser.ConstantClass;
|
import de.inetsoftware.classparser.ConstantClass;
|
||||||
import de.inetsoftware.classparser.TryCatchFinally;
|
import de.inetsoftware.classparser.TryCatchFinally;
|
||||||
import de.inetsoftware.jwebassembly.WasmException;
|
import de.inetsoftware.jwebassembly.WasmException;
|
||||||
|
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||||
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
||||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||||
@ -64,6 +65,7 @@ class BranchManager {
|
|||||||
|
|
||||||
private final ArrayList<BreakBlock> breakOperations = new ArrayList<>();
|
private final ArrayList<BreakBlock> breakOperations = new ArrayList<>();
|
||||||
|
|
||||||
|
private BlockType switchType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a branch manager.
|
* Create a branch manager.
|
||||||
@ -534,7 +536,7 @@ class BranchManager {
|
|||||||
// find the code position where the condition values are push on the stack
|
// find the code position where the condition values are push on the stack
|
||||||
List<WasmInstruction> instructions = this.instructions;
|
List<WasmInstruction> instructions = this.instructions;
|
||||||
int idx = instructions.indexOf( startBlock.instr );
|
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 ) ) {
|
if( parent.overlapped( startPos ) ) {
|
||||||
branch = addMiddleNode( parent, parent.startPos, endPos );
|
branch = addMiddleNode( parent, parent.startPos, endPos );
|
||||||
} else {
|
} else {
|
||||||
@ -853,6 +855,10 @@ class BranchManager {
|
|||||||
* the not consumed operations in the parent branch
|
* the not consumed operations in the parent branch
|
||||||
*/
|
*/
|
||||||
private void calculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock, List<ParsedBlock> parsedOperations ) {
|
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 startPosition = ((ParsedBlock)switchBlock).startPosition;
|
||||||
int posCount = switchBlock.positions.length;
|
int posCount = switchBlock.positions.length;
|
||||||
boolean isTable = switchBlock.keys == null;
|
boolean isTable = switchBlock.keys == null;
|
||||||
@ -883,7 +889,7 @@ class BranchManager {
|
|||||||
}
|
}
|
||||||
lastPosition = currentPosition;
|
lastPosition = currentPosition;
|
||||||
blockCount++;
|
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 ) {
|
if( blockNode != null ) {
|
||||||
node.add( blockNode );
|
node.add( blockNode );
|
||||||
}
|
}
|
||||||
@ -914,7 +920,7 @@ class BranchManager {
|
|||||||
while( parentNode != null && end > parentNode.endPos ) {
|
while( parentNode != null && end > parentNode.endPos ) {
|
||||||
parentNode = parentNode.parent;
|
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 ) {
|
if( parentNode != null ) {
|
||||||
BranchNode child = parentNode.remove( 0 );
|
BranchNode child = parentNode.remove( 0 );
|
||||||
parentNode.add( middleNode );
|
parentNode.add( middleNode );
|
||||||
@ -980,7 +986,7 @@ class BranchManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the main block around the switch
|
// 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 );
|
switchNode.add( blockNode );
|
||||||
parent.add( switchNode );
|
parent.add( switchNode );
|
||||||
|
|
||||||
@ -1467,7 +1473,8 @@ class BranchManager {
|
|||||||
* @return the new node
|
* @return the new node
|
||||||
*/
|
*/
|
||||||
private BranchNode addMiddleNode( BranchNode parent, int startPos, int endPos ) {
|
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;
|
int idx = 0;
|
||||||
for( Iterator<BranchNode> it = parent.iterator(); it.hasNext(); ) {
|
for( Iterator<BranchNode> it = parent.iterator(); it.hasNext(); ) {
|
||||||
BranchNode child = it.next();
|
BranchNode child = it.next();
|
||||||
@ -1510,7 +1517,6 @@ class BranchManager {
|
|||||||
} while( codePosition < nextCodePosition );
|
} while( codePosition < nextCodePosition );
|
||||||
}
|
}
|
||||||
root.handle( byteCode.getCodePosition(), instructions, instructions.size(), byteCode.getLineNumber() );
|
root.handle( byteCode.getCodePosition(), instructions, instructions.size(), byteCode.getLineNumber() );
|
||||||
|
|
||||||
root.calculateBlockType( instructions );
|
root.calculateBlockType( instructions );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1725,9 +1731,20 @@ class BranchManager {
|
|||||||
@Override
|
@Override
|
||||||
public boolean add( BranchNode node ) {
|
public boolean add( BranchNode node ) {
|
||||||
node.parent = this;
|
node.parent = this;
|
||||||
assert node.startOp == null || (node.startPos >= startPos && node.endPos <= endPos): "Node outside parent: " + this + " + " + node;
|
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 );
|
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
|
* @return true, if the position is already consumed from a child
|
||||||
*/
|
*/
|
||||||
boolean overlapped( int startPos ) {
|
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 {
|
try {
|
||||||
ArrayDeque<AnyType> stack = new ArrayDeque<>();
|
ArrayDeque<AnyType> stack = new ArrayDeque<>();
|
||||||
stack.push( ValueType.empty );
|
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++ ) {
|
INSTRUCTIONS: for( int i = startIdx; i < instructions.size(); i++ ) {
|
||||||
WasmInstruction instr = instructions.get( i );
|
WasmInstruction instr = instructions.get( i );
|
||||||
if( instr.getType() == Type.Jump ) {
|
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 ) {
|
} catch( Throwable th ) {
|
||||||
throw WasmException.create( th, startBlock.getLineNumber() );
|
throw WasmException.create( th, startBlock.getLineNumber() );
|
||||||
}
|
}
|
||||||
|
@ -787,7 +787,6 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
byteCode.skip( 4 - padding );
|
byteCode.skip( 4 - padding );
|
||||||
}
|
}
|
||||||
startPosition--;
|
startPosition--;
|
||||||
int switchValuestartPosition = findBlockStartCodePosition( 1 );
|
|
||||||
|
|
||||||
int defaultPosition = startPosition + byteCode.readInt();
|
int defaultPosition = startPosition + byteCode.readInt();
|
||||||
int[] keys;
|
int[] keys;
|
||||||
@ -846,7 +845,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
addNumericInstruction( NumericOperator.sub, ValueType.i32, codePos, lineNumber );
|
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;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.inetsoftware.jwebassembly.module.TypeManager.BlockType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||||
import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
|
import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
|
||||||
@ -104,7 +106,14 @@ class WasmBlockInstruction extends WasmInstruction {
|
|||||||
switch( op ) {
|
switch( op ) {
|
||||||
case IF:
|
case IF:
|
||||||
case BLOCK:
|
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:
|
case RETURN:
|
||||||
return (AnyType)data;
|
return (AnyType)data;
|
||||||
default:
|
default:
|
||||||
@ -125,6 +134,8 @@ class WasmBlockInstruction extends WasmInstruction {
|
|||||||
case THROW:
|
case THROW:
|
||||||
case RETHROW:
|
case RETHROW:
|
||||||
return 1;
|
return 1;
|
||||||
|
case BLOCK:
|
||||||
|
return data instanceof BlockType ? ((BlockType)data).getParams().size() : 0;
|
||||||
case RETURN:
|
case RETURN:
|
||||||
return data == null ? 0 : 1;
|
return data == null ? 0 : 1;
|
||||||
default:
|
default:
|
||||||
@ -146,6 +157,8 @@ class WasmBlockInstruction extends WasmInstruction {
|
|||||||
case THROW:
|
case THROW:
|
||||||
case RETHROW:
|
case RETHROW:
|
||||||
return new AnyType[] { ValueType.exnref };
|
return new AnyType[] { ValueType.exnref };
|
||||||
|
case BLOCK:
|
||||||
|
return data instanceof BlockType ? ((BlockType)data).getParams().toArray( new AnyType[0] ) : null;
|
||||||
case RETURN:
|
case RETURN:
|
||||||
return data == null ? null : new AnyType[] { (AnyType)data };
|
return data == null ? null : new AnyType[] { (AnyType)data };
|
||||||
default:
|
default:
|
||||||
|
@ -162,41 +162,13 @@ public abstract class WasmCodeBuilder {
|
|||||||
*
|
*
|
||||||
* @param count
|
* @param count
|
||||||
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
|
* 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
|
* @param instructions
|
||||||
* the instruction list for searching
|
* the instruction list for searching
|
||||||
* @param idx
|
* @param idx
|
||||||
* the start index for the search. Between 0 and instructions.size().
|
* the start index for the search. Between 0 and instructions.size().
|
||||||
* @return the code position that push the last instruction
|
* @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;
|
int valueCount = 0;
|
||||||
for( int i = idx - 1; i >= 0; i-- ) {
|
for( int i = idx - 1; i >= 0; i-- ) {
|
||||||
WasmInstruction instr = instructions.get( i );
|
WasmInstruction instr = instructions.get( i );
|
||||||
@ -204,12 +176,13 @@ public abstract class WasmCodeBuilder {
|
|||||||
if( valueType != null ) {
|
if( valueType != null ) {
|
||||||
valueCount++;
|
valueCount++;
|
||||||
}
|
}
|
||||||
valueCount -= instr.getPopCount();
|
int popCount = instr.getPopCount();
|
||||||
if( valueCount == count ) {
|
valueCount -= popCount;
|
||||||
|
if( valueCount == count && popCount == 0 ) {
|
||||||
int codePos = instr.getCodePosition();
|
int codePos = instr.getCodePosition();
|
||||||
if( i == 0 || instructions.get( i - 1 ).getCodePosition() < codePos ) {
|
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
|
// 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
|
* if any I/O error occur
|
||||||
*/
|
*/
|
||||||
private void writeTypeName( Appendable output, AnyType type ) throws IOException {
|
private void writeTypeName( Appendable output, AnyType type ) throws IOException {
|
||||||
if( !type.isRefType() ) {
|
if( type instanceof ValueType ) {
|
||||||
String name;
|
String name;
|
||||||
switch( (ValueType)type ) {
|
switch( (ValueType)type ) {
|
||||||
case u16:
|
case u16:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user