started adding support for methods

This commit is contained in:
Sander Hautvast 2020-11-11 13:53:21 +01:00
parent a1e78f5ed9
commit ab4662f86e
24 changed files with 260 additions and 175 deletions

View file

@ -1,9 +1,8 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass;
import nl.sander.beejava.constantpool.ConstantPool; import nl.sander.beejava.constantpool.ConstantPool;
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
import nl.sander.beejava.flags.ClassAccessFlag; import nl.sander.beejava.flags.AccessFlags;
import nl.sander.beejava.util.ByteBuf; import nl.sander.beejava.util.ByteBuf;
public class BytecodeGenerator { public class BytecodeGenerator {
@ -23,19 +22,20 @@ public class BytecodeGenerator {
private byte[] generate() { private byte[] generate() {
ByteBuf buf = new ByteBuf(); ByteBuf buf = new ByteBuf();
buf.addU8(0xCA, 0xFE, 0xBA, 0xBE); buf.addU8(0xCA, 0xFE, 0xBA, 0xBE);
buf.addU16(compiledClass.getBeeClass().getClassFileVersion().getMinor()); buf.addU16(compiledClass.getSource().getClassFileVersion().getMinor());
buf.addU16(compiledClass.getBeeClass().getClassFileVersion().getMajor()); buf.addU16(compiledClass.getSource().getClassFileVersion().getMajor());
ConstantPool constantPool = constantPoolCreator.createConstantPool(compiledClass.getConstantTree()); ConstantPool constantPool = constantPoolCreator.createConstantPool(compiledClass.getConstantTree());
buf.addU16(constantPool.getLength()); buf.addU16(constantPool.getLength());
buf.addU8(constantPool.getBytes()); constantPool.addTo(buf);
buf.addU16(ClassAccessFlag.getSum(compiledClass.getBeeClass().getAccessFlags())); buf.addU16(AccessFlags.combine(compiledClass.getSource().getAccessFlags()));
buf.addU16(compiledClass.geThisIndex()); buf.addU16(compiledClass.geThisIndex());
buf.addU16(compiledClass.getSuperIndex()); buf.addU16(compiledClass.getSuperIndex());
buf.addU16(compiledClass.getInterfaces().size()); buf.addU16(compiledClass.getInterfaces().size());
compiledClass.getInterfaces().forEach(interfase -> buf.addU16(interfase.getIndex())); compiledClass.getInterfaces().forEach(interfase -> buf.addU16(interfase.getIndex()));
buf.addU16(compiledClass.getFields().size());
compiledClass.getFields().forEach(fieldInfo -> fieldInfo.addBytes(buf));
int x = 1; int x = 1;
for (ConstantPoolEntry e : constantPool) { for (ConstantPoolEntry e : constantPool) {

View file

@ -5,6 +5,9 @@ import nl.sander.beejava.api.CodeLine;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
/**
* parent of a constructor or a method.
*/
public abstract class CodeContainer { public abstract class CodeContainer {
protected final List<CodeLine> code = new LinkedList<>(); protected final List<CodeLine> code = new LinkedList<>();

View file

@ -1,6 +1,7 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass; import nl.sander.beejava.api.BeeSource;
import nl.sander.beejava.classinfo.FieldInfo;
import nl.sander.beejava.constantpool.entry.ClassEntry; import nl.sander.beejava.constantpool.entry.ClassEntry;
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
@ -11,12 +12,13 @@ import java.util.Set;
class CompiledClass { class CompiledClass {
private final Set<ConstantPoolEntry> constantTree = new LinkedHashSet<>(); private final Set<ConstantPoolEntry> constantTree = new LinkedHashSet<>();
private final Set<ClassEntry> interfaces = new HashSet<>(); private final Set<ClassEntry> interfaces = new HashSet<>();
private final BeeClass beeClass; private final Set<FieldInfo> fields = new HashSet<>();
private final BeeSource beeSource;
private ClassEntry thisClass; private ClassEntry thisClass;
private ClassEntry superClass; private ClassEntry superClass;
CompiledClass(BeeClass beeClass) { CompiledClass(BeeSource beeSource) {
this.beeClass = beeClass; this.beeSource = beeSource;
} }
int getSuperIndex() { int getSuperIndex() {
@ -49,12 +51,8 @@ class CompiledClass {
interfaces.add(interfaceEntry); interfaces.add(interfaceEntry);
} }
BeeClass getBeeClass() { BeeSource getSource() {
return beeClass; return beeSource;
}
ClassEntry getThisClass() {
return thisClass;
} }
public void setThisClass(ClassEntry newThisClass) { public void setThisClass(ClassEntry newThisClass) {
@ -62,4 +60,12 @@ class CompiledClass {
thisClass = newThisClass; thisClass = newThisClass;
} }
} }
public void addField(FieldInfo fieldInfo) {
fields.add(fieldInfo);
}
public Set<FieldInfo> getFields() {
return fields;
}
} }

View file

@ -1,12 +1,12 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass; import nl.sander.beejava.api.BeeSource;
import nl.sander.beejava.api.CodeLine; import nl.sander.beejava.api.CodeLine;
/** /**
* Builds a set of a tree of constant pool entries that refer to each other. * Builds a set of a tree of constant pool entries that refer to each other.
* <p> * <p>
* A client must supply a {@link BeeClass} containing a set of {@link CodeLine}s that is assumed to be correct. * A client must supply a {@link BeeSource} containing a set of {@link CodeLine}s that is assumed to be correct.
* It doesn't check if a valid state is reached. * It doesn't check if a valid state is reached.
*/ */
/* So the name isn't entirely correct. Waiting for inspiration. /* So the name isn't entirely correct. Waiting for inspiration.
@ -16,36 +16,45 @@ public class Compiler {
private final CompiledClass compiledClass; private final CompiledClass compiledClass;
private final ConstantPoolEntryCreator constantPoolEntryCreator; private final ConstantPoolEntryCreator constantPoolEntryCreator;
Compiler(CompiledClass compiledClass) { /**
* construct a compiler object.
*/
/*
* At this moment I'm not sure if this class will be able to reused.
*/
public Compiler(CompiledClass compiledClass) {
this.compiledClass = compiledClass; this.compiledClass = compiledClass;
this.constantPoolEntryCreator = new ConstantPoolEntryCreator(compiledClass); this.constantPoolEntryCreator = new ConstantPoolEntryCreator(compiledClass);
} }
/** /**
* Creates a Set of nested entries that make up a single reference. For instance a class reference whose name is a utf8 reference. * compile a BeeSource object into a CompiledClass object.
* In the constant pool they are consecutive entries, but they are created like nodes in a tree structure that models their relation.
* *
* @param beeClass the Class object for which the constant pool needs to be created * @param beeSource the Class object for which the constant pool needs to be created
* @return a Set of constant pool entries * @return a CompiledClass object (that can be turned into bytecode)
*/ */
public static CompiledClass compile(BeeClass beeClass) { public static CompiledClass compile(BeeSource beeSource) {
return new Compiler(new CompiledClass(beeClass)).compile(); return new Compiler(new CompiledClass(beeSource)).compile();
} }
CompiledClass compile() { /**
compiledClass.getBeeClass().getConstructors().forEach(this::updateConstantPool); * construct a CompiledClass object that contains all information for generating the bytecode
compiledClass.getBeeClass().getMethods().forEach(this::updateConstantPool); */
public CompiledClass compile() {
compiledClass.getSource().getConstructors().forEach(this::updateConstantPool);
compiledClass.getSource().getMethods().forEach(this::updateConstantPool);
// TODO update constant pool for fields ? // TODO update constant pool for fields ?
// TODO update constant pool for methods
constantPoolEntryCreator.addThisClass(); compiledClass.setThisClass(constantPoolEntryCreator.addThisClass());
constantPoolEntryCreator.addInterfaces(); constantPoolEntryCreator.addInterfaces();
constantPoolEntryCreator.addFields(); constantPoolEntryCreator.addFields();
return compiledClass; return compiledClass;
} }
/*
* inspect a method or constructor, extract items that need to be added, and add them to the constant pool
*/
private void updateConstantPool(CodeContainer codeContainer) { private void updateConstantPool(CodeContainer codeContainer) {
codeContainer.getCode().forEach(this::updateConstantPool); codeContainer.getCode().forEach(this::updateConstantPool);
} }

View file

@ -2,6 +2,7 @@ package nl.sander.beejava;
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.classinfo.FieldInfo;
import nl.sander.beejava.constantpool.entry.*; import nl.sander.beejava.constantpool.entry.*;
import java.util.HashMap; import java.util.HashMap;
@ -51,13 +52,12 @@ class ConstantPoolEntryCreator {
private ClassEntry getOrCreateClassEntry(CodeLine codeline) { private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
if (codeline.hasRef()) { 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.getSource().getSuperClass().getName());
compiledClass.setSuperClass(superClass); compiledClass.setSuperClass(superClass);
return superClass; return superClass;
} else if (codeline.getRef() == Ref.THIS) { } else if (codeline.getRef() == Ref.THIS) {
addThisClass(); return addThisClass();
return compiledClass.getThisClass();
} }
} else if (codeline.hasClassName()) { } else if (codeline.hasClassName()) {
return getClassEntry(codeline.getClassName()); return getClassEntry(codeline.getClassName());
@ -66,24 +66,32 @@ class ConstantPoolEntryCreator {
throw new RuntimeException("shouldn't be here"); throw new RuntimeException("shouldn't be here");
} }
void addThisClass() { ClassEntry addThisClass() {
ClassEntry classEntry = getClassEntry(compiledClass.getBeeClass().getName()); ClassEntry classEntry = getClassEntry(compiledClass.getSource().getName());
compiledClass.addConstantPoolEntry(classEntry); compiledClass.addConstantPoolEntry(classEntry);
compiledClass.setThisClass(classEntry); return classEntry;
} }
private ClassEntry getClassEntry(String externalClassName) { private ClassEntry getClassEntry(String externalClassName) {
return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName))))); return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName)))));
} }
/*
* Adds interfaces to the constant pool as well as the class.
*
* interfaces[] in the class file is an array of cp entries
*/
public void addInterfaces() { public void addInterfaces() {
compiledClass.getBeeClass().getInterfaces().forEach(interfase -> { compiledClass.getSource().getInterfaces().forEach(interfase -> {
ClassEntry interfaceEntry = cache(new ClassEntry(cache(new Utf8Entry(internalName(interfase.getName()))))); ClassEntry interfaceEntry = cache(new ClassEntry(cache(new Utf8Entry(internalName(interfase.getName())))));
compiledClass.addInterface(interfaceEntry); compiledClass.addInterface(interfaceEntry);
compiledClass.addConstantPoolEntry(interfaceEntry); compiledClass.addConstantPoolEntry(interfaceEntry);
}); });
} }
/*
* If a constant is in the codeline, it needs to be added to the constant pool.
*/
public ConstantPoolEntry getOrCreatePrimitiveEntry(CodeLine codeline) { public ConstantPoolEntry getOrCreatePrimitiveEntry(CodeLine codeline) {
Object v = codeline.getConstValue(); Object v = codeline.getConstValue();
@ -102,9 +110,12 @@ class ConstantPoolEntryCreator {
} }
public void addFields() { public void addFields() {
compiledClass.getBeeClass().getFields().forEach(field -> { compiledClass.getSource().getFields()
// TODO .forEach(f -> {
}); Utf8Entry name = cache(new Utf8Entry(f.getName()));
Utf8Entry descriptor = cache(new Utf8Entry(internalName(f.getType().getName())));
compiledClass.addField(new FieldInfo(name, descriptor).addAccessFlags(f.getAccessFlags()));
});
} }
private String internalName(String name) { private String internalName(String name) {
@ -116,8 +127,7 @@ 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();
T a = (T) cache.computeIfAbsent(hash, k -> newEntry); return (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

@ -1,7 +1,7 @@
package nl.sander.beejava.api; package nl.sander.beejava.api;
import nl.sander.beejava.CodeContainer; import nl.sander.beejava.CodeContainer;
import nl.sander.beejava.flags.MethodAccessFlag; import nl.sander.beejava.flags.MethodAccessFlags;
import java.util.*; import java.util.*;
@ -9,10 +9,10 @@ import java.util.*;
* Models a constructor * Models a constructor
*/ */
public class BeeConstructor extends CodeContainer { public class BeeConstructor extends CodeContainer {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>(); private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
private final Set<BeeParameter> formalParameters = new HashSet<>(); private final Set<BeeParameter> formalParameters = new HashSet<>();
private BeeConstructor(Set<MethodAccessFlag> accessFlags, private BeeConstructor(Set<MethodAccessFlags> accessFlags,
List<BeeParameter> formalParameters, List<BeeParameter> formalParameters,
List<CodeLine> code) { List<CodeLine> code) {
this.formalParameters.addAll(formalParameters); this.formalParameters.addAll(formalParameters);
@ -24,7 +24,7 @@ public class BeeConstructor extends CodeContainer {
return new Builder(); return new Builder();
} }
Set<MethodAccessFlag> getAccessFlags() { Set<MethodAccessFlags> getAccessFlags() {
return accessFlags; return accessFlags;
} }
@ -53,7 +53,7 @@ public class BeeConstructor extends CodeContainer {
} }
public static class Builder { public static class Builder {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>(); private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
private final List<BeeParameter> formalParameters = new LinkedList<>(); private final List<BeeParameter> formalParameters = new LinkedList<>();
private final List<CodeLine> code = new LinkedList<>(); private final List<CodeLine> code = new LinkedList<>();
@ -66,7 +66,7 @@ public class BeeConstructor extends CodeContainer {
return this; return this;
} }
public Builder withAccessFlags(MethodAccessFlag... accessFlags) { public Builder withAccessFlags(MethodAccessFlags... accessFlags) {
this.accessFlags.addAll(Arrays.asList(accessFlags)); this.accessFlags.addAll(Arrays.asList(accessFlags));
return this; return this;
} }

View file

@ -1,6 +1,6 @@
package nl.sander.beejava.api; package nl.sander.beejava.api;
import nl.sander.beejava.flags.FieldAccessFlag; import nl.sander.beejava.flags.FieldAccessFlags;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@ -9,11 +9,11 @@ import java.util.Set;
public class BeeField { public class BeeField {
private final Set<FieldAccessFlag> accessFlags = new HashSet<>(); private final Set<FieldAccessFlags> accessFlags = new HashSet<>();
private final Class<?> type; private final Class<?> type;
private final String name; private final String name;
private BeeField(Set<FieldAccessFlag> accessFlags, Class<?> type, String name) { private BeeField(Set<FieldAccessFlags> accessFlags, Class<?> type, String name) {
this.accessFlags.addAll(accessFlags); this.accessFlags.addAll(accessFlags);
this.type = type; this.type = type;
this.name = name; this.name = name;
@ -23,7 +23,7 @@ public class BeeField {
return new Builder(); return new Builder();
} }
public Set<FieldAccessFlag> getAccessFlags() { public Set<FieldAccessFlags> getAccessFlags() {
return accessFlags; return accessFlags;
} }
@ -49,7 +49,7 @@ public class BeeField {
} }
public static class Builder { public static class Builder {
private final Set<FieldAccessFlag> accessFlags = new HashSet<>(); private final Set<FieldAccessFlags> accessFlags = new HashSet<>();
private Class<?> type; private Class<?> type;
private String name; private String name;
@ -57,7 +57,7 @@ public class BeeField {
} }
public BeeField.Builder withAccessFlags(FieldAccessFlag... accessFlags) { public BeeField.Builder withAccessFlags(FieldAccessFlags... accessFlags) {
this.accessFlags.addAll(Arrays.asList(accessFlags)); this.accessFlags.addAll(Arrays.asList(accessFlags));
return this; return this;
} }

View file

@ -1,16 +1,16 @@
package nl.sander.beejava.api; package nl.sander.beejava.api;
import nl.sander.beejava.CodeContainer; import nl.sander.beejava.CodeContainer;
import nl.sander.beejava.flags.MethodAccessFlag; import nl.sander.beejava.flags.MethodAccessFlags;
import java.util.*; import java.util.*;
public final class BeeMethod extends CodeContainer { public final class BeeMethod extends CodeContainer {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>(); private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
private final Set<BeeParameter> formalParameters = new HashSet<>(); private final Set<BeeParameter> formalParameters = new HashSet<>();
private final Class<?> returnType; private final Class<?> returnType;
private BeeMethod(Set<MethodAccessFlag> accessFlags, private BeeMethod(Set<MethodAccessFlags> accessFlags,
List<BeeParameter> formalParameters, List<BeeParameter> formalParameters,
Class<?> returnType, List<CodeLine> code) { Class<?> returnType, List<CodeLine> code) {
this.accessFlags.addAll(accessFlags); this.accessFlags.addAll(accessFlags);
@ -24,7 +24,7 @@ public final class BeeMethod extends CodeContainer {
} }
public static class Builder { public static class Builder {
private final Set<MethodAccessFlag> accessFlags = new HashSet<>(); private final Set<MethodAccessFlags> accessFlags = new HashSet<>();
private final List<BeeParameter> formalParameters = new LinkedList<>(); private final List<BeeParameter> formalParameters = new LinkedList<>();
private final List<CodeLine> code = new LinkedList<>(); private final List<CodeLine> code = new LinkedList<>();
private Class<?> returnType; private Class<?> returnType;
@ -32,7 +32,7 @@ public final class BeeMethod extends CodeContainer {
private Builder() { private Builder() {
} }
public Builder withAccessFlags(MethodAccessFlag... accessFlags) { public Builder withAccessFlags(MethodAccessFlags... accessFlags) {
this.accessFlags.addAll(Arrays.asList(accessFlags)); this.accessFlags.addAll(Arrays.asList(accessFlags));
return this; return this;
} }

View file

@ -1,16 +1,15 @@
package nl.sander.beejava.api; package nl.sander.beejava.api;
import nl.sander.beejava.flags.ClassAccessFlag; import nl.sander.beejava.flags.ClassAccessFlags;
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;
public class BeeClass { public class BeeSource {
private final Version classFileVersion; private final Version classFileVersion;
private final BeePackage beePackage; private final BeePackage beePackage;
private final Set<ClassAccessFlag> accessFlags = new HashSet<>(); private final Set<ClassAccessFlags> accessFlags = new HashSet<>();
private final String simpleName; private final String simpleName;
private final Class<?> superClass; private final Class<?> superClass;
private final Set<Class<?>> interfaces = new HashSet<>(); private final Set<Class<?>> interfaces = new HashSet<>();
@ -18,9 +17,9 @@ public class BeeClass {
private final Set<BeeConstructor> constructors = new HashSet<>(); private final Set<BeeConstructor> constructors = new HashSet<>();
private final Set<BeeMethod> methods = new HashSet<>(); private final Set<BeeMethod> methods = new HashSet<>();
private BeeClass(Version classFileVersion, private BeeSource(Version classFileVersion,
BeePackage beePackage, Set<ClassAccessFlag> accessFlags, String simpleName, Class<?> superClass, BeePackage beePackage, Set<ClassAccessFlags> accessFlags, String simpleName, Class<?> superClass,
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors, Set<BeeMethod> methods) { 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);
@ -32,7 +31,7 @@ public class BeeClass {
this.methods.addAll(methods); this.methods.addAll(methods);
} }
public static BeeClass.Builder builder() { public static BeeSource.Builder builder() {
return new Builder(); return new Builder();
} }
@ -59,7 +58,7 @@ public class BeeClass {
return methods; return methods;
} }
public Set<ClassAccessFlag> getAccessFlags() { public Set<ClassAccessFlags> getAccessFlags() {
return accessFlags; return accessFlags;
} }
@ -83,7 +82,7 @@ public class BeeClass {
} }
public static class Builder { public static class Builder {
private final Set<ClassAccessFlag> accessFlags = new HashSet<>(); private final Set<ClassAccessFlags> 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 Version version; private Version version;
@ -101,17 +100,17 @@ public class BeeClass {
return this; return this;
} }
public BeeClass.Builder withPackage(String beePackage) { public BeeSource.Builder withPackage(String beePackage) {
this.beePackage = new BeePackage(beePackage); this.beePackage = new BeePackage(beePackage);
return this; return this;
} }
public BeeClass.Builder withAccessFlags(ClassAccessFlag... accessFlags) { public BeeSource.Builder withAccessFlags(ClassAccessFlags... accessFlags) {
this.accessFlags.addAll(Arrays.asList(accessFlags)); this.accessFlags.addAll(Arrays.asList(accessFlags));
return this; return this;
} }
public BeeClass.Builder withSimpleName(String simpleName) { public BeeSource.Builder withSimpleName(String simpleName) {
this.simpleName = simpleName; this.simpleName = simpleName;
return this; return this;
} }
@ -141,8 +140,8 @@ public class BeeClass {
return this; return this;
} }
public BeeClass build() { public BeeSource build() {
return new BeeClass(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods); return new BeeSource(version, beePackage, accessFlags, simpleName, superClass, interfaces, fields, constructors, methods);
} }
} }

View file

@ -0,0 +1,11 @@
package nl.sander.beejava.classinfo;
import nl.sander.beejava.constantpool.entry.Utf8Entry;
import nl.sander.beejava.util.ByteBuf;
public abstract class AttributeInfo {
private Utf8Entry nameEntry;
private int length;
public abstract void addBytes(ByteBuf buf);
}

View file

@ -0,0 +1,50 @@
package nl.sander.beejava.classinfo;
import nl.sander.beejava.constantpool.entry.Utf8Entry;
import nl.sander.beejava.flags.AccessFlags;
import nl.sander.beejava.flags.FieldAccessFlags;
import nl.sander.beejava.util.ByteBuf;
import java.util.HashSet;
import java.util.Set;
public class FieldInfo {
private final Set<FieldAccessFlags> accessFlags=new HashSet<>();
private final Utf8Entry nameEntry;
private final Utf8Entry descriptorEntry;
private final Set<AttributeInfo> attributes=new HashSet<>();
public FieldInfo(Utf8Entry nameEntry, Utf8Entry descriptorEntry) {
this.nameEntry = nameEntry;
this.descriptorEntry = descriptorEntry;
}
public FieldInfo addAccessFlags(Set<FieldAccessFlags> accessFlags){
this.accessFlags.addAll(accessFlags);
return this;
}
public Set<FieldAccessFlags> getAccessFlags() {
return accessFlags;
}
public Utf8Entry getNameEntry() {
return nameEntry;
}
public Utf8Entry getDescriptorEntry() {
return descriptorEntry;
}
public Set<AttributeInfo> getAttributes() {
return attributes;
}
public void addBytes(ByteBuf buf) {
buf.addU16(AccessFlags.combine(accessFlags));
buf.addU16(nameEntry.getIndex());
buf.addU16(descriptorEntry.getIndex());
buf.addU16(attributes.size());
attributes.forEach(ai -> ai.addBytes(buf));
}
}

View file

@ -7,10 +7,12 @@ import java.util.ArrayList;
public class ConstantPool extends ArrayList<ConstantPoolEntry>{ public class ConstantPool extends ArrayList<ConstantPoolEntry>{
public byte[] getBytes() { /**
ByteBuf bytes = new ByteBuf(); * Add the bytes for all entries to the given ByteBuf
forEach(entry -> bytes.addU8(entry.getBytes())); * @param buf the buffer that will contain the bytes for the constant pool
return bytes.toBytes(); */
public void addTo(ByteBuf buf) {
forEach(entry -> buf.addU8(entry.getBytes()));
} }
/** /**

View file

@ -1,13 +0,0 @@
package nl.sander.beejava.flags;
import java.util.Set;
// TODO all access flags can be moved together
public interface AccessFlag {
int getBytecode();
default int getCombineBytecode(Set<AccessFlag> accessflags) {
return accessflags.stream().mapToInt(AccessFlag::getBytecode).sum();
}
}

View file

@ -0,0 +1,12 @@
package nl.sander.beejava.flags;
import java.util.Collection;
public interface AccessFlags {
static int combine(Collection<? extends AccessFlags> flags) {
return flags.stream().mapToInt(AccessFlags::getBytecode).reduce(0, (result, value) -> result | value);
}
int getBytecode();
}

View file

@ -1,8 +1,6 @@
package nl.sander.beejava.flags; package nl.sander.beejava.flags;
import java.util.Collection; public enum ClassAccessFlags implements AccessFlags {
public enum ClassAccessFlag implements AccessFlag {
PUBLIC(0x0001), // Declared public; may be accessed from outside its package. PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
FINAL(0x0010), // Declared final; no subclasses allowed. FINAL(0x0010), // Declared final; no subclasses allowed.
SUPER(0x0020), // Treat superclass methods specially when invoked by the invokespecial instruction. SUPER(0x0020), // Treat superclass methods specially when invoked by the invokespecial instruction.
@ -16,13 +14,11 @@ public enum ClassAccessFlag implements AccessFlag {
private final int bytecode; private final int bytecode;
ClassAccessFlag(int bytecode) { ClassAccessFlags(int bytecode) {
this.bytecode = bytecode; this.bytecode = bytecode;
} }
public static int getSum(Collection<ClassAccessFlag> flags) {
return flags.stream().mapToInt(ClassAccessFlag::getBytecode).reduce(0, (result, value) -> result | value);
}
@Override @Override
public int getBytecode() { public int getBytecode() {

View file

@ -1,8 +1,6 @@
package nl.sander.beejava.flags; package nl.sander.beejava.flags;
import nl.sander.beejava.flags.AccessFlag; public enum FieldAccessFlags implements AccessFlags {
public enum FieldAccessFlag implements AccessFlag {
PUBLIC(0x0001), // Declared public; may be accessed from outside itspackage. PUBLIC(0x0001), // Declared public; may be accessed from outside itspackage.
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the samenest (§5.4.4). PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the samenest (§5.4.4).
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses. PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
@ -15,7 +13,7 @@ public enum FieldAccessFlag implements AccessFlag {
private final int bytecode; private final int bytecode;
FieldAccessFlag(int bytecode) { FieldAccessFlags(int bytecode) {
this.bytecode = bytecode; this.bytecode = bytecode;
} }

View file

@ -1,8 +1,6 @@
package nl.sander.beejava.flags; package nl.sander.beejava.flags;
import nl.sander.beejava.flags.AccessFlag; public enum MethodAccessFlags implements AccessFlags {
public enum MethodAccessFlag implements AccessFlag {
PUBLIC(0x0001), // Declared public; may be accessed from outside its package. PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4).
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses. PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
@ -18,7 +16,7 @@ public enum MethodAccessFlag implements AccessFlag {
private final int bytecode; private final int bytecode;
MethodAccessFlag(int bytecode) { MethodAccessFlags(int bytecode) {
this.bytecode = bytecode; this.bytecode = bytecode;
} }

View file

@ -21,4 +21,9 @@ public class BytecodeGeneratorTests {
public void testInterface() { public void testInterface() {
BytecodeGenerator.generate(Compiler.compile(TestData.emptyClassWithInterface())); BytecodeGenerator.generate(Compiler.compile(TestData.emptyClassWithInterface()));
} }
@Test
public void testFields() {
BytecodeGenerator.generate(Compiler.compile(TestData.createClassWithField(int.class)));
}
} }

View file

@ -16,7 +16,7 @@ public class CompilerTests {
@Test // This is not a maintainable test @Test // This is not a maintainable test
public void testMethodRefEntryForSuperConstructor() { public void testMethodRefEntryForSuperConstructor() {
// Arrange // Arrange
BeeClass classWithIntField = TestData.emptyClass(); BeeSource classWithIntField = TestData.emptyClass();
// Act // Act
CompiledClass compiledClass = Compiler.compile(classWithIntField); CompiledClass compiledClass = Compiler.compile(classWithIntField);

View file

@ -1,6 +1,6 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass; import nl.sander.beejava.api.BeeSource;
import nl.sander.beejava.constantpool.ConstantPool; import nl.sander.beejava.constantpool.ConstantPool;
import nl.sander.beejava.constantpool.entry.ClassEntry; import nl.sander.beejava.constantpool.entry.ClassEntry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -14,7 +14,7 @@ public class ConstantPoolUniquenessTests {
@Test @Test
public void test() { public void test() {
// Arrange // Arrange
BeeClass someClass = TestData.createClassWithTwoReferencesToSomeClass(); BeeSource someClass = TestData.createClassWithTwoReferencesToSomeClass();
// Act // Act
CompiledClass compiledClass = Compiler.compile(someClass); CompiledClass compiledClass = Compiler.compile(someClass);

View file

@ -1,18 +1,18 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.*; import nl.sander.beejava.api.*;
import nl.sander.beejava.flags.FieldAccessFlag; import nl.sander.beejava.flags.FieldAccessFlags;
import nl.sander.beejava.flags.MethodAccessFlag; import nl.sander.beejava.flags.MethodAccessFlags;
import java.io.Serializable; import java.io.Serializable;
import static nl.sander.beejava.api.CodeLine.line; import static nl.sander.beejava.api.CodeLine.line;
import static nl.sander.beejava.api.Opcode.*; import static nl.sander.beejava.api.Opcode.*;
import static nl.sander.beejava.flags.ClassAccessFlag.PUBLIC; import static nl.sander.beejava.flags.ClassAccessFlags.PUBLIC;
public class TestData { public class TestData {
public static BeeClass emptyClass() { public static BeeSource emptyClass() {
return BeeClass.builder() return BeeSource.builder()
.withClassFileVersion(Version.V14) .withClassFileVersion(Version.V14)
.withPackage("nl.sander.beejava.test") .withPackage("nl.sander.beejava.test")
.withAccessFlags(PUBLIC) .withAccessFlags(PUBLIC)
@ -22,8 +22,8 @@ public class TestData {
.build(); .build();
} }
public static BeeClass emptyClassWithInterface() { public static BeeSource emptyClassWithInterface() {
return BeeClass.builder() return BeeSource.builder()
.withClassFileVersion(Version.V14) .withClassFileVersion(Version.V14)
.withPackage("nl.sander.beejava.test") .withPackage("nl.sander.beejava.test")
.withAccessFlags(PUBLIC) .withAccessFlags(PUBLIC)
@ -34,9 +34,9 @@ public class TestData {
.build(); .build();
} }
public static BeeClass createClassWithTwoReferencesToSomeClass() { public static BeeSource createClassWithTwoReferencesToSomeClass() {
BeeMethod print1 = BeeMethod.builder() BeeMethod print1 = BeeMethod.builder()
.withAccessFlags(MethodAccessFlag.PUBLIC) .withAccessFlags(MethodAccessFlags.PUBLIC)
.withCode( .withCode(
line(0, GET, "java.lang.System","out"), line(0, GET, "java.lang.System","out"),
line(1, LD_CONST, "1"), line(1, LD_CONST, "1"),
@ -45,7 +45,7 @@ public class TestData {
.build(); .build();
BeeMethod print2 = BeeMethod.builder() BeeMethod print2 = BeeMethod.builder()
.withAccessFlags(MethodAccessFlag.PUBLIC) .withAccessFlags(MethodAccessFlags.PUBLIC)
.withCode( .withCode(
line(0, GET, "java.lang.System","out"), line(0, GET, "java.lang.System","out"),
line(1, LD_CONST, "2"), line(1, LD_CONST, "2"),
@ -53,7 +53,7 @@ public class TestData {
line(3, RETURN)) line(3, RETURN))
.build(); .build();
return BeeClass.builder() return BeeSource.builder()
.withClassFileVersion(Version.V14) .withClassFileVersion(Version.V14)
.withPackage("nl.sander.beejava.test") .withPackage("nl.sander.beejava.test")
.withAccessFlags(PUBLIC) .withAccessFlags(PUBLIC)
@ -63,9 +63,9 @@ public class TestData {
.build(); .build();
} }
public static BeeClass createClassWithField(Class<?> fieldType) { public static BeeSource createClassWithField(Class<?> fieldType) {
BeeField field = BeeField.builder() BeeField field = BeeField.builder()
.withAccessFlags(FieldAccessFlag.PRIVATE) .withAccessFlags(FieldAccessFlags.PRIVATE)
.withType(fieldType) .withType(fieldType)
.withName("field") .withName("field")
.build(); .build();
@ -73,7 +73,7 @@ public class TestData {
BeeParameter parameter = BeeParameter.create(fieldType, "value"); BeeParameter parameter = BeeParameter.create(fieldType, "value");
BeeConstructor constructor = BeeConstructor.builder() BeeConstructor constructor = BeeConstructor.builder()
.withAccessFlags(MethodAccessFlag.PUBLIC) .withAccessFlags(MethodAccessFlags.PUBLIC)
.withFormalParameters(parameter) .withFormalParameters(parameter)
.withCode( .withCode(
line(0, LD_VAR, Ref.THIS), line(0, LD_VAR, Ref.THIS),
@ -84,7 +84,7 @@ public class TestData {
line(5, RETURN)) line(5, RETURN))
.build(); .build();
return BeeClass.builder() return BeeSource.builder()
.withClassFileVersion(Version.V14) .withClassFileVersion(Version.V14)
.withPackage("nl.sander.beejava.test") .withPackage("nl.sander.beejava.test")
.withAccessFlags(PUBLIC) .withAccessFlags(PUBLIC)
@ -97,7 +97,7 @@ public class TestData {
private static BeeConstructor createConstructor() { private static BeeConstructor createConstructor() {
return BeeConstructor.builder() return BeeConstructor.builder()
.withAccessFlags(MethodAccessFlag.PUBLIC) .withAccessFlags(MethodAccessFlags.PUBLIC)
.withCode( .withCode(
line(0, LD_VAR, Ref.THIS), line(0, LD_VAR, Ref.THIS),
line(1, INVOKE, Ref.SUPER, "<init>", "()"), line(1, INVOKE, Ref.SUPER, "<init>", "()"),

View file

@ -1,6 +1,6 @@
package nl.sander.beejava; package nl.sander.beejava;
import nl.sander.beejava.api.BeeClass; import nl.sander.beejava.api.BeeSource;
import nl.sander.beejava.constantpool.ConstantPool; import nl.sander.beejava.constantpool.ConstantPool;
import nl.sander.beejava.constantpool.entry.NameAndTypeEntry; import nl.sander.beejava.constantpool.entry.NameAndTypeEntry;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -13,10 +13,10 @@ public class TypeMapperTest {
@Test @Test
public void test_int() { public void test_int() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(int.class); BeeSource beeSource = TestData.createClassWithField(int.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -26,10 +26,10 @@ public class TypeMapperTest {
@Test @Test
public void test_double() { public void test_double() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(double.class); BeeSource beeSource = TestData.createClassWithField(double.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -39,10 +39,10 @@ public class TypeMapperTest {
@Test @Test
public void test_float() { public void test_float() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(float.class); BeeSource beeSource = TestData.createClassWithField(float.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -52,10 +52,10 @@ public class TypeMapperTest {
@Test @Test
public void test_byte() { public void test_byte() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(byte.class); BeeSource beeSource = TestData.createClassWithField(byte.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -65,10 +65,10 @@ public class TypeMapperTest {
@Test @Test
public void test_short() { public void test_short() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(short.class); BeeSource beeSource = TestData.createClassWithField(short.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -78,10 +78,10 @@ public class TypeMapperTest {
@Test @Test
public void test_long() { public void test_long() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(long.class); BeeSource beeSource = TestData.createClassWithField(long.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -91,10 +91,10 @@ public class TypeMapperTest {
@Test @Test
public void test_char() { public void test_char() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(char.class); BeeSource beeSource = TestData.createClassWithField(char.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -104,10 +104,10 @@ public class TypeMapperTest {
@Test @Test
public void test_boolean() { public void test_boolean() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(boolean.class); BeeSource beeSource = TestData.createClassWithField(boolean.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -117,10 +117,10 @@ public class TypeMapperTest {
@Test @Test
public void test_Object() { public void test_Object() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(Object.class); BeeSource beeSource = TestData.createClassWithField(Object.class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -130,10 +130,10 @@ public class TypeMapperTest {
@Test @Test
public void test_int_array() { public void test_int_array() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(int[].class); BeeSource beeSource = TestData.createClassWithField(int[].class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
@ -143,18 +143,18 @@ public class TypeMapperTest {
@Test @Test
public void test_Object_array() { public void test_Object_array() {
// Arrange // Arrange
BeeClass beeClass = TestData.createClassWithField(String[].class); BeeSource beeSource = TestData.createClassWithField(String[].class);
// Act // Act
ConstantPool constantPool = createConstantPool(beeClass); ConstantPool constantPool = createConstantPool(beeSource);
// Assert // Assert
NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool); NameAndTypeEntry fieldEntry = getFieldNameAndType(constantPool);
assertEquals("[Ljava/lang/String;", fieldEntry.getType()); assertEquals("[Ljava/lang/String;", fieldEntry.getType());
} }
private ConstantPool createConstantPool(BeeClass beeClass) { private ConstantPool createConstantPool(BeeSource beeSource) {
CompiledClass compiledClass = Compiler.compile(beeClass); CompiledClass compiledClass = Compiler.compile(beeSource);
return ConstantPoolCreator.create(compiledClass.getConstantTree()); return ConstantPoolCreator.create(compiledClass.getConstantTree());
} }

View file

@ -1,23 +0,0 @@
package nl.sander.beejava.flags;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ClassAccessFlagTest {
@Test
public void test_mustOr1Value() {
assertEquals(1, ClassAccessFlag.getSum(Collections.singletonList(ClassAccessFlag.PUBLIC)));
}
@Test
public void test_mustOr2Values() {
assertEquals(17, ClassAccessFlag.getSum(Arrays.asList(ClassAccessFlag.PUBLIC, ClassAccessFlag.FINAL)));
}
}

View file

@ -0,0 +1,22 @@
package nl.sander.beejava.flags;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ClassAccessFlagsTest {
@Test
public void test_mustOr1Value() {
assertEquals(1, AccessFlags.combine(List.of(ClassAccessFlags.PUBLIC)));
}
@Test
public void test_mustOr2Values() {
assertEquals(17, AccessFlags.combine(List.of(ClassAccessFlags.PUBLIC, ClassAccessFlags.FINAL)));
}
}