From f0d3027553453c6edce2026e2cf3550460733ea8 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 12 May 2019 18:38:11 +0200 Subject: [PATCH] Replace a function name in call with its supper method if real target name does not exists. --- .../inetsoftware/classparser/ClassFile.java | 18 +++++++++++---- .../jwebassembly/module/FunctionManager.java | 23 +++++++++++++++++-- .../jwebassembly/module/FunctionName.java | 19 +++++++++++---- .../jwebassembly/module/ModuleGenerator.java | 20 +++++++++++++--- .../module/WasmCallInstruction.java | 16 ++++++------- 5 files changed, 73 insertions(+), 23 deletions(-) diff --git a/src/de/inetsoftware/classparser/ClassFile.java b/src/de/inetsoftware/classparser/ClassFile.java index 8a573df..639f168 100644 --- a/src/de/inetsoftware/classparser/ClassFile.java +++ b/src/de/inetsoftware/classparser/ClassFile.java @@ -171,14 +171,22 @@ public class ClassFile { return methods; } - public int getMethodCount( String name ) { - int count = 0; + /** + * Find a method via name and signature. + * + * @param name + * the name + * @param signature + * the signature + * @return the method or null if not found + */ + public MethodInfo getMethod( String name, String signature ) { for( MethodInfo method : methods ) { - if( name.equals( method.getName() ) ) { - count++; + if( name.equals( method.getName() ) && signature.equals( method.getType() ) ) { + return method; } } - return count; + return null; } public FieldInfo getField( String name ) { diff --git a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java index e65609b..9256453 100644 --- a/src/de/inetsoftware/jwebassembly/module/FunctionManager.java +++ b/src/de/inetsoftware/jwebassembly/module/FunctionManager.java @@ -78,16 +78,18 @@ public class FunctionManager { } /** - * Mark a function as used/called. + * Mark a function as used/called and return the real name if there is an alias. * * @param name * the function name + * @return the real function name */ - void markAsNeeded( FunctionName name ) { + FunctionName markAsNeeded( FunctionName name ) { FunctionState state = getOrCreate( name ); if( state.state == State.None ) { state.state = State.Needed; } + return state.alias == null ? name : state.alias; } /** @@ -167,6 +169,21 @@ public class FunctionManager { getOrCreate( name ).method = method; } + /** + * Set an alias for the method. If this method should be called then the alias method should be really called. This + * is typical a virtual super method. + * + * @param name + * the original name + * @param alias + * the new name. + */ + void setAlias( FunctionName name, FunctionName alias ) { + FunctionState state = getOrCreate( name ); + state.alias = alias; + state.state = State.Written; + } + /** * Check if there is a replacement method * @@ -189,6 +206,8 @@ public class FunctionManager { private State state = State.None; private MethodInfo method; + + private FunctionName alias; } private static enum State { diff --git a/src/de/inetsoftware/jwebassembly/module/FunctionName.java b/src/de/inetsoftware/jwebassembly/module/FunctionName.java index 8382e3e..e078f2e 100644 --- a/src/de/inetsoftware/jwebassembly/module/FunctionName.java +++ b/src/de/inetsoftware/jwebassembly/module/FunctionName.java @@ -38,6 +38,12 @@ public class FunctionName { @Nonnull public final String className; + /** + * The method name. + */ + @Nonnull + public final String methodName; + /** * The name in the WebAssembly. */ @@ -54,7 +60,7 @@ public class FunctionName { * The signature */ @Nonnull - private final String signature; + public final String signature; /** * Create a new instance from the given reference in the ConstantPool or parsed method. @@ -90,6 +96,7 @@ public class FunctionName { */ FunctionName( String className, String methodName, String signature ) { this.className = className; + this.methodName = methodName; this.fullName = className + '.' + methodName; this.signatureName = fullName + signature; this.signature = signature; @@ -102,11 +109,13 @@ public class FunctionName { * the full Java method signature like "com/foo/Bar.method()V" */ FunctionName( String signatureName ) { - this.className = signatureName.substring( 0, signatureName.indexOf( '.' ) ); - int idx = signatureName.indexOf( '(' ); - this.fullName = signatureName.substring( 0, idx ); + int idx1 = signatureName.indexOf( '.' ); + this.className = signatureName.substring( 0, idx1 ); + int idx2 = signatureName.indexOf( '(', idx1 ); + this.methodName = signatureName.substring( idx1 + 1, idx2 ); + this.fullName = signatureName.substring( 0, idx2 ); this.signatureName = signatureName; - this.signature = signatureName.substring( idx ); + this.signature = signatureName.substring( idx2 ); } /** diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 61fd939..240f1ce 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -156,6 +156,7 @@ public class ModuleGenerator { // scan all methods that should be write to build optimize structures FunctionName next; + NEXT: while( (next = functions.nextScannLater()) != null ) { ClassFile classFile = ClassFile.get( next.className, libraries ); if( classFile == null ) { @@ -176,7 +177,20 @@ public class ModuleGenerator { } } ); } - if( functions.needToScan( next ) ) { + + if( functions.needToScan( next ) ) { // function was not found + ClassFile superClassFile = classFile; + while( superClassFile != null ) { + MethodInfo method = superClassFile.getMethod( next.methodName, next.signature ); + if( method != null ) { + FunctionName name = new FunctionName( method ); + functions.markAsNeeded( name ); + functions.setAlias( next, name ); + continue NEXT; + } + ConstantClass superClass = superClassFile.getSuperClass(); + superClassFile = superClass == null ? null : ClassFile.get( superClass.getName(), libraries ); + } throw new WasmException( "Missing function: " + next.signatureName, -1 ); } } @@ -199,7 +213,7 @@ public class ModuleGenerator { for( WasmInstruction instruction : instructions ) { switch( instruction.getType() ) { case Call: - functions.markAsNeeded( ((WasmCallInstruction)instruction).getFunctionName() ); + ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; default: } @@ -477,7 +491,7 @@ public class ModuleGenerator { } break; case Call: - functions.markAsNeeded( ((WasmCallInstruction)instruction).getFunctionName() ); + ((WasmCallInstruction)instruction).markAsNeeded( functions ); break; case Struct: WasmStructInstruction instr = (WasmStructInstruction)instruction; diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java index 142e34e..d0cfcda 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java @@ -31,11 +31,11 @@ import de.inetsoftware.jwebassembly.wasm.AnyType; */ class WasmCallInstruction extends WasmInstruction { - private AnyType valueType; + private AnyType valueType; - private final FunctionName name; + private FunctionName name; - private int paramCount = -1; + private int paramCount = -1; /** * Create an instance of a function call instruction @@ -61,13 +61,13 @@ class WasmCallInstruction extends WasmInstruction { } /** - * Get the function name that should be called + * Mark the function as needed in the functions manager and replace the function name with a possible super name. * - * @return the name + * @param functions + * the function manager */ - @Nonnull - FunctionName getFunctionName() { - return name; + void markAsNeeded( @Nonnull FunctionManager functions ) { + name = functions.markAsNeeded( name ); } /**