870 lines
34 KiB
Java
Raw Normal View History

/*
2018-03-27 20:04:35 +02:00
* Copyright 2017 - 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;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
2017-04-17 12:10:56 +02:00
import java.util.function.Consumer;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
2017-04-09 18:46:27 +02:00
import javax.annotation.Nullable;
import de.inetsoftware.classparser.Annotations;
import de.inetsoftware.classparser.ClassFile;
import de.inetsoftware.classparser.Code;
import de.inetsoftware.classparser.CodeInputStream;
2017-04-08 18:48:45 +02:00
import de.inetsoftware.classparser.ConstantPool;
2017-04-17 12:10:56 +02:00
import de.inetsoftware.classparser.ConstantRef;
2017-04-09 22:45:52 +02:00
import de.inetsoftware.classparser.LocalVariableTable;
import de.inetsoftware.classparser.MethodInfo;
import de.inetsoftware.jwebassembly.WasmException;
/**
* Module Writer for text format with S-expressions.
*
* @author Volker Berlin
*/
public abstract class ModuleWriter implements Closeable {
private int paramCount;
private ArrayList<ValueType> locals = new ArrayList<>();
2017-04-09 22:45:52 +02:00
private LocalVariableTable localTable;
2017-04-09 18:18:53 +02:00
private String sourceFile;
2018-03-25 12:57:04 +02:00
private BranchManger branchManager = new BranchManger();
/**
2017-04-17 12:10:56 +02:00
* Prepare the content of the class.
*
* @param classFile
* the class file
* @throws WasmException
* if some Java code can't converted
*/
2017-04-17 12:10:56 +02:00
public void prepare( ClassFile classFile ) {
iterateMethods( classFile, m -> prepareMethod( m ) );
}
/**
* Write the content of the class to the writer.
*
* @param classFile
* the class file
* @throws WasmException
* if some Java code can't converted
*/
public void write( ClassFile classFile ) throws WasmException {
iterateMethods( classFile, m -> writeMethod( m ) );
}
private void iterateMethods( ClassFile classFile, Consumer<MethodInfo> handler ) throws WasmException {
sourceFile = null; // clear previous value for the case an IO exception occur
try {
sourceFile = classFile.getSourceFile();
if( sourceFile == null ) {
sourceFile = classFile.getThisClass().getName();
}
MethodInfo[] methods = classFile.getMethods();
for( MethodInfo method : methods ) {
Code code = method.getCode();
if( method.getName().equals( "<init>" ) && method.getDescription().equals( "()V" )
&& code.isSuperInitReturn( classFile.getSuperClass() ) ) {
continue; //default constructor
}
handler.accept( method );
}
2017-04-17 12:10:56 +02:00
} catch( IOException ioex ) {
throw WasmException.create( ioex, sourceFile, -1 );
}
}
2017-04-17 12:10:56 +02:00
/**
* Prepare the method.
*
* @param method
* the method
* @throws WasmException
* if some Java code can't converted
*/
protected void prepareMethod( MethodInfo method ) throws WasmException {
// Nothing
2017-04-17 12:10:56 +02:00
}
/**
* Write the content of a method.
*
* @param method
* the method
* @throws WasmException
* if some Java code can't converted
*/
2017-04-17 12:10:56 +02:00
private void writeMethod( MethodInfo method ) throws WasmException {
try {
Code code = method.getCode();
if( code != null ) { // abstract methods and interface methods does not have code
String methodName = method.getName();
String className = method.getDeclaringClassFile().getThisClass().getName();
String fullName = className + '.' + methodName;
String signatureName = fullName + method.getDescription();
writeExport( signatureName, fullName, method );
writeMethodStart( signatureName, fullName );
2017-04-17 12:10:56 +02:00
writeMethodSignature( method );
locals.clear();
localTable = code.getLocalVariableTable();
2018-03-27 20:04:35 +02:00
branchManager.reset();
for( CodeInputStream byteCode : code.getByteCodes() ) {
prepareBranchManager( byteCode, byteCode.getLineNumber() );
}
branchManager.calculate();
for( CodeInputStream byteCode : code.getByteCodes() ) {
writeCodeChunk( byteCode, byteCode.getLineNumber(), method.getConstantPool() );
}
2017-04-17 12:10:56 +02:00
for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) {
locals.remove( 0 );
}
writeMethodFinish( locals );
}
2017-04-17 12:10:56 +02:00
} catch( IOException ioex ) {
throw WasmException.create( ioex, sourceFile, -1 );
}
}
/**
* Look for a Export annotation and if there write an export directive.
2017-04-17 12:10:56 +02:00
*
* @param signatureName
* the full name with signature
* @param methodName
2017-04-17 12:10:56 +02:00
* the normalized method name
* @param method
2017-04-17 12:10:56 +02:00
* the moethod
*
* @throws IOException
2017-04-17 12:10:56 +02:00
* if any IOException occur
*/
private void writeExport( String signatureName, String methodName, MethodInfo method ) throws IOException {
Annotations annotations = method.getRuntimeInvisibleAnnotations();
if( annotations != null ) {
Map<String,Object> export = annotations.get( "org.webassembly.annotation.Export" );
if( export != null ) {
String exportName = (String)export.get( "name" );
if( exportName == null ) {
exportName = method.getName(); // TODO naming conversion rule if no name was set
}
writeExport( signatureName, methodName, exportName );
}
}
}
/**
* Write an export directive
* @param signatureName
* the full name with signature
* @param methodName
* the method name
* @param exportName
* the export name, if null then the same like the method name
*
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeExport( String signatureName, String methodName, String exportName ) throws IOException;
/**
* Write the method header.
* @param signatureName
* the full name with signature
* @param name
* the method name
*
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeMethodStart( String signatureName, String name ) throws IOException;
/**
* Write the parameter and return signatures
*
* @param method
* the method
* @throws IOException
* if any I/O error occur
* @throws WasmException
* if some Java code can't converted
*/
private void writeMethodSignature( MethodInfo method ) throws IOException, WasmException {
String signature = method.getDescription();
String kind = "param";
int paramCount = 0;
for( int i = 1; i < signature.length(); i++ ) {
paramCount++;
String javaType;
switch( signature.charAt( i ) ) {
case '[': // array
javaType = "array";
break;
case 'L':
javaType = "object";
break;
case 'B': // byte
case 'C': // char
case 'S': // short
case 'I': // int
writeMethodParam( kind, ValueType.i32 );
continue;
case 'D': // double
writeMethodParam( kind, ValueType.f64 );
continue;
case 'F': // float
writeMethodParam( kind, ValueType.f32 );
continue;
case 'J': // long
writeMethodParam( kind, ValueType.i64 );
continue;
case 'V': // void
continue;
case ')':
this.paramCount = paramCount - 1;
kind = "result";
continue;
default:
javaType = signature.substring( i, i + 1 );
}
int lineNumber = method.getCode().getFirstLineNr();
2017-04-09 18:18:53 +02:00
throw new WasmException( "Not supported Java data type in method signature: " + javaType, sourceFile, lineNumber );
}
}
/**
* Write a method parameter.
*
* @param kind
* "param", "result" or "local"
* @param valueType
* the data type of the parameter
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeMethodParam( String kind, ValueType valueType ) throws IOException;
/**
* Complete the method
*
* @param locals
* a list with types of local variables
*
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeMethodFinish( List<ValueType> locals ) throws IOException;
2018-03-27 20:04:35 +02:00
/**
* Write a chunk of byte code.
*
* @param byteCode
* a stream of byte code
* @param lineNumber
* the current line number
* @throws WasmException
* if some Java code can't converted
*/
private void prepareBranchManager( CodeInputStream byteCode, int lineNumber ) throws WasmException {
try {
while( byteCode.available() > 0 ) {
int op = byteCode.readUnsignedByte();
switch( op ) {
case 16: // bipush
case 18: // ldc
case 21: //iload
case 22: //lload
case 23: //fload
case 24: //dload
case 25: //aload
case 54: // istore
case 55: // lstore
case 56: // fstore
case 57: // dstore
case 58: // astore
case 179: // putstatic
case 181: // putfield
byteCode.skip(1);
break;
case 17: // sipush
2018-04-01 11:33:15 +02:00
case 19: // ldc_w
2018-03-27 20:04:35 +02:00
case 20: // ldc2_w
case 132: // iinc
case 184: // invokestatic
byteCode.skip( 2);
break;
case 153: // ifeq
case 154: // ifne
case 155: // iflt
case 156: // ifge
case 157: // ifgt
case 158: // ifle
case 159: // if_icmpeq
case 160: // if_icmpne
case 161: // if_icmplt
case 162: // if_icmpge
case 163: // if_icmpgt
case 164: // if_icmple
case 165: // if_acmpeq
case 166: // if_acmpne
int startPosition = byteCode.getCodePosition() + 2;
int offset = byteCode.readShort();
2018-03-27 20:04:35 +02:00
branchManager.start( BlockOperator.IF, startPosition, offset - 3 );
break;
case 167: // goto
startPosition = byteCode.getCodePosition() - 1;
offset = byteCode.readShort();
2018-03-27 20:04:35 +02:00
branchManager.start( BlockOperator.GOTO, startPosition, offset );
break;
}
}
} catch( Exception ex ) {
throw WasmException.create( ex, sourceFile, lineNumber );
}
}
/**
* Write a chunk of byte code.
*
* @param byteCode
* a stream of byte code
* @param lineNumber
* the current line number
2017-04-09 18:18:53 +02:00
* @param constantPool
* the constant pool of the the current class
* @throws WasmException
* if some Java code can't converted
*/
2017-04-08 18:48:45 +02:00
private void writeCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool ) throws WasmException {
try {
while( byteCode.available() > 0 ) {
2018-03-25 12:57:04 +02:00
branchManager.handle( byteCode, this );
int op = byteCode.readUnsignedByte();
switch( op ) {
case 0: // nop
return;
2018-04-02 11:53:12 +02:00
//TODO case 1: // aconst_null
2017-04-11 17:59:06 +02:00
case 2: // iconst_m1
case 3: // iconst_0
case 4: // iconst_1
2017-04-11 17:59:06 +02:00
case 5: // iconst_2
case 6: // iconst_3
case 7: // iconst_4
case 8: // iconst_5
writeConstInt( op - 3 );
break;
2017-04-11 17:59:06 +02:00
case 9: // lconst_0
case 10: // lconst_1
writeConstLong( op - 9 );
break;
2017-04-14 16:31:35 +02:00
case 11: // fconst_0
case 12: // fconst_1
case 13: // fconst_2
writeConstFloat( op - 11 );
break;
case 14: // dconst_0
case 15: // dconst_1
writeConstDouble( op - 14 );
break;
2017-04-11 17:59:06 +02:00
case 16: // bipush
2017-04-02 19:40:42 +02:00
writeConstInt( byteCode.readByte() );
break;
2017-04-14 16:31:35 +02:00
case 17: // sipush
writeConstInt( byteCode.readShort() );
break;
2017-04-11 17:59:06 +02:00
case 18: // ldc
2017-04-09 12:44:01 +02:00
writeConst( constantPool.get( byteCode.readUnsignedByte() ) );
break;
case 19: // ldc_w
2017-04-11 17:59:06 +02:00
case 20: // ldc2_w
2017-04-09 12:44:01 +02:00
writeConst( constantPool.get( byteCode.readUnsignedShort() ) );
2017-04-08 18:48:45 +02:00
break;
case 21: // iload
writeLoadStore( true, ValueType.i32, byteCode.readUnsignedByte() );
break;
case 22: // lload
writeLoadStore( true, ValueType.i64, byteCode.readUnsignedByte() );
break;
case 23: // fload
writeLoadStore( true, ValueType.f32, byteCode.readUnsignedByte() );
break;
case 24: // dload
writeLoadStore( true, ValueType.f64, byteCode.readUnsignedByte() );
break;
//TODO case 25: // aload
case 26: // iload_0
case 27: // iload_1
case 28: // iload_2
case 29: // iload_3
writeLoadStore( true, ValueType.i32, op - 26 );
break;
2017-04-09 18:46:27 +02:00
case 30: // lload_0
case 31: // lload_1
case 32: // lload_2
case 33: // lload_3
writeLoadStore( true, ValueType.i64, op - 30 );
break;
case 34: // fload_0
case 35: // fload_1
case 36: // fload_2
case 37: // fload_3
writeLoadStore( true, ValueType.f32, op - 34 );
break;
case 38: // dload_0
case 39: // dload_1
case 40: // dload_2
case 41: // dload_3
writeLoadStore( true, ValueType.f64, op - 38 );
break;
case 54: // istore
writeLoadStore( false, ValueType.i32, byteCode.readUnsignedByte() );
break;
case 55: // lstore
writeLoadStore( false, ValueType.i64, byteCode.readUnsignedByte() );
break;
case 56: // fstore
writeLoadStore( false, ValueType.f32, byteCode.readUnsignedByte() );
break;
case 57: // dstore
writeLoadStore( false, ValueType.f64, byteCode.readUnsignedByte() );
break;
//TODO case 58: // astore
case 59: // istore_0
case 60: // istore_1
case 61: // istore_2
case 62: // istore_3
writeLoadStore( false, ValueType.i32, op - 59 );
break;
2017-04-11 17:59:06 +02:00
case 63: // lstore_0
case 64: // lstore_1
case 65: // lstore_2
case 66: // lstore_3
writeLoadStore( false, ValueType.i64, op - 63 );
break;
2017-04-14 16:31:35 +02:00
case 67: // fstore_0
case 68: // fstore_1
case 69: // fstore_2
case 70: // fstore_3
writeLoadStore( false, ValueType.f32, op - 67 );
break;
case 71: // dstore_0
case 72: // dstore_1
case 73: // dstore_2
case 74: // dstore_3
writeLoadStore( false, ValueType.f64, op - 71 );
break;
2018-04-02 11:53:12 +02:00
case 87: // pop
case 88: // pop2
writeBlockCode( BlockOperator.DROP );
break;
case 89: // dup: duplicate the value on top of the stack
case 90: // dup_x1
case 91: // dup_x2
case 92: // dup2
case 93: // dup2_x1
case 94: // dup2_x2
case 95: // swap
// 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, lineNumber );
case 96: // iadd
2017-04-11 21:12:27 +02:00
writeNumericOperator( NumericOperator.add, ValueType.i32);
2017-04-09 18:46:27 +02:00
break;
2017-04-09 20:45:23 +02:00
case 97: // ladd
2017-04-11 21:12:27 +02:00
writeNumericOperator( NumericOperator.add, ValueType.i64 );
2017-04-09 20:45:23 +02:00
break;
2017-04-09 18:46:27 +02:00
case 98: // fadd
2017-04-11 21:12:27 +02:00
writeNumericOperator( NumericOperator.add, ValueType.f32 );
break;
2017-04-09 20:45:23 +02:00
case 99: // dadd
2017-04-11 21:12:27 +02:00
writeNumericOperator( NumericOperator.add, ValueType.f64 );
break;
case 100: // isub
writeNumericOperator( NumericOperator.sub, ValueType.i32 );
break;
case 101: // lsub
writeNumericOperator( NumericOperator.sub, ValueType.i64 );
break;
case 102: // fsub
writeNumericOperator( NumericOperator.sub, ValueType.f32 );
break;
case 103: // dsub
writeNumericOperator( NumericOperator.sub, ValueType.f64 );
2017-04-09 20:45:23 +02:00
break;
2017-04-14 16:31:35 +02:00
case 104: // imul;
writeNumericOperator( NumericOperator.mul, ValueType.i32 );
break;
case 105: // lmul
writeNumericOperator( NumericOperator.mul, ValueType.i64 );
break;
case 106: // fmul
writeNumericOperator( NumericOperator.mul, ValueType.f32 );
break;
case 107: // dmul
writeNumericOperator( NumericOperator.mul, ValueType.f64 );
break;
case 108: // idiv
writeNumericOperator( NumericOperator.div, ValueType.i32 );
break;
case 109: // ldiv
writeNumericOperator( NumericOperator.div, ValueType.i64 );
break;
case 110: // fdiv
writeNumericOperator( NumericOperator.div, ValueType.f32 );
break;
case 111: // ddiv
writeNumericOperator( NumericOperator.div, ValueType.f64 );
break;
case 112: // irem
writeNumericOperator( NumericOperator.rem, ValueType.i32 );
break;
case 113: // lrem
writeNumericOperator( NumericOperator.rem, ValueType.i64 );
break;
case 114: // frem
case 115: // drem
throw new WasmException( "Modulo/Remainder for floating numbers is not supported in WASM. Use int or long data types." + op, sourceFile, lineNumber );
2017-04-16 12:20:53 +02:00
case 120: // ishl
writeNumericOperator( NumericOperator.shl, ValueType.i32 );
break;
case 121: // lshl
writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
2017-04-16 12:20:53 +02:00
writeNumericOperator( NumericOperator.shl, ValueType.i64 );
break;
case 122: // ishr
writeNumericOperator( NumericOperator.shr_s, ValueType.i32 );
break;
case 123: // lshr
writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
2017-04-16 12:20:53 +02:00
writeNumericOperator( NumericOperator.shr_s, ValueType.i64 );
break;
case 124: // iushr
writeNumericOperator( NumericOperator.shr_u, ValueType.i32 );
break;
case 125: // lushr
writeCast( ValueTypeConvertion.i2l ); // the shift parameter must be of type long!!!
2017-04-16 12:20:53 +02:00
writeNumericOperator( NumericOperator.shr_u, ValueType.i64 );
break;
case 126: // iand
writeNumericOperator( NumericOperator.and, ValueType.i32 );
break;
case 127: // land
writeNumericOperator( NumericOperator.and, ValueType.i64 );
break;
case 128: // ior
writeNumericOperator( NumericOperator.or, ValueType.i32 );
break;
case 129: // lor
writeNumericOperator( NumericOperator.or, ValueType.i64 );
break;
case 130: // ixor
writeNumericOperator( NumericOperator.xor, ValueType.i32 );
break;
case 131: // lxor
writeNumericOperator( NumericOperator.xor, ValueType.i64 );
break;
2017-04-16 11:28:11 +02:00
case 132: // iinc
int idx = byteCode.readUnsignedByte();
writeLoadStore( true, ValueType.i32, idx );
writeConstInt( byteCode.readUnsignedByte() );
writeNumericOperator( NumericOperator.add, ValueType.i32);
writeLoadStore( false, ValueType.i32, idx );
break;
case 133: // i2l
writeCast( ValueTypeConvertion.i2l );
break;
case 134: // i2f
writeCast( ValueTypeConvertion.i2f );
break;
case 135: // i2d
writeCast( ValueTypeConvertion.i2d );
break;
case 136: // l2i
writeCast( ValueTypeConvertion.l2i );
break;
case 137: // l2f
writeCast( ValueTypeConvertion.l2f );
break;
case 138: // l2d
writeCast( ValueTypeConvertion.l2d );
break;
case 139: // f2i
writeCast( ValueTypeConvertion.f2i );
break;
case 140: // f2l
writeCast( ValueTypeConvertion.f2l );
break;
case 141: // f2d
writeCast( ValueTypeConvertion.f2d );
break;
case 142: // d2i
writeCast( ValueTypeConvertion.d2i );
break;
case 143: // d2l
writeCast( ValueTypeConvertion.d2l );
break;
case 144: // d2f
writeCast( ValueTypeConvertion.d2f );
break;
case 145: // i2b
writeConstInt( 24 );
writeNumericOperator( NumericOperator.shl, ValueType.i32 );
writeConstInt( 24 );
writeNumericOperator( NumericOperator.shr_s, ValueType.i32 );
break;
case 146: // i2c
writeConstInt( 0xFFFF );
writeNumericOperator( NumericOperator.and, ValueType.i32 );
break;
case 147: // i2s
writeConstInt( 16 );
writeNumericOperator( NumericOperator.shl, ValueType.i32 );
writeConstInt( 16 );
writeNumericOperator( NumericOperator.shr_s, ValueType.i32 );
break;
2018-03-25 12:57:04 +02:00
case 153: // ifeq
opIfCondition( NumericOperator.ne, byteCode );
break;
2018-03-25 21:06:18 +02:00
case 154: // ifne
opIfCondition( NumericOperator.eq, byteCode );
break;
2018-03-27 20:04:35 +02:00
case 155: // iflt
opIfCondition( NumericOperator.gt, byteCode );
break;
2018-03-28 20:07:51 +02:00
case 156: // ifge
opIfCondition( NumericOperator.le_s, byteCode );
break;
case 157: // ifgt
opIfCondition( NumericOperator.lt_s, byteCode );
break;
case 158: // ifle
opIfCondition( NumericOperator.ge_s, byteCode );
break;
2018-03-25 12:57:04 +02:00
case 167: // goto
2018-03-27 20:04:35 +02:00
byteCode.skip(2);
2018-03-25 12:57:04 +02:00
break;
2017-04-02 19:40:42 +02:00
case 172: // ireturn
2017-04-08 18:48:45 +02:00
case 173: // lreturn
2017-04-09 12:44:01 +02:00
case 174: // freturn
case 175: // dreturn
case 177: // return void
2018-04-02 11:53:12 +02:00
writeBlockCode( BlockOperator.RETURN );
break;
case 184: // invokestatic
idx = byteCode.readUnsignedShort();
ConstantRef method = (ConstantRef)constantPool.get( idx );
writeFunctionCall( method.getConstantClass().getName() + '.' + method.getName() + method.getType() );
break;
default:
throw new WasmException( "Unimplemented Java byte code operation: " + op, sourceFile, lineNumber );
}
}
2018-04-02 11:53:12 +02:00
} catch( WasmException ex ) {
throw ex;
} catch( Exception ex ) {
2017-04-09 18:18:53 +02:00
throw WasmException.create( ex, sourceFile, lineNumber );
}
}
2018-03-25 12:57:04 +02:00
/**
* Handle the if<condition> of the Java byte code. This Java instruction compare the first stack value with value 0.
* Important: In Java the condition for the jump to the else block is saved. In WebAssembler we need to use
* condition for the if block. The caller of the method must already negate this
*
* @param numOp
* The condition for the if block.
* @param byteCode
* current byte code stream to read the taget offset.
* @throws IOException
* if any I/O errors occur.
*/
private void opIfCondition( NumericOperator numOp, CodeInputStream byteCode ) throws IOException {
2018-03-27 20:04:35 +02:00
byteCode.skip(2);
2018-03-25 12:57:04 +02:00
writeConstInt( 0 );
writeNumericOperator( numOp, ValueType.i32 );
2018-03-27 20:04:35 +02:00
//writeBlockCode( BlockOperator.IF );
2018-03-25 12:57:04 +02:00
}
2017-04-09 18:18:53 +02:00
/**
* 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
*/
2017-04-09 12:44:01 +02:00
private void writeConst( Object value ) throws IOException, WasmException {
Class<?> clazz = value.getClass();
if( clazz == Integer.class ) {
writeConstInt( ((Integer)value).intValue() );
} else if( clazz == Long.class ) {
writeConstLong( ((Long)value).longValue() );
} else if( clazz == Float.class ) {
writeConstFloat( ((Float)value).floatValue() );
} else if( clazz == Double.class ) {
writeConstDouble( ((Double)value).doubleValue() );
} else {
2017-04-09 18:18:53 +02:00
throw new WasmException( "Not supported constant type: " + clazz, sourceFile, -1 );
2017-04-09 12:44:01 +02:00
}
}
/**
* Write a constant integer value
*
* @param value
* the value
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeConstInt( int value ) throws IOException;
2017-04-08 18:48:45 +02:00
/**
* Write a constant long value
*
* @param value
* the value
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeConstLong( long value ) throws IOException;
2017-04-09 12:44:01 +02:00
/**
* Write a constant float value
*
* @param value
* the value
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeConstFloat( float value ) throws IOException;
/**
* Write a constant double value
*
* @param value
* the value
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeConstDouble( double value ) throws IOException;
2017-04-08 18:48:45 +02:00
/**
* Write or Load a local variable.
*
* @param load
* true: if load
* @param valueType
* the type of the variable
* @param idx
2017-04-09 22:45:52 +02:00
* the memory/slot idx of the variable
2017-04-08 18:48:45 +02:00
* @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, @Nonnull ValueType valueType, @Nonnegative int idx ) throws WasmException, IOException {
2017-04-09 22:45:52 +02:00
idx = localTable.get( idx ).getPosition(); // translate slot index to position index
while( locals.size() <= idx ) {
locals.add( null );
}
ValueType oldType = locals.get( idx );
if( oldType != null && oldType != valueType ) {
2017-04-09 18:18:53 +02:00
throw new WasmException( "Redefine local variable type from " + oldType + " to " + valueType, sourceFile, -1 );
}
locals.set( idx, valueType );
if( load ) {
writeLoad( idx );
} else {
writeStore( idx );
}
}
/**
* Write a variable load.
*
* @param idx
* the index of the parameter variable
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeLoad( int idx ) throws IOException;
/**
* Write a variable store.
*
* @param idx
* the index of the parameter variable
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeStore( int idx ) throws IOException;
/**
* Write a add operator
*
* @param numOp
* the numeric operation
2017-04-09 18:46:27 +02:00
* @param valueType
* the type of the parameters
*
* @throws IOException
* if any I/O error occur
*/
2017-04-11 21:12:27 +02:00
protected abstract void writeNumericOperator( NumericOperator numOp, @Nullable ValueType valueType ) throws IOException;
/**
* Cast a value from one type to another
*
* @param cast
* the operator
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeCast( ValueTypeConvertion cast ) throws IOException;
/**
* Write a call to a function.
*
* @param name
* the full qualified method name
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeFunctionCall( String name ) throws IOException;
2018-03-25 12:57:04 +02:00
/**
* Write a block/branch code
*
* @param op
* the operation
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeBlockCode( BlockOperator op ) throws IOException;
}