diff --git a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java index 9256453..77d6997 100644 --- a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java +++ b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java @@ -19,6 +19,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -199,6 +200,18 @@ public class FunctionManager { return newMethod != null ? newMethod : method; } + + /** + * Get all function names for the class. + * + * @param className + * the className + * @return a stream with the names + */ + Stream getNamesOfClass( String className ) { + return states.keySet().stream().filter( ( name ) -> name.className.equals( className ) ); + } + /** * State of a function/method */ diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index 5ade3e1..1f94744 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -576,6 +576,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { addStructInstruction( StructOperator.SET, ref.getClassName(), new NamedStorageType( ref, getTypeManager() ), codePos, lineNumber ); break; case 182: // invokevirtual + idx = byteCode.readUnsignedShort(); + ref = (ConstantRef)constantPool.get( idx ); + addCallVirtualInstruction( new FunctionName( ref ), codePos, lineNumber ); + break; case 183: // invokespecial, invoke a constructor case 184: // invokestatic idx = byteCode.readUnsignedShort(); diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 240f1ce..416c87a 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -23,6 +23,7 @@ import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -213,6 +214,7 @@ public class ModuleGenerator { for( WasmInstruction instruction : instructions ) { switch( instruction.getType() ) { case Call: + case CallIndirect: ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; default: @@ -314,13 +316,23 @@ public class ModuleGenerator { listStructFields( superClassName, list ); } - FieldInfo[] fields = classFile.getFields(); - for( FieldInfo field : fields ) { + for( FieldInfo field : classFile.getFields() ) { if( field.isStatic() ) { continue; } list.add( new NamedStorageType( className, field, types ) ); } + + HashMap virtualFunctions = new HashMap<>(); + functions.getNamesOfClass( className ).forEach( (name) -> { + String methodName = name.methodName; + Boolean virtual = virtualFunctions.get( methodName ); + if( virtual == null ) { + virtualFunctions.put( methodName, Boolean.FALSE ); + } else { + virtualFunctions.put( methodName, Boolean.TRUE ); + } + } ); } /** @@ -491,6 +503,7 @@ public class ModuleGenerator { } break; case Call: + case CallIndirect: ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; case Struct: diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java index b4e7023..a8a6de2 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java @@ -17,25 +17,16 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; -import java.util.Iterator; import javax.annotation.Nonnull; -import de.inetsoftware.jwebassembly.wasm.AnyType; - /** * WasmInstruction for a function call. * * @author Volker Berlin * */ -class WasmCallIndirectInstruction extends WasmInstruction { - - private AnyType valueType; - - private final FunctionName name; - - private int paramCount = -1; +class WasmCallIndirectInstruction extends WasmCallInstruction { /** * Create an instance of a function call instruction @@ -48,8 +39,7 @@ class WasmCallIndirectInstruction extends WasmInstruction { * the line number in the Java source code */ WasmCallIndirectInstruction( FunctionName name, int javaCodePos, int lineNumber ) { - super( javaCodePos, lineNumber ); - this.name = name; + super( name, javaCodePos, lineNumber ); } /** @@ -60,29 +50,16 @@ class WasmCallIndirectInstruction extends WasmInstruction { return Type.CallIndirect; } - /** - * Get the function name that should be called - * - * @return the name - */ - @Nonnull - FunctionName getFunctionName() { - return name; - } - /** * {@inheritDoc} */ + @Override public void writeTo( @Nonnull ModuleWriter writer ) throws IOException { - writer.writeFunctionCallIndirect( name ); - } - - /** - * {@inheritDoc} - */ - AnyType getPushValueType() { - countParams(); - return valueType; + if( true ) { // TODO + super.writeTo( writer ); + } else { + writer.writeFunctionCallIndirect( getFunctionName() ); + } } /** @@ -90,26 +67,6 @@ class WasmCallIndirectInstruction extends WasmInstruction { */ @Override int getPopCount() { - countParams(); - return paramCount; - } - - /** - * Count the parameters in the signature - */ - private void countParams() { - if( paramCount >= 0 ) { - return; - } - Iterator parser = name.getSignature(); - paramCount = 1; - while( parser.next() != null ) { - paramCount++; - } - valueType = parser.next(); - while( parser.hasNext() ) { - valueType = parser.next(); - paramCount--; - } + return super.getPopCount() + 1; // this -> +1 } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java index d0cfcda..ccf6b8a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java @@ -60,6 +60,16 @@ class WasmCallInstruction extends WasmInstruction { return Type.Call; } + /** + * Get the function name that should be called + * + * @return the name + */ + @Nonnull + FunctionName getFunctionName() { + return name; + } + /** * Mark the function as needed in the functions manager and replace the function name with a possible super name. * diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 6deb603..9f43eec 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -273,6 +273,20 @@ public abstract class WasmCodeBuilder { instructions.add( new WasmCallInstruction( name, javaCodePos, lineNumber ) ); } + /** + * Add a virtual/method function call. + * + * @param name + * the function name that should be called + * @param javaCodePos + * the code position/offset in the Java method + * @param lineNumber + * the line number in the Java source code + */ + protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { + instructions.add( new WasmCallIndirectInstruction( name, javaCodePos, lineNumber ) ); + } + /** * Add a block operation. *