implement more Lambda stuff

This commit is contained in:
Volker Berlin 2021-01-23 22:16:16 +01:00
parent cde24d98ed
commit 3e42160655
4 changed files with 144 additions and 5 deletions

View File

@ -1,5 +1,5 @@
/*
Copyright 2020 Volker Berlin (i-net software)
Copyright 2020 - 2021 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -42,7 +42,11 @@ public class BootstrapMethod {
*/
private String instantiatedMethodType;
/**
* Create an instance.
*/
BootstrapMethod( DataInputStream input, ConstantPool constantPool ) throws IOException {
//TODO check that it is a known implementation type
int ref = input.readUnsignedShort();
//ConstantMethodRef method = (ConstantMethodRef)constantPool.get( ref ); // ever: java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
@ -53,4 +57,13 @@ public class BootstrapMethod {
implMethod = (ConstantMethodRef)constantPool.get( input.readUnsignedShort() );
instantiatedMethodType = (String)constantPool.get( input.readUnsignedShort() );
}
/**
* The real method in the parent class that implements the lambda expression
*
* @return the method
*/
public ConstantMethodRef getImplMethod() {
return implMethod;
}
}

View File

@ -631,10 +631,11 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
idx = byteCode.readUnsignedShort(); // ever zero
idx = dynamic.getBootstrapMethodIndex();
BootstrapMethod method = classFile.getBootstrapMethod( idx );
throw new WasmException( "InvokeDynamic/Lambda is not supported.", lineNumber );
//TODO break;
String name = dynamic.getType();
addInvokeDynamic( method, name, dynamic.getName(), codePos, lineNumber );
break;
case 187: // new
String name = ((ConstantClass)constantPool.get( byteCode.readUnsignedShort() )).getName();
name = ((ConstantClass)constantPool.get( byteCode.readUnsignedShort() )).getName();
addStructInstruction( StructOperator.NEW_DEFAULT, name, null, codePos, lineNumber );
break;
case 188: // newarray

View File

@ -357,6 +357,29 @@ public class TypeManager {
return type;
}
/**
* Create a lambda type
*
* @param typeName
* the name (className) of the lambda class
* @param interfaceType
* the implemented interface
* @param methodName
* the real method in the parent class that implements the lambda expression
* @param interfaceMethodName
* the name of the implemented method in the interface
* @return the type
*/
StructType lambdaType( String typeName, StructType interfaceType, FunctionName methodName, String interfaceMethodName ) {
StructType type = structTypes.get( typeName );
if( type == null ) {
type = new LambdaType( typeName, interfaceType, methodName, interfaceMethodName, this );
structTypes.put( typeName, type );
}
return type;
}
/**
* Create the FunctionName for a virtual call. The function has 2 parameters (THIS,
* virtualfunctionIndex) and returns the index of the function.
@ -506,7 +529,7 @@ public class TypeManager {
* @author Volker Berlin
*/
public static enum StructTypeKind {
primitive, normal, array, array_native;
primitive, normal, array, array_native, lambda;
}
/**
@ -602,6 +625,15 @@ public class TypeManager {
case array_native:
fields.add( new NamedStorageType( ((ArrayType)this).getArrayType(), null, null ) );
break;
case lambda:
allNeededFields = new HashSet<>();
listStructFields( "java/lang/Object", functions, types, classFileLoader, allNeededFields );
LambdaType lambda = (LambdaType)this;
List<FunctionName> iMethods = new ArrayList<>();
iMethods.add( lambda.getLambdaMethod() );
interfaceMethods.put( lambda.getInterfaceType(), iMethods );
functions.setITableIndex( new FunctionName( lambda.getInterfaceType().name, lambda.getInterfaceMethodName(), lambda.getLambdaMethod().signature ), 2 );
break;
default:
// add all interfaces to the instanceof set
listInterfaces( functions, types, classFileLoader );
@ -1029,4 +1061,64 @@ public class TypeManager {
return "$" + name;
}
}
/**
* A generated type that represent a lambda expression
*/
class LambdaType extends StructType {
private StructType interfaceType;
private FunctionName methodName;
private String interfaceMethodName;
/**
* Create a lambda type
*
* @param name
* the Java class name
* @param interfaceType
* the implemented interface type
* @param methodName
* the real method in the parent class that implements the lambda expression
* @param interfaceMethodName
* the name of the implemented method in the interface
* @param manager
* the manager which hold all StructTypes
*/
LambdaType( String name, StructType interfaceType, FunctionName methodName, String interfaceMethodName, TypeManager manager ) {
super( name, StructTypeKind.lambda, manager );
this.interfaceType = interfaceType;
this.methodName = methodName;
this.interfaceMethodName = interfaceMethodName;
}
/**
* The implemented interface type
*
* @return the interface type
*/
StructType getInterfaceType() {
return interfaceType;
}
/**
* The real method in the parent class that implements the lambda expression
*
* @return the function name
*/
FunctionName getLambdaMethod() {
return methodName;
}
/**
* The name of the implemented method in the interface
*
* @return the name
*/
String getInterfaceMethodName() {
return interfaceMethodName;
}
}
}

View File

@ -25,14 +25,17 @@ import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import de.inetsoftware.classparser.BootstrapMethod;
import de.inetsoftware.classparser.ClassFile;
import de.inetsoftware.classparser.ConstantClass;
import de.inetsoftware.classparser.ConstantMethodRef;
import de.inetsoftware.classparser.LocalVariableTable;
import de.inetsoftware.classparser.Member;
import de.inetsoftware.classparser.MethodInfo;
import de.inetsoftware.jwebassembly.WasmException;
import de.inetsoftware.jwebassembly.javascript.NonGC;
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue;
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;
@ -844,6 +847,36 @@ public abstract class WasmCodeBuilder {
}
}
/**
* Add invoke dynamic operation.
*
* @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
* <code>Runnable run = () -&gt; foo();</code>
* @param interfaceMethodName
* The simple name of the generated method of the single function interface.
* @param javaCodePos
* the code position/offset in the Java method
* @param lineNumber
* the line number in the Java source code
*/
protected void addInvokeDynamic( BootstrapMethod method, String factorySignature, String interfaceMethodName, int javaCodePos, int lineNumber ) {
ConstantMethodRef implMethod = method.getImplMethod();
FunctionName name = new FunctionName( implMethod );
functions.markAsNeeded( name );
String typeName = implMethod.getClassName() + "$$" + implMethod.getName() + "/";
ValueTypeParser parser = new ValueTypeParser( factorySignature, types );
while( parser.next() != null ) {
// skip parameters TODO
}
StructType interfaceType = (StructType)parser.next();
StructType type = types.lambdaType( typeName, interfaceType, name, interfaceMethodName );
addStructInstruction( StructOperator.NEW_DEFAULT, typeName, null, javaCodePos, lineNumber );
throw new WasmException( "InvokeDynamic/Lambda is not supported.", lineNumber );
}
/**
* Create an instance of a load/store to the linear memory instruction
*