mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 15:37:52 +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.classparser.MethodInfo;
|
||||||
import de.inetsoftware.jwebassembly.WasmException;
|
import de.inetsoftware.jwebassembly.WasmException;
|
||||||
|
import de.inetsoftware.jwebassembly.module.BlockOperator;
|
||||||
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
||||||
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
||||||
import de.inetsoftware.jwebassembly.module.ValueType;
|
import de.inetsoftware.jwebassembly.module.ValueType;
|
||||||
@ -437,9 +438,39 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
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 ) {
|
if( op == 0 ) {
|
||||||
throw new Error();
|
throw new Error( valueType + "." + numOp );
|
||||||
}
|
}
|
||||||
codeStream.write( op );
|
codeStream.write( op );
|
||||||
}
|
}
|
||||||
@ -483,4 +514,22 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
}
|
}
|
||||||
codeStream.writeVaruint32( func.id );
|
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 String sourceFile;
|
||||||
|
|
||||||
|
private BranchManger branchManager = new BranchManger();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the content of the class.
|
* 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 {
|
private void writeCodeChunk( CodeInputStream byteCode, int lineNumber, ConstantPool constantPool ) throws WasmException {
|
||||||
try {
|
try {
|
||||||
while( byteCode.available() > 0 ) {
|
while( byteCode.available() > 0 ) {
|
||||||
|
branchManager.handle( byteCode, this );
|
||||||
int op = byteCode.readUnsignedByte();
|
int op = byteCode.readUnsignedByte();
|
||||||
switch( op ) {
|
switch( op ) {
|
||||||
case 2: // iconst_m1
|
case 2: // iconst_m1
|
||||||
@ -493,6 +496,14 @@ public abstract class ModuleWriter implements Closeable {
|
|||||||
case 136: // l2i
|
case 136: // l2i
|
||||||
writeCast( ValueTypeConvertion.l2i );
|
writeCast( ValueTypeConvertion.l2i );
|
||||||
break;
|
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 172: // ireturn
|
||||||
case 173: // lreturn
|
case 173: // lreturn
|
||||||
case 174: // freturn
|
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.
|
* Write a constant value.
|
||||||
*
|
*
|
||||||
@ -670,4 +702,14 @@ public abstract class ModuleWriter implements Closeable {
|
|||||||
* if any I/O error occur
|
* if any I/O error occur
|
||||||
*/
|
*/
|
||||||
protected abstract void writeFunctionCall( String name ) throws IOException;
|
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,
|
shl,
|
||||||
shr_s,
|
shr_s,
|
||||||
shr_u,
|
shr_u,
|
||||||
|
eq,
|
||||||
|
ne,
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ public enum ValueType {
|
|||||||
f32(-3),
|
f32(-3),
|
||||||
f64(-4),
|
f64(-4),
|
||||||
func(-0x20);
|
func(-0x20);
|
||||||
|
// void(-0x40);
|
||||||
|
|
||||||
private int code;
|
private int code;
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import de.inetsoftware.jwebassembly.module.BlockOperator;
|
||||||
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
import de.inetsoftware.jwebassembly.module.ModuleWriter;
|
||||||
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
import de.inetsoftware.jwebassembly.module.NumericOperator;
|
||||||
import de.inetsoftware.jwebassembly.module.ValueType;
|
import de.inetsoftware.jwebassembly.module.ValueType;
|
||||||
@ -221,4 +222,25 @@ public class TextModuleWriter extends ModuleWriter {
|
|||||||
name = name.substring( 0, name.indexOf( '(' ) );
|
name = name.substring( 0, name.indexOf( '(' ) );
|
||||||
methodOutput.append( "call $" ).append( name );
|
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