diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index 483a3df..cc6b033 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -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 ); + } } diff --git a/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java b/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java index c255ea0..6b20dd9 100644 --- a/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java +++ b/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java @@ -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; } diff --git a/src/de/inetsoftware/jwebassembly/module/ArrayOperator.java b/src/de/inetsoftware/jwebassembly/module/ArrayOperator.java new file mode 100644 index 0000000..d0df590 --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/ArrayOperator.java @@ -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, +} \ No newline at end of file diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index 33a93a2..1fcd9d8 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -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 diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java index 4d651b5..7ed9b0c 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleWriter.java @@ -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; } diff --git a/src/de/inetsoftware/jwebassembly/module/NativeHelperCode.java b/src/de/inetsoftware/jwebassembly/module/NativeHelperCode.java index 09e488b..c93e426 100644 --- a/src/de/inetsoftware/jwebassembly/module/NativeHelperCode.java +++ b/src/de/inetsoftware/jwebassembly/module/NativeHelperCode.java @@ -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(); } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java new file mode 100644 index 0000000..eafcdf1 --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java @@ -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 ); + } + } +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index b9caefe..08630ba 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -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 ) ); + } } diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 22f0fc6..6239a1b 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -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 ); + } } diff --git a/test/de/inetsoftware/jwebassembly/runtime/Arrays.java b/test/de/inetsoftware/jwebassembly/runtime/Arrays.java new file mode 100644 index 0000000..5601306 --- /dev/null +++ b/test/de/inetsoftware/jwebassembly/runtime/Arrays.java @@ -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 data() { + ArrayList 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; + } + } +}