mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
Also static code from Java VM code must be registered. Disable static code to find a solution for the cyclic dependency between static code.
This commit is contained in:
parent
c1b3e34eb7
commit
87f986e30b
@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@ -37,9 +38,9 @@ import de.inetsoftware.jwebassembly.WasmException;
|
|||||||
*/
|
*/
|
||||||
class FunctionManager {
|
class FunctionManager {
|
||||||
|
|
||||||
private final Map<FunctionName, FunctionState> states = new LinkedHashMap<>();
|
private final Map<FunctionName, FunctionState> states = new LinkedHashMap<>();
|
||||||
|
|
||||||
private final Map<String, FunctionName> classesWithClinit = new HashMap<>();
|
private final Set<String> usedClasses = new LinkedHashSet<>();
|
||||||
|
|
||||||
private boolean isFinish;
|
private boolean isFinish;
|
||||||
|
|
||||||
@ -87,13 +88,13 @@ class FunctionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark that a class has static initializer.
|
* Mark a class as used. This means the static initializer must be used.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param className
|
||||||
* the "<clinit>" function name
|
* the name of the class like "java/lang/Object"
|
||||||
*/
|
*/
|
||||||
void markClassWithClinit( FunctionName name ) {
|
void markClassAsUsed( String className ) {
|
||||||
classesWithClinit.put( name.className, name );
|
usedClasses.add( className );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,10 +153,7 @@ class FunctionManager {
|
|||||||
}
|
}
|
||||||
state.state = State.Needed;
|
state.state = State.Needed;
|
||||||
JWebAssembly.LOGGER.fine( "\t\tcall: " + name.signatureName );
|
JWebAssembly.LOGGER.fine( "\t\tcall: " + name.signatureName );
|
||||||
FunctionName cInit = classesWithClinit.get( name.className );
|
usedClasses.add( name.className );
|
||||||
if( cInit != null ) {
|
|
||||||
markAsNeeded( cInit );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return state.alias == null ? name : state.alias;
|
return state.alias == null ? name : state.alias;
|
||||||
}
|
}
|
||||||
@ -243,6 +241,16 @@ class FunctionManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all used classes.
|
||||||
|
*
|
||||||
|
* @return an iterator
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
Iterator<String> getUsedClasses() {
|
||||||
|
return usedClasses.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all static constructor FunctionName of used classes.
|
* Get all static constructor FunctionName of used classes.
|
||||||
*
|
*
|
||||||
@ -250,10 +258,7 @@ class FunctionManager {
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Iterator<FunctionName> getWriteLaterClinit() {
|
Iterator<FunctionName> getWriteLaterClinit() {
|
||||||
return classesWithClinit.values().stream().filter( ( name ) -> {
|
return iterator( entry -> entry.getKey().methodName.equals( "<clinit>" ) );
|
||||||
FunctionState state = states.get( name );
|
|
||||||
return state != null && (state.state == State.Needed || state.state == State.Scanned);
|
|
||||||
} ).iterator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,8 +196,8 @@ public class ModuleGenerator {
|
|||||||
NEXT:
|
NEXT:
|
||||||
while( (next = functions.nextScannLater()) != null ) {
|
while( (next = functions.nextScannLater()) != null ) {
|
||||||
className = next.className;
|
className = next.className;
|
||||||
|
JWebAssembly.LOGGER.fine( "scan " + next.signatureName );
|
||||||
if( next instanceof SyntheticFunctionName ) {
|
if( next instanceof SyntheticFunctionName ) {
|
||||||
JWebAssembly.LOGGER.fine( '\t' + next.methodName + next.signature );
|
|
||||||
SyntheticFunctionName synth = (SyntheticFunctionName)next;
|
SyntheticFunctionName synth = (SyntheticFunctionName)next;
|
||||||
if( synth.hasWasmCode() ) {
|
if( synth.hasWasmCode() ) {
|
||||||
synth.getCodeBuilder( watParser );
|
synth.getCodeBuilder( watParser );
|
||||||
@ -208,7 +208,6 @@ public class ModuleGenerator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
JWebAssembly.LOGGER.fine( "scan " + next.signatureName );
|
|
||||||
MethodInfo method = null;
|
MethodInfo method = null;
|
||||||
ClassFile classFile = classFileLoader.get( next.className );
|
ClassFile classFile = classFileLoader.get( next.className );
|
||||||
if( classFile != null ) {
|
if( classFile != null ) {
|
||||||
@ -275,6 +274,7 @@ public class ModuleGenerator {
|
|||||||
do {
|
do {
|
||||||
scanFunctions();
|
scanFunctions();
|
||||||
functCount = functions.size(); // scan the functions can find new needed types
|
functCount = functions.size(); // scan the functions can find new needed types
|
||||||
|
//TODO static code disabled: scanForClinit();
|
||||||
types.scanTypeHierarchy( classFileLoader ); // scan the type hierarchy can find new functions
|
types.scanTypeHierarchy( classFileLoader ); // scan the type hierarchy can find new functions
|
||||||
} while( functCount < functions.size() );
|
} while( functCount < functions.size() );
|
||||||
|
|
||||||
@ -321,6 +321,26 @@ public class ModuleGenerator {
|
|||||||
writer.prepareFinish();
|
writer.prepareFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan for needed static constructors. The static code of all classes that used in any form must be executed.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if any I/O error occur
|
||||||
|
*/
|
||||||
|
private void scanForClinit() throws IOException {
|
||||||
|
JWebAssembly.LOGGER.fine( "scan for needed <clinit>" );
|
||||||
|
for( Iterator<String> iterator = functions.getUsedClasses(); iterator.hasNext(); ) {
|
||||||
|
String className = iterator.next();
|
||||||
|
ClassFile classFile = classFileLoader.get( className );
|
||||||
|
if( classFile != null ) {
|
||||||
|
MethodInfo method = classFile.getMethod( "<clinit>", "()V" );
|
||||||
|
if( method != null ) {
|
||||||
|
functions.markAsNeeded( new FunctionName( method ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a start method for the static class constructors
|
* Add a start method for the static class constructors
|
||||||
*
|
*
|
||||||
@ -329,8 +349,7 @@ public class ModuleGenerator {
|
|||||||
*/
|
*/
|
||||||
private void prepareStartFunction() throws IOException {
|
private void prepareStartFunction() throws IOException {
|
||||||
// add the start function/section only if there are static code
|
// add the start function/section only if there are static code
|
||||||
Iterator<FunctionName> iterator = functions.getWriteLaterClinit();
|
if( functions.getWriteLaterClinit().hasNext() ) {
|
||||||
if( iterator.hasNext() ) {
|
|
||||||
FunctionName cinit = new SyntheticFunctionName( "", "<clinit>", "()V" ) {
|
FunctionName cinit = new SyntheticFunctionName( "", "<clinit>", "()V" ) {
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasWasmCode() {
|
protected boolean hasWasmCode() {
|
||||||
@ -341,6 +360,7 @@ public class ModuleGenerator {
|
|||||||
protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) {
|
protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) {
|
||||||
watParser.reset( null, null, getSignature( null ) );
|
watParser.reset( null, null, getSignature( null ) );
|
||||||
|
|
||||||
|
Iterator<FunctionName> iterator = functions.getWriteLaterClinit();
|
||||||
while( iterator.hasNext() ) {
|
while( iterator.hasNext() ) {
|
||||||
FunctionName name = iterator.next();
|
FunctionName name = iterator.next();
|
||||||
//TODO if not in the debug mode then inlining would produce smaller output and should be faster
|
//TODO if not in the debug mode then inlining would produce smaller output and should be faster
|
||||||
@ -440,9 +460,6 @@ public class ModuleGenerator {
|
|||||||
private void prepareMethod( MethodInfo method ) throws WasmException {
|
private void prepareMethod( MethodInfo method ) throws WasmException {
|
||||||
try {
|
try {
|
||||||
FunctionName name = new FunctionName( method );
|
FunctionName name = new FunctionName( method );
|
||||||
if( "<clinit>".equals( name.methodName ) ) {
|
|
||||||
functions.markClassWithClinit( name );
|
|
||||||
}
|
|
||||||
if( functions.isKnown( name ) ) {
|
if( functions.isKnown( name ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -533,6 +550,10 @@ public class ModuleGenerator {
|
|||||||
strings.getStringConstantFunction(); // we will need also the string constant function for the Class Name, in the other case a program with only new Object().getClass().getName() will fail to compile
|
strings.getStringConstantFunction(); // we will need also the string constant function for the Class Name, in the other case a program with only new Object().getClass().getName() will fail to compile
|
||||||
return types.getTypeTableMemoryOffsetFunctionName().getCodeBuilder( watParser );
|
return types.getTypeTableMemoryOffsetFunctionName().getCodeBuilder( watParser );
|
||||||
}
|
}
|
||||||
|
if( "de/inetsoftware/jwebassembly/module/StringManager.stringsMemoryOffset()I".equals( name.signatureName ) ) {
|
||||||
|
strings.getStringConstantFunction();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
throw new WasmException( "Abstract or native method can not be used: " + name.signatureName, -1 );
|
throw new WasmException( "Abstract or native method can not be used: " + name.signatureName, -1 );
|
||||||
}
|
}
|
||||||
} catch( Exception ioex ) {
|
} catch( Exception ioex ) {
|
||||||
|
@ -329,6 +329,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
FunctionName name = new FunctionName( ref );
|
FunctionName name = new FunctionName( ref );
|
||||||
AnyType type = new ValueTypeParser( ref.getType(), types ).next();
|
AnyType type = new ValueTypeParser( ref.getType(), types ).next();
|
||||||
instructions.add( new WasmGlobalInstruction( load, name, type, javaCodePos, lineNumber ) );
|
instructions.add( new WasmGlobalInstruction( load, name, type, javaCodePos, lineNumber ) );
|
||||||
|
functions.markClassAsUsed( name.className );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -486,6 +487,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
instructions.add( instruction );
|
instructions.add( instruction );
|
||||||
|
functions.markClassAsUsed( name.className );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -535,6 +537,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
name = functions.markAsNeeded( name );
|
name = functions.markAsNeeded( name );
|
||||||
addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) );
|
addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) );
|
||||||
options.getCallVirtual(); // mark the function as needed
|
options.getCallVirtual(); // mark the function as needed
|
||||||
|
functions.markClassAsUsed( name.className );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -549,6 +552,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) {
|
protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) {
|
||||||
//TODO name = functions.markAsNeeded( name );
|
//TODO name = functions.markAsNeeded( name );
|
||||||
addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) );
|
addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) );
|
||||||
|
functions.markClassAsUsed( name.className );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user