From ac9758334dae2e383bfae2cf2aa6af67293cde29 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Fri, 4 May 2018 20:52:54 +0200 Subject: [PATCH] Split BlockOperator; handle the br operator --- .../binary/BinaryModuleWriter.java | 9 +- .../jwebassembly/module/BranchManger.java | 146 ++++++++++++++++-- .../module/JavaBlockOperator.java | 29 ++++ .../jwebassembly/module/ModuleWriter.java | 12 +- ...ckOperator.java => WasmBlockOperator.java} | 8 +- .../jwebassembly/text/TextModuleWriter.java | 8 +- 6 files changed, 182 insertions(+), 30 deletions(-) create mode 100644 src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java rename src/de/inetsoftware/jwebassembly/module/{BlockOperator.java => WasmBlockOperator.java} (88%) diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 50f1576..e489173 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -23,11 +23,12 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.WasmException; -import de.inetsoftware.jwebassembly.module.BlockOperator; +import de.inetsoftware.jwebassembly.module.WasmBlockOperator; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.NumericOperator; import de.inetsoftware.jwebassembly.module.ValueType; @@ -617,7 +618,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod * {@inheritDoc} */ @Override - protected void writeBlockCode( BlockOperator op ) throws IOException { + protected void writeBlockCode( @Nonnull WasmBlockOperator op, @Nullable Object data ) throws IOException { switch( op ) { case RETURN: codeStream.write( RETURN ); @@ -639,6 +640,10 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod codeStream.write( BLOCK ); codeStream.write( 0x40 ); // void; the return type of the block. currently we does not use it break; + case BR: + codeStream.write( BR ); + codeStream.writeVaruint32( (Integer)data ); + break; default: throw new Error( "Unknown block: " + op ); } diff --git a/src/de/inetsoftware/jwebassembly/module/BranchManger.java b/src/de/inetsoftware/jwebassembly/module/BranchManger.java index aa11ad2..c2ce137 100644 --- a/src/de/inetsoftware/jwebassembly/module/BranchManger.java +++ b/src/de/inetsoftware/jwebassembly/module/BranchManger.java @@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import de.inetsoftware.classparser.CodeInputStream; @@ -55,10 +56,30 @@ class BranchManger { * @param lineNumber * the current line number */ - void start( BlockOperator op, int startPosition, int offset, int lineNumber ) { + void start( JavaBlockOperator op, int startPosition, int offset, int lineNumber ) { allParsedOperations.add( new ParsedBlock( op, startPosition, offset, lineNumber ) ); } + /** + * Start a new switch block. + * + * @param startPosition + * the byte position of the start position + * @param offset + * the relative jump position + * @param lineNumber + * the current line number + * @param keys + * the values of the cases + * @param positions + * the code positions + * @param the + * code position of the default block + */ + void startSwitch( int startPosition, int offset, int lineNumber, int[] keys, int[] positions, int defaultPosition ) { + allParsedOperations.add( new SwitchParsedBlock( startPosition, offset, lineNumber, keys, positions, defaultPosition ) ); + } + /** * Calculate all block operators from the parsed information. */ @@ -79,6 +100,9 @@ class BranchManger { case IF: caculateIf( parent, parsedBlock, parsedOperations ); break; + case SWITCH: + caculateSwitch( parent, (SwitchParsedBlock)parsedBlock, parsedOperations ); + break; default: throw new WasmException( "Unimplemented block code operation: " + parsedBlock.op, null, parsedBlock.lineNumber ); } @@ -102,15 +126,15 @@ class BranchManger { BranchNode branch = null; for( ; i < parsedOperations.size(); i++ ) { ParsedBlock parsedBlock = parsedOperations.get( i ); - if( parsedBlock.startPosition == gotoPos && parsedBlock.op == BlockOperator.GOTO ) { + if( parsedBlock.startPosition == gotoPos && parsedBlock.op == JavaBlockOperator.GOTO ) { parsedOperations.remove( i ); - branch = new BranchNode( startBlock.startPosition, startBlock.endPosition, BlockOperator.IF, null ); + branch = new BranchNode( startBlock.startPosition, startBlock.endPosition, WasmBlockOperator.IF, null ); parent.add( branch ); if( i > 0 ) { calculate( branch, parsedOperations.subList( 0, i ) ); } endPos = parsedBlock.endPosition; - branch = new BranchNode( startBlock.endPosition, endPos, BlockOperator.ELSE, BlockOperator.END ); + branch = new BranchNode( startBlock.endPosition, endPos, WasmBlockOperator.ELSE, WasmBlockOperator.END ); parent.add( branch ); break; } @@ -120,7 +144,7 @@ class BranchManger { } if( branch == null ) { - branch = new BranchNode( startBlock.startPosition, endPos, BlockOperator.IF, BlockOperator.END ); + branch = new BranchNode( startBlock.startPosition, endPos, WasmBlockOperator.IF, WasmBlockOperator.END ); parent.add( branch ); } @@ -138,6 +162,55 @@ class BranchManger { } } + /** + * Calculate the blocks of a switch. + * + * Sample: The follow Java code: + * + *
+     * int b;
+     * switch( a ) {
+     *     case 8:
+     *         b = 1;
+     *         break;
+     *     default:
+     *         b = 9;
+     * }
+     * return b;
+     * 
+ * + * Should be converted to the follow Wasm code: + * + *
+        block
+          block
+            block
+              get_local 0
+              i32.const 8
+              i32.sub
+              br_table 0 1 
+            end
+            i32.const 1
+            set_local 1
+            br 1
+          end
+          i32.const 9
+          set_local 1
+        end
+        get_local 1
+        return
+     * 
+ * + * @param parent + * the parent branch + * @param switchBlock + * the start block of the if control structure + * @param parsedOperations + * the not consumed operations in the parent branch + */ + private void caculateSwitch( BranchNode parent, SwitchParsedBlock switchBlock, List parsedOperations ) { + } + /** * Check on every instruction position if there any branch is ending * @@ -156,15 +229,15 @@ class BranchManger { * Description of single block/branch from the parsed Java byte code. The parsed branches are plain. */ private static class ParsedBlock { - private BlockOperator op; + private JavaBlockOperator op; - private int startPosition; + int startPosition; - private int endPosition; + int endPosition; - private int lineNumber; + private int lineNumber; - private ParsedBlock( BlockOperator op, int startPosition, int offset, int lineNumber ) { + private ParsedBlock( JavaBlockOperator op, int startPosition, int offset, int lineNumber ) { this.op = op; this.startPosition = startPosition; this.endPosition = startPosition + offset; @@ -172,18 +245,38 @@ class BranchManger { } } + /** + * Description of a parsed switch structure. + */ + private static class SwitchParsedBlock extends ParsedBlock { + private int[] keys; + + private int[] positions; + + private int defaultPosition; + + public SwitchParsedBlock( int startPosition, int offset, int lineNumber, int[] keys, int[] positions, int defaultPosition ) { + super( JavaBlockOperator.SWITCH, startPosition, offset, lineNumber ); + this.keys = keys; + this.positions = positions; + this.defaultPosition = defaultPosition; + } + } + /** * Described a code branch/block node in a tree structure. */ private static class BranchNode extends ArrayList { - final int startPos; + final int startPos; - final int endPos; + final int endPos; - private final BlockOperator startOp; + private final WasmBlockOperator startOp; - private final BlockOperator endOp; + private final WasmBlockOperator endOp; + + private final Object data; /** * Create a new description. @@ -197,11 +290,30 @@ class BranchManger { * @param endOp * the WASM operation on the end position. Can be null if there is nothing in WASM. */ - BranchNode( int startPos, int endPos, BlockOperator startOp, BlockOperator endOp ) { + BranchNode( int startPos, int endPos, WasmBlockOperator startOp, WasmBlockOperator endOp ) { + this( startPos, endPos, startOp, endOp, null ); + } + + /** + * Create a new description. + * + * @param startPos + * the start position in the Java code. Limit also the children. + * @param endPos + * the end position in the Java code. Limit also the children. + * @param startOp + * The WASM operation on the start position. Can be null if there is nothing in WASM. + * @param endOp + * the WASM operation on the end position. Can be null if there is nothing in WASM. + * @param data + * extra data depending of the start operator + */ + BranchNode( int startPos, int endPos, WasmBlockOperator startOp, WasmBlockOperator endOp, Object data ) { this.startPos = startPos; this.endPos = endPos; this.startOp = startOp; this.endOp = endOp; + this.data = data; } void handle( int codePositions, ModuleWriter writer ) throws IOException { @@ -209,13 +321,13 @@ class BranchManger { return; } if( codePositions == startPos && startOp != null ) { - writer.writeBlockCode( startOp ); + writer.writeBlockCode( startOp, data ); } for( BranchNode branch : this ) { branch.handle( codePositions, writer ); } if( codePositions == endPos && endOp != null ) { - writer.writeBlockCode( endOp ); + writer.writeBlockCode( endOp, null ); } } } diff --git a/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java new file mode 100644 index 0000000..f2a0e0b --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/JavaBlockOperator.java @@ -0,0 +1,29 @@ +/* + Copyright 2018 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. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +package de.inetsoftware.jwebassembly.module; + +/** + * Block operators in the Java byte code. + * + * @author Volker Berlin + * + */ +public enum JavaBlockOperator { + IF, + GOTO, + SWITCH, +} diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index 942de0e..3e148b6 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -335,12 +335,12 @@ public abstract class ModuleWriter implements Closeable { case 166: // if_acmpne int startPosition = byteCode.getCodePosition() + 2; int offset = byteCode.readShort(); - branchManager.start( BlockOperator.IF, startPosition, offset - 3, lineNumber ); + branchManager.start( JavaBlockOperator.IF, startPosition, offset - 3, lineNumber ); break; case 167: // goto startPosition = byteCode.getCodePosition() - 1; offset = byteCode.readShort(); - branchManager.start( BlockOperator.GOTO, startPosition, offset, lineNumber ); + branchManager.start( JavaBlockOperator.GOTO, startPosition, offset, lineNumber ); break; case 170: // tableswitch case 171: // lookupswitch @@ -512,7 +512,7 @@ public abstract class ModuleWriter implements Closeable { break; case 87: // pop case 88: // pop2 - writeBlockCode( BlockOperator.DROP ); + writeBlockCode( WasmBlockOperator.DROP, null ); break; case 89: // dup: duplicate the value on top of the stack case 90: // dup_x1 @@ -742,7 +742,7 @@ public abstract class ModuleWriter implements Closeable { case 174: // freturn case 175: // dreturn case 177: // return void - writeBlockCode( BlockOperator.RETURN ); + writeBlockCode( WasmBlockOperator.RETURN, null ); break; case 184: // invokestatic idx = byteCode.readUnsignedShort(); @@ -933,8 +933,10 @@ public abstract class ModuleWriter implements Closeable { * * @param op * the operation + * @param data + * extra data depending of the operator * @throws IOException * if any I/O error occur */ - protected abstract void writeBlockCode( BlockOperator op ) throws IOException; + protected abstract void writeBlockCode( @Nonnull WasmBlockOperator op, @Nullable Object data ) throws IOException; } diff --git a/src/de/inetsoftware/jwebassembly/module/BlockOperator.java b/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java similarity index 88% rename from src/de/inetsoftware/jwebassembly/module/BlockOperator.java rename to src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java index 16c5f68..36a6b31 100644 --- a/src/de/inetsoftware/jwebassembly/module/BlockOperator.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmBlockOperator.java @@ -17,18 +17,18 @@ package de.inetsoftware.jwebassembly.module; /** - * Block operators + * Block operators in the WASM byte code. * * @author Volker Berlin * */ -public enum BlockOperator { +public enum WasmBlockOperator { RETURN, IF, ELSE, END, - GOTO, DROP, BLOCK, - SWITCH, + BR, + BR_TABLE, } diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index ea6e3be..b3a0afb 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -18,9 +18,10 @@ package de.inetsoftware.jwebassembly.text; import java.io.IOException; import java.util.List; +import javax.annotation.Nonnull; import javax.annotation.Nullable; -import de.inetsoftware.jwebassembly.module.BlockOperator; +import de.inetsoftware.jwebassembly.module.WasmBlockOperator; import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.NumericOperator; import de.inetsoftware.jwebassembly.module.ValueType; @@ -248,7 +249,7 @@ public class TextModuleWriter extends ModuleWriter { * {@inheritDoc} */ @Override - protected void writeBlockCode( BlockOperator op ) throws IOException { + protected void writeBlockCode( @Nonnull WasmBlockOperator op, @Nullable Object data ) throws IOException { String name; int insetAfter = 0; switch( op ) { @@ -275,6 +276,9 @@ public class TextModuleWriter extends ModuleWriter { name = "block"; insetAfter++; break; + case BR: + name = "br " + data; + break; default: throw new Error( "Unknown block: " + op ); }