Merge branch 'bytecode2' of ssh://gohorb.ba-horb.de/bahome/projekt/git/JavaCompilerCore into bytecode2

This commit is contained in:
JanUlrich 2017-11-22 13:15:21 +01:00
commit 4616f82b09
7 changed files with 87 additions and 28 deletions

View File

@ -29,6 +29,7 @@ public class BytecodeGen implements ASTVisitor {
String type; String type;
String className; String className;
private boolean isInterface;
// stores parameter, local vars and the next index on the local variable table, which use for aload_i, astore_i,... // stores parameter, local vars and the next index on the local variable table, which use for aload_i, astore_i,...
HashMap<String, Integer> paramsAndLocals;// = new HashMap<>(); HashMap<String, Integer> paramsAndLocals;// = new HashMap<>();
@ -43,6 +44,8 @@ public class BytecodeGen implements ASTVisitor {
@Override @Override
public void visit(SourceFile sourceFile) { public void visit(SourceFile sourceFile) {
for(ClassOrInterface cl : sourceFile.getClasses()) { for(ClassOrInterface cl : sourceFile.getClasses()) {
isInterface = (cl.getModifiers()&512)==512;
System.out.println("IS Interface = "+"modifiers= "+cl.getModifiers()+" ->"+(cl.getModifiers()&512) + isInterface);
BytecodeGen classGen = new BytecodeGen(classFiles); BytecodeGen classGen = new BytecodeGen(classFiles);
cl.accept(classGen); cl.accept(classGen);
classGen.writeClass(cl.getClassName().toString()); classGen.writeClass(cl.getClassName().toString());
@ -88,9 +91,9 @@ public class BytecodeGen implements ASTVisitor {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", desc.getDesc(), null, null); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", desc.getDesc(), null, null);
mv.visitCode(); mv.visitCode();
System.out.println("-----Constructor-----"); System.out.println("-----Constructor-----");
BytecodeGenMethod gen = new BytecodeGenMethod(className,field, mv,paramsAndLocals,desc.getDesc(),cw); BytecodeGenMethod gen = new BytecodeGenMethod(className,field, mv,paramsAndLocals,desc.getDesc(),cw,isInterface);
mv.visitInsn(Opcodes.RETURN); // mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
} }
@ -103,7 +106,7 @@ public class BytecodeGen implements ASTVisitor {
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), methDesc.getDesc(), null, null); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), methDesc.getDesc(), null, null);
mv.visitCode(); mv.visitCode();
BytecodeGenMethod gen = new BytecodeGenMethod(className,method, mv,paramsAndLocals,methDesc.getDesc(),cw); BytecodeGenMethod gen = new BytecodeGenMethod(className,method, mv,paramsAndLocals,methDesc.getDesc(),cw,isInterface);
mv.visitMaxs(0, 0); mv.visitMaxs(0, 0);
mv.visitEnd(); mv.visitEnd();
} }

View File

@ -1,11 +1,10 @@
package de.dhbwstuttgart.bytecode; package de.dhbwstuttgart.bytecode;
import java.io.PrintStream;
import java.lang.invoke.CallSite; import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.security.GeneralSecurityException; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import de.dhbwstuttgart.syntaxtree.statement.*; import de.dhbwstuttgart.syntaxtree.statement.*;
@ -31,17 +30,21 @@ public class BytecodeGenMethod implements StatementVisitor{
private String className; private String className;
private int lamCounter; private int lamCounter;
private ClassWriter cw; private ClassWriter cw;
private boolean isInterface;
//for tests ** //for tests **
private String fieldName; private String fieldName;
private String fieldDesc; private String fieldDesc;
private Expression rightSideTemp; private Expression rightSideTemp;
private String where; private String where;
private boolean isRightSideALambda = false;
private ArrayList<RefTypeOrTPHOrWildcardOrGeneric> varsFunInterface;
public BytecodeGenMethod(String className, Method m, MethodVisitor mv, HashMap<String, Integer> paramsAndLocals, public BytecodeGenMethod(String className, Method m, MethodVisitor mv, HashMap<String, Integer> paramsAndLocals,
String desc, ClassWriter cw) { String desc, ClassWriter cw, boolean isInterface) {
this.where = "NORMAL METHOD"; this.where = "<<<<<< NORMAL METHOD >>>>>>";
this.className = className; this.className = className;
this.m = m; this.m = m;
@ -49,23 +52,27 @@ public class BytecodeGenMethod implements StatementVisitor{
this.paramsAndLocals = paramsAndLocals; this.paramsAndLocals = paramsAndLocals;
this.desc = desc; this.desc = desc;
this.cw = cw; this.cw = cw;
this.isInterface = isInterface;
this.lamCounter = -1; this.lamCounter = -1;
this.varsFunInterface = new ArrayList<>();
this.m.block.accept(this); this.m.block.accept(this);
} }
public BytecodeGenMethod(LambdaExpression lambdaExpression, MethodVisitor mv, public BytecodeGenMethod(LambdaExpression lambdaExpression, MethodVisitor mv,
HashMap<String, Integer> paramsAndLocals, String desc) { HashMap<String, Integer> paramsAndLocals, String desc,boolean isInterface) {
System.out.println("++++++IN LAMBDA -------"); System.out.println("\t\t++++++IN LAMBDA -------");
this.where = "&&&&&&&& LAMBDA METHOD"; this.where = "<<<<<< LAMBDA METHOD >>>>>>";
this.mv = mv; this.mv = mv;
this.paramsAndLocals = paramsAndLocals; this.paramsAndLocals = paramsAndLocals;
this.desc = desc; this.desc = desc;
this.isInterface = isInterface;
this.lamCounter = -1; this.lamCounter = -1;
this.varsFunInterface = new ArrayList<>();
lambdaExpression.methodBody.accept(this); lambdaExpression.methodBody.accept(this);
} }
@ -85,19 +92,20 @@ public class BytecodeGenMethod implements StatementVisitor{
superCall.receiver.accept(this); superCall.receiver.accept(this);
superCall.arglist.accept(this); superCall.arglist.accept(this);
// mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", superCall.name, desc,false); // mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", superCall.name, desc,false);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, desc,false); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, desc,isInterface);
} }
// ?? // ??
@Override @Override
public void visit(LocalVar localVar) { public void visit(LocalVar localVar) {
System.out.println("in Local Var"); System.out.println("in Local Var");
mv.visitVarInsn(Opcodes.ALOAD, paramsAndLocals.get(localVar.name));
} }
// ?? // ??
@Override @Override
public void visit(LocalVarDecl localVarDecl) { public void visit(LocalVarDecl localVarDecl) {
// Integer i; // Integer i;
paramsAndLocals.put(localVarDecl.getName(), paramsAndLocals.size()+1); // paramsAndLocals.put(localVarDecl.getName(), paramsAndLocals.size()+1);
System.out.println("In localVarDecl"); System.out.println("In localVarDecl");
} }
@ -105,6 +113,14 @@ public class BytecodeGenMethod implements StatementVisitor{
public void visit(Assign assign) { public void visit(Assign assign) {
System.out.println("Assign : \nright = "+assign.rightSide + "\nLeft = " + assign.lefSide); System.out.println("Assign : \nright = "+assign.rightSide + "\nLeft = " + assign.lefSide);
// if the right side is a lambda => the left side must be a functional interface
if(assign.rightSide.getClass().equals(LambdaExpression.class)) {
isRightSideALambda = true;
}else {
isRightSideALambda = false;
}
System.out.println("\t isRight Side lambda: " + isRightSideALambda);
if(assign.lefSide.getClass().equals(AssignToField.class)) { if(assign.lefSide.getClass().equals(AssignToField.class)) {
// load_0, ldc or .. then putfield // load_0, ldc or .. then putfield
this.rightSideTemp = assign.rightSide; this.rightSideTemp = assign.rightSide;
@ -120,7 +136,7 @@ public class BytecodeGenMethod implements StatementVisitor{
@Override @Override
public void visit(Binary binary) { public void visit(Binary binary) {
System.out.println("++ In Binary: "); System.out.println("\t++ In Binary: ");
} }
@Override @Override
@ -147,10 +163,13 @@ public class BytecodeGenMethod implements StatementVisitor{
MethodVisitor mvLambdaBody = cw.visitMethod(Opcodes.ACC_PRIVATE+ Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC, MethodVisitor mvLambdaBody = cw.visitMethod(Opcodes.ACC_PRIVATE+ Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC,
methodName, arg3.toString(), null, null); methodName, arg3.toString(), null, null);
// new BytecodeGenLambda(lambdaExpression, mvLambdaBody); // new BytecodeGenLambda(lambdaExpression, mvLambdaBody);
HashMap<String, Integer> paramsAndLocalsLambda = new HashMap<>();
new BytecodeGenMethod(lambdaExpression, mvLambdaBody, paramsAndLocalsLambda, arg3.toString(),isInterface);
new BytecodeGenMethod(lambdaExpression, mvLambdaBody, new HashMap<>(), arg3.toString());
mvLambdaBody.visitMaxs(0, 0); mvLambdaBody.visitMaxs(0, 0);
mvLambdaBody.visitEnd(); mvLambdaBody.visitEnd();
cw.visitInnerClass("java/lang/invoke/MethodHandles$Lookup", "java/lang/invoke/MethodHandles", "Lookup",
Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL);
} }
@Override @Override
@ -202,7 +221,7 @@ public class BytecodeGenMethod implements StatementVisitor{
@Override @Override
public void visit(MethodCall methodCall) { public void visit(MethodCall methodCall) {
System.out.println(" In Methodcall: (" +methodCall.name+")" ); System.out.println(" In Methodcall: (" +methodCall.name+")" );
System.out.print(" Method-Receiver: "); System.out.print("\t\tMethod-Receiver: ");
if(methodCall.receiver instanceof ExpressionReceiver){ if(methodCall.receiver instanceof ExpressionReceiver){
System.out.print(((ExpressionReceiver) methodCall.receiver).expr + "\n"); System.out.print(((ExpressionReceiver) methodCall.receiver).expr + "\n");
}else{ }else{
@ -214,18 +233,26 @@ public class BytecodeGenMethod implements StatementVisitor{
Descriptor mDesc = new Descriptor(methodCall.arglist, methodCall.getType()); Descriptor mDesc = new Descriptor(methodCall.arglist, methodCall.getType());
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, methodCall.receiver.getType().toString(), System.out.println("is Vars empty: "+varsFunInterface.isEmpty());
methodCall.name, mDesc.getDesc(), false);
// test // is methodCall.receiver functional Interface)?
if(!methodCall.getType().toString().equals("V")) { if(varsFunInterface.contains(methodCall.receiver.getType())) {
mv.visitInsn(Opcodes.POP); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, methodCall.receiver.getType().toString().replace(".", "/"),
methodCall.name, mDesc.getDesc(), false);
}else {
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, methodCall.receiver.getType().toString().replace(".", "/"),
methodCall.name, mDesc.getDesc(), isInterface);
} }
// test
// if(!methodCall.getType().toString().equals("V")) {
// mv.visitInsn(Opcodes.POP);
// }
} }
@Override @Override
public void visit(NewClass methodCall) { public void visit(NewClass methodCall) {
System.out.println("In NewClass: "); System.out.println("In NewClass: ");
System.out.println("name: " + methodCall.name + " *** " + "Receiver: " + methodCall.receiver); System.out.println("\t\tname: " + methodCall.name + " *** " + "Receiver: " + methodCall.receiver);
mv.visitTypeInsn(Opcodes.NEW, methodCall.name.replace(".", "/")); mv.visitTypeInsn(Opcodes.NEW, methodCall.name.replace(".", "/"));
mv.visitInsn(Opcodes.DUP); mv.visitInsn(Opcodes.DUP);
@ -237,7 +264,7 @@ public class BytecodeGenMethod implements StatementVisitor{
} }
d += ")V"; d += ")V";
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, methodCall.name.replace(".", "/"), "<init>", d, false); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, methodCall.name.replace(".", "/"), "<init>", d, isInterface);
} }
@Override @Override
@ -320,6 +347,8 @@ public class BytecodeGenMethod implements StatementVisitor{
@Override @Override
public void visit(AssignToField assignLeftSide) { public void visit(AssignToField assignLeftSide) {
if(isRightSideALambda)
varsFunInterface.add(assignLeftSide.field.getType());
// Loads the an object reference from the local variable // Loads the an object reference from the local variable
// array slot onto the top of the operand stack. // array slot onto the top of the operand stack.
assignLeftSide.field.receiver.accept(this); assignLeftSide.field.receiver.accept(this);
@ -330,6 +359,9 @@ public class BytecodeGenMethod implements StatementVisitor{
@Override @Override
public void visit(AssignToLocal assignLeftSide) { public void visit(AssignToLocal assignLeftSide) {
System.out.println("In Assign To Local: ");
if(isRightSideALambda)
varsFunInterface.add(assignLeftSide.localVar.getType());
paramsAndLocals.put(assignLeftSide.localVar.name, paramsAndLocals.size()+1); paramsAndLocals.put(assignLeftSide.localVar.name, paramsAndLocals.size()+1);
mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size()); mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size());
} }

View File

@ -0,0 +1,3 @@
public interface Interface1{
public void test();
}

View File

@ -21,19 +21,26 @@ import static org.junit.Assert.*;
public class JavaTXCompilerTest { public class JavaTXCompilerTest {
private static final String rootDirectory = System.getProperty("user.dir")+"/test/javFiles/"; private static final String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/";
private static final List<File> filesToTest = new ArrayList<>(); private static final List<File> filesToTest = new ArrayList<>();
@Test @Test
public void test() throws IOException, java.lang.ClassNotFoundException { public void test() throws IOException, java.lang.ClassNotFoundException {
System.out.println(rootDirectory); System.out.println(rootDirectory);
filesToTest.add(new File(rootDirectory+"EmptyClass.jav")); String fileName = "LamRunnable";
filesToTest.add(new File(rootDirectory+fileName+".jav"));
System.out.println(rootDirectory+fileName+".jav");
JavaTXCompiler compiler = new JavaTXCompiler(filesToTest); JavaTXCompiler compiler = new JavaTXCompiler(filesToTest);
System.out.println("test"); System.out.println("test");
for(File f : filesToTest){ for(File f : filesToTest){
String content = readFile(f.getPath(), StandardCharsets.UTF_8); String content = readFile(f.getPath(), StandardCharsets.UTF_8);
HashMap<String,byte[]> bytecode = this.getBytecode(compiler.sourceFiles.get(f)); HashMap<String,byte[]> bytecode = this.getBytecode(compiler.sourceFiles.get(f));
this.writeClassFile(bytecode, "EmptyClass"); String name = "";
int pos = f.getName().lastIndexOf(".");
if(pos != -1) {
name = f.getName().substring(0, pos);
}
this.writeClassFile(bytecode, name);
} }
} }
@ -51,7 +58,7 @@ public class JavaTXCompilerTest {
byte[] bytecode = classFiles.get(name); byte[] bytecode = classFiles.get(name);
try { try {
System.out.println("generating .class file"); System.out.println("generating .class file");
output = new FileOutputStream(new File(System.getProperty("user.dir") + "/testBytecode/" +name+".class")); output = new FileOutputStream(new File(System.getProperty("user.dir") + "/testBytecode/generatedBC/" +name+".class"));
output.write(bytecode); output.write(bytecode);
output.close(); output.close();
System.out.println(".class file generated"); System.out.println(".class file generated");

View File

@ -0,0 +1,9 @@
public class LamRunnable{
public LamRunnable(){
Runnable lam = () -> {System.out.println("lambda");};
lam.run();
}
}

View File

@ -0,0 +1,5 @@
public class VoidMeth{
public void test(){
System.out.print("");
}
}

View File

@ -4,6 +4,6 @@ import java.io.File;
public class FiniteClosureTest extends JavaTXCompilerTest{ public class FiniteClosureTest extends JavaTXCompilerTest{
public FiniteClosureTest() { public FiniteClosureTest() {
this.fileToTest = new File(rootDirectory+"fc.jav"); // this.fileToTest = new File(rootDirectory+"fc.jav");
} }
} }