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.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.module.ArrayOperator;
import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.NumericOperator;
@ -778,4 +779,30 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
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_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
addLoadStoreInstruction( ValueType.f64, true, byteCode.readUnsignedByte(), codePos );
break;
//TODO case 25: // aload
case 25: // aload
addLoadStoreInstruction( ValueType.anyref, true, byteCode.readUnsignedByte(), codePos );
break;
case 26: // iload_0
case 27: // iload_1
case 28: // iload_2
@ -156,11 +158,15 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 41: // dload_3
addLoadStoreInstruction( ValueType.f64, true, op - 38, codePos );
break;
//TODO case 42: //aload_0
//TODO case 43: //aload_1
//TODO case 44: //aload_2
//TODO case 45: //aload_3
//TODO case 46: // iaload
case 42: //aload_0
case 43: //aload_1
case 44: //aload_2
case 45: //aload_3
addLoadStoreInstruction( ValueType.anyref, true, op - 42, codePos );
break;
case 46: // iaload
addArrayInstruction( ArrayOperator.GET, ValueType.i32, codePos );
break;
//TODO case 47: // laload
//TODO case 48: // faload
//TODO case 49: // daload
@ -180,7 +186,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 57: // dstore
addLoadStoreInstruction( ValueType.f64, false, byteCode.readUnsignedByte(), codePos );
break;
//TODO case 58: // astore
case 58: // astore
addLoadStoreInstruction( ValueType.anyref, false, byteCode.readUnsignedByte(), codePos );
break;
case 59: // istore_0
case 60: // istore_1
case 61: // istore_2
@ -211,14 +219,16 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 78: // astore_3
addLoadStoreInstruction( ValueType.anyref, false, op - 75, codePos );
break;
//TODO case 79: // iastore
//TODO case 80: // lastore
//TODO case 81: // fastore
//TODO case 82: // dastore
//TODO case 83: // aastore
//TODO case 84: // bastore
//TODO case 85: // castore
//TODO case 86: // sastore
case 79: // iastore
addArrayInstruction( ArrayOperator.SET, ValueType.i32, codePos );
break;
//TODO case 80: // lastore
//TODO case 81: // fastore
//TODO case 82: // dastore
//TODO case 83: // aastore
//TODO case 84: // bastore
//TODO case 85: // castore
//TODO case 86: // sastore
case 87: // pop
case 88: // pop2
addBlockInstruction( WasmBlockOperator.DROP, null, codePos );
@ -238,6 +248,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case f64:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_f64", "(D)DD" ), codePos );
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$
case 90: // dup_x1
@ -518,9 +531,36 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
//TODO case 185: // invokeinterface
//TODO case 186: // invokedynamic
//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 190: // arraylength
case 190: // arraylength
addArrayInstruction( ArrayOperator.LENGTH, ValueType.i32, codePos );
break;
//TODO case 191: // athrow
//TODO case 192: // checkcast
//TODO case 193: // instanceof

View File

@ -203,4 +203,16 @@ public abstract class ModuleWriter implements Closeable {
* if any I/O error occur
*/
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" )
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 ) {
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.jwebassembly.JWebAssembly;
import de.inetsoftware.jwebassembly.module.ArrayOperator;
import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.ModuleWriter;
import de.inetsoftware.jwebassembly.module.NumericOperator;
@ -362,4 +363,27 @@ public class TextModuleWriter extends ModuleWriter {
methodOutput.append( name );
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;
}
}
}