diff --git a/src/de/inetsoftware/jwebassembly/module/MultiArrayFunctionName.java b/src/de/inetsoftware/jwebassembly/module/MultiArrayFunctionName.java index f42c708..7bf31ba 100644 --- a/src/de/inetsoftware/jwebassembly/module/MultiArrayFunctionName.java +++ b/src/de/inetsoftware/jwebassembly/module/MultiArrayFunctionName.java @@ -1,35 +1,42 @@ +/* + Copyright 2020 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.util.Arrays; -/* -Copyright 2020 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. - -*/ -import java.util.function.Supplier; - -import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName; import de.inetsoftware.jwebassembly.wasm.AnyType; +import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayType; +import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; +import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; +import de.inetsoftware.jwebassembly.watparser.WatParser; /** * Synthetic functions for creating multidimensional dimensional arrays * * @author Volker Berlin */ -public class MultiArrayFunctionName extends JavaScriptSyntheticFunctionName { +public class MultiArrayFunctionName extends WatCodeSyntheticFunctionName { + + private int dim; + + private ArrayType type; /** * Create a new instance @@ -39,8 +46,10 @@ public class MultiArrayFunctionName extends JavaScriptSyntheticFunctionName { * @param type * the full type of the allocated array */ - public MultiArrayFunctionName( int dim, ArrayType type ) { - super( "NonGC", createName( dim, type ), createJS( dim, type ), createSignature( dim, type ) ); + MultiArrayFunctionName( int dim, ArrayType type ) { + super( "NonGC", createName( dim, type ), "()V", null, createSignature( dim, type ) ); + this.dim = dim; + this.type = type; } /** @@ -53,7 +62,7 @@ public class MultiArrayFunctionName extends JavaScriptSyntheticFunctionName { private static ValueType getElementType( ArrayType type ) { do { AnyType arrayType = type.getArrayType(); - if( arrayType.getClass() != ArrayType.class ) { + if( arrayType.getClass() == ArrayType.class ) { type = (ArrayType)arrayType; continue; } @@ -91,74 +100,59 @@ public class MultiArrayFunctionName extends JavaScriptSyntheticFunctionName { } /** - * Get the factory for the JavaScript method - * - * @param dim - * the dimension - * @param type - * the full type of the allocated array - * @return the JavaScript factory + * {@inheritDoc} */ - private static Supplier createJS( int dim, ArrayType type ) { - return () -> { - // the dimention that must be array and not typed array - int dimMulti = dim - 1; + @Override + protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) { + watParser.reset( null, null, getSignature( null ) ); + int javaCodePos = 0; - // create parameter signature - StringBuilder js = new StringBuilder( "(" ); - for( int i = 0; i < dimMulti; i++ ) { - js.append( 'd' ).append( i ); - js.append( ',' ); + // allocate the main array (top most) and save it in a local variable + AnyType arrayType = type.getArrayType(); + watParser.addLocalInstruction( VariableOperator.get, 0, javaCodePos++, -1 ); + watParser.addArrayInstruction( ArrayOperator.NEW, arrayType, javaCodePos++, -1 ); + watParser.addLocalInstruction( VariableOperator.set, dim, javaCodePos++, -1 ); + + watParser.addBlockInstruction( WasmBlockOperator.BLOCK, null, javaCodePos++, -1 ); + watParser.addBlockInstruction( WasmBlockOperator.LOOP, null, javaCodePos++, -1 ); + { + // end condition + watParser.addLocalInstruction( VariableOperator.get, 0, javaCodePos++, -1 ); + watParser.addNumericInstruction( NumericOperator.eqz, ValueType.i32, javaCodePos++, -1 ); + watParser.addBlockInstruction( WasmBlockOperator.BR_IF, 1, javaCodePos++, -1 ); + + // get the reference to the top most array + watParser.addLocalInstruction( VariableOperator.get, dim, javaCodePos++, -1 ); + + // decrement the counter + watParser.addLocalInstruction( VariableOperator.get, 0, javaCodePos++, -1 ); + watParser.addConstInstruction( 1, javaCodePos++, -1 ); + watParser.addNumericInstruction( NumericOperator.sub, ValueType.i32, javaCodePos++, -1 ); + watParser.addLocalInstruction( VariableOperator.tee, 0, javaCodePos++, -1 ); + + // allocate a sub array + for( int i = 1; i < dim; i++ ) { + watParser.addLocalInstruction( VariableOperator.get, i, javaCodePos++, -1 ); } - js.append( "l)=>" ); - - createJsArray( js, 0, dimMulti, type ); - - return js.toString(); - }; - } - - /** - * Recursion for the allocation with default value - * - * @param js - * the target - * @param idx - * running dimension index - * @param dimMulti - * the count of not typed dimensions - * @param type - * the full type of the allocated array - */ - private static void createJsArray( StringBuilder js, int idx, int dimMulti, ArrayType type ) { - js.append( "Array.from({length:d" ).append( idx ).append( "}, ()=>" ); - idx++; - if( idx < dimMulti ) { - createJsArray( js, idx, dimMulti, type ); - } else { - switch( getElementType( type ) ) { - case i8: - js.append( "new Uint8Array(l)" ); - break; - case i16: - js.append( "new Int16Array(l)" ); - break; - case i32: - js.append( "new Int32Array(l)" ); - break; - case i64: - js.append( "new BigInt64Array(l)" ); - break; - case f32: - js.append( "new Float32Array(l)" ); - break; - case f64: - js.append( "new Float64Array(l)" ); - break; - default: - js.append( "Object.seal(new Array(l).fill(null))" ); + if( dim > 2 ) { + watParser.addMultiNewArrayInstruction( dim - 1, (ArrayType)arrayType, javaCodePos++, -1 ); + } else { + watParser.addArrayInstruction( ArrayOperator.NEW, arrayType, javaCodePos++, -1 ); } + + // set the sub array into the main array + watParser.addArrayInstruction( ArrayOperator.SET, arrayType, javaCodePos++, -1 ); + + // continue the loop + watParser.addBlockInstruction( WasmBlockOperator.BR, 0, javaCodePos++, -1 ); } - js.append( ')' ); + watParser.addBlockInstruction( WasmBlockOperator.END, null, javaCodePos++, -1 ); + watParser.addBlockInstruction( WasmBlockOperator.END, null, javaCodePos++, -1 ); + + //return the created array + watParser.addLocalInstruction( VariableOperator.get, dim, javaCodePos++, -1 ); + watParser.addBlockInstruction( WasmBlockOperator.RETURN, null, javaCodePos++, -1 ); + + return watParser; } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 45f94f0..0b2e7cf 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -31,7 +31,6 @@ import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.Member; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.WasmException; -import de.inetsoftware.jwebassembly.javascript.JavaScriptNewMultiArrayFunctionName; import de.inetsoftware.jwebassembly.javascript.NonGC; import de.inetsoftware.jwebassembly.module.StackInspector.StackValue; import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; @@ -737,15 +736,14 @@ public abstract class WasmCodeBuilder { * the line number in the Java source code */ protected void addArrayInstruction( ArrayOperator op, AnyType type, int javaCodePos, int lineNumber ) { - if( options.useGC() ) { - instructions.add( new WasmArrayInstruction( op, type, types, javaCodePos, lineNumber ) ); - } else { - if( type.getCode() >= 0 || type.getCode() == ValueType.externref.getCode() ) { - type = ValueType.externref; // handle all not native types as anyref + 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() ); } - String api = "array_" + op.toString().toLowerCase() + "_" + type; - FunctionName name = getNonGC( api, lineNumber ); - addCallInstruction( name, javaCodePos, lineNumber ); } } @@ -763,12 +761,24 @@ public abstract class WasmCodeBuilder { */ protected void addMultiNewArrayInstruction( int dim, String typeName, int javaCodePos, int lineNumber ) { ArrayType type = (ArrayType)new ValueTypeParser( typeName, types ).next(); - if( options.useGC() ) { - throw new WasmException( "multi new array is not supported", lineNumber ); - } else { - FunctionName name = new JavaScriptNewMultiArrayFunctionName( dim, type ); - addCallInstruction( name, javaCodePos, lineNumber ); - } + addMultiNewArrayInstruction( dim, type, javaCodePos, lineNumber ); + } + + /** + * Add a new multi dimensional array instruction + * + * @param dim + * the dimension of the array >= 2 + * @param type + * the full type + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + */ + protected void addMultiNewArrayInstruction( int dim, ArrayType type, int javaCodePos, int lineNumber ) { + MultiArrayFunctionName name = new MultiArrayFunctionName( dim, type ); + addCallInstruction( name, javaCodePos, lineNumber ); } /**