From 32e609b32f2cb2b664a6efda46b8c6a7aaeda843 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 11 Aug 2019 13:11:22 +0200 Subject: [PATCH] use GC Feature of the JavaScript host for arrays as replacement for the missing GC feature in WASM --- .../jwebassembly/javascript/NonGC.java | 130 ++++++++++++++++++ .../jwebassembly/module/WasmCodeBuilder.java | 28 +++- 2 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 src/de/inetsoftware/jwebassembly/javascript/NonGC.java diff --git a/src/de/inetsoftware/jwebassembly/javascript/NonGC.java b/src/de/inetsoftware/jwebassembly/javascript/NonGC.java new file mode 100644 index 0000000..18a6e8e --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/javascript/NonGC.java @@ -0,0 +1,130 @@ +/* + * Copyright 2019 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.javascript; + +import de.inetsoftware.jwebassembly.api.annotation.Import; + +/** + * Workaround for the missing GC feature of WebAssembly. This call add import functions to allocate the objects in the JavaScript host. + * + * @author Volker Berlin + * + */ +public abstract class NonGC { + + @Import( js = "(l) => new Uint8Array(l)" ) + static byte[] array_new_i8( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => new Int16Array(l)" ) + static short[] array_new_i16( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => new Int32Array(l)" ) + static int[] array_new_i32( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => Object.seal(new Array(l).fill(0n))" ) + static long[] array_new_i64( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => new Float32Array(l)" ) + static float[] array_new_f32( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => new Float64Array(l)" ) + static double[] array_new_f64( int length ) { + return null; // for compiler + } + + @Import( js = "(l) => Object.seal(new Array(l))" ) + static Object[] array_new_anyref( int length ) { + return null; // for compiler + } + + @Import( js = "(a) => a.length" ) + static int array_len_i32( Object array ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_i8( byte[] array, int idx, byte value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_i16( short[] array, int idx, short value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_i32( int[] array, int idx, int value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_i64( long[] array, int idx, long value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_f32( float[] array, int idx, float value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_f64( double[] array, int idx, double value ) { + } + + @Import( js = "(a,i,v) => a[i]=v" ) + static void array_set_anyref( Object[] array, int idx, Object value ) { + } + + @Import( js = "(a,i,v) => a[i]" ) + static byte array_get_i8( byte[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static short array_get_i16( short[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static int array_get_i32( int[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static long array_get_i64( long[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static float array_get_f32( float[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static double array_get_f64( double[] array, int idx ) { + return 0; // for compiler + } + + @Import( js = "(a,i,v) => a[i]" ) + static Object array_get_anyref( Object[] array, int idx ) { + return 0; // for compiler + } +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 709e3c0..9514e95 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -15,6 +15,7 @@ */ package de.inetsoftware.jwebassembly.module; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -23,8 +24,13 @@ import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.Member; +import de.inetsoftware.classparser.MethodInfo; +import de.inetsoftware.jwebassembly.JWebAssembly; +import de.inetsoftware.jwebassembly.WasmException; +import de.inetsoftware.jwebassembly.javascript.NonGC; import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; import de.inetsoftware.jwebassembly.wasm.AnyType; @@ -49,6 +55,8 @@ public abstract class WasmCodeBuilder { private TypeManager types; + private final boolean useGC; + /** * Create a new code builder. * @@ -56,6 +64,7 @@ public abstract class WasmCodeBuilder { * compiler properties */ public WasmCodeBuilder( HashMap properties ) { + useGC = Boolean.parseBoolean( properties.getOrDefault( JWebAssembly.WASM_USE_GC, "false" ) ); } /** @@ -341,7 +350,24 @@ public abstract class WasmCodeBuilder { * the line number in the Java source code */ protected void addArrayInstruction( ArrayOperator op, AnyType type, int javaCodePos, int lineNumber ) { - instructions.add( new WasmArrayInstruction( op, type, javaCodePos, lineNumber ) ); + if( useGC ) { + instructions.add( new WasmArrayInstruction( op, type, javaCodePos, lineNumber ) ); + } else { + try { + String api = "array_" + op.toString().toLowerCase() + "_" + type; + ClassFile classFile = ClassFile.get( NonGC.class.getName().replace( '.', '/' ), getClass().getClassLoader() ); + for( MethodInfo method : classFile.getMethods() ) { + if( api.equals( method.getName() ) ) { + FunctionName name = new FunctionName( method ); + addCallInstruction( name, javaCodePos, lineNumber ); + return; + } + } + } catch( IOException ex ) { + throw WasmException.create( ex, lineNumber ); + } + throw new WasmException( "Not implemented array op " + op + " for type " + type, lineNumber ); + } } /**