mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +01:00
fix lambda expressions with field access
This commit is contained in:
parent
fbbbae0980
commit
024be2c50c
@ -395,22 +395,35 @@ public class TypeManager {
|
||||
*
|
||||
* @param method
|
||||
* the name BootstrapMethod from the parsed class file
|
||||
* @param params
|
||||
* the parameters of the constructor and type fields
|
||||
* @param interfaceType
|
||||
* the implemented interface
|
||||
* @param factorySignature
|
||||
* Get the signature of the factory method. For example "()Ljava.lang.Runnable;" for the lambda expression
|
||||
* <code>Runnable run = () -> foo();</code>
|
||||
* @param interfaceMethodName
|
||||
* the name of the implemented method in the interface
|
||||
* @param lineNumber
|
||||
* the line number in the Java source code
|
||||
* @return the type
|
||||
*/
|
||||
LambdaType lambdaType( @Nonnull BootstrapMethod method, ArrayList<AnyType> params, StructType interfaceType, String interfaceMethodName ) {
|
||||
LambdaType lambdaType( @Nonnull BootstrapMethod method, String factorySignature, String interfaceMethodName, int lineNumber ) {
|
||||
ConstantRef implMethod = method.getImplMethod();
|
||||
FunctionName methodName = new FunctionName( implMethod );
|
||||
FunctionName syntheticLambdaFunctionName = new FunctionName( implMethod );
|
||||
|
||||
Iterator<AnyType> parser = new ValueTypeParser( factorySignature, this );
|
||||
ArrayList<AnyType> params = new ArrayList<>();
|
||||
do {
|
||||
AnyType param = parser.next();
|
||||
if( param == null ) {
|
||||
break;
|
||||
}
|
||||
params.add( param );
|
||||
} while( true );
|
||||
StructType interfaceType = (StructType)parser.next();
|
||||
|
||||
String typeName = implMethod.getClassName() + "$$" + implMethod.getName() + "/" + Math.abs( implMethod.getName().hashCode() );
|
||||
|
||||
LambdaType type = (LambdaType)structTypes.get( typeName );
|
||||
if( type == null ) {
|
||||
type = new LambdaType( typeName, method, params, interfaceType, methodName, interfaceMethodName, this );
|
||||
type = new LambdaType( typeName, method, params, interfaceType, syntheticLambdaFunctionName, interfaceMethodName, this, lineNumber );
|
||||
|
||||
structTypes.put( typeName, type );
|
||||
}
|
||||
@ -1215,8 +1228,10 @@ public class TypeManager {
|
||||
* the name of the implemented method in the interface
|
||||
* @param manager
|
||||
* the manager which hold all StructTypes
|
||||
* @param lineNumber
|
||||
* the line number in the Java source code
|
||||
*/
|
||||
LambdaType( @Nonnull String name, @Nonnull BootstrapMethod method, ArrayList<AnyType> params, StructType interfaceType, FunctionName syntheticLambdaFunctionName, String interfaceMethodName, @Nonnull TypeManager manager ) {
|
||||
LambdaType( @Nonnull String name, @Nonnull BootstrapMethod method, ArrayList<AnyType> params, StructType interfaceType, FunctionName syntheticLambdaFunctionName, String interfaceMethodName, @Nonnull TypeManager manager, int lineNumber ) {
|
||||
super( name, StructTypeKind.lambda, manager );
|
||||
this.paramFields = new ArrayList<>( params.size() );
|
||||
for( int i = 0; i < params.size(); i++ ) {
|
||||
@ -1246,10 +1261,10 @@ public class TypeManager {
|
||||
}
|
||||
watParser.reset( null, null, sig.iterator() );
|
||||
|
||||
// first add the values from the Lambda constructor which is saves in the syntetic class
|
||||
// first add the values from the Lambda constructor which is saved in the synthetic class
|
||||
for( int i = 0; i < paramFields.size(); i++ ) {
|
||||
codebuilder.addLoadStoreInstruction( LambdaType.this, true, 0, 0, -1 );
|
||||
codebuilder.addStructInstruction( StructOperator.GET, name, paramFields.get( i ), 0, -1 );
|
||||
codebuilder.addStructInstruction( StructOperator.GET, name, paramFields.get( i ), 0, lineNumber );
|
||||
}
|
||||
|
||||
// forward the parameter from the current call without the THIS parameter because the call lambda method is static
|
||||
@ -1258,10 +1273,20 @@ public class TypeManager {
|
||||
if( anyType == null ) {
|
||||
break;
|
||||
}
|
||||
codebuilder.addLoadStoreInstruction( anyType, true, i, 0, -1 );
|
||||
codebuilder.addLoadStoreInstruction( anyType, true, i, 0, lineNumber );
|
||||
}
|
||||
|
||||
codebuilder.addCallInstruction( syntheticLambdaFunctionName, false, 0, -1 );
|
||||
boolean needThisParameter = false;
|
||||
try {
|
||||
// a lambda expression function is mostly static else it need access to field.
|
||||
ClassFile classFile = classFileLoader.get( syntheticLambdaFunctionName.className );
|
||||
MethodInfo methodInfo = classFile.getMethod( syntheticLambdaFunctionName.methodName, syntheticLambdaFunctionName.signature );
|
||||
needThisParameter = !methodInfo.isStatic();
|
||||
} catch( Exception ex ) {
|
||||
throw WasmException.create( ex, null, syntheticLambdaFunctionName.className, syntheticLambdaFunctionName.methodName, lineNumber );
|
||||
}
|
||||
|
||||
codebuilder.addCallInstruction( syntheticLambdaFunctionName, needThisParameter, 0, lineNumber );
|
||||
return watParser;
|
||||
}
|
||||
};
|
||||
|
@ -36,7 +36,6 @@ import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.javascript.NonGC;
|
||||
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.LambdaType;
|
||||
import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
|
||||
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
|
||||
@ -650,13 +649,14 @@ public abstract class WasmCodeBuilder {
|
||||
*
|
||||
* @param name
|
||||
* the function name that should be called
|
||||
* @param needThisParameter true, if the hidden THIS parameter is needed, If it is an instance method call.
|
||||
* @param needThisParameter
|
||||
* true, if the hidden THIS parameter is needed, If it is an instance method call.
|
||||
* @param javaCodePos
|
||||
* the code position/offset in the Java method
|
||||
* @param lineNumber
|
||||
* the line number in the Java source code
|
||||
*/
|
||||
protected void addCallInstruction( FunctionName name, boolean needThisParameter, int javaCodePos, int lineNumber ) {
|
||||
protected void addCallInstruction( @Nonnull FunctionName name, boolean needThisParameter, int javaCodePos, int lineNumber ) {
|
||||
name = functions.markAsNeeded( name, needThisParameter );
|
||||
WasmCallInstruction instruction = new WasmCallInstruction( name, javaCodePos, lineNumber, types, needThisParameter );
|
||||
|
||||
@ -970,7 +970,7 @@ public abstract class WasmCodeBuilder {
|
||||
* @param method
|
||||
* the BootstrapMethod, described the method that should be executed
|
||||
* @param factorySignature
|
||||
* Get the signature of the factory method. For example "()Ljava.lang.Runnable;" for the lamba expression
|
||||
* Get the signature of the factory method. For example "()Ljava.lang.Runnable;" for the lambda expression
|
||||
* <code>Runnable run = () -> foo();</code>
|
||||
* @param interfaceMethodName
|
||||
* The simple name of the generated method of the single function interface.
|
||||
@ -981,17 +981,7 @@ public abstract class WasmCodeBuilder {
|
||||
*/
|
||||
protected void addInvokeDynamic( BootstrapMethod method, String factorySignature, String interfaceMethodName, int javaCodePos, int lineNumber ) {
|
||||
// Create the synthetic lambda class that hold the lambda expression.
|
||||
ValueTypeParser parser = new ValueTypeParser( factorySignature, types );
|
||||
ArrayList<AnyType> params = new ArrayList<>();
|
||||
do {
|
||||
AnyType param = parser.next();
|
||||
if( param == null ) {
|
||||
break;
|
||||
}
|
||||
params.add( param );
|
||||
} while( true );
|
||||
StructType interfaceType = (StructType)parser.next();
|
||||
LambdaType type = types.lambdaType( method, params, interfaceType, interfaceMethodName );
|
||||
LambdaType type = types.lambdaType( method, factorySignature, interfaceMethodName, lineNumber );
|
||||
functions.markAsNeeded( type.getLambdaMethod(), true );
|
||||
String lambdaTypeName = type.getName();
|
||||
|
||||
|
@ -76,6 +76,7 @@ public class StructsNonGC extends AbstractBaseTest {
|
||||
addParam( list, script, "lambda1" );
|
||||
addParam( list, script, "lambda2" );
|
||||
addParam( list, script, "lambda3" );
|
||||
addParam( list, script, "lambdaWithInstanceAccess" );
|
||||
addParam( list, script, "simpleName_Object" );
|
||||
addParam( list, script, "simpleName_Anonymous" );
|
||||
addParam( list, script, "simpleName_Array" );
|
||||
@ -336,6 +337,18 @@ public class StructsNonGC extends AbstractBaseTest {
|
||||
return val.applyAsDouble( 13 );
|
||||
}
|
||||
|
||||
@Export
|
||||
public static int lambdaWithInstanceAccess() {
|
||||
TestClass test = new TestClass();
|
||||
return test.lambdaWithInstanceAccessImpl();
|
||||
}
|
||||
private int field;
|
||||
private int lambdaWithInstanceAccessImpl() {
|
||||
field = 13;
|
||||
IntSupplier val = () -> field;
|
||||
return val.getAsInt();
|
||||
}
|
||||
|
||||
@Export
|
||||
static boolean isPrimitive_int() {
|
||||
return int.class.isPrimitive();
|
||||
|
Loading…
x
Reference in New Issue
Block a user