forked from JavaTX/JavaCompilerCore
Bytecode fuer Lambdas in denen Variablen von lexical scope verwendet werden
This commit is contained in:
parent
7bfc222037
commit
5c74c69b9e
@ -46,7 +46,8 @@ public class BytecodeGen implements ASTVisitor {
|
||||
ClassWriter cw =new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
|
||||
|
||||
String type;
|
||||
|
||||
|
||||
public static RefTypeOrTPHOrWildcardOrGeneric THISTYPE = null;
|
||||
String className;
|
||||
private boolean isInterface;
|
||||
private List<ResultSet> listOfResultSets;
|
||||
|
@ -109,7 +109,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
|
||||
}
|
||||
|
||||
public BytecodeGenMethod(LambdaExpression lambdaExpression, ResultSet resultSet, MethodVisitor mv,
|
||||
public BytecodeGenMethod(LambdaExpression lambdaExpression, ArrayList<String> usedVars, ResultSet resultSet, MethodVisitor mv,
|
||||
int indexOfFirstParamLam, boolean isInterface, HashMap<String, byte[]> classFiles, String path, int lamCounter, SourceFile sf) {
|
||||
|
||||
this.resultSet = resultSet;
|
||||
@ -121,6 +121,12 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
this.sf = sf;
|
||||
Iterator<FormalParameter> itr = lambdaExpression.params.iterator();
|
||||
int i = indexOfFirstParamLam;
|
||||
|
||||
for(String var : usedVars) {
|
||||
this.paramsAndLocals.put(var, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
while (itr.hasNext()) {
|
||||
FormalParameter fp = itr.next();
|
||||
this.paramsAndLocals.put(fp.getName(), i);
|
||||
@ -520,7 +526,7 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
@Override
|
||||
public void visit(LambdaExpression lambdaExpression) {
|
||||
this.lamCounter++;
|
||||
|
||||
|
||||
String typeErasure = "(";
|
||||
Iterator<FormalParameter> itr = lambdaExpression.params.iterator();
|
||||
while (itr.hasNext()) {
|
||||
@ -560,16 +566,31 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
this.kindOfLambda = new KindOfLambda(lambdaExpression);
|
||||
|
||||
if (kindOfLambda.isInstanceCapturingLambda()) {
|
||||
// if(!kindOfLambda.getArgumentList().contains(BytecodeGen.THISTYPE))
|
||||
// kindOfLambda.getArgumentList().add(0, BytecodeGen.THISTYPE);
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
for(String v : kindOfLambda.getUsedVars()) {
|
||||
mv.visitVarInsn(Opcodes.ALOAD, paramsAndLocals.get(v));
|
||||
}
|
||||
staticOrSpecial = Opcodes.H_INVOKESPECIAL;
|
||||
indexOfFirstParamLam = 1;
|
||||
} else {
|
||||
staticOrSpecial = Opcodes.H_INVOKESTATIC;
|
||||
staticOrInstance = Opcodes.ACC_STATIC;
|
||||
}
|
||||
|
||||
String newDesc = "(";
|
||||
int pos = 0;
|
||||
if(kindOfLambda.isHasThis()) {
|
||||
pos = 1;
|
||||
}
|
||||
|
||||
for(int i=pos;i<kindOfLambda.getArgumentList().size();i++) {
|
||||
String t = "L" + getResolvedType(kindOfLambda.getArgumentList().get(i)) + ";";
|
||||
newDesc += t;
|
||||
}
|
||||
newDesc += lamDesc.substring(1);
|
||||
// first check if capturing lambda then invokestatic or invokespecial
|
||||
Handle arg2 = new Handle(staticOrSpecial, this.className, methodName, arg3.toString(), false);
|
||||
Handle arg2 = new Handle(staticOrSpecial, this.className, methodName, newDesc, false);
|
||||
// Descriptor of functional interface methode
|
||||
SamMethod samMethod = new SamMethod(kindOfLambda.getArgumentList(), lambdaExpression.getType());
|
||||
// Desc: (this/nothing)TargetType
|
||||
@ -577,9 +598,11 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
mv.visitInvokeDynamicInsn("apply", fiMethodDesc, bootstrap, arg1, arg2, arg3);
|
||||
|
||||
MethodVisitor mvLambdaBody = cw.visitMethod(Opcodes.ACC_PRIVATE + staticOrInstance + Opcodes.ACC_SYNTHETIC,
|
||||
methodName, arg3.toString(), null, null);
|
||||
|
||||
new BytecodeGenMethod(lambdaExpression, this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface,
|
||||
methodName, newDesc, null, null);
|
||||
|
||||
ArrayList<String> usedVars = kindOfLambda.getUsedVars();
|
||||
|
||||
new BytecodeGenMethod(lambdaExpression, usedVars,this.resultSet, mvLambdaBody, indexOfFirstParamLam, isInterface,
|
||||
classFiles,this.path, lamCounter, sf);
|
||||
|
||||
mvLambdaBody.visitMaxs(0, 0);
|
||||
@ -654,7 +677,10 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
if (!fieldVar.receiver.getClass().equals(StaticClassName.class)) {
|
||||
mv.visitFieldInsn(Opcodes.GETFIELD, getResolvedType(fieldVar.receiver.getType()), fieldName, fieldDesc);
|
||||
}
|
||||
|
||||
|
||||
if (isBinaryExp) {
|
||||
doUnboxing(getResolvedType(fieldVar.getType()));
|
||||
}
|
||||
// mv.visitFieldInsn(Opcodes.GETSTATIC,
|
||||
// fieldVar.receiver.getType().toString().replace(".", "/"),
|
||||
// fieldVar.fieldVarName, fieldVar.getType().toString());
|
||||
@ -1081,6 +1107,10 @@ public class BytecodeGenMethod implements StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(This aThis) {
|
||||
|
||||
if(BytecodeGen.THISTYPE == null)
|
||||
BytecodeGen.THISTYPE = aThis.getType();
|
||||
|
||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||
}
|
||||
|
||||
|
@ -4,22 +4,33 @@ import de.dhbwstuttgart.exceptions.NotImplementedException;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
|
||||
import de.dhbwstuttgart.syntaxtree.FormalParameter;
|
||||
import de.dhbwstuttgart.syntaxtree.ParameterList;
|
||||
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
|
||||
import de.dhbwstuttgart.syntaxtree.statement.Literal;
|
||||
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
|
||||
|
||||
public class KindOfLambda implements StatementVisitor{
|
||||
private ParameterList params;
|
||||
private boolean isInstanceCapturingLambda = false;
|
||||
private List<RefTypeOrTPHOrWildcardOrGeneric> argumentList = new ArrayList<>();
|
||||
private ArrayList<String> usedVars = new ArrayList<>();
|
||||
private boolean hasThis = false;
|
||||
|
||||
public KindOfLambda(LambdaExpression lambdaExpression) {
|
||||
this.params = lambdaExpression.params;
|
||||
lambdaExpression.methodBody.accept(this);
|
||||
|
||||
}
|
||||
|
||||
public ArrayList<String> getUsedVars() {
|
||||
return usedVars;
|
||||
}
|
||||
|
||||
public boolean isInstanceCapturingLambda() {
|
||||
return this.isInstanceCapturingLambda;
|
||||
}
|
||||
@ -28,6 +39,10 @@ public class KindOfLambda implements StatementVisitor{
|
||||
return argumentList;
|
||||
}
|
||||
|
||||
public boolean isHasThis() {
|
||||
return hasThis;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ArgumentList argumentList) {
|
||||
// TODO Auto-generated method stub
|
||||
@ -95,8 +110,26 @@ public class KindOfLambda implements StatementVisitor{
|
||||
|
||||
@Override
|
||||
public void visit(LocalVar localVar) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
if(!contain(params, localVar.name)) {
|
||||
argumentList.add(localVar.getType());
|
||||
if(hasThis) {
|
||||
usedVars.add(1, localVar.name);
|
||||
} else {
|
||||
usedVars.add(0, localVar.name);
|
||||
}
|
||||
if(!isInstanceCapturingLambda)
|
||||
isInstanceCapturingLambda=true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean contain(ParameterList params2, String name) {
|
||||
Iterator<FormalParameter> itr = params2.iterator();
|
||||
while(itr.hasNext()) {
|
||||
FormalParameter fp = itr.next();
|
||||
if(fp.getName().equals(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -157,9 +190,13 @@ public class KindOfLambda implements StatementVisitor{
|
||||
|
||||
@Override
|
||||
public void visit(This aThis) {
|
||||
if(!hasThis) {
|
||||
hasThis = true;
|
||||
this.argumentList.add(0,aThis.getType());
|
||||
}
|
||||
if(!isInstanceCapturingLambda) {
|
||||
this.isInstanceCapturingLambda = true;
|
||||
this.argumentList.add(aThis.getType());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
43
test/bytecode/LambdaCapturetest.java
Normal file
43
test/bytecode/LambdaCapturetest.java
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package bytecode;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import de.dhbwstuttgart.core.JavaTXCompiler;
|
||||
|
||||
/**
|
||||
* @author fayez
|
||||
*
|
||||
*/
|
||||
public class LambdaCapturetest {
|
||||
private static String path;
|
||||
private static File fileToTest;
|
||||
private static JavaTXCompiler compiler;
|
||||
private static ClassLoader loader;
|
||||
private static Class<?> classToTest;
|
||||
private static String pathToClassFile;
|
||||
private static Object instanceOfClass;
|
||||
|
||||
@Test
|
||||
public void generateBC() throws Exception {
|
||||
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/LambdaCapture.jav";
|
||||
fileToTest = new File(path);
|
||||
compiler = new JavaTXCompiler(fileToTest);
|
||||
compiler.generateBytecode(System.getProperty("user.dir")+"/testBytecode/generatedBC/");
|
||||
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
|
||||
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
|
||||
classToTest = loader.loadClass("LambdaCapture");
|
||||
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
}
|
12
test/bytecode/javFiles/LambdaCapture.jav
Normal file
12
test/bytecode/javFiles/LambdaCapture.jav
Normal file
@ -0,0 +1,12 @@
|
||||
import java.lang.Integer;
|
||||
public class LambdaCapture {
|
||||
Integer i = 8;
|
||||
f;
|
||||
public LambdaCapture(){
|
||||
Integer w = 7;
|
||||
f = j ->{
|
||||
return w+i;};
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user