Use an intermediate model in the memory of the parsed Java bytecode.

This commit is contained in:
Volker 2018-06-21 18:49:55 +02:00
parent 95afeb17a7
commit 24bfe22a51
2 changed files with 155 additions and 174 deletions

View File

@ -40,6 +40,18 @@ class BranchManger {
private final HashMap<Integer, ParsedBlock> loops = new HashMap<>(); private final HashMap<Integer, ParsedBlock> loops = new HashMap<>();
private final List<WasmInstruction> instructions;
/**
* Create a branch manager.
*
* @param instructions
* the target for instructions
*/
public BranchManger( List<WasmInstruction> instructions ) {
this.instructions = instructions;
}
/** /**
* Remove all branch information for reusing the manager. * Remove all branch information for reusing the manager.
*/ */
@ -427,13 +439,9 @@ class BranchManger {
* *
* @param byteCode * @param byteCode
* the byte code stream * the byte code stream
* @param writer
* the current module writer
* @throws IOException
* if any I/O exception occur
*/ */
void handle( CodeInputStream byteCode, ModuleWriter writer ) throws IOException { void handle( CodeInputStream byteCode ) {
root.handle( byteCode.getCodePosition(), writer ); root.handle( byteCode.getCodePosition(), instructions );
} }
/** /**
@ -538,18 +546,26 @@ class BranchManger {
return super.add( e ); return super.add( e );
} }
void handle( int codePositions, ModuleWriter writer ) throws IOException { /**
* Handle branches on the current codePosition
*
* @param codePositions
* current code position
* @param instructions
* the target for instructions
*/
void handle( int codePositions, List<WasmInstruction> instructions ) {
if( codePositions < startPos || codePositions > endPos ) { if( codePositions < startPos || codePositions > endPos ) {
return; return;
} }
if( codePositions == startPos && startOp != null ) { if( codePositions == startPos && startOp != null ) {
writer.writeBlockCode( startOp, data ); instructions.add( new WasmBlockInstruction( startOp, data ) );
} }
for( BranchNode branch : this ) { for( BranchNode branch : this ) {
branch.handle( codePositions, writer ); branch.handle( codePositions, instructions );
} }
if( codePositions == endPos && endOp != null ) { if( codePositions == endPos && endOp != null ) {
writer.writeBlockCode( endOp, null ); instructions.add( new WasmBlockInstruction( endOp, null ) );
} }
} }
} }

View File

@ -16,10 +16,11 @@
package de.inetsoftware.jwebassembly.module; package de.inetsoftware.jwebassembly.module;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.classparser.ClassFile;
@ -47,7 +48,9 @@ public class ModuleGenerator {
private String sourceFile; private String sourceFile;
private BranchManger branchManager = new BranchManger(); private final List<WasmInstruction> instructions = new ArrayList<>();
private BranchManger branchManager = new BranchManger( instructions );
private ValueStackManger stackManager = new ValueStackManger(); private ValueStackManger stackManager = new ValueStackManger();
@ -167,6 +170,9 @@ public class ModuleGenerator {
byteCode = code.getByteCode(); byteCode = code.getByteCode();
writeCode( byteCode, method.getConstantPool() ); writeCode( byteCode, method.getConstantPool() );
for( WasmInstruction instruction : instructions ) {
instruction.writeTo( writer );
}
writer.writeMethodFinish( localVariables.getLocalTypes( paramCount ) ); writer.writeMethodFinish( localVariables.getLocalTypes( paramCount ) );
} }
} catch( Exception ioex ) { } catch( Exception ioex ) {
@ -517,10 +523,12 @@ public class ModuleGenerator {
* if some Java code can't converted * if some Java code can't converted
*/ */
private void writeCode( CodeInputStream byteCode, ConstantPool constantPool ) throws WasmException { private void writeCode( CodeInputStream byteCode, ConstantPool constantPool ) throws WasmException {
instructions.clear();
boolean endWithReturn = false; boolean endWithReturn = false;
try { try {
while( byteCode.available() > 0 ) { while( byteCode.available() > 0 ) {
branchManager.handle( byteCode, writer ); WasmInstruction instr = null;
branchManager.handle( byteCode );
endWithReturn = false; endWithReturn = false;
int op = byteCode.readUnsignedByte(); int op = byteCode.readUnsignedByte();
switch( op ) { switch( op ) {
@ -534,111 +542,111 @@ public class ModuleGenerator {
case 6: // iconst_3 case 6: // iconst_3
case 7: // iconst_4 case 7: // iconst_4
case 8: // iconst_5 case 8: // iconst_5
writer.writeConstInt( op - 3 ); instr = new WasmConstInstruction( Integer.valueOf( op - 3 ) );
break; break;
case 9: // lconst_0 case 9: // lconst_0
case 10: // lconst_1 case 10: // lconst_1
writer.writeConstLong( op - 9 ); instr = new WasmConstInstruction( Long.valueOf( op - 9 ) );
break; break;
case 11: // fconst_0 case 11: // fconst_0
case 12: // fconst_1 case 12: // fconst_1
case 13: // fconst_2 case 13: // fconst_2
writer.writeConstFloat( op - 11 ); instr = new WasmConstInstruction( Float.valueOf( op - 11 ) );
break; break;
case 14: // dconst_0 case 14: // dconst_0
case 15: // dconst_1 case 15: // dconst_1
writer.writeConstDouble( op - 14 ); instr = new WasmConstInstruction( Double.valueOf( op - 14 ) );
break; break;
case 16: // bipush case 16: // bipush
writer.writeConstInt( byteCode.readByte() ); instr = new WasmConstInstruction( Integer.valueOf( byteCode.readByte() ) );
break; break;
case 17: // sipush case 17: // sipush
writer.writeConstInt( byteCode.readShort() ); instr = new WasmConstInstruction( Integer.valueOf( byteCode.readShort() ) );
break; break;
case 18: // ldc case 18: // ldc
writeConst( constantPool.get( byteCode.readUnsignedByte() ) ); instr = new WasmConstInstruction( (Number)constantPool.get( byteCode.readUnsignedByte() ) );
break; break;
case 19: // ldc_w case 19: // ldc_w
case 20: // ldc2_w case 20: // ldc2_w
writeConst( constantPool.get( byteCode.readUnsignedShort() ) ); instr = new WasmConstInstruction( (Number)constantPool.get( byteCode.readUnsignedShort() ) );
break; break;
case 21: // iload case 21: // iload
writeLoadStore( true, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( true, byteCode.readUnsignedByte(), localVariables );
break; break;
case 22: // lload case 22: // lload
writeLoadStore( true, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( true, byteCode.readUnsignedByte(), localVariables );
break; break;
case 23: // fload case 23: // fload
writeLoadStore( true, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( true, byteCode.readUnsignedByte(), localVariables );
break; break;
case 24: // dload case 24: // dload
writeLoadStore( true, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( true, byteCode.readUnsignedByte(), localVariables );
break; break;
//TODO case 25: // aload //TODO case 25: // aload
case 26: // iload_0 case 26: // iload_0
case 27: // iload_1 case 27: // iload_1
case 28: // iload_2 case 28: // iload_2
case 29: // iload_3 case 29: // iload_3
writeLoadStore( true, op - 26 ); instr = new WasmLoadStoreInstruction( true, op - 26, localVariables );
break; break;
case 30: // lload_0 case 30: // lload_0
case 31: // lload_1 case 31: // lload_1
case 32: // lload_2 case 32: // lload_2
case 33: // lload_3 case 33: // lload_3
writeLoadStore( true, op - 30 ); instr = new WasmLoadStoreInstruction( true, op - 30, localVariables );
break; break;
case 34: // fload_0 case 34: // fload_0
case 35: // fload_1 case 35: // fload_1
case 36: // fload_2 case 36: // fload_2
case 37: // fload_3 case 37: // fload_3
writeLoadStore( true, op - 34 ); instr = new WasmLoadStoreInstruction( true, op - 34, localVariables );
break; break;
case 38: // dload_0 case 38: // dload_0
case 39: // dload_1 case 39: // dload_1
case 40: // dload_2 case 40: // dload_2
case 41: // dload_3 case 41: // dload_3
writeLoadStore( true, op - 38 ); instr = new WasmLoadStoreInstruction( true, op - 38, localVariables );
break; break;
case 54: // istore case 54: // istore
writeLoadStore( false, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( false, byteCode.readUnsignedByte(), localVariables );
break; break;
case 55: // lstore case 55: // lstore
writeLoadStore( false, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( false, byteCode.readUnsignedByte(), localVariables );
break; break;
case 56: // fstore case 56: // fstore
writeLoadStore( false, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( false, byteCode.readUnsignedByte(), localVariables );
break; break;
case 57: // dstore case 57: // dstore
writeLoadStore( false, byteCode.readUnsignedByte() ); instr = new WasmLoadStoreInstruction( false, byteCode.readUnsignedByte(), localVariables );
break; break;
//TODO case 58: // astore //TODO case 58: // astore
case 59: // istore_0 case 59: // istore_0
case 60: // istore_1 case 60: // istore_1
case 61: // istore_2 case 61: // istore_2
case 62: // istore_3 case 62: // istore_3
writeLoadStore( false, op - 59 ); instr = new WasmLoadStoreInstruction( false, op - 59, localVariables );
break; break;
case 63: // lstore_0 case 63: // lstore_0
case 64: // lstore_1 case 64: // lstore_1
case 65: // lstore_2 case 65: // lstore_2
case 66: // lstore_3 case 66: // lstore_3
writeLoadStore( false, op - 63 ); instr = new WasmLoadStoreInstruction( false, op - 63, localVariables );
break; break;
case 67: // fstore_0 case 67: // fstore_0
case 68: // fstore_1 case 68: // fstore_1
case 69: // fstore_2 case 69: // fstore_2
case 70: // fstore_3 case 70: // fstore_3
writeLoadStore( false, op - 67 ); instr = new WasmLoadStoreInstruction( false, op - 67, localVariables );
break; break;
case 71: // dstore_0 case 71: // dstore_0
case 72: // dstore_1 case 72: // dstore_1
case 73: // dstore_2 case 73: // dstore_2
case 74: // dstore_3 case 74: // dstore_3
writeLoadStore( false, op - 71 ); instr = new WasmLoadStoreInstruction( false, op - 71, localVariables );
break; break;
case 87: // pop case 87: // pop
case 88: // pop2 case 88: // pop2
writer.writeBlockCode( WasmBlockOperator.DROP, null ); instr = new WasmBlockInstruction( WasmBlockOperator.DROP, null );
break; break;
case 89: // dup: duplicate the value on top of the stack case 89: // dup: duplicate the value on top of the stack
case 90: // dup_x1 case 90: // dup_x1
@ -650,174 +658,174 @@ public class ModuleGenerator {
// can be do with functions with more as one return value in future WASM standard // can be do with functions with more as one return value in future WASM standard
throw new WasmException( "Stack duplicate is not supported in current WASM. try to save immediate values in a local variable: " + op, sourceFile, byteCode.getLineNumber() ); throw new WasmException( "Stack duplicate is not supported in current WASM. try to save immediate values in a local variable: " + op, sourceFile, byteCode.getLineNumber() );
case 96: // iadd case 96: // iadd
writer.writeNumericOperator( NumericOperator.add, ValueType.i32); instr = new WasmNumericInstruction( NumericOperator.add, ValueType.i32);
break; break;
case 97: // ladd case 97: // ladd
writer.writeNumericOperator( NumericOperator.add, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.add, ValueType.i64 );
break; break;
case 98: // fadd case 98: // fadd
writer.writeNumericOperator( NumericOperator.add, ValueType.f32 ); instr = new WasmNumericInstruction( NumericOperator.add, ValueType.f32 );
break; break;
case 99: // dadd case 99: // dadd
writer.writeNumericOperator( NumericOperator.add, ValueType.f64 ); instr = new WasmNumericInstruction( NumericOperator.add, ValueType.f64 );
break; break;
case 100: // isub case 100: // isub
writer.writeNumericOperator( NumericOperator.sub, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.sub, ValueType.i32 );
break; break;
case 101: // lsub case 101: // lsub
writer.writeNumericOperator( NumericOperator.sub, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.sub, ValueType.i64 );
break; break;
case 102: // fsub case 102: // fsub
writer.writeNumericOperator( NumericOperator.sub, ValueType.f32 ); instr = new WasmNumericInstruction( NumericOperator.sub, ValueType.f32 );
break; break;
case 103: // dsub case 103: // dsub
writer.writeNumericOperator( NumericOperator.sub, ValueType.f64 ); instr = new WasmNumericInstruction( NumericOperator.sub, ValueType.f64 );
break; break;
case 104: // imul; case 104: // imul;
writer.writeNumericOperator( NumericOperator.mul, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.i32 );
break; break;
case 105: // lmul case 105: // lmul
writer.writeNumericOperator( NumericOperator.mul, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.i64 );
break; break;
case 106: // fmul case 106: // fmul
writer.writeNumericOperator( NumericOperator.mul, ValueType.f32 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.f32 );
break; break;
case 107: // dmul case 107: // dmul
writer.writeNumericOperator( NumericOperator.mul, ValueType.f64 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.f64 );
break; break;
case 108: // idiv case 108: // idiv
writer.writeNumericOperator( NumericOperator.div, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.div, ValueType.i32 );
break; break;
case 109: // ldiv case 109: // ldiv
writer.writeNumericOperator( NumericOperator.div, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.div, ValueType.i64 );
break; break;
case 110: // fdiv case 110: // fdiv
writer.writeNumericOperator( NumericOperator.div, ValueType.f32 ); instr = new WasmNumericInstruction( NumericOperator.div, ValueType.f32 );
break; break;
case 111: // ddiv case 111: // ddiv
writer.writeNumericOperator( NumericOperator.div, ValueType.f64 ); instr = new WasmNumericInstruction( NumericOperator.div, ValueType.f64 );
break; break;
case 112: // irem case 112: // irem
writer.writeNumericOperator( NumericOperator.rem, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.rem, ValueType.i32 );
break; break;
case 113: // lrem case 113: // lrem
writer.writeNumericOperator( NumericOperator.rem, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.rem, ValueType.i64 );
break; break;
case 114: // frem case 114: // frem
case 115: // drem case 115: // drem
//TODO can be implemented with a helper function like: (a - (long)(a / b) * (double)b) //TODO can be implemented with a helper function like: (a - (long)(a / b) * (double)b)
throw new WasmException( "Modulo/Remainder for floating numbers is not supported in WASM. Use int or long data types." + op, sourceFile, byteCode.getLineNumber() ); throw new WasmException( "Modulo/Remainder for floating numbers is not supported in WASM. Use int or long data types." + op, sourceFile, byteCode.getLineNumber() );
case 116: // ineg case 116: // ineg
writer.writeConstInt( -1 ); instructions.add( new WasmConstInstruction( -1 ) );
writer.writeNumericOperator( NumericOperator.mul, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.i32 );
break; break;
case 117: // lneg case 117: // lneg
writer.writeConstLong( -1 ); instructions.add( new WasmConstInstruction( (long)-1 ) ) ;
writer.writeNumericOperator( NumericOperator.mul, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.mul, ValueType.i64 );
break; break;
case 118: // fneg case 118: // fneg
writer.writeNumericOperator( NumericOperator.neg, ValueType.f32 ); instr = new WasmNumericInstruction( NumericOperator.neg, ValueType.f32 );
break; break;
case 119: // dneg case 119: // dneg
writer.writeNumericOperator( NumericOperator.neg, ValueType.f64 ); instr = new WasmNumericInstruction( NumericOperator.neg, ValueType.f64 );
break; break;
case 120: // ishl case 120: // ishl
writer.writeNumericOperator( NumericOperator.shl, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.shl, ValueType.i32 );
break; break;
case 121: // lshl case 121: // lshl
writer.writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!! instructions.add( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
writer.writeNumericOperator( NumericOperator.shl, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.shl, ValueType.i64 );
break; break;
case 122: // ishr case 122: // ishr
writer.writeNumericOperator( NumericOperator.shr_s, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.shr_s, ValueType.i32 );
break; break;
case 123: // lshr case 123: // lshr
writer.writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!! instructions.add( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
writer.writeNumericOperator( NumericOperator.shr_s, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.shr_s, ValueType.i64 );
break; break;
case 124: // iushr case 124: // iushr
writer.writeNumericOperator( NumericOperator.shr_u, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.shr_u, ValueType.i32 );
break; break;
case 125: // lushr case 125: // lushr
writer.writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!! instructions.add( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
writer.writeNumericOperator( NumericOperator.shr_u, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.shr_u, ValueType.i64 );
break; break;
case 126: // iand case 126: // iand
writer.writeNumericOperator( NumericOperator.and, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.and, ValueType.i32 );
break; break;
case 127: // land case 127: // land
writer.writeNumericOperator( NumericOperator.and, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.and, ValueType.i64 );
break; break;
case 128: // ior case 128: // ior
writer.writeNumericOperator( NumericOperator.or, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.or, ValueType.i32 );
break; break;
case 129: // lor case 129: // lor
writer.writeNumericOperator( NumericOperator.or, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.or, ValueType.i64 );
break; break;
case 130: // ixor case 130: // ixor
writer.writeNumericOperator( NumericOperator.xor, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.xor, ValueType.i32 );
break; break;
case 131: // lxor case 131: // lxor
writer.writeNumericOperator( NumericOperator.xor, ValueType.i64 ); instr = new WasmNumericInstruction( NumericOperator.xor, ValueType.i64 );
break; break;
case 132: // iinc case 132: // iinc
int idx = byteCode.readUnsignedByte(); int idx = byteCode.readUnsignedByte();
writeLoadStore( true, idx ); instructions.add( new WasmLoadStoreInstruction( true, idx, localVariables ) );
writer.writeConstInt( byteCode.readUnsignedByte() ); instructions.add( new WasmConstInstruction( byteCode.readUnsignedByte() ) );
writer.writeNumericOperator( NumericOperator.add, ValueType.i32); instructions.add( new WasmNumericInstruction( NumericOperator.add, ValueType.i32) );
writeLoadStore( false, idx ); instr = new WasmLoadStoreInstruction( false, idx, localVariables );
break; break;
case 133: // i2l case 133: // i2l
writer.writeCast( ValueTypeConvertion.i2l ); instr = ValueTypeConvertion.i2l;
break; break;
case 134: // i2f case 134: // i2f
writer.writeCast( ValueTypeConvertion.i2f ); instr = ValueTypeConvertion.i2f;
break; break;
case 135: // i2d case 135: // i2d
writer.writeCast( ValueTypeConvertion.i2d ); instr = ValueTypeConvertion.i2d;
break; break;
case 136: // l2i case 136: // l2i
writer.writeCast( ValueTypeConvertion.l2i ); instr = ValueTypeConvertion.l2i;
break; break;
case 137: // l2f case 137: // l2f
writer.writeCast( ValueTypeConvertion.l2f ); instr = ValueTypeConvertion.l2f;
break; break;
case 138: // l2d case 138: // l2d
writer.writeCast( ValueTypeConvertion.l2d ); instr = ValueTypeConvertion.l2d;
break; break;
case 139: // f2i case 139: // f2i
writer.writeCast( ValueTypeConvertion.f2i ); instr = ValueTypeConvertion.f2i;
break; break;
case 140: // f2l case 140: // f2l
writer.writeCast( ValueTypeConvertion.f2l ); instr = ValueTypeConvertion.f2l;
break; break;
case 141: // f2d case 141: // f2d
writer.writeCast( ValueTypeConvertion.f2d ); instr = ValueTypeConvertion.f2d;
break; break;
case 142: // d2i case 142: // d2i
writer.writeCast( ValueTypeConvertion.d2i ); instr = ValueTypeConvertion.d2i;
break; break;
case 143: // d2l case 143: // d2l
writer.writeCast( ValueTypeConvertion.d2l ); instr = ValueTypeConvertion.d2l;
break; break;
case 144: // d2f case 144: // d2f
writer.writeCast( ValueTypeConvertion.d2f ); instr = ValueTypeConvertion.d2f;
break; break;
case 145: // i2b case 145: // i2b
writer.writeConstInt( 24 ); instructions.add( new WasmConstInstruction( 24 ) );
writer.writeNumericOperator( NumericOperator.shl, ValueType.i32 ); instructions.add( new WasmNumericInstruction( NumericOperator.shl, ValueType.i32 ) );
writer.writeConstInt( 24 ); instructions.add( new WasmConstInstruction( 24 ) );
writer.writeNumericOperator( NumericOperator.shr_s, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.shr_s, ValueType.i32 );
break; break;
case 146: // i2c case 146: // i2c
writer.writeConstInt( 0xFFFF ); instructions.add( new WasmConstInstruction( 0xFFFF ) );
writer.writeNumericOperator( NumericOperator.and, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.and, ValueType.i32 );
break; break;
case 147: // i2s case 147: // i2s
writer.writeConstInt( 16 ); instructions.add( new WasmConstInstruction( 16 ) );
writer.writeNumericOperator( NumericOperator.shl, ValueType.i32 ); instructions.add( new WasmNumericInstruction( NumericOperator.shl, ValueType.i32 ) );
writer.writeConstInt( 16 ); instructions.add( new WasmConstInstruction( 16 ) );
writer.writeNumericOperator( NumericOperator.shr_s, ValueType.i32 ); instr = new WasmNumericInstruction( NumericOperator.shr_s, ValueType.i32 );
break; break;
case 148: // lcmp case 148: // lcmp
opCompare( ValueType.i64, byteCode ); opCompare( ValueType.i64, byteCode );
@ -880,39 +888,42 @@ public class ModuleGenerator {
case 174: // freturn case 174: // freturn
case 175: // dreturn case 175: // dreturn
case 177: // return void case 177: // return void
writer.writeBlockCode( WasmBlockOperator.RETURN, null ); instr = new WasmBlockInstruction( WasmBlockOperator.RETURN, null );
endWithReturn = true; endWithReturn = true;
break; break;
case 184: // invokestatic case 184: // invokestatic
idx = byteCode.readUnsignedShort(); idx = byteCode.readUnsignedShort();
ConstantRef method = (ConstantRef)constantPool.get( idx ); ConstantRef method = (ConstantRef)constantPool.get( idx );
writer.writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() ); instr = new WasmCallInstruction( method.getConstantClass().getName() + '.' + method.getName() + method.getType() );
break; break;
default: default:
throw new WasmException( "Unimplemented Java byte code operation: " + op, sourceFile, byteCode.getLineNumber() ); throw new WasmException( "Unimplemented Java byte code operation: " + op, sourceFile, byteCode.getLineNumber() );
} }
if( instr != null ) {
instructions.add( instr );
} }
branchManager.handle( byteCode, writer ); // write the last end operators }
branchManager.handle( byteCode ); // write the last end operators
if( !endWithReturn && returnType != null ) { if( !endWithReturn && returnType != null ) {
// if a method ends with a loop without a break then code after the loop is no reachable // if a method ends with a loop without a break then code after the loop is no reachable
// Java does not need a return byte code in this case // Java does not need a return byte code in this case
// But WebAssembly need the dead code to validate // But WebAssembly need the dead code to validate
switch( returnType ) { switch( returnType ) {
case i32: case i32:
writer.writeConstInt( 0 ); instructions.add( new WasmConstInstruction( 0 ) );
break; break;
case i64: case i64:
writer.writeConstLong( 0 ); instructions.add( new WasmConstInstruction( 0L ) );
break; break;
case f32: case f32:
writer.writeConstFloat( 0 ); instructions.add( new WasmConstInstruction( 0F ) );
break; break;
case f64: case f64:
writer.writeConstDouble( 0 ); instructions.add( new WasmConstInstruction( 0D ) );
break; break;
default: default:
} }
writer.writeBlockCode( WasmBlockOperator.RETURN, null ); instructions.add( new WasmBlockInstruction( WasmBlockOperator.RETURN, null ) );
} }
} catch( WasmException ex ) { } catch( WasmException ex ) {
throw ex; throw ex;
@ -952,7 +963,7 @@ public class ModuleGenerator {
int block = 0; int block = 0;
int defaultBlock = -1; int defaultBlock = -1;
int currentPos = -1; int currentPos = -1;
writeLoadStore( false, tempI32 ); instructions.add( new WasmLoadStoreInstruction( false, tempI32, localVariables ) );
do { do {
int nextPos = findNext( currentPos, positions ); int nextPos = findNext( currentPos, positions );
if( nextPos == currentPos ) { if( nextPos == currentPos ) {
@ -969,10 +980,10 @@ public class ModuleGenerator {
} }
for( int i = 0; i < positions.length; i++ ) { for( int i = 0; i < positions.length; i++ ) {
if( positions[i] == currentPos ) { if( positions[i] == currentPos ) {
writeLoadStore( true, tempI32 ); instructions.add( new WasmLoadStoreInstruction( true, tempI32, localVariables ) );
writer.writeConstInt( keys[i] ); instructions.add( new WasmConstInstruction( keys[i] ) );
writer.writeNumericOperator( NumericOperator.eq, ValueType.i32 ); instructions.add( new WasmNumericInstruction( NumericOperator.eq, ValueType.i32 ) );
writer.writeBlockCode( WasmBlockOperator.BR_IF, block ); instructions.add( new WasmBlockInstruction( WasmBlockOperator.BR_IF, block ) );
} }
} }
block++; block++;
@ -980,7 +991,7 @@ public class ModuleGenerator {
if( defaultBlock < 0 ) { if( defaultBlock < 0 ) {
defaultBlock = block; defaultBlock = block;
} }
writer.writeBlockCode( WasmBlockOperator.BR, defaultBlock ); instructions.add( new WasmBlockInstruction( WasmBlockOperator.BR, defaultBlock ) );
} else { } else {
int low = byteCode.readInt(); int low = byteCode.readInt();
int count = byteCode.readInt() - low + 1; int count = byteCode.readInt() - low + 1;
@ -988,8 +999,8 @@ public class ModuleGenerator {
byteCode.readInt(); byteCode.readInt();
} }
if( low != 0 ) { // the br_table starts ever with the value 0. That we need to subtract the start value if it different if( low != 0 ) { // the br_table starts ever with the value 0. That we need to subtract the start value if it different
writer.writeConstInt( low ); instructions.add( new WasmConstInstruction( low ) );
writer.writeNumericOperator( NumericOperator.sub, ValueType.i32 ); instructions.add( new WasmNumericInstruction( NumericOperator.sub, ValueType.i32 ) );
} }
} }
} }
@ -1030,7 +1041,7 @@ public class ModuleGenerator {
* if any I/O errors occur. * if any I/O errors occur.
*/ */
private void opIfCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException { private void opIfCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException {
writer.writeConstInt( 0 ); instructions.add( new WasmConstInstruction( 0 ) );
opIfCompareCondition( ifNumOp, continueNumOp, byteCode ); opIfCompareCondition( ifNumOp, continueNumOp, byteCode );
} }
@ -1050,7 +1061,7 @@ public class ModuleGenerator {
*/ */
private void opIfCompareCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException { private void opIfCompareCondition( NumericOperator ifNumOp, NumericOperator continueNumOp, CodeInputStream byteCode ) throws IOException {
int offset = byteCode.readShort(); int offset = byteCode.readShort();
writer.writeNumericOperator( offset > 0 ? ifNumOp : continueNumOp, ValueType.i32 ); instructions.add( new WasmNumericInstruction( offset > 0 ? ifNumOp : continueNumOp, ValueType.i32 ) );
} }
/** /**
@ -1090,53 +1101,7 @@ public class ModuleGenerator {
throw new WasmException( "Unexpected compare sub operation: " + nextOp, null, -1 ); throw new WasmException( "Unexpected compare sub operation: " + nextOp, null, -1 );
} }
byteCode.skip(2); byteCode.skip(2);
writer.writeNumericOperator( numOp, valueType ); instructions.add( new WasmNumericInstruction( numOp, valueType ) );
}
/**
* Write a constant value.
*
* @param value
* the value
* @throws IOException
* if any I/O error occur
* @throws WasmException
* if the value type is not supported
*/
private void writeConst( Object value ) throws IOException, WasmException {
Class<?> clazz = value.getClass();
if( clazz == Integer.class ) {
writer.writeConstInt( ((Integer)value).intValue() );
} else if( clazz == Long.class ) {
writer.writeConstLong( ((Long)value).longValue() );
} else if( clazz == Float.class ) {
writer.writeConstFloat( ((Float)value).floatValue() );
} else if( clazz == Double.class ) {
writer.writeConstDouble( ((Double)value).doubleValue() );
} else {
throw new WasmException( "Not supported constant type: " + clazz, sourceFile, -1 );
}
}
/**
* Write or Load a local variable.
*
* @param load
* true: if load
* @param idx
* the memory/slot idx of the variable
* @throws WasmException
* occur a if a variable was used for a different type
* @throws IOException
* if any I/O error occur
*/
private void writeLoadStore( boolean load, @Nonnegative int idx ) throws WasmException, IOException {
idx = localVariables.get( idx ); // translate slot index to position index
if( load ) {
writer.writeLoad( idx );
} else {
writer.writeStore( idx );
}
} }
} }