experimental code for arrays

This commit is contained in:
Volker Berlin 2018-12-02 19:54:59 +01:00
parent 8f365d629b
commit 74dcb4dc09
10 changed files with 354 additions and 17 deletions

View File

@ -31,6 +31,7 @@ import javax.annotation.Nullable;
import de.inetsoftware.classparser.Member; import de.inetsoftware.classparser.Member;
import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.module.ArrayOperator;
import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.NumericOperator; import de.inetsoftware.jwebassembly.module.NumericOperator;
@ -778,4 +779,30 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
throw new Error( "Unknown block: " + op ); throw new Error( "Unknown block: " + op );
} }
} }
/**
* {@inheritDoc}
*/
@Override
protected void writeArrayOperator( @Nonnull ArrayOperator op, ValueType valueType ) throws IOException {
int opCode;
switch(op) {
case NEW:
opCode = ARRAY_NEW;
break;
case GET:
opCode = ARRAY_GET;
break;
case SET:
opCode = ARRAY_SET;
break;
case LENGTH:
opCode = ARRAY_LEN;
break;
default:
throw new Error( "Unknown operator: " + op );
}
codeStream.writeOpCode( opCode );
codeStream.writeValueType( valueType );
}
} }

View File

@ -396,4 +396,23 @@ interface InstructionOpcodes {
static final int I64_TRUNC_S_SAT_F64 = 0xFC06; static final int I64_TRUNC_S_SAT_F64 = 0xFC06;
static final int I64_TRUNC_U_SAT_F64 = 0xFC07; static final int I64_TRUNC_U_SAT_F64 = 0xFC07;
// === GC opcodes (unofficial, experimental) ===== https://github.com/lars-t-hansen/moz-gc-experiments/blob/master/version2.md
static final int STRUCT_NEW = 0xFC50;
static final int STRUCT_GET = 0xFC51;
static final int STRUCT_SET = 0xFC52;
static final int STRUCT_NARROW = 0xFC53;
static final int ARRAY_NEW = 0xFC60;
static final int ARRAY_GET = 0xFC61;
static final int ARRAY_SET = 0xFC62;
static final int ARRAY_LEN = 0xFC63;
} }

View File

@ -0,0 +1,29 @@
/*
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;
/**
* Operation on Arrays.
*
* @author Volker Berlin
*/
public enum ArrayOperator {
NEW,
GET,
SET,
LENGTH,
}

View File

@ -131,7 +131,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 24: // dload case 24: // dload
addLoadStoreInstruction( ValueType.f64, true, byteCode.readUnsignedByte(), codePos ); addLoadStoreInstruction( ValueType.f64, true, byteCode.readUnsignedByte(), codePos );
break; break;
//TODO case 25: // aload case 25: // aload
addLoadStoreInstruction( ValueType.anyref, true, byteCode.readUnsignedByte(), codePos );
break;
case 26: // iload_0 case 26: // iload_0
case 27: // iload_1 case 27: // iload_1
case 28: // iload_2 case 28: // iload_2
@ -156,11 +158,15 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 41: // dload_3 case 41: // dload_3
addLoadStoreInstruction( ValueType.f64, true, op - 38, codePos ); addLoadStoreInstruction( ValueType.f64, true, op - 38, codePos );
break; break;
//TODO case 42: //aload_0 case 42: //aload_0
//TODO case 43: //aload_1 case 43: //aload_1
//TODO case 44: //aload_2 case 44: //aload_2
//TODO case 45: //aload_3 case 45: //aload_3
//TODO case 46: // iaload addLoadStoreInstruction( ValueType.anyref, true, op - 42, codePos );
break;
case 46: // iaload
addArrayInstruction( ArrayOperator.GET, ValueType.i32, codePos );
break;
//TODO case 47: // laload //TODO case 47: // laload
//TODO case 48: // faload //TODO case 48: // faload
//TODO case 49: // daload //TODO case 49: // daload
@ -180,7 +186,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 57: // dstore case 57: // dstore
addLoadStoreInstruction( ValueType.f64, false, byteCode.readUnsignedByte(), codePos ); addLoadStoreInstruction( ValueType.f64, false, byteCode.readUnsignedByte(), codePos );
break; break;
//TODO case 58: // astore case 58: // astore
addLoadStoreInstruction( ValueType.anyref, false, byteCode.readUnsignedByte(), codePos );
break;
case 59: // istore_0 case 59: // istore_0
case 60: // istore_1 case 60: // istore_1
case 61: // istore_2 case 61: // istore_2
@ -211,14 +219,16 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 78: // astore_3 case 78: // astore_3
addLoadStoreInstruction( ValueType.anyref, false, op - 75, codePos ); addLoadStoreInstruction( ValueType.anyref, false, op - 75, codePos );
break; break;
//TODO case 79: // iastore case 79: // iastore
//TODO case 80: // lastore addArrayInstruction( ArrayOperator.SET, ValueType.i32, codePos );
//TODO case 81: // fastore break;
//TODO case 82: // dastore //TODO case 80: // lastore
//TODO case 83: // aastore //TODO case 81: // fastore
//TODO case 84: // bastore //TODO case 82: // dastore
//TODO case 85: // castore //TODO case 83: // aastore
//TODO case 86: // sastore //TODO case 84: // bastore
//TODO case 85: // castore
//TODO case 86: // sastore
case 87: // pop case 87: // pop
case 88: // pop2 case 88: // pop2
addBlockInstruction( WasmBlockOperator.DROP, null, codePos ); addBlockInstruction( WasmBlockOperator.DROP, null, codePos );
@ -238,6 +248,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case f64: case f64:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_f64", "(D)DD" ), codePos ); addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_f64", "(D)DD" ), codePos );
break OP; break OP;
case anyref:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_anyref", "(Ljava.lang.Object;)Ljava.lang.Object;Ljava.lang.Object;" ), codePos );
break OP;
} }
//$FALL-THROUGH$ //$FALL-THROUGH$
case 90: // dup_x1 case 90: // dup_x1
@ -518,9 +531,36 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
//TODO case 185: // invokeinterface //TODO case 185: // invokeinterface
//TODO case 186: // invokedynamic //TODO case 186: // invokedynamic
//TODO case 187: // new //TODO case 187: // new
//TODO case 188: // newarray case 188: // newarray
int typeValue = byteCode.readByte();
switch( typeValue ) {
case 4: // boolean
case 5: // char
type = ValueType.i32;
break;
case 6: //float
type = ValueType.f32;
break;
case 7: //double
type = ValueType.f64;
break;
case 8: //byte
case 9: //short
case 10: //int
type = ValueType.i32;
break;
case 11: //long
type = ValueType.i64;
break;
default:
throw new WasmException( "Invalid Java byte code newarray: " + typeValue, byteCode.getLineNumber() );
}
addArrayInstruction( ArrayOperator.NEW, type, codePos );
break;
//TODO case 189: // anewarray //TODO case 189: // anewarray
//TODO case 190: // arraylength case 190: // arraylength
addArrayInstruction( ArrayOperator.LENGTH, ValueType.i32, codePos );
break;
//TODO case 191: // athrow //TODO case 191: // athrow
//TODO case 192: // checkcast //TODO case 192: // checkcast
//TODO case 193: // instanceof //TODO case 193: // instanceof

View File

@ -203,4 +203,16 @@ public abstract class ModuleWriter implements Closeable {
* if any I/O error occur * if any I/O error occur
*/ */
protected abstract void writeBlockCode( @Nonnull WasmBlockOperator op, @Nullable Object data ) throws IOException; protected abstract void writeBlockCode( @Nonnull WasmBlockOperator op, @Nullable Object data ) throws IOException;
/**
* Write an array operation.
*
* @param op
* the operation
* @param valueType
* the resulting type
* @throws IOException
* if any I/O error occur
*/
protected abstract void writeArrayOperator( @Nonnull ArrayOperator op, ValueType valueType ) throws IOException;
} }

View File

@ -30,4 +30,7 @@ public class NativeHelperCode {
@WasmTextCode( signature = "(D)DD", value = "get_local 0 get_local 0 return" ) @WasmTextCode( signature = "(D)DD", value = "get_local 0 get_local 0 return" )
native static void dup_f64(); native static void dup_f64();
@WasmTextCode( signature = "(Ljava.lang.Object;)Ljava.lang.Object;Ljava.lang.Object;", value = "get_local 0 get_local 0 return" )
native static void dup_anyref();
} }

View File

@ -0,0 +1,95 @@
/*
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;
import de.inetsoftware.jwebassembly.WasmException;
/**
* WasmInstruction for numeric operation.
*
* @author Volker Berlin
*
*/
class WasmArrayInstruction extends WasmInstruction {
private final ArrayOperator op;
private final ValueType valueType;
/**
* Create an instance of numeric operation.
*
* @param numOp
* the numeric operation
* @param valueType
* the type of the parameters
* @param javaCodePos
* the code position/offset in the Java method
*/
WasmArrayInstruction( @Nullable ArrayOperator op, @Nullable ValueType valueType, int javaCodePos ) {
super( javaCodePos );
this.op = op;
this.valueType = valueType;
}
/**
* {@inheritDoc}
*/
public void writeTo( @Nonnull ModuleWriter writer ) throws IOException {
writer.writeArrayOperator( op, valueType );
}
/**
* {@inheritDoc}
*/
ValueType getPushValueType() {
switch( op ) {
case NEW:
return ValueType.anyref;
case GET:
return valueType;
case SET:
return null;
case LENGTH:
return ValueType.i32;
default:
throw new WasmException( "Unknown array operation: " + op, -1 );
}
}
/**
* {@inheritDoc}
*/
@Override
int getPopCount() {
switch( op ) {
case NEW:
case GET:
case LENGTH:
return 1;
case SET:
return 0;
default:
throw new WasmException( "Unknown array operation: " + op, -1 );
}
}
}

View File

@ -205,4 +205,18 @@ public abstract class WasmCodeBuilder {
protected void addNopInstruction( int javaCodePos ) { protected void addNopInstruction( int javaCodePos ) {
instructions.add( new WasmNopInstruction( javaCodePos ) ); instructions.add( new WasmNopInstruction( javaCodePos ) );
} }
/**
* Add an array operation to the instruction list as marker on the code position.
*
* @param op
* the operation
* @param type
* the array type
* @param javaCodePos
* the code position/offset in the Java method
*/
protected void addArrayInstruction( ArrayOperator op, ValueType type, int javaCodePos ) {
instructions.add( new WasmArrayInstruction( op, type, javaCodePos ) );
}
} }

View File

@ -24,6 +24,7 @@ import javax.annotation.Nullable;
import de.inetsoftware.classparser.Member; import de.inetsoftware.classparser.Member;
import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.module.ArrayOperator;
import de.inetsoftware.jwebassembly.module.FunctionName; import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter; import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.NumericOperator; import de.inetsoftware.jwebassembly.module.NumericOperator;
@ -362,4 +363,27 @@ public class TextModuleWriter extends ModuleWriter {
methodOutput.append( name ); methodOutput.append( name );
inset += insetAfter; inset += insetAfter;
} }
@Override
protected void writeArrayOperator( @Nonnull ArrayOperator op, ValueType valueType ) throws IOException {
String operation;
switch( op ) {
case NEW:
operation = "new";
break;
case GET:
operation = "get";
break;
case SET:
operation = "set";
break;
case LENGTH:
operation = "len";
break;
default:
throw new Error( "Unknown operator: " + op );
}
newline( methodOutput );
methodOutput.append( "array." ).append( operation ).append( ' ' ).append( valueType );
}
} }

View File

@ -0,0 +1,74 @@
/*
* 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.runtime;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Assume;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runners.Parameterized.Parameters;
import de.inetsoftware.jwebassembly.ScriptEngine;
import de.inetsoftware.jwebassembly.WasmRule;
import de.inetsoftware.jwebassembly.api.annotation.Export;
public class Arrays extends AbstractBaseTest {
@ClassRule
public static WasmRule rule = new WasmRule( TestClass.class );
public Arrays( 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, "length" );
addParam( list, script, "loop" );
}
return list;
}
@Ignore
@Test
public void test() {
super.test();
}
static class TestClass {
@Export
static int length() {
return new int[5].length;
}
@Export
static int loop() {
int[] data = {1,2,3};
int sum = 0;
for( int i : data ) {
sum += i;
}
return sum;
}
}
}