Replace a function name in call with its supper method if real target name does not exists.

This commit is contained in:
Volker Berlin 2019-05-12 18:38:11 +02:00
parent aa1ed68b3f
commit f0d3027553
5 changed files with 73 additions and 23 deletions

View File

@ -171,14 +171,22 @@ public class ClassFile {
return methods; 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 ) { for( MethodInfo method : methods ) {
if( name.equals( method.getName() ) ) { if( name.equals( method.getName() ) && signature.equals( method.getType() ) ) {
count++; return method;
} }
} }
return count; return null;
} }
public FieldInfo getField( String name ) { public FieldInfo getField( String name ) {

View File

@ -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 * @param name
* the function name * the function name
* @return the real function name
*/ */
void markAsNeeded( FunctionName name ) { FunctionName markAsNeeded( FunctionName name ) {
FunctionState state = getOrCreate( name ); FunctionState state = getOrCreate( name );
if( state.state == State.None ) { if( state.state == State.None ) {
state.state = State.Needed; state.state = State.Needed;
} }
return state.alias == null ? name : state.alias;
} }
/** /**
@ -167,6 +169,21 @@ public class FunctionManager {
getOrCreate( name ).method = method; 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 * Check if there is a replacement method
* *
@ -189,6 +206,8 @@ public class FunctionManager {
private State state = State.None; private State state = State.None;
private MethodInfo method; private MethodInfo method;
private FunctionName alias;
} }
private static enum State { private static enum State {

View File

@ -38,6 +38,12 @@ public class FunctionName {
@Nonnull @Nonnull
public final String className; public final String className;
/**
* The method name.
*/
@Nonnull
public final String methodName;
/** /**
* The name in the WebAssembly. * The name in the WebAssembly.
*/ */
@ -54,7 +60,7 @@ public class FunctionName {
* The signature * The signature
*/ */
@Nonnull @Nonnull
private final String signature; public final String signature;
/** /**
* Create a new instance from the given reference in the ConstantPool or parsed method. * 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 ) { FunctionName( String className, String methodName, String signature ) {
this.className = className; this.className = className;
this.methodName = methodName;
this.fullName = className + '.' + methodName; this.fullName = className + '.' + methodName;
this.signatureName = fullName + signature; this.signatureName = fullName + signature;
this.signature = signature; this.signature = signature;
@ -102,11 +109,13 @@ public class FunctionName {
* the full Java method signature like "com/foo/Bar.method()V" * the full Java method signature like "com/foo/Bar.method()V"
*/ */
FunctionName( String signatureName ) { FunctionName( String signatureName ) {
this.className = signatureName.substring( 0, signatureName.indexOf( '.' ) ); int idx1 = signatureName.indexOf( '.' );
int idx = signatureName.indexOf( '(' ); this.className = signatureName.substring( 0, idx1 );
this.fullName = signatureName.substring( 0, idx ); int idx2 = signatureName.indexOf( '(', idx1 );
this.methodName = signatureName.substring( idx1 + 1, idx2 );
this.fullName = signatureName.substring( 0, idx2 );
this.signatureName = signatureName; this.signatureName = signatureName;
this.signature = signatureName.substring( idx ); this.signature = signatureName.substring( idx2 );
} }
/** /**

View File

@ -156,6 +156,7 @@ public class ModuleGenerator {
// scan all methods that should be write to build optimize structures // scan all methods that should be write to build optimize structures
FunctionName next; FunctionName next;
NEXT:
while( (next = functions.nextScannLater()) != null ) { while( (next = functions.nextScannLater()) != null ) {
ClassFile classFile = ClassFile.get( next.className, libraries ); ClassFile classFile = ClassFile.get( next.className, libraries );
if( classFile == null ) { 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 ); throw new WasmException( "Missing function: " + next.signatureName, -1 );
} }
} }
@ -199,7 +213,7 @@ public class ModuleGenerator {
for( WasmInstruction instruction : instructions ) { for( WasmInstruction instruction : instructions ) {
switch( instruction.getType() ) { switch( instruction.getType() ) {
case Call: case Call:
functions.markAsNeeded( ((WasmCallInstruction)instruction).getFunctionName() ); ((WasmCallInstruction)instruction).markAsNeeded( functions );
break; break;
default: default:
} }
@ -477,7 +491,7 @@ public class ModuleGenerator {
} }
break; break;
case Call: case Call:
functions.markAsNeeded( ((WasmCallInstruction)instruction).getFunctionName() ); ((WasmCallInstruction)instruction).markAsNeeded( functions );
break; break;
case Struct: case Struct:
WasmStructInstruction instr = (WasmStructInstruction)instruction; WasmStructInstruction instr = (WasmStructInstruction)instruction;

View File

@ -31,11 +31,11 @@ import de.inetsoftware.jwebassembly.wasm.AnyType;
*/ */
class WasmCallInstruction extends WasmInstruction { 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 * 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 void markAsNeeded( @Nonnull FunctionManager functions ) {
FunctionName getFunctionName() { name = functions.markAsNeeded( name );
return name;
} }
/** /**