mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 10:44:47 +01:00
import only the needed functions to reduce the needed JS glue code
This commit is contained in:
parent
b90d7e1dea
commit
6bcda0daa5
@ -17,6 +17,7 @@ package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@ -57,6 +58,19 @@ public class FunctionManager {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the a function as a import function. Only if the function is also needed then it will imported from
|
||||
* compiler.
|
||||
*
|
||||
* @param name
|
||||
* the function name
|
||||
* @param importAnannotation
|
||||
* the annotation of the import
|
||||
*/
|
||||
void markAsImport( FunctionName name, Map<String,Object> importAnannotation ) {
|
||||
getOrCreate( name ).importAnannotation = importAnannotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the a function as scanned in the prepare phase. This should only occur with needed functions.
|
||||
*
|
||||
@ -82,16 +96,48 @@ public class FunctionManager {
|
||||
*
|
||||
* @param name
|
||||
* the function name
|
||||
* @param isStatic
|
||||
* true, if the method is static
|
||||
* @return the real function name
|
||||
*/
|
||||
FunctionName markAsNeeded( FunctionName name ) {
|
||||
FunctionName markAsNeeded( FunctionName name, boolean isStatic ) {
|
||||
FunctionState state = getOrCreate( name );
|
||||
if( state.state == State.None ) {
|
||||
state.state = State.Needed;
|
||||
}
|
||||
state.isStatic = isStatic;
|
||||
return state.alias == null ? name : state.alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all FunctionNames that need imported
|
||||
*
|
||||
* @return an iterator
|
||||
*/
|
||||
Iterator<FunctionName> getNeededImports() {
|
||||
return states.entrySet().stream().filter( entry -> {
|
||||
FunctionState state = entry.getValue();
|
||||
switch( state.state ) {
|
||||
case Needed:
|
||||
case Scanned:
|
||||
return state.importAnannotation != null;
|
||||
default:
|
||||
}
|
||||
return false;
|
||||
} ).map( entry -> entry.getKey() ).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the annotation of an import function
|
||||
*
|
||||
* @param name
|
||||
* the function name
|
||||
* @return the annotation or null
|
||||
*/
|
||||
Map<String, Object> getImportAnannotation( FunctionName name ) {
|
||||
return getOrCreate( name ).importAnannotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first FunctionName that is required but was not scanned.
|
||||
*
|
||||
@ -125,6 +171,24 @@ public class FunctionManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all FunctionNames that need imported
|
||||
*
|
||||
* @return an iterator
|
||||
*/
|
||||
Iterator<FunctionName> getNeededFunctions() {
|
||||
return states.entrySet().stream().filter( entry -> {
|
||||
FunctionState state = entry.getValue();
|
||||
switch( state.state ) {
|
||||
case Needed:
|
||||
case Scanned:
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
return false;
|
||||
} ).map( entry -> entry.getKey() ).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* if the given function is required but was not scanned.
|
||||
*
|
||||
@ -158,6 +222,17 @@ public class FunctionManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if the given function is static.
|
||||
*
|
||||
* @param name
|
||||
* the function name
|
||||
* @return true, if the function is static
|
||||
*/
|
||||
boolean isStatic( FunctionName name ) {
|
||||
return getOrCreate( name ).isStatic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a replacement for a method
|
||||
*
|
||||
@ -227,13 +302,17 @@ public class FunctionManager {
|
||||
* State of a function/method
|
||||
*/
|
||||
private static class FunctionState {
|
||||
private State state = State.None;
|
||||
private State state = State.None;
|
||||
|
||||
private MethodInfo method;
|
||||
private MethodInfo method;
|
||||
|
||||
private FunctionName alias;
|
||||
private FunctionName alias;
|
||||
|
||||
private int functionIdx = -1;
|
||||
private Map<String, Object> importAnannotation;
|
||||
|
||||
private int functionIdx = -1;
|
||||
|
||||
private boolean isStatic;
|
||||
}
|
||||
|
||||
private static enum State {
|
||||
|
@ -156,7 +156,6 @@ public class ModuleGenerator {
|
||||
ClassFile classFile = ClassFile.get( next.className, libraries );
|
||||
if( classFile == null ) {
|
||||
if( next instanceof SyntheticFunctionName ) {
|
||||
writeMethodSignature( next, true, null );
|
||||
scanMethod( ((SyntheticFunctionName)next).getCodeBuilder( watParser ) );
|
||||
functions.markAsScanned( next );
|
||||
}
|
||||
@ -165,7 +164,6 @@ public class ModuleGenerator {
|
||||
try {
|
||||
FunctionName name = new FunctionName( method );
|
||||
if( functions.needToScan( name ) ) {
|
||||
writeMethodSignature( name, method.isStatic(), null );
|
||||
scanMethod( createInstructions( functions.replace( name, method ) ) );
|
||||
functions.markAsScanned( name );
|
||||
}
|
||||
@ -182,7 +180,7 @@ public class ModuleGenerator {
|
||||
MethodInfo method = superClassFile.getMethod( next.methodName, next.signature );
|
||||
if( method != null ) {
|
||||
FunctionName name = new FunctionName( method );
|
||||
functions.markAsNeeded( name );
|
||||
functions.markAsNeeded( name, method.isStatic() );
|
||||
functions.setAlias( next, name );
|
||||
continue NEXT; // we have found a super method
|
||||
}
|
||||
@ -202,6 +200,25 @@ public class ModuleGenerator {
|
||||
*/
|
||||
public void prepareFinish() throws IOException {
|
||||
prepareFunctions();
|
||||
|
||||
// write only the needed imports to the output
|
||||
for( Iterator<FunctionName> iterator = functions.getNeededImports(); iterator.hasNext(); ) {
|
||||
FunctionName name = iterator.next();
|
||||
|
||||
functions.markAsWritten( name );
|
||||
Map<String, Object> importAnannotation = functions.getImportAnannotation( name );
|
||||
String impoarModule = (String)importAnannotation.get( "module" );
|
||||
String importName = (String)importAnannotation.get( "name" );
|
||||
writer.prepareImport( name, impoarModule, importName );
|
||||
writeMethodSignature( name, true, null );
|
||||
}
|
||||
|
||||
// init/write the function types
|
||||
for( Iterator<FunctionName> iterator = functions.getNeededFunctions(); iterator.hasNext(); ) {
|
||||
FunctionName name = iterator.next();
|
||||
writeMethodSignature( name, functions.isStatic( name ), null );
|
||||
}
|
||||
|
||||
types.prepareFinish( writer, functions, libraries );
|
||||
prepareFunctions(); // prepare of types can add some override methods as needed
|
||||
functions.prepareFinish();
|
||||
@ -224,8 +241,10 @@ public class ModuleGenerator {
|
||||
for( WasmInstruction instruction : instructions ) {
|
||||
switch( instruction.getType() ) {
|
||||
case Call:
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions, true );
|
||||
break;
|
||||
case CallIndirect:
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions );
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions, false );
|
||||
break;
|
||||
default:
|
||||
}
|
||||
@ -315,28 +334,23 @@ public class ModuleGenerator {
|
||||
try {
|
||||
FunctionName name = new FunctionName( method );
|
||||
Map<String,Object> annotationValues;
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.REPLACE_ANNOTATION )) != null ) {
|
||||
String signatureName = (String)annotationValues.get( "value" );
|
||||
name = new FunctionName( signatureName );
|
||||
functions.addReplacement( name, method );
|
||||
}
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION )) != null ) {
|
||||
if( !method.isStatic() ) {
|
||||
throw new WasmException( "Import method must be static: " + name.fullName, -1 );
|
||||
}
|
||||
functions.markAsWritten( name );
|
||||
String impoarModule = (String)annotationValues.get( "module" );
|
||||
String importName = (String)annotationValues.get( "name" );
|
||||
writer.prepareImport( name, impoarModule, importName );
|
||||
writeMethodSignature( name, true, null );
|
||||
functions.markAsImport( name, annotationValues );
|
||||
return;
|
||||
}
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION )) != null ) {
|
||||
if( !method.isStatic() ) {
|
||||
throw new WasmException( "Export method must be static: " + name.fullName, -1 );
|
||||
}
|
||||
functions.markAsNeeded( name );
|
||||
return;
|
||||
}
|
||||
if( (annotationValues = method.getAnnotation( JWebAssembly.REPLACE_ANNOTATION )) != null ) {
|
||||
String signatureName = (String)annotationValues.get( "value" );
|
||||
name = new FunctionName( signatureName );
|
||||
functions.addReplacement( name, method );
|
||||
functions.markAsNeeded( name, true );
|
||||
return;
|
||||
}
|
||||
} catch( Exception ioex ) {
|
||||
@ -446,8 +460,10 @@ public class ModuleGenerator {
|
||||
}
|
||||
break;
|
||||
case Call:
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions, true );
|
||||
break;
|
||||
case CallIndirect:
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions );
|
||||
((WasmCallInstruction)instruction).markAsNeeded( functions, false );
|
||||
break;
|
||||
case Struct:
|
||||
WasmStructInstruction instr = (WasmStructInstruction)instruction;
|
||||
|
@ -42,6 +42,7 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||
*/
|
||||
public class TypeManager {
|
||||
|
||||
/** name of virtual function table, start with a point for an invalid Java identifier */
|
||||
static final String VTABLE = ".vtable";
|
||||
|
||||
private Map<String, StructType> map = new LinkedHashMap<>();
|
||||
@ -204,7 +205,7 @@ public class TypeManager {
|
||||
FunctionName func = methods.get( idx );
|
||||
if( func.methodName.equals( funcName.methodName ) && func.signature.equals( funcName.signature ) ) {
|
||||
methods.set( idx, funcName ); // use the override method
|
||||
functions.markAsNeeded( funcName ); // mark all overridden methods also as needed if the super method is used
|
||||
functions.markAsNeeded( funcName, false ); // mark all overridden methods also as needed if the super method is used
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -74,8 +74,8 @@ class WasmCallIndirectInstruction extends WasmCallInstruction {
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
void markAsNeeded( FunctionManager functions ) {
|
||||
super.markAsNeeded( functions );
|
||||
void markAsNeeded( FunctionManager functions, boolean isStatic ) {
|
||||
super.markAsNeeded( functions, isStatic );
|
||||
virtualFunctionIdx = functions.getFunctionIndex( getFunctionName() );
|
||||
}
|
||||
|
||||
|
@ -75,9 +75,11 @@ class WasmCallInstruction extends WasmInstruction {
|
||||
*
|
||||
* @param functions
|
||||
* the function manager
|
||||
* @param isStatic
|
||||
* true, if the method is static
|
||||
*/
|
||||
void markAsNeeded( @Nonnull FunctionManager functions ) {
|
||||
name = functions.markAsNeeded( name );
|
||||
void markAsNeeded( @Nonnull FunctionManager functions, boolean isStatic ) {
|
||||
name = functions.markAsNeeded( name, isStatic );
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user