Skip to content

Commit

Permalink
Use a BLOCK with input parameters for SWITCHES so that the start posi…
Browse files Browse the repository at this point in the history
…tion of the SWITCH value does not have to be determined. #43
  • Loading branch information
Horcrux7 committed Jun 5, 2022
1 parent 3d5543f commit c392afc
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 54 deletions.
10 changes: 3 additions & 7 deletions src/de/inetsoftware/jwebassembly/binary/WasmOutputStream.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -84,12 +84,8 @@ public void writeOpCode( int op ) throws IOException {
* 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() );
}
Expand Down
62 changes: 51 additions & 11 deletions src/de/inetsoftware/jwebassembly/module/BranchManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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;
Expand Down Expand Up @@ -64,6 +65,7 @@ class BranchManager {

private final ArrayList<BreakBlock> breakOperations = new ArrayList<>();

private BlockType switchType;

/**
* Create a branch manager.
Expand Down Expand Up @@ -534,7 +536,7 @@ private void calculateIf( BranchNode parent, IfParsedBlock startBlock, List<Pars
// 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 {
Expand Down Expand Up @@ -853,6 +855,10 @@ private int calculateBreakDeep( BranchNode parent, int endPos ) {
* 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;
Expand Down Expand Up @@ -883,7 +889,7 @@ private void calculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock,
}
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 );
}
Expand Down Expand Up @@ -914,7 +920,7 @@ private void calculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock,
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 );
Expand Down Expand Up @@ -980,7 +986,7 @@ private void calculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock,
}

// 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 );

Expand Down Expand Up @@ -1467,7 +1473,8 @@ private void calculateBreak( BreakBlock breakBlock ) {
* @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();
Expand Down Expand Up @@ -1510,7 +1517,6 @@ void handle( CodeInputStream byteCode ) {
} while( codePosition < nextCodePosition );
}
root.handle( byteCode.getCodePosition(), instructions, instructions.size(), byteCode.getLineNumber() );

root.calculateBlockType( instructions );
}

Expand Down Expand Up @@ -1725,9 +1731,20 @@ private static class BranchNode extends ArrayList<BranchNode> {
@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;
}

/**
Expand All @@ -1746,7 +1763,16 @@ public void add( int index, BranchNode node ) {
* @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;
}

/**
Expand Down Expand Up @@ -1801,6 +1827,14 @@ void calculateBlockType( List<WasmInstruction> instructions ) {
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 ) {
Expand Down Expand Up @@ -1852,7 +1886,13 @@ void calculateBlockType( List<WasmInstruction> instructions ) {
}
}
}
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() );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,6 @@ private void writeSwitchCode( CodeInputStream byteCode, boolean isLookupSwitch )
byteCode.skip( 4 - padding );
}
startPosition--;
int switchValuestartPosition = findBlockStartCodePosition( 1 );

int defaultPosition = startPosition + byteCode.readInt();
int[] keys;
Expand Down Expand Up @@ -846,7 +845,7 @@ private void writeSwitchCode( CodeInputStream byteCode, boolean isLookupSwitch )
addNumericInstruction( NumericOperator.sub, ValueType.i32, codePos, lineNumber );
}
}
branchManager.addSwitchOperator( switchValuestartPosition, 0, lineNumber, keys, positions, defaultPosition );
branchManager.addSwitchOperator( startPosition, 0, lineNumber, keys, positions, defaultPosition );
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -104,7 +106,14 @@ AnyType getPushValueType() {
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:
Expand All @@ -125,6 +134,8 @@ int getPopCount() {
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:
Expand All @@ -146,6 +157,8 @@ AnyType[] getPopValueTypes() {
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:
Expand Down
37 changes: 5 additions & 32 deletions src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,54 +162,27 @@ boolean isEndsWithReturn() {
*
* @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 );
AnyType valueType = instr.getPushValueType();
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;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ protected void writeExport( FunctionName name, String exportName ) throws IOExce
* 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:
Expand Down

0 comments on commit c392afc

Please sign in to comment.