erzeugt bytecode für generics

This commit is contained in:
Fayez Abu Alia 2018-01-10 11:36:29 +01:00
parent 01339ca7ec
commit 268056542b
16 changed files with 526 additions and 63 deletions

View File

@ -1,5 +1,6 @@
package de.dhbwstuttgart.bytecode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -8,6 +9,9 @@ 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 org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;
import de.dhbwstuttgart.parser.SyntaxTreeGenerator.AssignToLocal;
import de.dhbwstuttgart.syntaxtree.*;
@ -16,6 +20,7 @@ import de.dhbwstuttgart.syntaxtree.statement.literal.Null;
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
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.ResultSet;
@ -23,7 +28,6 @@ import de.dhbwstuttgart.typeinference.result.ResultSet;
public class BytecodeGen implements ASTVisitor {
ClassWriter cw =new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
// String methDesc;
String type;
@ -34,6 +38,12 @@ public class BytecodeGen implements ASTVisitor {
// 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<>();
// stores generics and their bounds of class
HashMap<String, String> genericsAndBounds = new HashMap<>();
// stores generics and their bounds of method
HashMap<String, String> genericsAndBoundsMethod = new HashMap<>();
HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes = new HashMap<>();
byte[] bytecode;
HashMap<String,byte[]> classFiles;
@ -45,14 +55,19 @@ public class BytecodeGen implements ASTVisitor {
@Override
public void visit(SourceFile sourceFile) {
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, resultSet);
cl.accept(classGen);
System.out.println("In CLASS: "+(cl.getClassName().toString()));
classGen.writeClass(cl.getClassName().toString());
}
}
/**
* Associates the bytecode of the class that was build with the classWriter {@link #cw}
* with the class name in the map {@link #classFiles}
*
* @param name name of the class with which the the bytecode is to be associated
*/
private void writeClass(String name) {
bytecode = cw.toByteArray();
classFiles.put(name, bytecode);
@ -62,12 +77,30 @@ public class BytecodeGen implements ASTVisitor {
public HashMap<String,byte[]> getClassFiles() {
return classFiles;
}
@Override
public void visit(ClassOrInterface classOrInterface) {
className = classOrInterface.getClassName().toString();
// access flages??
cw.visit(Opcodes.V1_8, classOrInterface.getModifiers()+Opcodes.ACC_SUPER, classOrInterface.getClassName().toString()
, null, classOrInterface.getSuperClass().toString().replace(".", "/"), null);
isInterface = (classOrInterface.getModifiers()&512)==512;
System.out.println("IS Interface = "+"modifiers= "+classOrInterface.getModifiers()+" ->"+(classOrInterface.getModifiers()&512) + isInterface);
int acc = isInterface?classOrInterface.getModifiers()+Opcodes.ACC_ABSTRACT:classOrInterface.getModifiers()+Opcodes.ACC_SUPER;
String sig = null;
/* if class has generics then creates signature
* Signature looks like:
* <E:Ljava/...>Superclass
*/
if(classOrInterface.getGenerics().iterator().hasNext()) {
Signature signature = new Signature(classOrInterface, genericsAndBounds);
System.out.println(signature.toString());
sig = signature.toString();
}
// needs implemented Interfaces?
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()) {
@ -85,17 +118,34 @@ public class BytecodeGen implements ASTVisitor {
}
cw.visitSource(classOrInterface.getClassName().toString()+".jav", null);
}
@Override
public void visit(Constructor field) {
NormalConstructor constructor = new NormalConstructor(field);
String desc = constructor.accept(new DescriptorToString(resultSet));
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", desc, null, null);
field.getParameterList().accept(this);
String desc = null;
boolean hasGen = false;
for(String paramName : methodParamsAndTypes.keySet()) {
genericsAndBounds.containsKey(paramName);
hasGen = true;
}
String sig = null;
if(hasGen) {
System.out.println("IM IN CONST HAS Gens");
Signature signature = new Signature(field, genericsAndBounds,methodParamsAndTypes);
sig = signature.toString();
System.out.println(sig);
}
NormalConstructor constructor = new NormalConstructor(field,genericsAndBounds,hasGen);
desc = constructor.accept(new DescriptorToString(resultSet));
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", desc, sig, null);
mv.visitCode();
System.out.println("-----Constructor-----");
BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,field, mv,paramsAndLocals,desc,cw,isInterface);
mv.visitInsn(Opcodes.RETURN);
BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,field, mv,paramsAndLocals,cw,
genericsAndBoundsMethod,genericsAndBounds,isInterface);
if(!field.getParameterList().iterator().hasNext()) {
mv.visitInsn(Opcodes.RETURN);
}
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@ -106,14 +156,48 @@ public class BytecodeGen implements ASTVisitor {
// else it will be stored in pos 1 and this will be stored in pos 0
method.getParameterList().accept(this);
NormalMethod meth = new NormalMethod(method);
String methDesc = meth.accept(new DescriptorToString(resultSet));
String methDesc = null;
// Method getModifiers() ?
int acc = isInterface?Opcodes.ACC_ABSTRACT:0;
System.out.println("-----Method-----");
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, method.getName(), methDesc, null, null);
boolean hasGenInParameterList = genericsAndBounds.containsKey(method.getReturnType().acceptTV(new TypeToDescriptor()));
if(!hasGenInParameterList) {
for(String paramName : methodParamsAndTypes.keySet()) {
if(genericsAndBounds.containsKey(paramName)) {
hasGenInParameterList = true;
break;
}
}
}
String sig = null;
boolean hasGen = method.getGenerics().iterator().hasNext() || hasGenInParameterList;
// Wenn ReturnType has Generics?? Fun1<...> wie testet man das generic hat??
System.out.println(method.getReturnType().acceptTV(new TypeToString()));
// if(method.getReturnType().acceptTV(new TypeToString()).equals("TPH")) {
// Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet);
// sig = signature.toString();
// System.out.println(sig);
// }
/* if method has generics, create signature */
if(hasGen) {
// resultset hier zum testen
Signature signature = new Signature(method, genericsAndBoundsMethod, methodParamsAndTypes,resultSet);
sig = signature.toString();
System.out.println(sig);
}
NormalMethod meth = new NormalMethod(method,genericsAndBounds,genericsAndBoundsMethod,hasGen);
methDesc = meth.accept(new DescriptorToString(resultSet));
System.out.println("methDesc" + 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,methDesc,cw,isInterface);
BytecodeGenMethod gen = new BytecodeGenMethod(className,resultSet,method, mv,paramsAndLocals,cw,genericsAndBounds,genericsAndBounds,isInterface);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
@ -121,11 +205,13 @@ public class BytecodeGen implements ASTVisitor {
@Override
public void visit(ParameterList formalParameters) {
paramsAndLocals = new HashMap<>();
methodParamsAndTypes = new HashMap<>();
Iterator<FormalParameter> itr = formalParameters.iterator();
int i = 1;
while(itr.hasNext()) {
FormalParameter fp = itr.next();
paramsAndLocals.put(fp.getName(), i);
methodParamsAndTypes.put(fp.getName(), fp.getType());
fp.accept(this);
i++;
}

View File

@ -21,6 +21,7 @@ import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.StatementVisitor;
import de.dhbwstuttgart.syntaxtree.statement.literal.Literal;
import de.dhbwstuttgart.syntaxtree.statement.literal.Null;
import de.dhbwstuttgart.syntaxtree.type.FunN;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.result.ResultSet;
@ -29,12 +30,13 @@ public class BytecodeGenMethod implements StatementVisitor{
private Method m;
private MethodVisitor mv;
private HashMap<String, Integer> paramsAndLocals = new HashMap<>();
private String desc;
private String className;
private int lamCounter;
private ClassWriter cw;
private ResultSet resultSet;
private boolean isInterface;
HashMap<String, String> genericsAndBoundsMethod;
private HashMap<String,String> genericsAndBounds;
//for tests **
private String fieldName;
@ -46,8 +48,9 @@ public class BytecodeGenMethod implements StatementVisitor{
private ArrayList<RefTypeOrTPHOrWildcardOrGeneric> varsFunInterface;
public BytecodeGenMethod(String className,ResultSet resultSet, Method m, MethodVisitor mv, HashMap<String, Integer> paramsAndLocals,
String desc, ClassWriter cw, boolean isInterface) {
public BytecodeGenMethod(String className,ResultSet resultSet, Method m, MethodVisitor mv,
HashMap<String, Integer> paramsAndLocals, ClassWriter cw,
HashMap<String, String> genericsAndBoundsMethod, HashMap<String,String> genericsAndBounds, boolean isInterface) {
this.where = "<<<<<< NORMAL METHOD >>>>>>";
@ -56,29 +59,32 @@ public class BytecodeGenMethod implements StatementVisitor{
this.m = m;
this.mv = mv;
this.paramsAndLocals = paramsAndLocals;
this.desc = desc;
this.cw = cw;
this.genericsAndBoundsMethod = genericsAndBoundsMethod;
this.genericsAndBounds = genericsAndBounds;
this.isInterface = isInterface;
this.lamCounter = -1;
this.varsFunInterface = new ArrayList<>();
System.out.println("PARAMS = "+this.paramsAndLocals.size());
this.m.block.accept(this);
System.out.println("PARAMS = "+this.paramsAndLocals.size());
for(int i = 0; i<this.paramsAndLocals.size();i++) {
System.out.println(this.paramsAndLocals.keySet().toArray()[i]);
}
if(!isInterface)
this.m.block.accept(this);
// System.out.println("PARAMS = "+this.paramsAndLocals.size());
// for(int i = 0; i<this.paramsAndLocals.size();i++) {
// System.out.println(this.paramsAndLocals.keySet().toArray()[i]);
// }
}
public BytecodeGenMethod(LambdaExpression lambdaExpression,ResultSet resultSet ,MethodVisitor mv,
String desc,int indexOfFirstParamLam, boolean isInterface) {
int indexOfFirstParamLam, boolean isInterface) {
System.out.println("\t\t++++++IN LAMBDA -------");
this.where = "<<<<<< LAMBDA METHOD >>>>>>";
this.resultSet = resultSet;
this.mv = mv;
this.desc = desc;
this.isInterface = isInterface;
this.lamCounter = -1;
this.varsFunInterface = new ArrayList<>();
@ -114,7 +120,7 @@ public class BytecodeGenMethod implements StatementVisitor{
superCall.receiver.accept(this);
superCall.arglist.accept(this);
// mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", superCall.name, desc,false);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, desc,isInterface);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), superCall.name, "()V",isInterface);
}
// ??
@ -151,9 +157,6 @@ public class BytecodeGenMethod implements StatementVisitor{
assign.rightSide.accept(this);
assign.lefSide.accept(this);
}
}
@Override
@ -165,7 +168,9 @@ public class BytecodeGenMethod implements StatementVisitor{
public void visit(LambdaExpression lambdaExpression) {
System.out.println("\n++ In Lambda: ");
this.lamCounter++;
System.out.println("Lam Hs Gens: " + lambdaExpression.getGenerics().iterator().hasNext());
System.out.println("Lam Hs Gens: " + lambdaExpression.getReturnType().acceptTV(new TypeToString()));
Lambda lam = new Lambda(lambdaExpression);
String lamDesc = lam.accept(new DescriptorToString(resultSet));
//Call site, which, when invoked, returns an instance of the functional interface to which
@ -177,7 +182,9 @@ public class BytecodeGenMethod implements StatementVisitor{
Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/LambdaMetafactory",
"metafactory", mt.toMethodDescriptorString(), false);
String methodName = "lambda$new$" + this.lamCounter;
// String typeErasure = "(Ljava/lang/Object;)Ljava/lang/Object;";
// Type erasure
// Type arg1 = Type.getMethodType(typeErasure);
Type arg1 = Type.getMethodType(lamDesc);
// real Type
Type arg3 = Type.getMethodType(lamDesc);
@ -209,7 +216,7 @@ public class BytecodeGenMethod implements StatementVisitor{
MethodVisitor mvLambdaBody = cw.visitMethod(Opcodes.ACC_PRIVATE+ staticOrInstance + Opcodes.ACC_SYNTHETIC,
methodName, arg3.toString(), null, null);
new BytecodeGenMethod(lambdaExpression,this.resultSet,mvLambdaBody,arg3.toString(),indexOfFirstParamLam,isInterface);
new BytecodeGenMethod(lambdaExpression,this.resultSet,mvLambdaBody,indexOfFirstParamLam,isInterface);
mvLambdaBody.visitMaxs(0, 0);
mvLambdaBody.visitEnd();
@ -277,7 +284,8 @@ public class BytecodeGenMethod implements StatementVisitor{
methodCall.receiver.accept(this);
methodCall.arglist.accept(this);
MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType());
MethodFromMethodCall method = new MethodFromMethodCall(methodCall.arglist, methodCall.getType(),
genericsAndBoundsMethod,genericsAndBounds);
String mDesc = method.accept(new DescriptorToString(resultSet));
System.out.println("is Vars empty: "+varsFunInterface.isEmpty());
@ -287,6 +295,7 @@ public class BytecodeGenMethod implements StatementVisitor{
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, getResolvedType(methodCall.receiver.getType()),
methodCall.name, mDesc, false);
}else {
System.out.println("mDesc = " + mDesc);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getResolvedType(methodCall.receiver.getType()),
methodCall.name, mDesc, isInterface);
}
@ -397,6 +406,8 @@ public class BytecodeGenMethod implements StatementVisitor{
@Override
public void visit(AssignToField assignLeftSide) {
// temporäre Lösung für testen, bis ich weiss wie man funktionale
// interfaces erkennt
if(isRightSideALambda)
varsFunInterface.add(assignLeftSide.field.getType());
// Loads the an object reference from the local variable

View File

@ -30,9 +30,37 @@ public class DescriptorToString implements DescriptorVisitor{
Iterator<FormalParameter> itr = method.getParameterList().iterator();
while(itr.hasNext()) {
FormalParameter fp = itr.next();
desc = desc + "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
if(method.hasGen()) {
String fpDesc = fp.getType().acceptTV(new TypeToDescriptor());
if(method.getGenericsAndBoundsMethod().containsKey(fpDesc)) {
desc += "L"+method.getGenericsAndBoundsMethod().get(fpDesc)+ ";";
}else if(method.getGenericsAndBounds().containsKey(fpDesc)){
desc += "L"+method.getGenericsAndBounds().get(fpDesc)+ ";";
}else {
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}else {
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}
desc = addReturnType(desc,method.getReturnType(), resultSet);
if(resultSet.resolveType(method.getReturnType()).resolvedType.toString().equals("void")) {
desc += ")V";
}else {
if(method.hasGen()) {
String ret = method.getReturnType().acceptTV(new TypeToDescriptor());
if(method.getGenericsAndBoundsMethod().containsKey(ret)) {
desc += ")L"+method.getGenericsAndBoundsMethod().get(ret)+ ";";
}else if(method.getGenericsAndBounds().containsKey(ret)){
desc += ")L"+method.getGenericsAndBounds().get(ret)+ ";";
}else {
desc += ")" + "L"+resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}else {
desc += ")" + "L"+resultSet.resolveType(method.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}
// desc = addReturnType(desc,method.getReturnType(), resultSet);
return desc;
}
@ -42,7 +70,19 @@ public class DescriptorToString implements DescriptorVisitor{
Iterator<FormalParameter> itr = constructor.getParameterList().iterator();
while(itr.hasNext()) {
FormalParameter fp = itr.next();
desc = desc + "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
if(constructor.hasGen()) {
System.out.println("Cons has Gens");
String fpDesc = fp.getType().acceptTV(new TypeToDescriptor());
System.out.println(fpDesc);
if(constructor.getGenericsAndBounds().containsKey(fpDesc)){
desc += "L"+constructor.getGenericsAndBounds().get(fpDesc)+ ";";
}else {
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}else {
System.out.println("Cons has NOT Gens");
desc += "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}
desc = desc + ")V";
return desc;
@ -56,6 +96,7 @@ public class DescriptorToString implements DescriptorVisitor{
FormalParameter fp = itr.next();
desc = desc + "L"+resultSet.resolveType(fp.getType()).resolvedType.acceptTV(new TypeToDescriptor()) + ";";
}
System.out.println("LamReturnType: "+lambdaExpression.getReturnType().acceptTV(new TypeToString()));
desc = addReturnType(desc, lambdaExpression.getReturnType(), resultSet);
return desc;
}
@ -75,10 +116,30 @@ public class DescriptorToString implements DescriptorVisitor{
@Override
public String visit(MethodFromMethodCall methodFromMethodCall) {
String desc = "(";
for(Expression e : methodFromMethodCall.argList.getArguments()) {
desc = desc + "L"+resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
for(Expression e : methodFromMethodCall.getArgList().getArguments()) {
String d = e.getType().acceptTV(new TypeToDescriptor());
if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(d)) {
desc += "L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(d)+ ";";
}else if(methodFromMethodCall.getGenericsAndBounds().containsKey(d)) {
desc += "L"+methodFromMethodCall.getGenericsAndBounds().get(d)+ ";";
}else {
desc += "L"+resultSet.resolveType(e.getType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}
desc = addReturnType(desc, methodFromMethodCall.returnType, resultSet);
if(resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.toString().equals("void")) {
desc += ")V";
}else {
String ret = resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor());
if(methodFromMethodCall.getGenericsAndBoundsMethod().containsKey(ret)) {
desc += ")L"+methodFromMethodCall.getGenericsAndBoundsMethod().get(ret)+ ";";
}else if(methodFromMethodCall.getGenericsAndBounds().containsKey(ret)){
desc += ")L"+methodFromMethodCall.getGenericsAndBounds().get(ret)+ ";";
}else {
desc += ")" + "L"+resultSet.resolveType(methodFromMethodCall.getReturnType()).resolvedType.acceptTV(new TypeToDescriptor())+ ";";
}
}
// desc = addReturnType(desc, methodFromMethodCall.getReturnType(), resultSet);
return desc;
}

View File

@ -1,15 +1,38 @@
package de.dhbwstuttgart.bytecode;
import java.util.HashMap;
import de.dhbwstuttgart.syntaxtree.statement.ArgumentList;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
public class MethodFromMethodCall {
ArgumentList argList;
RefTypeOrTPHOrWildcardOrGeneric returnType;
private ArgumentList argList;
private RefTypeOrTPHOrWildcardOrGeneric returnType;
private HashMap<String, String> genericsAndBoundsMethod;
private HashMap<String,String> genericsAndBounds;
public MethodFromMethodCall(ArgumentList argList,RefTypeOrTPHOrWildcardOrGeneric returnType) {
public MethodFromMethodCall(ArgumentList argList,RefTypeOrTPHOrWildcardOrGeneric returnType,
HashMap<String, String> genericsAndBoundsMethod,HashMap<String,String> genericsAndBounds) {
this.argList = argList;
this.returnType = returnType;
this.genericsAndBoundsMethod = genericsAndBoundsMethod;
this.genericsAndBounds = genericsAndBounds;
}
public ArgumentList getArgList() {
return argList;
}
public RefTypeOrTPHOrWildcardOrGeneric getReturnType() {
return returnType;
}
public HashMap<String, String> getGenericsAndBoundsMethod(){
return genericsAndBoundsMethod;
}
public HashMap<String,String> getGenericsAndBounds(){
return genericsAndBounds;
}
public String accept(DescriptorVisitor descVisitor) {

View File

@ -1,15 +1,34 @@
package de.dhbwstuttgart.bytecode;
import java.util.HashMap;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.ParameterList;
public class NormalConstructor {
private Constructor constructor;
private HashMap<String, String> genericsAndBounds;
private boolean hasGenerics;
public NormalConstructor(Constructor constructor) {
public NormalConstructor(Constructor constructor, boolean hasGenerics) {
this.constructor = constructor;
this.hasGenerics = hasGenerics;
}
public NormalConstructor(Constructor constructor, HashMap<String, String> genericsAndBounds, boolean hasGenerics) {
this.constructor = constructor;
this.genericsAndBounds = genericsAndBounds;
this.hasGenerics = hasGenerics;
}
public HashMap<String, String> getGenericsAndBounds() {
return genericsAndBounds;
}
public boolean hasGen() {
return hasGenerics;
}
public ParameterList getParameterList() {
return constructor.getParameterList();
}

View File

@ -1,14 +1,28 @@
package de.dhbwstuttgart.bytecode;
import java.util.HashMap;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.ParameterList;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
public class NormalMethod {
private Method method;
private HashMap<String, String> genericsAndBounds;
private HashMap<String, String> genericsAndBoundsMethod;
private boolean hasGenerics;
public NormalMethod(Method method) {
public NormalMethod(Method method, boolean hasGenerics) {
this.method = method;
this.hasGenerics = hasGenerics;
}
public NormalMethod(Method method, HashMap<String, String> genericsAndBounds,
HashMap<String, String> genericsAndBoundsMethod,boolean hasGenerics) {
this.method = method;
this.genericsAndBounds = genericsAndBounds;
this.genericsAndBoundsMethod = genericsAndBoundsMethod;
this.hasGenerics = hasGenerics;
}
public Method getMethod() {
@ -19,10 +33,22 @@ public class NormalMethod {
return method.getParameterList();
}
public HashMap<String, String> getGenericsAndBounds(){
return genericsAndBounds;
}
public HashMap<String, String> getGenericsAndBoundsMethod(){
return genericsAndBoundsMethod;
}
public RefTypeOrTPHOrWildcardOrGeneric getReturnType() {
return method.getType();
}
public boolean hasGen() {
return this.hasGenerics;
}
public String accept(DescriptorVisitor descVisitor) {
return descVisitor.visit(this);
}

View File

@ -0,0 +1,155 @@
package de.dhbwstuttgart.bytecode;
import java.util.HashMap;
import java.util.Iterator;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;
import de.dhbwstuttgart.syntaxtree.ClassOrInterface;
import de.dhbwstuttgart.syntaxtree.Constructor;
import de.dhbwstuttgart.syntaxtree.GenericTypeVar;
import de.dhbwstuttgart.syntaxtree.Method;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefTypeOrTPHOrWildcardOrGeneric;
import de.dhbwstuttgart.typeinference.result.ResultSet;
public class Signature {
private ClassOrInterface classOrInterface;
private HashMap<String, String> genericsAndBounds;
private HashMap<String, String> genericsAndBoundsMethod;
private SignatureWriter sw;
private Constructor constructor;
private Method method;
private HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes;
private ResultSet resultSet;
public Signature(ClassOrInterface classOrInterface, HashMap<String, String> genericsAndBounds) {
this.classOrInterface = classOrInterface;
this.genericsAndBounds = genericsAndBounds;
sw = new SignatureWriter();
createSignatureForClassOrInterface();
}
public Signature(Constructor constructor, HashMap<String, String> genericsAndBounds, HashMap<String,RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes) {
this.constructor = constructor;
this.genericsAndBounds = genericsAndBounds;
this.methodParamsAndTypes = methodParamsAndTypes;
sw = new SignatureWriter();
createSignatureForConsOrMethod(this.constructor,true);
}
public Signature(Method method, HashMap<String, String> genericsAndBoundsMethod,
HashMap<String, RefTypeOrTPHOrWildcardOrGeneric> methodParamsAndTypes, ResultSet resultSet) {
this.method = method;
this.genericsAndBoundsMethod = genericsAndBoundsMethod;
this.methodParamsAndTypes = methodParamsAndTypes;
this.resultSet = resultSet;
sw = new SignatureWriter();
createSignatureForConsOrMethod(this.method,false);
}
/**
* Creates signature for a method or constructor with @see {@link SignatureWriter}
* Signature looks like:
* <typevaliables (K:Ljava/lang/Object "Bounds")>(params L.. OR T.. Or basistape)ReturnType
*
* @param method method or constructor
* @param isConstructor true if constructor
*/
private void createSignatureForConsOrMethod(Method method, boolean isConstructor) {
Iterator<? extends GenericTypeVar> itr = method.getGenerics().iterator();
// visits all formal type parameter and visits their bounds <T:...;B:...;...>
while(itr.hasNext()) {
GenericTypeVar g = itr.next();
getBoundsOfTypeVar(g,genericsAndBoundsMethod);
}
// visits each method-parameter to create the signature
for(String paramName : methodParamsAndTypes.keySet()) {
RefTypeOrTPHOrWildcardOrGeneric t = methodParamsAndTypes.get(paramName);
// parameter type deswegen ist true
doVisitParamsOrReturn(t,true);
}
if(isConstructor) {
sw.visitReturnType().visitBaseType('V');
}else {
RefTypeOrTPHOrWildcardOrGeneric returnType = method.getReturnType();
// return type deswegen ist false
doVisitParamsOrReturn(returnType, false);
}
// sw.visitEnd();
}
/**
* Visits parameter type or return type with {@link SignatureVisitor} to create
* the method signature
* @param t type of parameter or return type
* @param isParameterType true if t is type of parameter
*/
private void doVisitParamsOrReturn(RefTypeOrTPHOrWildcardOrGeneric t, boolean isParameterType) {
String type = t.acceptTV(new TypeToString());
SignatureVisitor sv;
if(isParameterType) {
sv = sw.visitParameterType();
}
else {
sv = sw.visitReturnType();
}
switch (type) {
case "RT":
sv.visitClassType(t.acceptTV(new TypeToDescriptor()));
break;
case "GRT":
GenericRefType g = (GenericRefType) t;
sv.visitTypeVariable(g.getParsedName());
break;
case "TPH":
System.out.println(resultSet.resolveType(t).resolvedType.acceptTV(new TypeToDescriptor()));
// sv.visitInterface().visitClassType(resultSet.resolveType(t).resolvedType.acceptTV(new TypeToDescriptor())+"<Ljava/lang/Integer;Ljava/lang/Integer;>;");
break;
default:
if(!isParameterType)
sv.visitBaseType('V');
break;
}
}
/**
* Creates signature for class or interface with {@link SignatureWriter}
* Signature looks like:
* <typevaliables (K:Ljava/lang/Object "Bounds")>superclass
*/
private void createSignatureForClassOrInterface() {
Iterator<GenericTypeVar> itr = classOrInterface.getGenerics().iterator();
while(itr.hasNext()) {
GenericTypeVar g = itr.next();
getBoundsOfTypeVar(g,genericsAndBounds);
}
sw.visitSuperclass().visitClassType(classOrInterface.getSuperClass().acceptTV(new TypeToDescriptor()));;
sw.visitEnd();
}
/**
* Get bounds of type variable
* @param g type variable
* @param genAndBounds
*/
private void getBoundsOfTypeVar(GenericTypeVar g, HashMap<String, String> genAndBounds) {
sw.visitFormalTypeParameter(g.getParsedName());
Iterator<? extends RefTypeOrTPHOrWildcardOrGeneric> bItr = g.getBounds().iterator();
while(bItr.hasNext()) {
RefTypeOrTPHOrWildcardOrGeneric b =bItr.next();
String boundDesc = b.acceptTV(new TypeToDescriptor());
// Ensure that <...> extends java.lang.Object OR ...
sw.visitClassBound().visitClassType(boundDesc);
genAndBounds.put(g.getParsedName(), boundDesc);
}
sw.visitClassBound().visitEnd();
}
public String toString() {
return sw.toString();
}
}

View File

@ -0,0 +1,38 @@
package de.dhbwstuttgart.bytecode;
import de.dhbwstuttgart.exceptions.NotImplementedException;
import de.dhbwstuttgart.syntaxtree.type.ExtendsWildcardType;
import de.dhbwstuttgart.syntaxtree.type.GenericRefType;
import de.dhbwstuttgart.syntaxtree.type.RefType;
import de.dhbwstuttgart.syntaxtree.type.SuperWildcardType;
import de.dhbwstuttgart.syntaxtree.type.TypePlaceholder;
import de.dhbwstuttgart.syntaxtree.type.TypeVisitor;
public class TypeToString implements TypeVisitor<String>{
@Override
public String visit(RefType refType) {
return "RT";
}
@Override
public String visit(SuperWildcardType superWildcardType) {
throw new NotImplementedException();
}
@Override
public String visit(TypePlaceholder typePlaceholder) {
return "TPH";
}
@Override
public String visit(ExtendsWildcardType extendsWildcardType) {
throw new NotImplementedException();
}
@Override
public String visit(GenericRefType genericRefType) {
return "GRT";
}
}

View File

@ -1,5 +1,7 @@
class Generics<B> {
Generics(B b){
}
B mt1(B b){
return mt1(b);
}

View File

@ -0,0 +1,6 @@
class Generics2<B extends String>{
<B extends Integer> B m1(B b){
return b;
}
}

View File

@ -0,0 +1,7 @@
package bytecode;
public class Generics2Test extends JavaTXCompilerTest{
public Generics2Test() {
this.fileName = "Generics2";
}
}

View File

@ -0,0 +1,7 @@
package bytecode;
public class GenericsTest extends JavaTXCompilerTest {
public GenericsTest() {
this.fileName = "Generics";
}
}

View File

@ -0,0 +1,7 @@
package bytecode;
public class InterfaceTest extends JavaTXCompilerTest{
public InterfaceTest() {
this.fileName = "Interface1";
}
}

View File

@ -25,11 +25,12 @@ public class JavaTXCompilerTest {
private static final String rootDirectory = System.getProperty("user.dir")+"/test/bytecode/";
private static final List<File> filesToTest = new ArrayList<>();
protected String fileName = "";
@Test
public void test() throws IOException, java.lang.ClassNotFoundException {
System.out.println(rootDirectory);
String fileName = "Faculty";
filesToTest.add(new File(rootDirectory+fileName+".jav"));
System.out.println(rootDirectory+fileName+".jav");
JavaTXCompiler compiler = new JavaTXCompiler(filesToTest);
@ -48,7 +49,7 @@ public class JavaTXCompilerTest {
if(pos != -1) {
name = f.getName().substring(0, pos);
}
this.writeClassFile(bytecode, name);
this.writeClassFile(bytecode);
}
}
@ -61,20 +62,23 @@ public class JavaTXCompilerTest {
return bytecodeGen.getClassFiles();
}
public void writeClassFile(HashMap<String,byte[]> classFiles, String name) {
public void writeClassFile(HashMap<String,byte[]> classFiles) {
FileOutputStream output;
byte[] bytecode = classFiles.get(name);
try {
System.out.println("generating .class file");
output = new FileOutputStream(new File(System.getProperty("user.dir") + "/testBytecode/generatedBC/" +name+".class"));
output.write(bytecode);
output.close();
System.out.println(".class file generated");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
for(String name : classFiles.keySet()) {
byte[] bytecode = classFiles.get(name);
try {
System.out.println("generating"+name+ ".class file");
output = new FileOutputStream(new File(System.getProperty("user.dir") + "/testBytecode/generatedBC/" +name+".class"));
output.write(bytecode);
output.close();
System.out.println(name+".class file generated");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
static String readFile(String path, Charset encoding)

View File

@ -7,3 +7,7 @@ class LamAssign {
return lam1;
}
}
interface Fun1<A,B>{
A apply(B b);
}

View File

@ -0,0 +1,7 @@
package bytecode;
public class LamAssignTest extends JavaTXCompilerTest{
public LamAssignTest() {
this.fileName = "LamAssign";
}
}