From 1556c36f32657a157a9a930497986d11b046ba1b Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Fri, 8 May 2020 15:01:01 +0200 Subject: [PATCH] add micro code for for interface calling, WIP --- .../jwebassembly/module/TypeManager.java | 72 +++++++++++++++++-- .../jwebassembly/module/WasmCodeBuilder.java | 1 + .../jwebassembly/module/WasmOptions.java | 21 +++++- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java index bda99f8..855c693 100644 --- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java +++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java @@ -238,13 +238,13 @@ public class TypeManager { } /** - * Create the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS, + * Create the FunctionName for a virtual call. The function has 2 parameters (THIS, * virtualfunctionIndex) and returns the index of the function. * * @return the name */ @Nonnull - WatCodeSyntheticFunctionName createCallVirtualGC() { + WatCodeSyntheticFunctionName createCallVirtual() { return new WatCodeSyntheticFunctionName( // "callVirtual", "local.get 0 " // THIS + "struct.get java/lang/Object .vtable " // vtable is on index 0 @@ -252,7 +252,70 @@ public class TypeManager { + "i32.add " // + "i32.load offset=0 align=4 " // + "return " // - , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); // + , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); // THIS, virtualfunctionIndex, returns functionIndex + } + + /** + * Create the FunctionName for a interface call. The function has 3 parameters (THIS,classIndex, + * virtualfunctionIndex) and returns the index of the function. + * + * @return the name + */ + @Nonnull + WatCodeSyntheticFunctionName createCallInterface() { + /* + static int callInterface( OBJECT THIS, int classIndex, int virtualfunctionIndex ) { + int table = THIS.vtable; + table += i32_load[table]; + + do { + int nextClass = i32_load[table]; + if( nextClass == classIndex ) { + return i32_load[table + virtualfunctionIndex]; + } + if( nextClass == 0 ) { + return -1;//throw new NoSuchMethodError(); + } + table += i32_load[table + 4]; + } while( true ); + } + */ + return new WatCodeSyntheticFunctionName( // + "callInterface", "local.get 0 " // $THIS + + "struct.get java/lang/Object .vtable " // vtable is on index 0 + + "local.tee 3 " // save $table + + "i32.load offset=" + TYPE_DESCRIPTION_INTERFACE_OFFSET + " align=4 " // get offset of itable (int position 0, byte position 0) + + "local.get 3 " // save $table + + "i32.add " // $table += i32_load[$table] + + "local.set 3 " // save $table, the itable start location + + "loop" // + + " local.get 3" // get $table + + " i32.load offset=0 align=4" + + " local.tee 4" // save $nextClass + + " local.get 1" // get $classIndex + + " i32.eq" // + + " if" // $nextClass == $classIndex + + " local.get 3" // get $table + + " local.get 2" // get $virtualfunctionIndex + + " i32.add" // $table + $virtualfunctionIndex + + " i32.load offset=0 align=4" // get the functionIndex + + " return" // + + " end" // + + " local.get 4" // save $nextClass + + " i32.eqz" // + + " if" // current offset == end offset + + " unreachable" // TODO throw a ClassCastException if exception handling is supported + + " end" // + + " local.get 3" // get $table + + " i32.const 4" // + + " i32.add" // $table + 4 + + " i32.load offset=0 align=4" // get the functionIndex + + " local.get 3" // $table + + " i32.add" // $table += i32_load[table + 4]; + + " local.set 3" // set $table + + " br 0 " // + + "end " // + , valueOf( "java/lang/Object" ), ValueType.i32, ValueType.i32, null, ValueType.i32 ); // THIS, classIndex, virtualfunctionIndex, returns functionIndex } /** @@ -295,7 +358,7 @@ public class TypeManager { + "end " // + "i32.const 1 " // class/interface found + "return " // - , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); // + , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); // THIS, classIndex, returns boolean } /** @@ -639,6 +702,7 @@ public class TypeManager { // header position TYPE_DESCRIPTION_INTERFACE_OFFSET header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of interface calls //TODO interface calls + data.writeInt32( 0 ); // no more interface in itable // header position TYPE_DESCRIPTION_INSTANCEOF_OFFSET header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of instanceeof list diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 7f163e4..0eeaa12 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -653,6 +653,7 @@ public abstract class WasmCodeBuilder { protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) { name = functions.markAsNeeded( name ); addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) ); + options.getCallInterface(); // mark the function as needed functions.markClassAsUsed( name.className ); } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmOptions.java b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java index d6450da..d6f6a18 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmOptions.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java @@ -57,6 +57,8 @@ public class WasmOptions { private FunctionName callVirtual; + private FunctionName callInterface; + private FunctionName instanceOf; private FunctionName cast; @@ -164,7 +166,24 @@ public class WasmOptions { FunctionName getCallVirtual() { FunctionName name = callVirtual; if( name == null ) { - callVirtual = name = types.createCallVirtualGC(); + callVirtual = name = types.createCallVirtual(); + functions.markAsNeeded( name ); + registerGet_i32(); + } + return name; + } + + /** + * Get the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS, + * virtualfunctionIndex) and returns the index of the function. + * + * @return the name + */ + @Nonnull + FunctionName getCallInterface() { + FunctionName name = callInterface; + if( name == null ) { + callInterface = name = types.createCallInterface(); functions.markAsNeeded( name ); registerGet_i32(); }