Implements the ELSE control structure

This commit is contained in:
Volker Berlin 2018-03-27 20:04:35 +02:00
parent e633fc79b5
commit 79ee98e8ce
6 changed files with 220 additions and 41 deletions

View File

@ -470,6 +470,22 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
break;
}
break;
case gt:
switch( valueType ) {
case i32:
op = I32_GT_S;
break;
case i64:
op = I64_NE;
break;
case f32:
op = F32_NE;
break;
case f64:
op = F64_NE;
break;
}
break;
}
if( op == 0 ) {
throw new Error( valueType + "." + numOp );
@ -527,6 +543,9 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
codeStream.write( IF );
codeStream.write( 0x40 ); // void; the return type of the block. currently we does not use it
break;
case ELSE:
codeStream.write( ELSE );
break;
case END:
codeStream.write( END );
break;

View File

@ -1,3 +1,19 @@
/*
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;
/**
@ -8,5 +24,7 @@ package de.inetsoftware.jwebassembly.module;
*/
public enum BlockOperator {
IF,
ELSE,
END,
GOTO,
}

View File

@ -1,7 +1,23 @@
/*
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;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import de.inetsoftware.classparser.CodeInputStream;
@ -13,20 +29,79 @@ import de.inetsoftware.classparser.CodeInputStream;
*/
class BranchManger {
private final ArrayDeque<Block> stack = new ArrayDeque<>();
private final ArrayList<Block> stack = new ArrayList<>();
/**
* Remove all branch information.
*/
void reset() {
stack.clear();
}
/**
* Start a new block.
*
* @param op
* the start operation
* @param basePosition
* @param startPosition
* 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 ) );
void start( BlockOperator op, int startPosition, int offset ) {
stack.add( new Block( op, startPosition, offset ) );
}
/**
* Calculate all block operators from the parsed information.
*/
void calculate() {
for( int i = 0; i < stack.size(); i++ ) {
Block block = stack.get( i );
switch( block.op ) {
case IF:
caculateIf( i, block );
break;
}
}
}
/**
* Calculate the ELSE and END position of an IF control structure.
*
* @param i
* the index in the stack
* @param startBlock
* the start block of the if control structure
*/
private void caculateIf( int i, Block startBlock ) {
i++;
int gotoPos = startBlock.endPosition - 3; // 3 - byte size of goto instruction
for( ; i < stack.size(); i++ ) {
Block block = stack.get( i );
if( block.startPosition == gotoPos && block.op == BlockOperator.GOTO ) {
block.op = BlockOperator.ELSE;
block.startPosition += 3;
startBlock = block;
i++;
break;
}
if( block.startPosition > gotoPos ) {
break;
}
}
/**
* Search the index in the stack to add the END operator
*/
int endPos = startBlock.endPosition;
for( ; i < stack.size(); i++ ) {
Block block = stack.get( i );
if( block.startPosition >= endPos ) {
break;
}
}
stack.add( i, new Block( BlockOperator.END, endPos, 0 ) );
}
/**
@ -40,13 +115,14 @@ class BranchManger {
* if any I/O exception occur
*/
void handle( CodeInputStream byteCode, ModuleWriter writer ) throws IOException {
if( stack.isEmpty() ) {
return;
}
int position = byteCode.getCodePosition();
Block block = stack.peek();
if( block != null ) {
if( block.endPosition == position ) {
writer.writeBlockCode( BlockOperator.END );
stack.pop();
}
Block block = stack.get( 0 );
if( block.startPosition == position ) {
writer.writeBlockCode( block.op );
stack.remove( 0 );
}
}
@ -56,14 +132,14 @@ class BranchManger {
private static class Block {
private BlockOperator op;
private int basePosition;
private int startPosition;
private int endPosition;
private Block( BlockOperator op, int basePosition, int offset ) {
private Block( BlockOperator op, int startPosition, int offset ) {
this.op = op;
this.basePosition = basePosition;
this.endPosition = basePosition + offset;
this.startPosition = startPosition;
this.endPosition = startPosition + offset;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 Volker Berlin (i-net software)
* 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.
@ -32,7 +32,6 @@ import de.inetsoftware.classparser.Code;
import de.inetsoftware.classparser.CodeInputStream;
import de.inetsoftware.classparser.ConstantPool;
import de.inetsoftware.classparser.ConstantRef;
import de.inetsoftware.classparser.LineNumberTable;
import de.inetsoftware.classparser.LocalVariableTable;
import de.inetsoftware.classparser.MethodInfo;
import de.inetsoftware.jwebassembly.WasmException;
@ -132,21 +131,15 @@ public abstract class ModuleWriter implements Closeable {
writeMethodSignature( method );
locals.clear();
localTable = code.getLocalVariableTable();
LineNumberTable lineNumberTable = code.getLineNumberTable();
if( lineNumberTable != null ) {
int lineNumber;
for( int i = 0; i < lineNumberTable.size(); i++ ) {
lineNumber = lineNumberTable.getLineNumber( i );
int offset = lineNumberTable.getStartOffset( i );
int nextOffset =
i + 1 == lineNumberTable.size() ? code.getCodeSize()
: lineNumberTable.getStartOffset( i + 1 );
CodeInputStream byteCode = code.getByteCode( offset, nextOffset - offset );
writeCodeChunk( byteCode, lineNumber, method.getConstantPool() );
}
} else {
CodeInputStream byteCode = code.getByteCode();
writeCodeChunk( byteCode, -1, method.getConstantPool() );
branchManager.reset();
for( CodeInputStream byteCode : code.getByteCodes() ) {
prepareBranchManager( byteCode, byteCode.getLineNumber() );
}
branchManager.calculate();
for( CodeInputStream byteCode : code.getByteCodes() ) {
writeCodeChunk( byteCode, byteCode.getLineNumber(), method.getConstantPool() );
}
for( int i = Math.min( paramCount, locals.size() ); i > 0; i-- ) {
locals.remove( 0 );
@ -290,6 +283,72 @@ public abstract class ModuleWriter implements Closeable {
*/
protected abstract void writeMethodFinish( List<ValueType> locals ) throws IOException;
/**
* 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
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.readUnsignedShort();
branchManager.start( BlockOperator.IF, startPosition, offset - 3 );
break;
case 167: // goto
startPosition = byteCode.getCodePosition() - 1;
offset = byteCode.readUnsignedShort();
branchManager.start( BlockOperator.GOTO, startPosition, offset );
break;
}
}
} catch( Exception ex ) {
throw WasmException.create( ex, sourceFile, lineNumber );
}
}
/**
* Write a chunk of byte code.
*
@ -502,10 +561,11 @@ public abstract class ModuleWriter implements Closeable {
case 154: // ifne
opIfCondition( NumericOperator.eq, byteCode );
break;
case 155: // iflt
opIfCondition( NumericOperator.gt, 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 );
byteCode.skip(2);
break;
case 172: // ireturn
case 173: // lreturn
@ -541,12 +601,10 @@ public abstract class ModuleWriter implements Closeable {
* 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 );
byteCode.skip(2);
writeConstInt( 0 );
writeNumericOperator( numOp, ValueType.i32 );
writeBlockCode( BlockOperator.IF );
//writeBlockCode( BlockOperator.IF );
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 Volker Berlin (i-net software)
* 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.
@ -32,4 +32,6 @@ public enum NumericOperator {
shr_u,
eq,
ne,
gt,
lt_s,
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 Volker Berlin (i-net software)
* 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.
@ -234,6 +234,12 @@ public class TextModuleWriter extends ModuleWriter {
methodOutput.append( "if" );
inset++;
break;
case ELSE:
inset--;
newline( methodOutput );
methodOutput.append( "else" );
inset++;
break;
case END:
inset--;
newline( methodOutput );