mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
call class initializer before access to static fields
This commit is contained in:
parent
710127bb44
commit
69b8db16d1
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import static de.inetsoftware.jwebassembly.module.WasmCodeBuilder.CLASS_INIT;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
@ -42,10 +44,10 @@ class FunctionManager {
|
|||||||
|
|
||||||
private final Set<String> usedClasses = new LinkedHashSet<>();
|
private final Set<String> usedClasses = new LinkedHashSet<>();
|
||||||
|
|
||||||
private boolean isFinish;
|
private boolean isFinish;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finish the prepare. Now no new function should be added.
|
* Finish the prepare. Now no new function should be added.
|
||||||
*/
|
*/
|
||||||
void prepareFinish() {
|
void prepareFinish() {
|
||||||
isFinish = true;
|
isFinish = true;
|
||||||
@ -108,8 +110,8 @@ class FunctionManager {
|
|||||||
* @param importAnannotation
|
* @param importAnannotation
|
||||||
* the annotation of the import
|
* the annotation of the import
|
||||||
*/
|
*/
|
||||||
void markAsImport( @Nonnull FunctionName name, Map<String,Object> importAnannotation ) {
|
void markAsImport( @Nonnull FunctionName name, Map<String, Object> importAnannotation ) {
|
||||||
markAsImport( name, (key) -> importAnannotation.get( key ) );
|
markAsImport( name, ( key ) -> importAnannotation.get( key ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -121,7 +123,7 @@ class FunctionManager {
|
|||||||
* @param importAnannotation
|
* @param importAnannotation
|
||||||
* the annotation of the import
|
* the annotation of the import
|
||||||
*/
|
*/
|
||||||
void markAsImport( @Nonnull FunctionName name, Function<String,Object> importAnannotation ) {
|
void markAsImport( @Nonnull FunctionName name, Function<String, Object> importAnannotation ) {
|
||||||
getOrCreate( name ).importAnannotation = importAnannotation;
|
getOrCreate( name ).importAnannotation = importAnannotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +262,7 @@ class FunctionManager {
|
|||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
Iterator<FunctionName> getWriteLaterClinit() {
|
Iterator<FunctionName> getWriteLaterClinit() {
|
||||||
return iterator( entry -> entry.getKey().methodName.equals( "<clinit>" ) && entry.getValue().state != State.None );
|
return iterator( entry -> entry.getKey().methodName.equals( CLASS_INIT ) && entry.getValue().state != State.None );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -299,7 +301,9 @@ class FunctionManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* get a iterator for function names
|
* get a iterator for function names
|
||||||
* @param filter the filter
|
*
|
||||||
|
* @param filter
|
||||||
|
* the filter
|
||||||
* @return the iterator
|
* @return the iterator
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@ -448,7 +452,7 @@ class FunctionManager {
|
|||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* the name
|
* the name
|
||||||
* @return the index in the itable
|
* @return the index in the itable
|
||||||
*/
|
*/
|
||||||
int getITableIndex( @Nonnull FunctionName name ) {
|
int getITableIndex( @Nonnull FunctionName name ) {
|
||||||
return getOrCreate( name ).itableIdx;
|
return getOrCreate( name ).itableIdx;
|
||||||
@ -458,7 +462,7 @@ class FunctionManager {
|
|||||||
* State of a function/method
|
* State of a function/method
|
||||||
*/
|
*/
|
||||||
private static class FunctionState {
|
private static class FunctionState {
|
||||||
private State state = State.None;
|
private State state = State.None;
|
||||||
|
|
||||||
private MethodInfo method;
|
private MethodInfo method;
|
||||||
|
|
||||||
|
@ -85,13 +85,13 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
reset( code.getLocalVariableTable(), method, null );
|
reset( code.getLocalVariableTable(), method, null );
|
||||||
branchManager.reset( code );
|
branchManager.reset( code );
|
||||||
|
|
||||||
if( "<clinit>".equals( method.getName() ) ) {
|
if( CLASS_INIT.equals( method.getName() ) ) {
|
||||||
// Add a hook to run the class/static constructor only once
|
// Add a hook to run the class/static constructor only once
|
||||||
FunctionName name = new FunctionName( method.getClassName(), "<clisinit>", "" );
|
FunctionName name = new FunctionName( method.getClassName(), "<class_isInit>", "" );
|
||||||
addGlobalInstruction( true, name, ValueType.i32, -1, -1 );
|
addGlobalInstruction( true, name, ValueType.i32, null, -1, -1 );
|
||||||
addBlockInstruction( WasmBlockOperator.BR_IF, 0, -1, -1 );
|
addBlockInstruction( WasmBlockOperator.BR_IF, 0, -1, -1 );
|
||||||
addConstInstruction( 1, ValueType.i32, -1, -1 );
|
addConstInstruction( 1, ValueType.i32, -1, -1 );
|
||||||
addGlobalInstruction( false, name, ValueType.i32, -1, -1 );
|
addGlobalInstruction( false, name, ValueType.i32, null, -1, -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
byteCode = code.getByteCode();
|
byteCode = code.getByteCode();
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import static de.inetsoftware.jwebassembly.module.WasmCodeBuilder.CLASS_INIT;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -387,7 +389,7 @@ public class ModuleGenerator {
|
|||||||
String className = iterator.next();
|
String className = iterator.next();
|
||||||
ClassFile classFile = classFileLoader.get( className );
|
ClassFile classFile = classFileLoader.get( className );
|
||||||
if( classFile != null ) {
|
if( classFile != null ) {
|
||||||
MethodInfo method = classFile.getMethod( "<clinit>", "()V" );
|
MethodInfo method = classFile.getMethod( CLASS_INIT, "()V" );
|
||||||
if( method != null ) {
|
if( method != null ) {
|
||||||
functions.markAsNeeded( new FunctionName( method ), false );
|
functions.markAsNeeded( new FunctionName( method ), false );
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.inetsoftware.jwebassembly.module;
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import static de.inetsoftware.jwebassembly.module.WasmCodeBuilder.CONSTRUCTOR;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
@ -58,38 +60,39 @@ import de.inetsoftware.jwebassembly.watparser.WatParser;
|
|||||||
*/
|
*/
|
||||||
public class TypeManager {
|
public class TypeManager {
|
||||||
|
|
||||||
/** name of virtual function table, start with a point for an invalid Java identifier */
|
/** name of virtual function table, start with a point for an invalid Java identifier */
|
||||||
static final String FIELD_VTABLE = ".vtable";
|
static final String FIELD_VTABLE = ".vtable";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of field with system hash code, start with a point for an invalid Java identifier.
|
* Name of field with system hash code, start with a point for an invalid Java identifier.
|
||||||
*/
|
*/
|
||||||
static final String FIELD_HASHCODE = ".hashcode";
|
static final String FIELD_HASHCODE = ".hashcode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of field with array value.
|
* Name of field with array value.
|
||||||
*/
|
*/
|
||||||
public static final String FIELD_VALUE = ".array";
|
public static final String FIELD_VALUE = ".array";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Byte position in the type description that contains the offset to the interfaces. Length 4 bytes.
|
* Byte position in the type description that contains the offset to the interfaces. Length 4 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int TYPE_DESCRIPTION_INTERFACE_OFFSET = 0;
|
public static final int TYPE_DESCRIPTION_INTERFACE_OFFSET = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Byte position in the type description that contains the offset to the instanceof list. Length 4 bytes.
|
* Byte position in the type description that contains the offset to the instanceof list. Length 4 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int TYPE_DESCRIPTION_INSTANCEOF_OFFSET = 4;
|
public static final int TYPE_DESCRIPTION_INSTANCEOF_OFFSET = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Byte position in the type description that contains the offset to class name idx in the string constant table. Length 4 bytes.
|
* Byte position in the type description that contains the offset to class name idx in the string constant table.
|
||||||
|
* Length 4 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int TYPE_DESCRIPTION_TYPE_NAME = 8;
|
public static final int TYPE_DESCRIPTION_TYPE_NAME = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Byte position in the type description that contains the type of the array (component type). Length 4 bytes.
|
* Byte position in the type description that contains the type of the array (component type). Length 4 bytes.
|
||||||
*/
|
*/
|
||||||
public static final int TYPE_DESCRIPTION_ARRAY_TYPE = 12;
|
public static final int TYPE_DESCRIPTION_ARRAY_TYPE = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reserved position on start of the vtable:
|
* The reserved position on start of the vtable:
|
||||||
@ -97,73 +100,74 @@ public class TypeManager {
|
|||||||
* <li>offset of instanceof list
|
* <li>offset of instanceof list
|
||||||
* <li>offset of class name idx in the string constant table
|
* <li>offset of class name idx in the string constant table
|
||||||
*/
|
*/
|
||||||
private static final int VTABLE_FIRST_FUNCTION_INDEX = 4;
|
private static final int VTABLE_FIRST_FUNCTION_INDEX = 4;
|
||||||
|
|
||||||
private static final FunctionName CLASS_CONSTANT_FUNCTION = new FunctionName( "java/lang/Class.classConstant(I)Ljava/lang/Class;" );
|
private static final FunctionName CLASS_CONSTANT_FUNCTION = new FunctionName( "java/lang/Class.classConstant(I)Ljava/lang/Class;" );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int BOOLEAN = 0;
|
public static final int BOOLEAN = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int BYTE = 1;
|
public static final int BYTE = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int CHAR = 2;
|
public static final int CHAR = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int DOUBLE = 3;
|
public static final int DOUBLE = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int FLOAT = 4;
|
public static final int FLOAT = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int INT = 5;
|
public static final int INT = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int LONG = 6;
|
public static final int LONG = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int SHORT = 7;
|
public static final int SHORT = 7;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type id of primitive class
|
* Type id of primitive class
|
||||||
*/
|
*/
|
||||||
public static final int VOID = 8;
|
public static final int VOID = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the list of primitive types. The order is important and must correlate with getPrimitiveClass.
|
* the list of primitive types. The order is important and must correlate with getPrimitiveClass.
|
||||||
*
|
*
|
||||||
* @see ReplacementForClass#getPrimitiveClass(String)
|
* @see ReplacementForClass#getPrimitiveClass(String)
|
||||||
*/
|
*/
|
||||||
private static final String[] PRIMITIVE_CLASSES = { "boolean", "byte", "char", "double", "float", "int", "long", "short", "void" };
|
private static final String[] PRIMITIVE_CLASSES =
|
||||||
|
{ "boolean", "byte", "char", "double", "float", "int", "long", "short", "void" };
|
||||||
|
|
||||||
private final Map<Object, StructType> structTypes = new LinkedHashMap<>();
|
private final Map<Object, StructType> structTypes = new LinkedHashMap<>();
|
||||||
|
|
||||||
private final Map<BlockType, BlockType> blockTypes = new LinkedHashMap<>();
|
private final Map<BlockType, BlockType> blockTypes = new LinkedHashMap<>();
|
||||||
|
|
||||||
private int typeIndexCounter;
|
private int typeIndexCounter;
|
||||||
|
|
||||||
private boolean isFinish;
|
private boolean isFinish;
|
||||||
|
|
||||||
final WasmOptions options;
|
final WasmOptions options;
|
||||||
|
|
||||||
private int typeTableOffset;
|
private int typeTableOffset;
|
||||||
|
|
||||||
private ClassFileLoader classFileLoader;
|
private ClassFileLoader classFileLoader;
|
||||||
|
|
||||||
@ -179,7 +183,9 @@ public class TypeManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the type manager
|
* Initialize the type manager
|
||||||
* @param classFileLoader for loading the class files
|
*
|
||||||
|
* @param classFileLoader
|
||||||
|
* for loading the class files
|
||||||
*/
|
*/
|
||||||
void init( ClassFileLoader classFileLoader ) {
|
void init( ClassFileLoader classFileLoader ) {
|
||||||
this.classFileLoader = classFileLoader;
|
this.classFileLoader = classFileLoader;
|
||||||
@ -260,6 +266,7 @@ public class TypeManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the function name to get a constant class.
|
* Get the function name to get a constant class.
|
||||||
|
*
|
||||||
* @return the function
|
* @return the function
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@ -424,8 +431,8 @@ public class TypeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the FunctionName for a virtual call. The function has 2 parameters (THIS,
|
* Create the FunctionName for a virtual call. The function has 2 parameters (THIS, virtualfunctionIndex) and
|
||||||
* virtualfunctionIndex) and returns the index of the function.
|
* returns the index of the function.
|
||||||
*
|
*
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
@ -453,7 +460,7 @@ public class TypeManager {
|
|||||||
static int callInterface( OBJECT THIS, int classIndex, int virtualfunctionIndex ) {
|
static int callInterface( OBJECT THIS, int classIndex, int virtualfunctionIndex ) {
|
||||||
int table = THIS.vtable;
|
int table = THIS.vtable;
|
||||||
table += i32_load[table];
|
table += i32_load[table];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int nextClass = i32_load[table];
|
int nextClass = i32_load[table];
|
||||||
if( nextClass == classIndex ) {
|
if( nextClass == classIndex ) {
|
||||||
@ -476,8 +483,7 @@ public class TypeManager {
|
|||||||
+ "local.set 3 " // save $table, the itable start location
|
+ "local.set 3 " // save $table, the itable start location
|
||||||
+ "loop" //
|
+ "loop" //
|
||||||
+ " local.get 3" // get $table
|
+ " local.get 3" // get $table
|
||||||
+ " i32.load offset=0 align=4"
|
+ " i32.load offset=0 align=4" + " local.tee 4" // save $nextClass
|
||||||
+ " local.tee 4" // save $nextClass
|
|
||||||
+ " local.get 1" // get $classIndex
|
+ " local.get 1" // get $classIndex
|
||||||
+ " i32.eq" //
|
+ " i32.eq" //
|
||||||
+ " if" // $nextClass == $classIndex
|
+ " if" // $nextClass == $classIndex
|
||||||
@ -587,30 +593,30 @@ public class TypeManager {
|
|||||||
*/
|
*/
|
||||||
public static class StructType implements AnyType {
|
public static class StructType implements AnyType {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private final StructTypeKind kind;
|
private final StructTypeKind kind;
|
||||||
|
|
||||||
private final TypeManager manager;
|
private final TypeManager manager;
|
||||||
|
|
||||||
private final int classIndex;
|
private final int classIndex;
|
||||||
|
|
||||||
private int code = Integer.MAX_VALUE;
|
private int code = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private HashSet<String> neededFields = new HashSet<>();
|
private HashSet<String> neededFields = new HashSet<>();
|
||||||
|
|
||||||
private List<NamedStorageType> fields;
|
private List<NamedStorageType> fields;
|
||||||
|
|
||||||
private List<FunctionName> vtable;
|
private List<FunctionName> vtable;
|
||||||
|
|
||||||
private Set<StructType> instanceOFs;
|
private Set<StructType> instanceOFs;
|
||||||
|
|
||||||
private Map<StructType,List<FunctionName>> interfaceMethods;
|
private Map<StructType, List<FunctionName>> interfaceMethods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The offset to the vtable in the data section.
|
* The offset to the vtable in the data section.
|
||||||
*/
|
*/
|
||||||
private int vtableOffset;
|
private int vtableOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a reference to type
|
* Create a reference to type
|
||||||
@ -770,7 +776,7 @@ public class TypeManager {
|
|||||||
|
|
||||||
// calculate the vtable (the function indexes of the virtual methods)
|
// calculate the vtable (the function indexes of the virtual methods)
|
||||||
for( MethodInfo method : classFile.getMethods() ) {
|
for( MethodInfo method : classFile.getMethods() ) {
|
||||||
if( method.isStatic() || "<init>".equals( method.getName() ) ) {
|
if( method.isStatic() || CONSTRUCTOR.equals( method.getName() ) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
FunctionName funcName = new FunctionName( method );
|
FunctionName funcName = new FunctionName( method );
|
||||||
@ -1017,6 +1023,7 @@ public class TypeManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get kind of the StructType
|
* Get kind of the StructType
|
||||||
|
*
|
||||||
* @return the type kind
|
* @return the type kind
|
||||||
*/
|
*/
|
||||||
public StructTypeKind getKind() {
|
public StructTypeKind getKind() {
|
||||||
@ -1025,6 +1032,7 @@ public class TypeManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the Java type
|
* Get the name of the Java type
|
||||||
|
*
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@ -1051,6 +1059,7 @@ public class TypeManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the fields of this struct
|
* Get the fields of this struct
|
||||||
|
*
|
||||||
* @return the fields
|
* @return the fields
|
||||||
*/
|
*/
|
||||||
public List<NamedStorageType> getFields() {
|
public List<NamedStorageType> getFields() {
|
||||||
@ -1189,7 +1198,7 @@ public class TypeManager {
|
|||||||
super( name, StructTypeKind.lambda, manager );
|
super( name, StructTypeKind.lambda, manager );
|
||||||
this.paramFields = new ArrayList<>( params.size() );
|
this.paramFields = new ArrayList<>( params.size() );
|
||||||
for( int i = 0; i < params.size(); i++ ) {
|
for( int i = 0; i < params.size(); i++ ) {
|
||||||
paramFields.add( new NamedStorageType( params.get( i ), "", "arg$" + (i+1) ) );
|
paramFields.add( new NamedStorageType( params.get( i ), "", "arg$" + (i + 1) ) );
|
||||||
}
|
}
|
||||||
this.interfaceType = interfaceType;
|
this.interfaceType = interfaceType;
|
||||||
this.interfaceMethodName = interfaceMethodName;
|
this.interfaceMethodName = interfaceMethodName;
|
||||||
@ -1199,10 +1208,12 @@ public class TypeManager {
|
|||||||
protected boolean hasWasmCode() {
|
protected boolean hasWasmCode() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean istStatic() {
|
protected boolean istStatic() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) {
|
protected WasmCodeBuilder getCodeBuilder( WatParser watParser ) {
|
||||||
WasmCodeBuilder codebuilder = watParser;
|
WasmCodeBuilder codebuilder = watParser;
|
||||||
@ -1290,12 +1301,15 @@ public class TypeManager {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final List<AnyType> params;
|
private final List<AnyType> params;
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final List<AnyType> results;
|
private final List<AnyType> results;
|
||||||
private int code;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
public BlockType(List<AnyType> params, List<AnyType> results) {
|
private int code;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public BlockType( List<AnyType> params, List<AnyType> results ) {
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.results = results;
|
this.results = results;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,12 @@ import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
|
|||||||
*/
|
*/
|
||||||
public abstract class WasmCodeBuilder {
|
public abstract class WasmCodeBuilder {
|
||||||
|
|
||||||
|
/** Java method name of of constructor */
|
||||||
|
static final String CONSTRUCTOR = "<init>";
|
||||||
|
|
||||||
|
/** Java method name of static constructor or initialization method */
|
||||||
|
static final String CLASS_INIT = "<clinit>";
|
||||||
|
|
||||||
private final LocaleVariableManager localVariables;
|
private final LocaleVariableManager localVariables;
|
||||||
|
|
||||||
private final List<WasmInstruction> instructions;
|
private final List<WasmInstruction> instructions;
|
||||||
@ -497,7 +503,16 @@ public abstract class WasmCodeBuilder {
|
|||||||
protected void addGlobalInstruction( boolean load, Member ref, int javaCodePos, int lineNumber ) {
|
protected void addGlobalInstruction( boolean load, Member ref, int javaCodePos, int lineNumber ) {
|
||||||
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();
|
||||||
addGlobalInstruction( load, name, type, javaCodePos, lineNumber );
|
FunctionName clinit;
|
||||||
|
if( load ) {
|
||||||
|
clinit = new FunctionName( name.className, CLASS_INIT, "()V" );
|
||||||
|
if( !functions.isUsed( clinit ) ) {
|
||||||
|
clinit = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
clinit = null;
|
||||||
|
}
|
||||||
|
addGlobalInstruction( load, name, type, clinit, javaCodePos, lineNumber );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -514,8 +529,8 @@ public abstract class WasmCodeBuilder {
|
|||||||
* @param lineNumber
|
* @param lineNumber
|
||||||
* the line number in the Java source code
|
* the line number in the Java source code
|
||||||
*/
|
*/
|
||||||
protected void addGlobalInstruction( boolean load, FunctionName name, AnyType type, int javaCodePos, int lineNumber ) {
|
protected void addGlobalInstruction( boolean load, FunctionName name, AnyType type, FunctionName clinit, int javaCodePos, int lineNumber ) {
|
||||||
instructions.add( new WasmGlobalInstruction( load, name, type, javaCodePos, lineNumber ) );
|
instructions.add( new WasmGlobalInstruction( load, name, type, clinit, javaCodePos, lineNumber ) );
|
||||||
functions.markClassAsUsed( name.className );
|
functions.markClassAsUsed( name.className );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -655,7 +670,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
name = functions.markAsNeeded( name, needThisParameter );
|
name = functions.markAsNeeded( name, needThisParameter );
|
||||||
WasmCallInstruction instruction = new WasmCallInstruction( name, javaCodePos, lineNumber, types, needThisParameter );
|
WasmCallInstruction instruction = new WasmCallInstruction( name, javaCodePos, lineNumber, types, needThisParameter );
|
||||||
|
|
||||||
if( "<init>".equals( name.methodName ) ) {
|
if( CONSTRUCTOR.equals( name.methodName ) ) {
|
||||||
// check if there a factory for the constructor in JavaScript then we need to do some more complex patching
|
// check if there a factory for the constructor in JavaScript then we need to do some more complex patching
|
||||||
Function<String, Object> importAnannotation = functions.getImportAnannotation( name );
|
Function<String, Object> importAnannotation = functions.getImportAnannotation( name );
|
||||||
FunctionName factoryName = null;
|
FunctionName factoryName = null;
|
||||||
@ -667,7 +682,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
factoryName = new ImportSyntheticFunctionName( "String", "init", signature, importAnannotation );
|
factoryName = new ImportSyntheticFunctionName( "String", "init", signature, importAnannotation );
|
||||||
} else {
|
} else {
|
||||||
MethodInfo replace = functions.replace( name, null );
|
MethodInfo replace = functions.replace( name, null );
|
||||||
if( replace != null && !"<init>".equals( replace.getName() ) ) {
|
if( replace != null && !CONSTRUCTOR.equals( replace.getName() ) ) {
|
||||||
// the constructor was replaced with a factory method. Typical this method called then a JavaScript replacement
|
// the constructor was replaced with a factory method. Typical this method called then a JavaScript replacement
|
||||||
factoryName = new FunctionName( replace );
|
factoryName = new FunctionName( replace );
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2018 - 2021 Volker Berlin (i-net software)
|
Copyright 2018 - 2022 Volker Berlin (i-net software)
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -19,6 +19,7 @@ package de.inetsoftware.jwebassembly.module;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||||
|
|
||||||
@ -30,11 +31,13 @@ import de.inetsoftware.jwebassembly.wasm.AnyType;
|
|||||||
*/
|
*/
|
||||||
class WasmGlobalInstruction extends WasmInstruction {
|
class WasmGlobalInstruction extends WasmInstruction {
|
||||||
|
|
||||||
private boolean load;
|
private boolean load;
|
||||||
|
|
||||||
private FunctionName name;
|
private FunctionName name;
|
||||||
|
|
||||||
private AnyType type;
|
private AnyType type;
|
||||||
|
|
||||||
|
private FunctionName clinit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of a load/store instruction
|
* Create an instance of a load/store instruction
|
||||||
@ -45,16 +48,19 @@ class WasmGlobalInstruction extends WasmInstruction {
|
|||||||
* the name of the static field
|
* the name of the static field
|
||||||
* @param type
|
* @param type
|
||||||
* the type of the static field
|
* the type of the static field
|
||||||
|
* @param clinit
|
||||||
|
* a reference to the class/static constructor which should executed before access a static field
|
||||||
* @param javaCodePos
|
* @param javaCodePos
|
||||||
* the code position/offset in the Java method
|
* the code position/offset in the Java method
|
||||||
* @param lineNumber
|
* @param lineNumber
|
||||||
* the line number in the Java source code
|
* the line number in the Java source code
|
||||||
*/
|
*/
|
||||||
WasmGlobalInstruction( boolean load, @Nonnull FunctionName name, AnyType type, int javaCodePos, int lineNumber ) {
|
WasmGlobalInstruction( boolean load, @Nonnull FunctionName name, AnyType type, @Nullable FunctionName clinit, int javaCodePos, int lineNumber ) {
|
||||||
super( javaCodePos, lineNumber );
|
super( javaCodePos, lineNumber );
|
||||||
this.load = load;
|
this.load = load;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.clinit = clinit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,6 +86,9 @@ class WasmGlobalInstruction extends WasmInstruction {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void writeTo( @Nonnull ModuleWriter writer ) throws IOException {
|
public void writeTo( @Nonnull ModuleWriter writer ) throws IOException {
|
||||||
|
if( clinit != null ) {
|
||||||
|
writer.writeFunctionCall( clinit, clinit.signatureName );
|
||||||
|
}
|
||||||
writer.writeGlobalAccess( load, name, type );
|
writer.writeGlobalAccess( load, name, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user