Bytecode für While-Schleifen

This commit is contained in:
Fayez Abu Alia 2018-03-14 15:51:38 +01:00
parent 52a5fd7904
commit dafcd2f125
10 changed files with 265 additions and 125 deletions

View File

@ -1,7 +1,9 @@
package de.dhbwstuttgart.bytecode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.syntaxtree.statement.*;
@ -9,6 +11,7 @@ import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import de.dhbwstuttgart.bytecode.descriptor.DescriptorToString;
import de.dhbwstuttgart.bytecode.descriptor.TypeToDescriptor;
@ -23,6 +26,7 @@ import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.typeinference.result.ResultPair;
import de.dhbwstuttgart.typeinference.result.ResultSet;
public class BytecodeGen implements ASTVisitor {
@ -30,9 +34,10 @@ public class BytecodeGen implements ASTVisitor {
ClassWriter cw =new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
String type;
String className;
private boolean isInterface;
private List<ResultSet> listOfResultSets;
private ResultSet resultSet;
private int indexOfFirstParam = 0;
@ -47,16 +52,18 @@ public class BytecodeGen implements ASTVisitor {
byte[] bytecode;
HashMap<String,byte[]> classFiles;
public BytecodeGen(HashMap<String,byte[]> classFiles, ResultSet resultSet) {
ArrayList<String> methodNameAndParamsT = new ArrayList<>();
public BytecodeGen(HashMap<String,byte[]> classFiles, List<ResultSet> listOfResultSets) {
this.classFiles = classFiles;
this.resultSet = resultSet;
this.listOfResultSets = listOfResultSets;
}
@Override
public void visit(SourceFile sourceFile) {
for(ClassOrInterface cl : sourceFile.getClasses()) {
System.out.println("in Class: " + cl.getClassName().toString());
BytecodeGen classGen = new BytecodeGen(classFiles, resultSet);
BytecodeGen classGen = new BytecodeGen(classFiles, listOfResultSets);
cl.accept(classGen);
classGen.writeClass(cl.getClassName().toString());
}
@ -101,18 +108,27 @@ public class BytecodeGen implements ASTVisitor {
cw.visit(Opcodes.V1_8, acc, classOrInterface.getClassName().toString()
, sig, classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()), null);
// for each field in the class
for(Field f : classOrInterface.getFieldDecl()) {
f.accept(this);
}
// resultSet = listOfResultSets.get(0);
boolean isConsWithNoParamsVisited = false;
for(ResultSet rs : listOfResultSets) {
resultSet = rs;
for(Constructor c : classOrInterface.getConstructors()) {
if(!isConsWithNoParamsVisited)
c.accept(this);
if(!c.getParameterList().iterator().hasNext())
isConsWithNoParamsVisited = true;
}
for(Method m : classOrInterface.getMethods()) {
m.accept(this);
}
for(Constructor c : classOrInterface.getConstructors()) {
c.accept(this);
}
for(Method m : classOrInterface.getMethods()) {
m.accept(this);
}
}
@Override
@ -146,13 +162,24 @@ public class BytecodeGen implements ASTVisitor {
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@Override
public void visit(Method method) {
// TODO: check if the method is static => if static then the first param will be stored in pos 0
// else it will be stored in pos 1 and this will be stored in pos 0
method.getParameterList().accept(this);
String methParamTypes = method.name+";";
Iterator<FormalParameter> itr = method.getParameterList().iterator();
while(itr.hasNext()) {
FormalParameter fp = itr.next();
methParamTypes = methParamTypes+ resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+";";
}
if(methodNameAndParamsT.contains(methParamTypes)) {
return;
}
methodNameAndParamsT.add(methParamTypes);
System.out.println("Method: "+method.name +" , paramsType: "+methParamTypes);
String methDesc = null;
// Method getModifiers() ?
@ -181,16 +208,17 @@ public class BytecodeGen implements ASTVisitor {
Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet);
sig = signature.toString();
}
System.out.println(sig);
// System.out.println(sig);
NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen);
methDesc = meth.accept(new DescriptorToString(resultSet));
System.out.println(methDesc);
// System.out.println(methDesc);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC+acc, method.getName(), methDesc, sig, null);
mv.visitCode();
BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,method, mv,paramsAndLocals,cw,
genericsAndBounds,genericsAndBounds,isInterface,classFiles);
genericsAndBoundsMethod,genericsAndBounds,isInterface,classFiles);
mv.visitMaxs(0, 0);
mv.visitEnd();
}

View File

@ -34,9 +34,6 @@ import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.FormalParameter;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.Literal;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.result.ResultSet;
@ -58,9 +55,13 @@ public class BytecodeGenMethod implements StatementVisitor {
private String fieldName;
private String fieldDesc;
private Expression rightSideTemp;
private boolean isRightSideALambda = false;
private KindOfLambda kindOfLambda;
private HashMap<String, byte[]> classFiles;
private boolean isAssignStmt = false;
private Statement loopBlock;
private ArrayList<RefTypeOrTPHOrWildcardOrGeneric> varsFunInterface = new ArrayList<>();;
@ -105,7 +106,7 @@ public class BytecodeGenMethod implements StatementVisitor {
private String getResolvedType(RefTypeOrTPHOrWildcardOrGeneric type) {
return resultSet.resolveType(type).resolvedType.acceptTV(new TypeToDescriptor());
}
@Override
public void visit(Block block) {
for (Statement stmt : block.getStatements()) {
@ -142,6 +143,8 @@ public class BytecodeGenMethod implements StatementVisitor {
@Override
public void visit(Assign assign) {
isAssignStmt = true;
// if the right side is a lambda => the left side must be a functional interface
if (assign.rightSide instanceof LambdaExpression) {
isRightSideALambda = true;
@ -151,6 +154,7 @@ public class BytecodeGenMethod implements StatementVisitor {
if (assign.rightSide instanceof BinaryExpr)
isBinaryExp = true;
if (assign.lefSide instanceof AssignToField) {
// load_0, ldc or .. then putfield
@ -159,10 +163,15 @@ public class BytecodeGenMethod implements StatementVisitor {
assign.rightSide.accept(this);
}
if (isBinaryExp) {
getValueOfIns(getResolvedType(assign.lefSide.getType()));
BinaryExpr binary = (BinaryExpr) assign.rightSide;
String lexpType = getResolvedType(binary.lexpr.getType());
String rexpType = getResolvedType(binary.rexpr.getType());
getValueOfIns(getLargerType(lexpType, rexpType));
isBinaryExp = false;
}
assign.lefSide.accept(this);
isAssignStmt =false;
}
/*
@ -171,20 +180,34 @@ public class BytecodeGenMethod implements StatementVisitor {
*/
@Override
public void visit(BinaryExpr binary) {
// if(!areTypesValid(binary)) {
// return;
// }
String lexpType = getResolvedType(binary.lexpr.getType());
String rexpType = getResolvedType(binary.rexpr.getType());
String largerType = getLargerType(lexpType,rexpType);
String typeOfBinary = getResolvedType(binary.getType());
// if(!(largerType.equals(typeOfBinary)&&typeOfBinary.equals(Type.getInternalName(Number.class))&&typeOfBinary.equals(Type.getInternalName(Object.class)))) {
// return;
// }
if (typeOfBinary.equals(Type.getInternalName(String.class))) {
mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(StringBuilder.class));
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(StringBuilder.class), "<init>", "()V",
false);
}
// tmp!!
Label endLabel = new Label();
// this case for while loops
if(!isAssignStmt)
mv.visitLabel(endLabel);
binary.lexpr.accept(this);
String lexpType = getResolvedType(binary.lexpr.getType());
String rexpType = getResolvedType(binary.rexpr.getType());
String largerType = getLargerType(lexpType,rexpType);
if(!lexpType.equals(rexpType) &&
!lexpType.equals(largerType))
doCast(lexpType, largerType);
@ -199,7 +222,7 @@ public class BytecodeGenMethod implements StatementVisitor {
switch (op) {
case ADD:
doVisitAddOpInsn(typeOfBinary);
doVisitAddOpInsn(largerType);
break;
case SUB:
@ -222,7 +245,8 @@ public class BytecodeGenMethod implements StatementVisitor {
case LESSEQUAL:
case BIGGERTHAN:
case BIGGEREQUAL:
doVisitRelOpInsn(op,largerType);
Label branchLabel = new Label();
doVisitRelOpInsn(op,largerType, branchLabel, endLabel);
break;
default:
@ -232,6 +256,10 @@ public class BytecodeGenMethod implements StatementVisitor {
}
private String getLargerType(String lexpType, String rexpType) {
if(lexpType.equals(Type.getInternalName(String.class)) ||
rexpType.equals(Type.getInternalName(String.class))) {
return Type.getInternalName(String.class);
} else
if(lexpType.equals(Type.getInternalName(Double.class)) ||
rexpType.equals(Type.getInternalName(Double.class))) {
return Type.getInternalName(Double.class);
@ -275,9 +303,7 @@ public class BytecodeGenMethod implements StatementVisitor {
}
}
private void doVisitRelOpInsn(Operator op, String typeOfBinary) {
Label branchLabel = new Label();
Label endLabel = new Label();
private void doVisitRelOpInsn(Operator op, String typeOfBinary, Label branchLabel, Label endLabel) {
switch (typeOfBinary) {
case "java/lang/Long":
@ -309,37 +335,52 @@ public class BytecodeGenMethod implements StatementVisitor {
default:
break;
}
if(isAssignStmt) {
mv.visitInsn(Opcodes.ICONST_1);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(branchLabel);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLabel(endLabel);
} else {
loopBlock.accept(this);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(branchLabel);
}
break;
}
}
private void doVisitIfInRelOp(Operator op, Label branchLabel, Label endLabel) {
switch (op) {
case LESSTHAN:
mv.visitJumpInsn(Opcodes.IFGE, branchLabel);
break;
case LESSEQUAL:
mv.visitJumpInsn(Opcodes.IFGT, branchLabel);
break;
case BIGGERTHAN:
mv.visitJumpInsn(Opcodes.IFLE, branchLabel);
break;
case BIGGEREQUAL:
mv.visitJumpInsn(Opcodes.IFLT, branchLabel);
break;
default:
break;
}
if(isAssignStmt) {
mv.visitInsn(Opcodes.ICONST_1);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(branchLabel);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLabel(endLabel);
break;
} else {
loopBlock.accept(this);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(branchLabel);
}
}
private void doVisitIfInRelOp(Operator op, Label greaterEq, Label lessThan) {
switch (op) {
case LESSTHAN:
mv.visitJumpInsn(Opcodes.IFGE, greaterEq);
break;
case LESSEQUAL:
mv.visitJumpInsn(Opcodes.IFGT, greaterEq);
break;
case BIGGERTHAN:
mv.visitJumpInsn(Opcodes.IFLE, greaterEq);
break;
case BIGGEREQUAL:
mv.visitJumpInsn(Opcodes.IFLT, greaterEq);
break;
default:
break;
}
mv.visitInsn(Opcodes.ICONST_1);
mv.visitJumpInsn(Opcodes.GOTO, lessThan);
mv.visitLabel(greaterEq);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLabel(lessThan);
}
@ -681,14 +722,19 @@ public class BytecodeGenMethod implements StatementVisitor {
@Override
public void visit(WhileStmt whileStmt) {
this.loopBlock = whileStmt.loopBlock;
if(whileStmt.expr instanceof BinaryExpr)
isBinaryExp = true;
whileStmt.expr.accept(this);
whileStmt.loopBlock.accept(this);
isBinaryExp = false;
}
@Override
public void visit(DoStmt whileStmt) {
// TODO Auto-generated method stub
whileStmt.expr.accept(this);
}
@Override
@ -916,7 +962,14 @@ public class BytecodeGenMethod implements StatementVisitor {
public void visit(AssignToLocal assignLeftSide) {
if (isRightSideALambda)
varsFunInterface.add(assignLeftSide.localVar.getType());
paramsAndLocals.put(assignLeftSide.localVar.name, paramsAndLocals.size() + 1);
int index = paramsAndLocals.size();
String var = assignLeftSide.localVar.name;
if(!paramsAndLocals.containsKey(var)) {
paramsAndLocals.put(var, index + 1);
}else {
paramsAndLocals.put(var, index);
}
mv.visitVarInsn(Opcodes.ASTORE, paramsAndLocals.size());
// Debug:::

View File

@ -138,7 +138,8 @@ public class JavaTXCompiler {
HashMap<String,byte[]> classFiles = new HashMap<>();
SourceFile sf = sourceFiles.get(f);
List<ResultSet> typeinferenceResult = this.typeInference();
BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult.get(0));
BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult);
// BytecodeGen bytecodeGen = new BytecodeGen(classFiles,typeinferenceResult.get(0));
bytecodeGen.visit(sf);
this.writeClassFile(bytecodeGen.getClassFiles());
}

View File

@ -184,7 +184,7 @@ public class TYPEStmt implements StatementVisitor{
receiver.expr.accept(this);
}
private final RefType number = new RefType(ASTFactory.createClass(Number.class).getClassName(), new NullToken());
private final RefType number = new RefType(ASTFactory.createClass(Integer.class).getClassName(), new NullToken());
private final RefType string = new RefType(ASTFactory.createClass(String.class).getClassName(), new NullToken());
private final RefType bool = new RefType(ASTFactory.createClass(Boolean.class).getClassName(), new NullToken());
@Override

View File

@ -39,7 +39,7 @@ public class GreaterEqualTest {
public void testName() {
assertEquals("GreaterEqual", classToTest.getName());
}
@Test
public void testIntegers() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method gE = classToTest.getDeclaredMethod("gE", Integer.class, Integer.class);
Boolean result = (Boolean) gE.invoke(instanceOfClass, 7, 5);

View File

@ -59,14 +59,14 @@ public class OpTest {
// assertEquals("ByteCode", result);
// }
//
// @Test
// public void testAddInt() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
// Method addInt = classToTest.getDeclaredMethod("addInt", Integer.class,Integer.class);
// Integer result = (Integer) addInt.invoke(instanceOfClass, 7,3);
// assertEquals(10, result);
// }
//
@Test
public void testAddInt() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Method addInt = classToTest.getDeclaredMethod("addInt", Integer.class,Integer.class);
Number result = (Number) addInt.invoke(instanceOfClass, 7,3);
assertEquals(10, result);
}
// @Test
// public void testAddLong() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
@ -159,35 +159,35 @@ public class OpTest {
// assertEquals(10d, result);
// }
@Test
public void testMulInt() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Method mulInt = classToTest.getDeclaredMethod("mulInt", Integer.class,Integer.class);
Integer result = (Integer) mulInt.invoke(instanceOfClass, 7,3);
assertEquals(21, result);
}
@Test
public void testMulLong() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Method mulLong = classToTest.getDeclaredMethod("mulLong", Long.class,Long.class);
Long result = (Long) mulLong.invoke(instanceOfClass, 7L,3L);
assertEquals(21L, result);
}
@Test
public void testMulFloat() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Method mulFloat = classToTest.getDeclaredMethod("mulFloat", Float.class,Float.class);
Float result = (Float) mulFloat.invoke(instanceOfClass, 7f,3f);
assertEquals(21f, result);
}
@Test
public void testMulDouble() throws NoSuchMethodException, SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
Method mulDouble = classToTest.getDeclaredMethod("mulDouble", Double.class,Double.class);
Double result = (Double) mulDouble.invoke(instanceOfClass, 7.0,3.0);
assertEquals(21.0, result);
}
// @Test
// public void testMulInt() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
// Method mulInt = classToTest.getDeclaredMethod("mulInt", Integer.class,Integer.class);
// Integer result = (Integer) mulInt.invoke(instanceOfClass, 7,3);
// assertEquals(21, result);
// }
//
// @Test
// public void testMulLong() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
// Method mulLong = classToTest.getDeclaredMethod("mulLong", Long.class,Long.class);
// Long result = (Long) mulLong.invoke(instanceOfClass, 7L,3L);
// assertEquals(21L, result);
// }
//
// @Test
// public void testMulFloat() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
// Method mulFloat = classToTest.getDeclaredMethod("mulFloat", Float.class,Float.class);
// Float result = (Float) mulFloat.invoke(instanceOfClass, 7f,3f);
// assertEquals(21f, result);
// }
//
// @Test
// public void testMulDouble() throws NoSuchMethodException, SecurityException, IllegalAccessException,
// IllegalArgumentException, InvocationTargetException, InstantiationException {
// Method mulDouble = classToTest.getDeclaredMethod("mulDouble", Double.class,Double.class);
// Double result = (Double) mulDouble.invoke(instanceOfClass, 7.0,3.0);
// assertEquals(21.0, result);
// }
}

View File

@ -0,0 +1,44 @@
package bytecode;
import static org.junit.Assert.*;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.junit.BeforeClass;
import org.junit.Test;
import de.dhbwstuttgart.core.JavaTXCompiler;
public class WhileTest {
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;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
path = System.getProperty("user.dir")+"/test/bytecode/javFiles/While.jav";
fileToTest = new File(path);
compiler = new JavaTXCompiler(fileToTest);
compiler.generateBytecode();
pathToClassFile = System.getProperty("user.dir")+"/testBytecode/generatedBC/";
loader = new URLClassLoader(new URL[] {new URL("file://"+pathToClassFile)});
classToTest = loader.loadClass("While");
instanceOfClass = classToTest.getDeclaredConstructor().newInstance();
}
@Test
public void test() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method m = classToTest.getDeclaredMethod("m", Integer.class);
Integer result = (Integer) m.invoke(instanceOfClass, 0);
assertEquals(2, result);
}
}

View File

@ -4,6 +4,7 @@ import java.lang.Float;
import java.lang.Double;
public class GreaterEqual {
gE(Integer a, Integer b){
var c = a>=b;
return c;

View File

@ -8,10 +8,13 @@ import java.lang.Short;
import java.lang.Byte;
public class Op {
// addInt(Integer a, Integer b) {
// Integer c = a+b;
// return c;
// }
addInt( a, b) {
var c = a+b;
return c;
}
// addString(String a, String b) {
// String c = a+b;
// return c;
@ -51,25 +54,25 @@ public class Op {
// return c;
// }
mulInt(Integer a, Integer b) {
Integer c = a*b;
return c;
}
mulLong(Long a, Long b) {
Long c = a*b;
return c;
}
mulFloat(Float a, Float b) {
Float c = a*b;
return c;
}
mulDouble(Double a, Double b) {
Double c = a*b;
return c;
}
// mulInt(Integer a, Integer b) {
// Integer c = a*b;
// return c;
// }
//
// mulLong(Long a, Long b) {
// Long c = a*b;
// return c;
// }
//
// mulFloat(Float a, Float b) {
// Float c = a*b;
// return c;
// }
//
// mulDouble(Double a, Double b) {
// Double c = a*b;
// return c;
// }
// add(Double a, Long b) {
// Double c = a+b;

View File

@ -0,0 +1,10 @@
import java.lang.Integer;
public class While {
m(x) {
while(x < 2) {
x = x+1;
}
return x;
}
}