mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +01:00
first step of a "if" implementation
This commit is contained in:
parent
014d3a1acf
commit
d26b9bbb94
@ -27,6 +27,7 @@ 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.ModuleWriter;
|
||||
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
||||
import de.inetsoftware.jwebassembly.module.ValueType;
|
||||
@ -437,9 +438,39 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case eq:
|
||||
switch( valueType ) {
|
||||
case i32:
|
||||
op = I32_EQ;
|
||||
break;
|
||||
case i64:
|
||||
op = I64_EQ;
|
||||
break;
|
||||
case f32:
|
||||
op = F32_EQ;
|
||||
break;
|
||||
case f64:
|
||||
op = F64_EQ;
|
||||
break;
|
||||
}
|
||||
case ne:
|
||||
switch( valueType ) {
|
||||
case i32:
|
||||
op = I32_NE;
|
||||
break;
|
||||
case i64:
|
||||
op = I64_NE;
|
||||
break;
|
||||
case f32:
|
||||
op = F32_NE;
|
||||
break;
|
||||
case f64:
|
||||
op = F64_NE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( op == 0 ) {
|
||||
throw new Error();
|
||||
throw new Error( valueType + "." + numOp );
|
||||
}
|
||||
codeStream.write( op );
|
||||
}
|
||||
@ -483,4 +514,22 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
||||
}
|
||||
codeStream.writeVaruint32( func.id );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void writeBlockCode( BlockOperator op ) throws IOException {
|
||||
switch( op ) {
|
||||
case IF:
|
||||
codeStream.write( IF );
|
||||
codeStream.write( 0x40 ); // void; the return type of the block. currently we does not use it
|
||||
break;
|
||||
case END:
|
||||
codeStream.write( END );
|
||||
break;
|
||||
default:
|
||||
throw new Error( "Unknown block: " + op );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
src/de/inetsoftware/jwebassembly/module/BlockOperator.java
Normal file
12
src/de/inetsoftware/jwebassembly/module/BlockOperator.java
Normal file
@ -0,0 +1,12 @@
|
||||
package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
/**
|
||||
* Block operators
|
||||
*
|
||||
* @author Volker Berlin
|
||||
*
|
||||
*/
|
||||
public enum BlockOperator {
|
||||
IF,
|
||||
END,
|
||||
}
|
69
src/de/inetsoftware/jwebassembly/module/BranchManger.java
Normal file
69
src/de/inetsoftware/jwebassembly/module/BranchManger.java
Normal file
@ -0,0 +1,69 @@
|
||||
package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
|
||||
import de.inetsoftware.classparser.CodeInputStream;
|
||||
|
||||
/**
|
||||
* This calculate the goto offsets from Java back to block operations
|
||||
*
|
||||
* @author Volker Berlin
|
||||
*
|
||||
*/
|
||||
class BranchManger {
|
||||
|
||||
private final ArrayDeque<Block> stack = new ArrayDeque<>();
|
||||
|
||||
/**
|
||||
* Start a new block.
|
||||
*
|
||||
* @param op
|
||||
* the start operation
|
||||
* @param basePosition
|
||||
* the byte position of the start position
|
||||
* @param offset
|
||||
* the relative jump position
|
||||
*/
|
||||
void start( BlockOperator op, int basePosition, int offset ) {
|
||||
stack.push( new Block( op, basePosition, offset ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check on every instruction position if there any branch is ending
|
||||
*
|
||||
* @param byteCode
|
||||
* 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 {
|
||||
int position = byteCode.getCodePosition();
|
||||
Block block = stack.peek();
|
||||
if( block != null ) {
|
||||
if( block.endPosition == position ) {
|
||||
writer.writeBlockCode( BlockOperator.END );
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of single block/branch
|
||||
*/
|
||||
private static class Block {
|
||||
private BlockOperator op;
|
||||
|
||||
private int basePosition;
|
||||
|
||||
private int endPosition;
|
||||
|
||||
private Block( BlockOperator op, int basePosition, int offset ) {
|
||||
this.op = op;
|
||||
this.basePosition = basePosition;
|
||||
this.endPosition = basePosition + offset;
|
||||
}
|
||||
}
|
||||
}
|
@ -52,6 +52,8 @@ public abstract class ModuleWriter implements Closeable {
|
||||
|
||||
private String sourceFile;
|
||||
|
||||
private BranchManger branchManager = new BranchManger();
|
||||
|
||||
/**
|
||||
* Prepare the content of the class.
|
||||
*
|
||||
@ -303,6 +305,7 @@ public abstract class ModuleWriter implements Closeable {
|
||||
private void writeCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool ) throws WasmException {
|
||||
try {
|
||||
while( byteCode.available() > 0 ) {
|
||||
branchManager.handle( byteCode, this );
|
||||
int op = byteCode.readUnsignedByte();
|
||||
switch( op ) {
|
||||
case 2: // iconst_m1
|
||||
@ -493,6 +496,14 @@ public abstract class ModuleWriter implements Closeable {
|
||||
case 136: // l2i
|
||||
writeCast( ValueTypeConvertion.l2i );
|
||||
break;
|
||||
case 153: // ifeq
|
||||
opIfCondition( NumericOperator.ne, byteCode );
|
||||
break;
|
||||
case 167: // goto
|
||||
int baseCodePosition = byteCode.getCodePosition() - 1;
|
||||
int offset = byteCode.readUnsignedShort();
|
||||
if(true)throw new WasmException( "Unimplemented byte code operation: " + op, sourceFile, lineNumber );
|
||||
break;
|
||||
case 172: // ireturn
|
||||
case 173: // lreturn
|
||||
case 174: // freturn
|
||||
@ -514,6 +525,27 @@ public abstract class ModuleWriter implements Closeable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
int baseCodePosition = byteCode.getCodePosition() - 1;
|
||||
int offset = byteCode.readUnsignedShort();
|
||||
branchManager.start( BlockOperator.IF, baseCodePosition, offset );
|
||||
writeConstInt( 0 );
|
||||
writeNumericOperator( numOp, ValueType.i32 );
|
||||
writeBlockCode( BlockOperator.IF );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a constant value.
|
||||
*
|
||||
@ -670,4 +702,14 @@ public abstract class ModuleWriter implements Closeable {
|
||||
* if any I/O error occur
|
||||
*/
|
||||
protected abstract void writeFunctionCall( String name ) throws IOException;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
@ -30,4 +30,6 @@ public enum NumericOperator {
|
||||
shl,
|
||||
shr_s,
|
||||
shr_u,
|
||||
eq,
|
||||
ne,
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ public enum ValueType {
|
||||
f32(-3),
|
||||
f64(-4),
|
||||
func(-0x20);
|
||||
// void(-0x40);
|
||||
|
||||
private int code;
|
||||
|
||||
|
@ -20,6 +20,7 @@ import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.jwebassembly.module.BlockOperator;
|
||||
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
||||
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
||||
import de.inetsoftware.jwebassembly.module.ValueType;
|
||||
@ -221,4 +222,25 @@ public class TextModuleWriter extends ModuleWriter {
|
||||
name = name.substring( 0, name.indexOf( '(' ) );
|
||||
methodOutput.append( "call $" ).append( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void writeBlockCode( BlockOperator op ) throws IOException {
|
||||
switch( op ) {
|
||||
case IF:
|
||||
newline( methodOutput );
|
||||
methodOutput.append( "if" );
|
||||
inset++;
|
||||
break;
|
||||
case END:
|
||||
inset--;
|
||||
newline( methodOutput );
|
||||
methodOutput.append( "end" );
|
||||
break;
|
||||
default:
|
||||
throw new Error( "Unknown block: " + op );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package de.inetsoftware.jwebassembly.runtime;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
import org.webassembly.annotation.Export;
|
||||
|
||||
import de.inetsoftware.jwebassembly.ScriptEngine;
|
||||
import de.inetsoftware.jwebassembly.WasmRule;
|
||||
|
||||
public class ControlFlowOperators extends AbstractBaseTest {
|
||||
|
||||
@ClassRule
|
||||
public static WasmRule rule = new WasmRule( TestClass.class );
|
||||
|
||||
public ControlFlowOperators( ScriptEngine script, String method, Object[] params ) {
|
||||
super( rule, script, method, params );
|
||||
}
|
||||
|
||||
@Parameters( name = "{0}-{1}" )
|
||||
public static Collection<Object[]> data() {
|
||||
ArrayList<Object[]> list = new ArrayList<>();
|
||||
for( ScriptEngine[] val : ScriptEngine.testParams() ) {
|
||||
ScriptEngine script = val[0];
|
||||
addParam( list, script, "ifThenElse_Int0" );
|
||||
addParam( list, script, "forLoop" );
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
static class TestClass {
|
||||
|
||||
@Export
|
||||
static int ifThenElse_Int0() {
|
||||
int condition = 0;
|
||||
if( condition != 0 ) {
|
||||
return 13;
|
||||
} else {
|
||||
return 76;
|
||||
}
|
||||
}
|
||||
|
||||
@Export
|
||||
static int forLoop() {
|
||||
int a = 0;
|
||||
// for( int i=0; i<10;i++) {
|
||||
// a += i;
|
||||
// }
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user