diff --git a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java index bb71820..ffb0b1f 100644 --- a/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/binary/BinaryModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2020 Volker Berlin (i-net software) + * Copyright 2017 - 2021 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. @@ -1363,7 +1363,9 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod int opCode; switch(op) { case NEW: - opCode = ARRAY_NEW; + codeStream.writeOpCode( RTT_CANON ); + codeStream.writeValueType( type.getNativeArrayType() ); + opCode = ARRAY_NEW_DEFAULT; break; case GET: opCode = ARRAY_GET; @@ -1374,11 +1376,14 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod case LEN: opCode = ARRAY_LEN; break; + case NEW_ARRAY_WITH_RTT: + opCode = ARRAY_NEW_DEFAULT; + break; default: throw new Error( "Unknown operator: " + op ); } codeStream.writeOpCode( opCode ); - codeStream.writeValueType( type ); + codeStream.writeValueType( type.getNativeArrayType() ); } /** @@ -1404,6 +1409,12 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod opCode = REF_NULL; type = options.useGC() ? type : ValueType.externref; break; + case RTT_CANON: + opCode = RTT_CANON; + break; + case NEW_WITH_RTT: + opCode = STRUCT_NEW; + break; default: throw new Error( "Unknown operator: " + op ); } @@ -1411,7 +1422,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod if( type != null ) { codeStream.writeValueType( type ); } - if( fieldName != null ) { + if( idx >= 0 ) { codeStream.writeVaruint32( idx ); } } diff --git a/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java b/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java index 03ef26e..1cec04f 100644 --- a/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java +++ b/src/de/inetsoftware/jwebassembly/binary/InstructionOpcodes.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2020 Volker Berlin (i-net software) + * Copyright 2017 - 2021 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. @@ -498,6 +498,8 @@ interface InstructionOpcodes { static final int ARRAY_NEW = 0xFB11; + static final int ARRAY_NEW_DEFAULT = 0xFB12; + static final int ARRAY_GET = 0xFB13; static final int ARRAY_SET = 0xFB16; diff --git a/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java index c5eaac7..ccbbcff 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -19,7 +19,6 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import de.inetsoftware.jwebassembly.WasmException; import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName; @@ -27,6 +26,7 @@ import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayType; +import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; /** @@ -37,6 +37,7 @@ import de.inetsoftware.jwebassembly.wasm.ValueType; */ class WasmArrayInstruction extends WasmInstruction { + @Nonnull private final ArrayOperator op; private final AnyType type; @@ -61,7 +62,7 @@ class WasmArrayInstruction extends WasmInstruction { * @param lineNumber * the line number in the Java source code */ - WasmArrayInstruction( @Nullable ArrayOperator op, @Nullable AnyType type, TypeManager types, int javaCodePos, int lineNumber ) { + WasmArrayInstruction( @Nonnull ArrayOperator op, @Nonnull AnyType type, TypeManager types, int javaCodePos, int lineNumber ) { super( javaCodePos, lineNumber ); this.op = op; this.type = type; @@ -70,61 +71,81 @@ class WasmArrayInstruction extends WasmInstruction { } /** - * Create the synthetic polyfill function of this instruction for nonGC mode. + * Create the synthetic function of this instruction if required for the operation. * + * @param useGC true, with GC code * @return the function or null if not needed */ - SyntheticFunctionName createNonGcFunction() { - // i8 and i16 are not valid in function signatures - AnyType functionType = type == ValueType.i8 || type == ValueType.i16 ? ValueType.i32 : type; - switch( op ) { - case NEW: - String cmd; - if( type.isRefType() ) { - cmd = "Object.seal(new Array(l).fill(null))"; - } else { - switch( (ValueType)type ) { - case i8: - cmd = "new Uint8Array(l)"; - break; - case i16: - cmd = "new Int16Array(l)"; - break; - case i32: - cmd = "new Int32Array(l)"; - break; - case i64: - cmd = "new BigInt64Array(l)"; - break; - case f32: - cmd = "new Float32Array(l)"; - break; - case f64: - cmd = "new Float64Array(l)"; - break; - default: - cmd = "Object.seal(new Array(l).fill(null))"; + SyntheticFunctionName createNonGcFunction( boolean useGC ) { + if( useGC ) { + switch( op ) { + case NEW: + functionName = new WatCodeSyntheticFunctionName( "array_new_" + validJsName( type ), "", ValueType.i32, null, arrayType ) { + @Override + protected String getCode() { + String nativeArrayTypeName = ((ArrayType)arrayType.getNativeArrayType()).getName(); + return "i32.const " + arrayType.getVTable() + " i32.const 0" // hashcode + + " local.get 0" // array size + + " rtt.canon " + nativeArrayTypeName // + + " array.new_default_with_rtt " + nativeArrayTypeName // + + " rtt.canon " + arrayType.getName() // + + " struct.new_with_rtt " + arrayType.getName() // + + " return"; + } + }; + } + } else { + // i8 and i16 are not valid in function signatures + AnyType functionType = type == ValueType.i8 || type == ValueType.i16 ? ValueType.i32 : type; + switch( op ) { + case NEW: + String cmd; + if( type.isRefType() ) { + cmd = "Object.seal(new Array(l).fill(null))"; + } else { + switch( (ValueType)type ) { + case i8: + cmd = "new Uint8Array(l)"; + break; + case i16: + cmd = "new Int16Array(l)"; + break; + case i32: + cmd = "new Int32Array(l)"; + break; + case i64: + cmd = "new BigInt64Array(l)"; + break; + case f32: + cmd = "new Float32Array(l)"; + break; + case f64: + cmd = "new Float64Array(l)"; + break; + default: + cmd = "Object.seal(new Array(l).fill(null))"; + } } - } - functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_new_" + validJsName( type ), () -> { - // create the default values of a new type - return new StringBuilder( "(l)=>Object.seal({0:" ) // fix count of elements - .append( arrayType.getVTable() ) // .vtable - .append( ",1:0,2:" ) // .hashCode - .append( cmd ) // the array data - .append( "})" ) // - .toString(); - }, ValueType.i32, null, ValueType.externref ); - break; - case GET: - functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_get_" + validJsName( functionType ), () -> "(a,i)=>a[2][i]", ValueType.externref, ValueType.i32, null, functionType ); - break; - case SET: - functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_set_" + validJsName( functionType ), () -> "(a,i,v)=>a[2][i]=v", ValueType.externref, ValueType.i32, functionType, null, null ); - break; - case LEN: - functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_len", () -> "(a)=>a[2].length", ValueType.externref, null, ValueType.i32 ); - break; + functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_new_" + validJsName( type ), () -> { + // create the default values of a new type + return new StringBuilder( "(l)=>Object.seal({0:" ) // fix count of elements + .append( arrayType.getVTable() ) // .vtable + .append( ",1:0,2:" ) // .hashCode + .append( cmd ) // the array data + .append( "})" ) // + .toString(); + }, ValueType.i32, null, ValueType.externref ); + break; + case GET: + functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_get_" + validJsName( functionType ), () -> "(a,i)=>a[2][i]", ValueType.externref, ValueType.i32, null, functionType ); + break; + case SET: + functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_set_" + validJsName( functionType ), () -> "(a,i,v)=>a[2][i]=v", ValueType.externref, ValueType.i32, functionType, null, null ); + break; + case LEN: + functionName = new JavaScriptSyntheticFunctionName( "NonGC", "array_len", () -> "(a)=>a[2].length", ValueType.externref, null, ValueType.i32 ); + break; + } } return functionName; } @@ -154,10 +175,19 @@ class WasmArrayInstruction extends WasmInstruction { /** * {@inheritDoc} */ + @Override public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { if( functionName != null ) { // nonGC writer.writeFunctionCall( functionName, null ); } else { + switch( op ) { + case GET: + case SET: + case LEN: + writer.writeStructOperator( StructOperator.GET, arrayType, null, 2 ); // the native array is on position 2 (vtable, hashcode are before) + break; + default: + } writer.writeArrayOperator( op, arrayType ); } } @@ -165,9 +195,11 @@ class WasmArrayInstruction extends WasmInstruction { /** * {@inheritDoc} */ + @Override AnyType getPushValueType() { switch( op ) { case NEW: + case NEW_ARRAY_WITH_RTT: return arrayType; case GET: return type instanceof ValueType ? (ValueType)type : ValueType.externref; @@ -187,6 +219,7 @@ class WasmArrayInstruction extends WasmInstruction { int getPopCount() { switch( op ) { case GET: + case NEW_ARRAY_WITH_RTT: return 2; case NEW: case LEN: diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 301f7e6..4e1ca1b 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2020 Volker Berlin (i-net software) + * Copyright 2018 - 2021 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. @@ -737,12 +737,10 @@ public abstract class WasmCodeBuilder { protected void addArrayInstruction( ArrayOperator op, AnyType type, int javaCodePos, int lineNumber ) { WasmArrayInstruction arrayInst = new WasmArrayInstruction( op, type, types, javaCodePos, lineNumber ); instructions.add( arrayInst ); - if( !options.useGC() ) { - SyntheticFunctionName name = arrayInst.createNonGcFunction(); - if( name != null ) { - functions.markAsNeeded( name ); - functions.markAsImport( name, name.getAnnotation() ); - } + SyntheticFunctionName name = arrayInst.createNonGcFunction( options.useGC() ); + if( name != null ) { + functions.markAsNeeded( name ); + functions.markAsImport( name, name.getAnnotation() ); } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java index 905c7c7..466da98 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -38,6 +38,7 @@ import de.inetsoftware.jwebassembly.wasm.ValueType; */ class WasmStructInstruction extends WasmInstruction { + @Nonnull private final StructOperator op; private final StructType type; @@ -64,7 +65,7 @@ class WasmStructInstruction extends WasmInstruction { * @param types * the type manager */ - WasmStructInstruction( @Nullable StructOperator op, @Nonnull String typeName, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber, TypeManager types ) { + WasmStructInstruction( @Nonnull StructOperator op, @Nonnull String typeName, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber, TypeManager types ) { super( javaCodePos, lineNumber ); this.op = op; this.type = types.valueOf( typeName ); @@ -166,6 +167,7 @@ class WasmStructInstruction extends WasmInstruction { /** * {@inheritDoc} */ + @Override public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { int idx = -1; switch( op ) { @@ -199,6 +201,7 @@ class WasmStructInstruction extends WasmInstruction { case CAST: idx = type.getClassIndex(); break; + default: } if( functionName != null ) { // nonGC if( idx >= 0 ) { @@ -213,6 +216,7 @@ class WasmStructInstruction extends WasmInstruction { /** * {@inheritDoc} */ + @Override AnyType getPushValueType() { switch( op ) { case NULL: @@ -220,6 +224,7 @@ class WasmStructInstruction extends WasmInstruction { case NEW: case NEW_DEFAULT: case CAST: + case NEW_WITH_RTT: return type; case GET: return fieldName.getType(); @@ -227,6 +232,8 @@ class WasmStructInstruction extends WasmInstruction { return null; case INSTANCEOF: return ValueType.i32; // a boolean value + case RTT_CANON: + return ValueType.i32; // rtt type default: throw new WasmException( "Unknown array operation: " + op, -1 ); } @@ -241,12 +248,14 @@ class WasmStructInstruction extends WasmInstruction { case GET: case INSTANCEOF: case CAST: + case NEW_WITH_RTT: return 1; case SET: return 2; case NEW: case NEW_DEFAULT: case NULL: + case RTT_CANON: return 0; default: throw new WasmException( "Unknown array operation: " + op, -1 ); diff --git a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java index 34391b6..77cab1f 100644 --- a/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java +++ b/src/de/inetsoftware/jwebassembly/text/TextModuleWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2020 Volker Berlin (i-net software) + * Copyright 2017 - 2021 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. @@ -831,7 +831,9 @@ public class TextModuleWriter extends ModuleWriter { String operation; switch( op ) { case NEW: - operation = "new"; + newline( methodOutput ); + methodOutput.append( "rtt.canon" ).append( ' ' ).append( normalizeName( type.getNativeArrayType().toString() ) ); + operation = "new_default_with_rtt"; break; case GET: operation = "get"; @@ -842,11 +844,14 @@ public class TextModuleWriter extends ModuleWriter { case LEN: operation = "len"; break; + case NEW_ARRAY_WITH_RTT: + operation = "new_default_with_rtt"; + break; default: throw new Error( "Unknown operator: " + op ); } newline( methodOutput ); - methodOutput.append( "array." ).append( operation ).append( ' ' ).append( normalizeName( type.toString() ) ); + methodOutput.append( "array." ).append( operation ).append( ' ' ).append( normalizeName( type.getNativeArrayType().toString() ) ); } /** @@ -860,7 +865,7 @@ public class TextModuleWriter extends ModuleWriter { case NEW_DEFAULT: newline( methodOutput ); methodOutput.append( "rtt.canon" ).append( ' ' ).append( normalizeName( type.toString() ) ); - operation = "struct.new"; + operation = "struct.new_default_with_rtt"; break; case GET: operation = "struct.get"; @@ -876,6 +881,12 @@ public class TextModuleWriter extends ModuleWriter { type = null; } break; + case RTT_CANON: + operation = "rtt.canon"; + break; + case NEW_WITH_RTT: + operation = "struct.new_with_rtt"; + break; default: throw new Error( "Unknown operator: " + op ); } @@ -884,8 +895,11 @@ public class TextModuleWriter extends ModuleWriter { if( type != null ) { methodOutput.append( ' ' ).append( normalizeName( type.toString() ) ); } - if( fieldName != null ) { - methodOutput.append( ' ' ).append( idx ).append( " ;; $" ).append( normalizeName( fieldName.getName() ) ); + if( idx >= 0 ) { + methodOutput.append( ' ' ).append( idx ); + if( fieldName != null ) { + methodOutput.append( " ;; $" ).append( normalizeName( fieldName.getName() ) ); + } } } diff --git a/src/de/inetsoftware/jwebassembly/wasm/ArrayOperator.java b/src/de/inetsoftware/jwebassembly/wasm/ArrayOperator.java index 39718d5..2fcd1e8 100644 --- a/src/de/inetsoftware/jwebassembly/wasm/ArrayOperator.java +++ b/src/de/inetsoftware/jwebassembly/wasm/ArrayOperator.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2019 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -26,4 +26,5 @@ public enum ArrayOperator { GET, SET, LEN, + NEW_ARRAY_WITH_RTT, } \ No newline at end of file diff --git a/src/de/inetsoftware/jwebassembly/wasm/StructOperator.java b/src/de/inetsoftware/jwebassembly/wasm/StructOperator.java index 96bdcba..b0ec362 100644 --- a/src/de/inetsoftware/jwebassembly/wasm/StructOperator.java +++ b/src/de/inetsoftware/jwebassembly/wasm/StructOperator.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -29,4 +29,6 @@ public enum StructOperator { NULL, CAST, INSTANCEOF, + RTT_CANON, + NEW_WITH_RTT, } \ No newline at end of file diff --git a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java index fdd5fbc..59179a9 100644 --- a/src/de/inetsoftware/jwebassembly/watparser/WatParser.java +++ b/src/de/inetsoftware/jwebassembly/watparser/WatParser.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -307,6 +307,19 @@ public class WatParser extends WasmCodeBuilder { AnyType type = ((ArrayType)getTypeManager().valueOf( typeName )).getArrayType(); addArrayInstruction( ArrayOperator.LEN, type, javaCodePos, lineNumber ); break; + case "array.new_default_with_rtt": + typeName = get( tokens, ++i ); + type = ((ArrayType)getTypeManager().valueOf( typeName )).getArrayType(); + addArrayInstruction( ArrayOperator.NEW_ARRAY_WITH_RTT, type, javaCodePos, lineNumber ); + break; + case "rtt.canon": + typeName = get( tokens, ++i ); + addStructInstruction( StructOperator.RTT_CANON, typeName, null, javaCodePos, lineNumber ); + break; + case "struct.new_with_rtt": + typeName = get( tokens, ++i ); + addStructInstruction( StructOperator.NEW_WITH_RTT, typeName, null, javaCodePos, lineNumber ); + break; default: throw new WasmException( "Unknown WASM token: " + tok, lineNumber ); }