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;
}
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 ) {

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
* 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 {

View File

@ -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 );
}
/**

View File

@ -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;

View File

@ -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 );
}
/**