Added support for methods

This commit is contained in:
Sander Hautvast 2020-11-10 21:17:16 +01:00
parent 321182aca7
commit 10ffe459e0
7 changed files with 230 additions and 40 deletions

View file

@ -34,6 +34,7 @@ public class Compiler {
CompiledClass compile() { CompiledClass compile() {
compiledClass.getBeeClass().getConstructors().forEach(this::updateConstantPool); compiledClass.getBeeClass().getConstructors().forEach(this::updateConstantPool);
compiledClass.getBeeClass().getMethods().forEach(this::updateConstantPool);
// TODO update constant pool for fields ? // TODO update constant pool for fields ?
// TODO update constant pool for methods // TODO update constant pool for methods
@ -45,7 +46,7 @@ public class Compiler {
} }
private void updateConstantPool(ContainsCode codeContainer) { private void updateConstantPool(CodeContainer codeContainer) {
codeContainer.getCode().forEach(this::updateConstantPool); codeContainer.getCode().forEach(this::updateConstantPool);
} }
@ -59,12 +60,16 @@ public class Compiler {
* So Compiled class also contains a set of unique root nodes. * So Compiled class also contains a set of unique root nodes.
*/ */
private void updateConstantPool(CodeLine codeline) { private void updateConstantPool(CodeLine codeline) {
if (codeline.hasMethod()) { if (codeline.hasMethodCall()) {
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline)); compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline));
} }
if (codeline.hasField()) { if (codeline.hasRefToOwnField() || codeline.hasRefToExternalField()) {
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline)); compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline));
} }
if (codeline.hasConstValue()) {
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreatePrimitiveEntry(codeline));
}
} }
} }

View file

@ -1,6 +1,5 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass;
import nl.sander.beejava.api.CodeLine; import nl.sander.beejava.api.CodeLine;
import nl.sander.beejava.api.Ref; import nl.sander.beejava.api.Ref;
import nl.sander.beejava.constantpool.entry.*; import nl.sander.beejava.constantpool.entry.*;
@ -31,7 +30,16 @@ class ConstantPoolEntryCreator {
} }
private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) { private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) {
return cache(new NameAndTypeEntry(cache(new Utf8Entry(codeline.getField().getName())), cache(new Utf8Entry(TypeMapper.map(codeline.getField().getType()))))); if (codeline.hasRefToOwnField()) {
return cache(new NameAndTypeEntry(
cache(new Utf8Entry(codeline.getOwnfield().getName())),
cache(new Utf8Entry(TypeMapper.map(codeline.getOwnfield().getType()))))); // is actually a shortcut
} else {
return cache(new NameAndTypeEntry(
cache(new Utf8Entry(codeline.getExternalfield())),
cache(new Utf8Entry("L" + codeline.getExternalfieldClass()))
));
}
} }
private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) { private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) {
@ -41,6 +49,7 @@ class ConstantPoolEntryCreator {
} }
private ClassEntry getOrCreateClassEntry(CodeLine codeline) { private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
if (codeline.hasRef()) {
if (codeline.getRef() == Ref.SUPER) { //this and super are rather special if (codeline.getRef() == Ref.SUPER) { //this and super are rather special
ClassEntry superClass = getClassEntry(compiledClass.getBeeClass().getSuperClass().getName()); ClassEntry superClass = getClassEntry(compiledClass.getBeeClass().getSuperClass().getName());
compiledClass.setSuperClass(superClass); compiledClass.setSuperClass(superClass);
@ -50,12 +59,16 @@ class ConstantPoolEntryCreator {
addThisClass(); addThisClass();
return compiledClass.getThisClass(); return compiledClass.getThisClass();
} }
//TODO other cases } else if (codeline.hasClassName()) {
return getClassEntry(codeline.getClassName());
}
throw new RuntimeException("shouldn't be here"); throw new RuntimeException("shouldn't be here");
} }
void addThisClass() { void addThisClass() {
ClassEntry classEntry = getClassEntry(compiledClass.getBeeClass().getName()); ClassEntry classEntry = getClassEntry(compiledClass.getBeeClass().getName());
compiledClass.addConstantPoolEntry(classEntry);
compiledClass.setThisClass(classEntry); compiledClass.setThisClass(classEntry);
} }
@ -71,7 +84,22 @@ class ConstantPoolEntryCreator {
}); });
} }
public ConstantPoolEntry getOrCreatePrimitiveEntry(CodeLine codeline) {
Object v = codeline.getConstValue();
if (v instanceof String) {
return cache(new StringEntry(cache(new Utf8Entry((String) v))));
} else if (v instanceof Integer) {
return cache(new IntegerEntry((Integer) v));
} else if (v instanceof Long) {
return cache(new LongEntry((Long) v));
} else if (v instanceof Float) {
return cache(new FloatEntry((Float) v));
} else if (v instanceof Double) {
return cache(new DoubleEntry((Double) v));
}
throw new RuntimeException(); // TODO find out why are you here
}
public void addFields() { public void addFields() {
compiledClass.getBeeClass().getFields().forEach(field -> { compiledClass.getBeeClass().getFields().forEach(field -> {
@ -88,9 +116,11 @@ class ConstantPoolEntryCreator {
// First create an object using the supplier, but if it's found in cache, return the cached entry and discard the first. // First create an object using the supplier, but if it's found in cache, return the cached entry and discard the first.
// Can't check for equality unless you create a potential new entry first // Can't check for equality unless you create a potential new entry first
int hash = newEntry.hashCode(); int hash = newEntry.hashCode();
return (T) cache.computeIfAbsent(hash, k -> newEntry); T a = (T) cache.computeIfAbsent(hash, k -> newEntry);
return a;
// a hashmap with key hash of value is weird right? // a hashmap with key hash of value is weird right?
// A HashSet is a HashMap with entry: key = value, which would work, but I cannot _get_ anything from a set. // A HashSet is a HashMap with entry: key = value, which would work, but I cannot _get_ anything from a set.
} }
} }

View file

@ -2,6 +2,7 @@ package nl.sander.beejava.api;
import nl.sander.beejava.flags.ClassAccessFlag; import nl.sander.beejava.flags.ClassAccessFlag;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -15,10 +16,11 @@ public class BeeClass {
private final Set<Class<?>> interfaces = new HashSet<>(); private final Set<Class<?>> interfaces = new HashSet<>();
private final Set<BeeField> fields = new HashSet<>(); private final Set<BeeField> fields = new HashSet<>();
private final Set<BeeConstructor> constructors = new HashSet<>(); private final Set<BeeConstructor> constructors = new HashSet<>();
private final Set<BeeMethod> methods = new HashSet<>();
private BeeClass(Version classFileVersion, private BeeClass(Version classFileVersion,
BeePackage beePackage, Set<ClassAccessFlag> accessFlags, String simpleName, Class<?> superClass, BeePackage beePackage, Set<ClassAccessFlag> accessFlags, String simpleName, Class<?> superClass,
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors) { Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors, Set<BeeMethod> methods) {
this.classFileVersion = classFileVersion; this.classFileVersion = classFileVersion;
this.beePackage = beePackage; this.beePackage = beePackage;
this.accessFlags.addAll(accessFlags); this.accessFlags.addAll(accessFlags);
@ -27,6 +29,7 @@ public class BeeClass {
this.interfaces.addAll(interfaces); this.interfaces.addAll(interfaces);
this.fields.addAll(fields); this.fields.addAll(fields);
this.constructors.addAll(constructors); this.constructors.addAll(constructors);
this.methods.addAll(methods);
} }
public static BeeClass.Builder builder() { public static BeeClass.Builder builder() {
@ -52,6 +55,10 @@ public class BeeClass {
return constructors; return constructors;
} }
public Set<BeeMethod> getMethods() {
return methods;
}
public Set<ClassAccessFlag> getAccessFlags() { public Set<ClassAccessFlag> getAccessFlags() {
return accessFlags; return accessFlags;
} }
@ -79,11 +86,12 @@ public class BeeClass {
private final Set<ClassAccessFlag> accessFlags = new HashSet<>(); private final Set<ClassAccessFlag> accessFlags = new HashSet<>();
private final Set<Class<?>> interfaces = new HashSet<>(); private final Set<Class<?>> interfaces = new HashSet<>();
private final Set<BeeField> fields = new HashSet<>(); private final Set<BeeField> fields = new HashSet<>();
private final Set<BeeConstructor> constructors = new HashSet<>();
private Version version; private Version version;
private BeePackage beePackage; private BeePackage beePackage;
private Class<?> superClass = Object.class; private Class<?> superClass = Object.class;
private String simpleName; private String simpleName;
private final Set<BeeConstructor> constructors = new HashSet<>();
private final Set<BeeMethod> methods = new HashSet<>();
private Builder() { private Builder() {
} }
@ -128,10 +136,14 @@ public class BeeClass {
return this; return this;
} }
public Builder withMethods(BeeMethod... methods) {
this.methods.addAll(Arrays.asList(methods));
return this;
}
public BeeClass build() { public BeeClass build() {
return new BeeClass(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors); return new BeeClass(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods);
} }
} }
} }

View file

@ -1,6 +1,6 @@
package nl.sander.beejava.api; package nl.sander.beejava.api;
import nl.sander.beejava.ContainsCode; import nl.sander.beejava.CodeContainer;
import nl.sander.beejava.flags.MethodAccessFlag; import nl.sander.beejava.flags.MethodAccessFlag;
import java.util.*; import java.util.*;
@ -8,17 +8,16 @@ import java.util.*;
/** /**
* Models a constructor * Models a constructor
*/ */
public class BeeConstructor implements ContainsCode { public class BeeConstructor extends CodeContainer {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>(); private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
private final Set<BeeParameter> formalParameters = new HashSet<>(); private final Set<BeeParameter> formalParameters = new HashSet<>();
private final List<CodeLine> code = new LinkedList<>();
private BeeConstructor(Set<MethodAccessFlag> accessFlags, private BeeConstructor(Set<MethodAccessFlag> accessFlags,
List<BeeParameter> formalParameters, List<BeeParameter> formalParameters,
List<CodeLine> code) { List<CodeLine> code) {
this.formalParameters.addAll(formalParameters); this.formalParameters.addAll(formalParameters);
this.accessFlags.addAll(accessFlags); this.accessFlags.addAll(accessFlags);
this.code.addAll(code); super.code.addAll(code);
} }
public static Builder builder() { public static Builder builder() {
@ -33,11 +32,6 @@ public class BeeConstructor implements ContainsCode {
return formalParameters; return formalParameters;
} }
@Override
public List<CodeLine> getCode() {
return code;
}
@Override @Override
public String toString() { public String toString() {
return "BeeConstructor{" + return "BeeConstructor{" +

View file

@ -0,0 +1,59 @@
package nl.sander.beejava.api;
import nl.sander.beejava.CodeContainer;
import nl.sander.beejava.flags.MethodAccessFlag;
import java.util.*;
public final class BeeMethod extends CodeContainer {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
private final Set<BeeParameter> formalParameters = new HashSet<>();
private final Class<?> returnType;
private BeeMethod(Set<MethodAccessFlag> accessFlags,
List<BeeParameter> formalParameters,
Class<?> returnType, List<CodeLine> code) {
this.accessFlags.addAll(accessFlags);
this.formalParameters.addAll(formalParameters);
this.returnType = returnType;
super.code.addAll(code);
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
private final List<BeeParameter> formalParameters = new LinkedList<>();
private final List<CodeLine> code = new LinkedList<>();
private Class<?> returnType;
private Builder() {
}
public Builder withAccessFlags(MethodAccessFlag... accessFlags) {
this.accessFlags.addAll(Arrays.asList(accessFlags));
return this;
}
public Builder withFormalParameters(BeeParameter... formalParameters) {
this.formalParameters.addAll(Arrays.asList(formalParameters));
return this;
}
public Builder withReturnType(Class<?> returnType) {
this.returnType = returnType;
return this;
}
public Builder withCode(CodeLine... lines) {
this.code.addAll(Arrays.asList(lines));
return this;
}
public BeeMethod build() {
return new BeeMethod(accessFlags, formalParameters, returnType, code);
}
}
}

View file

@ -6,10 +6,15 @@ public class CodeLine {
private final Opcode opcode; private final Opcode opcode;
private Ref ref; private Ref ref;
private BeeParameter parameter; private BeeParameter parameter;
private String className;
private String methodName; private String methodName;
private String inputSignature; private String inputSignature;
private String outputSignature; private String outputSignature;
private BeeField field; private BeeField ownfield; // when you create a class with a field, you can refer to it
private String externalfield; // when you refer to a field from another class
private Object constValue;
private String externalFieldType;
CodeLine(int linenumber, Opcode opcode) { CodeLine(int linenumber, Opcode opcode) {
this.linenumber = linenumber; this.linenumber = linenumber;
@ -20,6 +25,18 @@ public class CodeLine {
return new CodeLine(nr, opcode).withRef(ref); return new CodeLine(nr, opcode).withRef(ref);
} }
public static CodeLine line(int nr, Opcode opcode, String fieldClass, String fieldName) {
return new CodeLine(nr, opcode).withExternalFieldRef(fieldClass, fieldName);
}
public static CodeLine line(int nr, Opcode opcode, Object constValue) {
return new CodeLine(nr, opcode).withConstValue(constValue);
}
public static CodeLine line(int nr, Opcode opcode, String className, String methodName, String inputSignature) {
return new CodeLine(nr, opcode).withClassName(className).withMethodName(methodName).withInput(inputSignature).withVoidOutput();
}
public static CodeLine line(int nr, Opcode opcode, Ref ref, String methodNameRef, String inputSignature) { public static CodeLine line(int nr, Opcode opcode, Ref ref, String methodNameRef, String inputSignature) {
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(inputSignature).withVoidOutput(); return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(inputSignature).withVoidOutput();
} }
@ -37,7 +54,7 @@ public class CodeLine {
} }
public static CodeLine line(int nr, Opcode opcode, BeeField intField) { public static CodeLine line(int nr, Opcode opcode, BeeField intField) {
return new CodeLine(nr, opcode).withRef(Ref.THIS).withField(intField); return new CodeLine(nr, opcode).withRef(Ref.THIS).withOwnField(intField);
} }
private CodeLine withRef(Ref ref) { private CodeLine withRef(Ref ref) {
@ -45,6 +62,11 @@ public class CodeLine {
return this; return this;
} }
private CodeLine withClassName(String className) {
this.className = className;
return this;
}
private CodeLine withMethodName(String methodName) { private CodeLine withMethodName(String methodName) {
this.methodName = methodName; this.methodName = methodName;
return this; return this;
@ -69,16 +91,57 @@ public class CodeLine {
return this; return this;
} }
private CodeLine withField(BeeField field) { private CodeLine withConstValue(Object constValue) {
this.field = field; this.constValue = constValue;
return this; //TODO
}
private CodeLine withOwnField(BeeField beeField) {
this.ownfield = beeField;
return this; return this;
} }
private CodeLine withExternalFieldRef(String className, String field) {
this.className = className;
this.externalFieldType = getType(className, field);
this.externalfield = field;
return this;
}
// TODO decide whether to work with Strings or class objects...
/*
* Look up the type of a field in a class
*
* Assumes field is accessible
*
* @param className the class containing a field
* @param field name of the field
* @return the field type
*/
private String getType(String className, String field) {
try {
return Class.forName(className).getField(field).getType().getName();
} catch (ClassNotFoundException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
public boolean hasClassName() {
return className != null;
}
public String getClassName() {
return className;
}
public String getMethodName() { public String getMethodName() {
return methodName; return methodName;
} }
public boolean hasMethod() { public boolean hasMethodCall() {
return methodName != null; return methodName != null;
} }
@ -94,12 +157,21 @@ public class CodeLine {
return ref != null; return ref != null;
} }
public boolean hasField() { public boolean hasRefToOwnField() {
return field != null; return ownfield != null;
} }
public BeeField getField() {
return field; public Object getConstValue() {
return constValue;
}
public boolean hasConstValue() {
return constValue != null;
}
public BeeField getOwnfield() {
return ownfield;
} }
public BeeParameter getParameter() { public BeeParameter getParameter() {
@ -107,4 +179,15 @@ public class CodeLine {
} }
public boolean hasRefToExternalField() {
return externalfield != null;
}
public String getExternalfield() {
return externalfield;
}
public String getExternalfieldClass() {
return externalFieldType;
}
} }

View file

@ -1,5 +1,6 @@
package nl.sander.beejava.testclasses; package nl.sander.beejava.testclasses;
// two references to System. System should not be in the constant pool twice.
public class BeanWithClassReferences { public class BeanWithClassReferences {
public void print1() { public void print1() {
@ -7,6 +8,12 @@ public class BeanWithClassReferences {
} }
public void print2() { public void print2() {
System.out.println("2"); System.out.println(create2());
}
public String create2() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("2");
return stringBuilder.toString();
} }
} }