add support for multi dimension array allocation

This commit is contained in:
Volker Berlin 2020-02-09 18:05:31 +01:00
parent d460aac03f
commit 8379416cb8
4 changed files with 259 additions and 1 deletions

View File

@ -0,0 +1,163 @@
package de.inetsoftware.jwebassembly.javascript;
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.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayType;
import de.inetsoftware.jwebassembly.wasm.ValueType;
/**
* Synthetic functions for creating multidimensional dimensional arrays
*
* @author Volker Berlin
*/
public class JavaScriptNewMultiArrayFunctionName extends JavaScriptSyntheticFunctionName {
/**
* Create a new instance
*
* @param dim
* the count of dimensions, should be >= 2
* @param type
* the full type of the allocated array
*/
public JavaScriptNewMultiArrayFunctionName( int dim, ArrayType type ) {
super( "NonGC", createName( dim, type ), createJS( dim, type ), createSignature( dim, type ) );
}
/**
* The element type of the array
*
* @param type
* the full type of the allocated array
* @return the element type
*/
private static ValueType getElementType( ArrayType type ) {
do {
AnyType arrayType = type.getArrayType();
if( arrayType.getClass() != ArrayType.class ) {
type = (ArrayType)arrayType;
continue;
}
return arrayType.getClass() == ValueType.class ? (ValueType)arrayType : ValueType.anyref;
} while( true );
}
/**
* Create the unique name depends on dimension and type
*
* @param dim
* the dimension
* @param type
* the full type of the allocated array
* @return the name
*/
private static String createName( int dim, ArrayType type ) {
return "array_newmulti" + dim + "_" + getElementType( type );
}
/**
* Create the signature of the function.
*
* @param dim
* the dimension
* @param type
* the full type of the allocated array
* @return the signature
*/
private static AnyType[] createSignature( int dim, ArrayType type ) {
AnyType[] signature = new AnyType[dim + 2];
Arrays.fill( signature, 0, dim, ValueType.i32 );
signature[dim + 1] = type;
return signature;
}
/**
* Get the factory for the JavaScript method
*
* @param dim
* the dimension
* @param type
* the full type of the allocated array
* @return the JavaScript factory
*/
private static Supplier<String> createJS( int dim, ArrayType type ) {
return () -> {
// the dimention that must be array and not typed array
int dimMulti = dim - 1;
// create parameter signature
StringBuilder js = new StringBuilder( "(" );
for( int i = 0; i < dimMulti; i++ ) {
js.append( 'd' ).append( i );
js.append( ',' );
}
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))" );
}
}
js.append( ')' );
}
}

View File

@ -670,7 +670,11 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.wide
wide = true;
continue;
//TODO case 197: // multianewarray
case 197: // multianewarray
name = ((ConstantClass)constantPool.get( byteCode.readUnsignedShort() )).getName();
idx = byteCode.readUnsignedByte();
addMultiNewArrayInstruction( idx, name, codePos, lineNumber );
break;
case 198: // ifnull
opIfCompareCondition( NumericOperator.ifnull, byteCode, codePos, lineNumber );
break;

View File

@ -29,11 +29,13 @@ 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.JavaScriptSyntheticFunctionName;
import de.inetsoftware.jwebassembly.javascript.NonGC;
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
import de.inetsoftware.jwebassembly.wasm.ArrayType;
import de.inetsoftware.jwebassembly.wasm.MemoryOperator;
import de.inetsoftware.jwebassembly.wasm.NamedStorageType;
import de.inetsoftware.jwebassembly.wasm.NumericOperator;
@ -591,6 +593,28 @@ public abstract class WasmCodeBuilder {
}
}
/**
* Add a new multi dimensional array instruction
*
* @param dim
* the dimension of the array >= 2
* @param typeName
* the full type name
* @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, 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 );
}
}
/**
* Add an array operation to the instruction list as marker on the code position.
*

View File

@ -0,0 +1,67 @@
/*
* 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.runtime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.zip.CRC32;
import org.junit.Assume;
import org.junit.ClassRule;
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 MultiArrayOperations extends AbstractBaseTest {
@ClassRule
public static WasmRule rule = new WasmRule( TestClass.class );
public MultiArrayOperations( 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<>();
ScriptEngine[] engines = ScriptEngine.testEngines();
for( ScriptEngine script : engines ) {
addParam( list, script, "multi" );
}
rule.setTestParameters( list );
return list;
}
@Test
@Override
public void test() {
super.test();
}
static class TestClass {
@Export
static int multi() {
int[][][] val = new int[1][2][3];
return val.length;
}
}
}