mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
implements support for static class constructors
This commit is contained in:
parent
645996ceb0
commit
65a1f3ff76
@ -35,7 +35,7 @@ The project is currently not production ready but you can run already some tests
|
|||||||
* [x] invoke default method calls
|
* [x] invoke default method calls
|
||||||
* [x] String support
|
* [x] String support
|
||||||
* [x] Simple Class object support
|
* [x] Simple Class object support
|
||||||
* [ ] static constructors
|
* [x] static constructors
|
||||||
* [x] Optimizer - Optimize the WASM output of a single method after transpiling before writing to output
|
* [x] Optimizer - Optimize the WASM output of a single method after transpiling before writing to output
|
||||||
* [x] Hello World sample [(live)](https://i-net-software.github.io/JWebAssembly/samples/HelloWorld/HelloWorld.html), [(source code)](https://github.com/i-net-software/JWebAssembly/blob/master/docs/samples/HelloWorld/HelloWorld.java)
|
* [x] Hello World sample [(live)](https://i-net-software.github.io/JWebAssembly/samples/HelloWorld/HelloWorld.html), [(source code)](https://github.com/i-net-software/JWebAssembly/blob/master/docs/samples/HelloWorld/HelloWorld.java)
|
||||||
|
|
||||||
|
@ -91,6 +91,8 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
|
|
||||||
private boolean callIndirect;
|
private boolean callIndirect;
|
||||||
|
|
||||||
|
private FunctionName startFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new instance.
|
* Create new instance.
|
||||||
*
|
*
|
||||||
@ -133,6 +135,7 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
writeEventSection();
|
writeEventSection();
|
||||||
writeSection( SectionType.Global, globals.values() );
|
writeSection( SectionType.Global, globals.values() );
|
||||||
writeSection( SectionType.Export, exports );
|
writeSection( SectionType.Export, exports );
|
||||||
|
writeStartSection();
|
||||||
writeElementSection();
|
writeElementSection();
|
||||||
writeCodeSection();
|
writeCodeSection();
|
||||||
writeDataSection();
|
writeDataSection();
|
||||||
@ -253,6 +256,22 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write a start section. The id of the function that should be automatically executed.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if any I/O error occur
|
||||||
|
*/
|
||||||
|
private void writeStartSection() throws IOException {
|
||||||
|
if( startFunction == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int id = getFunction( startFunction ).id;
|
||||||
|
WasmOutputStream stream = new WasmOutputStream();
|
||||||
|
stream.writeVaruint32( id );
|
||||||
|
wasm.writeSection( SectionType.Start, stream );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write element section. This section create a matching between direct and indirect function call IDs.
|
* Write element section. This section create a matching between direct and indirect function call IDs.
|
||||||
*
|
*
|
||||||
@ -518,10 +537,15 @@ public class BinaryModuleWriter extends ModuleWriter implements InstructionOpcod
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void writeMethodParamStart( FunctionName name, FunctionType funcType ) throws IOException {
|
protected void writeMethodParamStart( FunctionName name, FunctionType funcType ) throws IOException {
|
||||||
if( funcType == FunctionType.Abstract ) {
|
switch( funcType ) {
|
||||||
abstracts.put( name.signatureName, function = new Function() );
|
case Abstract:
|
||||||
} else {
|
abstracts.put( name.signatureName, function = new Function() );
|
||||||
function = getFunction( name );
|
break;
|
||||||
|
case Start:
|
||||||
|
startFunction = name;
|
||||||
|
//$FALL-THROUGH$
|
||||||
|
default:
|
||||||
|
function = getFunction( name );
|
||||||
}
|
}
|
||||||
functionType = new FunctionTypeEntry();
|
functionType = new FunctionTypeEntry();
|
||||||
locals.clear();
|
locals.clear();
|
||||||
|
@ -37,9 +37,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> classesWithCInit = new HashMap<>();
|
private final Map<String, FunctionName> classesWithClinit = new HashMap<>();
|
||||||
|
|
||||||
private boolean isFinish;
|
private boolean isFinish;
|
||||||
|
|
||||||
@ -90,10 +90,10 @@ class FunctionManager {
|
|||||||
* Mark that a class has static initializer.
|
* Mark that a class has static initializer.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* the function name
|
* the "<clinit>" function name
|
||||||
*/
|
*/
|
||||||
void markClassWithCInit( FunctionName name ) {
|
void markClassWithClinit( FunctionName name ) {
|
||||||
classesWithCInit.put( name.className, name );
|
classesWithClinit.put( name.className, name );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -152,7 +152,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 = classesWithCInit.get( name.className );
|
FunctionName cInit = classesWithClinit.get( name.className );
|
||||||
if( cInit != null ) {
|
if( cInit != null ) {
|
||||||
markAsNeeded( cInit );
|
markAsNeeded( cInit );
|
||||||
}
|
}
|
||||||
@ -243,10 +243,23 @@ class FunctionManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all static constructor FunctionName of used classes.
|
||||||
|
*
|
||||||
|
* @return an iterator
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
Iterator<FunctionName> getWriteLaterClinit() {
|
||||||
|
return classesWithClinit.values().stream().filter( ( name ) -> {
|
||||||
|
FunctionState state = states.get( name );
|
||||||
|
return state != null && (state.state == State.Needed || state.state == State.Scanned);
|
||||||
|
} ).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all FunctionName that is required but was not written.
|
* Get all FunctionName that is required but was not written.
|
||||||
*
|
*
|
||||||
* @return the FunctionName or null
|
* @return an iterator
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Iterator<FunctionName> getWriteLater() {
|
Iterator<FunctionName> getWriteLater() {
|
||||||
|
@ -299,6 +299,9 @@ public class ModuleGenerator {
|
|||||||
javaScript.addImport( importModule, importName, importAnannotation );
|
javaScript.addImport( importModule, importName, importAnannotation );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add a start method for the static class constructors
|
||||||
|
prepareStartFunction();
|
||||||
|
|
||||||
// init/write the function types
|
// init/write the function types
|
||||||
for( Iterator<FunctionName> iterator = functions.getWriteLater(); iterator.hasNext(); ) {
|
for( Iterator<FunctionName> iterator = functions.getWriteLater(); iterator.hasNext(); ) {
|
||||||
FunctionName name = iterator.next();
|
FunctionName name = iterator.next();
|
||||||
@ -318,6 +321,39 @@ public class ModuleGenerator {
|
|||||||
writer.prepareFinish();
|
writer.prepareFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a start method for the static class constructors
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* if any I/O error occur
|
||||||
|
*/
|
||||||
|
private void prepareStartFunction() throws IOException {
|
||||||
|
// add the start function/section only if there are static code
|
||||||
|
Iterator<FunctionName> iterator = functions.getWriteLaterClinit();
|
||||||
|
if( iterator.hasNext() ) {
|
||||||
|
FunctionName cinit = new SyntheticFunctionName( "", "<clinit>", "()V" ) {
|
||||||
|
@Override
|
||||||
|
protected boolean hasWasmCode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) {
|
||||||
|
watParser.reset( null, null, getSignature( null ) );
|
||||||
|
|
||||||
|
while( iterator.hasNext() ) {
|
||||||
|
FunctionName name = iterator.next();
|
||||||
|
//TODO if not in the debug mode then inlining would produce smaller output and should be faster
|
||||||
|
watParser.addCallInstruction( name, 0, -1 );
|
||||||
|
}
|
||||||
|
return watParser;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
functions.markAsNeeded( cinit );
|
||||||
|
writeMethodSignature( cinit, FunctionType.Start, null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the code generation.
|
* Finish the code generation.
|
||||||
*
|
*
|
||||||
@ -405,7 +441,7 @@ public class ModuleGenerator {
|
|||||||
try {
|
try {
|
||||||
FunctionName name = new FunctionName( method );
|
FunctionName name = new FunctionName( method );
|
||||||
if( "<clinit>".equals( name.methodName ) ) {
|
if( "<clinit>".equals( name.methodName ) ) {
|
||||||
functions.markClassWithCInit( name );
|
functions.markClassWithClinit( name );
|
||||||
}
|
}
|
||||||
if( functions.isKnown( name ) ) {
|
if( functions.isKnown( name ) ) {
|
||||||
return;
|
return;
|
||||||
|
@ -329,8 +329,14 @@ public class TextModuleWriter extends ModuleWriter {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void writeMethodParamStart( @Nonnull FunctionName name, FunctionType funcType ) throws IOException {
|
protected void writeMethodParamStart( @Nonnull FunctionName name, FunctionType funcType ) throws IOException {
|
||||||
if( funcType == FunctionType.Abstract ) {
|
switch( funcType ) {
|
||||||
abstracts.put( name.signatureName, new Function() );
|
case Abstract:
|
||||||
|
abstracts.put( name.signatureName, new Function() );
|
||||||
|
break;
|
||||||
|
case Start:
|
||||||
|
newline( imports );
|
||||||
|
imports.append( "(start $" ).append( normalizeName( name ) ).append( ")" );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
typeOutput.setLength( 0 );
|
typeOutput.setLength( 0 );
|
||||||
methodParamNames.clear();
|
methodParamNames.clear();
|
||||||
|
@ -26,5 +26,7 @@ public enum FunctionType {
|
|||||||
/** has real code */
|
/** has real code */
|
||||||
Code,
|
Code,
|
||||||
/** abstract or interface, only used for indirrect call */
|
/** abstract or interface, only used for indirrect call */
|
||||||
Abstract;
|
Abstract,
|
||||||
|
/** the function of start section, should occur only once */
|
||||||
|
Start,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user