diff --git a/javap/nl.sander.beejava.testclasses.EmptyBeanWithInterface_javap.txt b/javap/nl.sander.beejava.testclasses.EmptyBeanWithInterface_javap.txt new file mode 100644 index 0000000..11596c8 --- /dev/null +++ b/javap/nl.sander.beejava.testclasses.EmptyBeanWithInterface_javap.txt @@ -0,0 +1,41 @@ +public class nl.sander.beejava.testclasses.EmptyBeanWithInterface implements java.io.Serializable + minor version: 0 + major version: 58 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #7 // nl/sander/beejava/testclasses/EmptyBeanWithInterface + super_class: #2 // java/lang/Object + interfaces: 1, fields: 0, methods: 1, attributes: 1 +Constant pool: + #1 = Methodref #2.#3 // java/lang/Object."":()V + #2 = Class #4 // java/lang/Object + #3 = NameAndType #5:#6 // "":()V + #4 = Utf8 java/lang/Object + #5 = Utf8 + #6 = Utf8 ()V + #7 = Class #8 // nl/sander/beejava/testclasses/EmptyBeanWithInterface + #8 = Utf8 nl/sander/beejava/testclasses/EmptyBeanWithInterface + #9 = Class #10 // java/io/Serializable + #10 = Utf8 java/io/Serializable + #11 = Utf8 Code + #12 = Utf8 LineNumberTable + #13 = Utf8 LocalVariableTable + #14 = Utf8 this + #15 = Utf8 Lnl/sander/beejava/testclasses/EmptyBeanWithInterface; + #16 = Utf8 SourceFile + #17 = Utf8 EmptyBeanWithInterface.java +{ + public nl.sander.beejava.testclasses.EmptyBeanWithInterface(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."":()V + 4: return + LineNumberTable: + line 5: 0 + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lnl/sander/beejava/testclasses/EmptyBeanWithInterface; +} +SourceFile: "EmptyBeanWithInterface.java" \ No newline at end of file diff --git a/pom.xml b/pom.xml index af08da6..b865ad5 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.apache.maven.plugins - maven-compiler-plugin + maven-bytecodeGenerator-plugin 14 14 @@ -21,8 +21,8 @@ jar - 15 - 15 + 15 + 15 UTF-8 diff --git a/src/main/java/nl/sander/beejava/BytecodeGenerator.java b/src/main/java/nl/sander/beejava/BytecodeGenerator.java new file mode 100644 index 0000000..e0f60be --- /dev/null +++ b/src/main/java/nl/sander/beejava/BytecodeGenerator.java @@ -0,0 +1,64 @@ +package nl.sander.beejava; + +import nl.sander.beejava.api.BeeClass; +import nl.sander.beejava.constantpool.ConstantPool; +import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; +import nl.sander.beejava.flags.ClassAccessFlag; +import nl.sander.beejava.util.ByteBuf; + +public class BytecodeGenerator { + + private final BeeClass beeClass; // maybe not a member? + private final Compiler compiler = new Compiler(); + private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator(); + + public BytecodeGenerator(BeeClass beeClass) { + this.beeClass = beeClass; + } + + public static byte[] compile(BeeClass beeClass) { + BytecodeGenerator bytecodeGenerator = new BytecodeGenerator(beeClass); + return bytecodeGenerator.doCompile(); + } + + private byte[] doCompile() { + ByteBuf buf = new ByteBuf(); + buf.addU8(0xCA, 0xFE, 0xBA, 0xBE); + buf.addU16(beeClass.getClassFileVersion().getMinor()); + buf.addU16(beeClass.getClassFileVersion().getMajor()); + + CompiledClass compiledClass = compiler.compile(beeClass); + ConstantPool constantPool = constantPoolCreator.createConstantPool(compiledClass.getConstantTree()); + + buf.addU16(constantPool.getLength()); + buf.addU8(constantPool.getBytes()); + buf.addU16(ClassAccessFlag.getSum(beeClass.getAccessFlags())); + buf.addU16(compiledClass.geThisIndex()); + buf.addU16(compiledClass.getSuperIndex()); + buf.addU16(compiledClass.getInterfaces().size()); + compiledClass.getInterfaces().forEach(interfase -> buf.addU16(interfase.getIndex())); + + int x = 1; + for (ConstantPoolEntry e : constantPool) { + System.out.println((x++) + ":" + e); + } + printBytes(buf); + + return buf.toBytes(); + } + + //TODO remove + private void printBytes(ByteBuf buf) { + byte[] bytes = buf.toBytes(); + int count = 0; + for (byte b : bytes) { + System.out.print(String.format("%2s", Integer.toHexString(b & 0xFF)).replace(' ', '0') + (count % 2 == 0 ? "" : " ")); + if (++count > 15) { + count = 0; + System.out.println(); + } + } + } + + +} diff --git a/src/main/java/nl/sander/beejava/CompiledClass.java b/src/main/java/nl/sander/beejava/CompiledClass.java new file mode 100644 index 0000000..eb2efb3 --- /dev/null +++ b/src/main/java/nl/sander/beejava/CompiledClass.java @@ -0,0 +1,80 @@ +package nl.sander.beejava; + +import nl.sander.beejava.api.BeeClass; +import nl.sander.beejava.constantpool.entry.ClassEntry; +import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; +import nl.sander.beejava.constantpool.entry.Utf8Entry; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +public class CompiledClass { + private final Set constantTree = new LinkedHashSet<>(); + private final Set interfaces = new HashSet<>(); + private final BeeClass beeClass; + private ClassEntry thisClass; + private ClassEntry superClass; + + public CompiledClass(BeeClass beeClass) { + this.beeClass = beeClass; + } + + public int getSuperIndex() { + return superClass.getIndex(); + } + + public int geThisIndex() { + return thisClass.getIndex(); + } + + public ClassEntry superClass() { + if (superClass == null) { + superClass = createClassEntry(beeClass.getSuperClass().getName()); + } + return superClass; + } + + public ClassEntry thisClass() { + if (thisClass == null) { + thisClass = createClassEntry(internalName(beeClass.getName())); + } + return thisClass; + } + + public Set getConstantTree() { + return constantTree; + } + + public Set getInterfaces() { + return interfaces; + } + + public void addInterface(ClassEntry interfaceEntry) { + interfaces.add(interfaceEntry); + } + + public void addConstantPoolEntry(ConstantPoolEntry interfaceEntry) { + constantTree.add(interfaceEntry); + } + + public void setThisClass() { + constantTree.add(thisClass()); + } + + public void setInterfaces() { + beeClass.getInterfaces().forEach(interfase -> { + ClassEntry interfaceEntry = new ClassEntry(new Utf8Entry(internalName(interfase.getName()))); + addInterface(interfaceEntry); + addConstantPoolEntry(interfaceEntry); + }); + } + + private ClassEntry createClassEntry(String name) { + return new ClassEntry(new Utf8Entry(internalName(name))); + } + + private String internalName(String name) { + return name.replaceAll("\\.", "/"); + } +} diff --git a/src/main/java/nl/sander/beejava/Compiler.java b/src/main/java/nl/sander/beejava/Compiler.java index 68a72db..17adf48 100644 --- a/src/main/java/nl/sander/beejava/Compiler.java +++ b/src/main/java/nl/sander/beejava/Compiler.java @@ -1,64 +1,83 @@ package nl.sander.beejava; import nl.sander.beejava.api.BeeClass; -import nl.sander.beejava.constantpool.ConstantPool; -import nl.sander.beejava.constantpool.entry.NodeConstant; -import nl.sander.beejava.flags.ClassAccessFlag; -import nl.sander.beejava.util.ByteBuf; - -import java.util.Set; +import nl.sander.beejava.api.CodeLine; +import nl.sander.beejava.api.Ref; +import nl.sander.beejava.constantpool.entry.*; +/** + * Builds a set of a tree of constant pool entries that refer to each other. + *

+ * A client must supply a {@link BeeClass} containing a set of {@link CodeLine}s that is assumed to be correct. + * It doesn't check if a valid state is reached. + */ +/* So the name isn't entirely correct. Waiting for inspiration. + * also TODO make sure entries aren't duplicates + */ public class Compiler { + private CompiledClass compiledClass; - private final BeeClass beeClass; // maybe not a member? - private final ConstantTreeCreator constantTreeCreator = new ConstantTreeCreator(); - private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator(); + /** + * Creates a Set of nested entries that make up a single reference. For instance a class reference whose name is a utf8 reference. + * 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 + * @return a Set of constant pool entries + */ + public CompiledClass compile(BeeClass beeClass) { + compiledClass = new CompiledClass(beeClass); + beeClass.getConstructors().forEach(this::updateConstantPool); + // TODO update constantTree for fields ? + // TODO update constantTree for methods - public Compiler(BeeClass beeClass) { - this.beeClass = beeClass; + compiledClass.setThisClass(); + compiledClass.setInterfaces(); + + return compiledClass; } - public static byte[] compile(BeeClass beeClass) { - Compiler compiler = new Compiler(beeClass); - return compiler.doCompile(); + + private void updateConstantPool(ContainsCode codeContainer) { + codeContainer.getCode().forEach(this::updateConstantPool); } - private byte[] doCompile() { - ByteBuf buf = new ByteBuf(); - buf.addU8(0xCA, 0xFE, 0xBA, 0xBE); - buf.addU16(beeClass.getClassFileVersion().getMinor()); - buf.addU16(beeClass.getClassFileVersion().getMajor()); - - Set constantTree = constantTreeCreator.createConstantTree(beeClass); - ConstantPool constantPool = constantPoolCreator.createConstantPool(constantTree); - - buf.addU16(constantPool.getLength()); - buf.addU8(constantPool.getBytes()); - buf.addU16(ClassAccessFlag.getSum(beeClass.getAccessFlags())); - buf.addU16(constantTreeCreator.getThisClass().getIndex()); - buf.addU16(constantTreeCreator.getSuperClass().getIndex()); - - int x = 1; - for (NodeConstant e : constantPool) { - System.out.println((x++) + ":" + e); + /* + * scan code line for items that need adding to the constant pool + */ + private void updateConstantPool(CodeLine codeline) { + if (codeline.hasMethod()) { + addMethod(codeline); } - printBytes(buf); - return buf.toBytes(); - } - - //TODO remove - private void printBytes(ByteBuf buf) { - byte[] bytes = buf.toBytes(); - int count = 0; - for (byte b : bytes) { - System.out.print(String.format("%2s", Integer.toHexString(b & 0xFF)).replace(' ', '0') + (count % 2 == 0 ? "" : " ")); - if (++count > 15) { - count = 0; - System.out.println(); - } + if (codeline.hasField()) { + addField(codeline); } } + private void addMethod(CodeLine codeline) { + compiledClass.addConstantPoolEntry(new MethodRefEntry(getOrCreateClassEntry(codeline), createMethodNameAndType(codeline))); + } + + private void addField(CodeLine codeline) { + compiledClass.addConstantPoolEntry(new FieldRefEntry(getOrCreateClassEntry(codeline), createFieldNameAndType(codeline))); + } + + private NameAndTypeEntry createMethodNameAndType(CodeLine codeline) { + return new NameAndTypeEntry(new Utf8Entry(codeline.getMethodName()), new Utf8Entry(codeline.getMethodSignature())); + } + + private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) { + return new NameAndTypeEntry(new Utf8Entry(codeline.getField().getName()), new Utf8Entry(TypeMapper.map(codeline.getField().getType()))); + } + + private ClassEntry getOrCreateClassEntry(CodeLine codeline) { + if (codeline.getRef() == Ref.SUPER) { + return compiledClass.superClass(); + } else if (codeline.getRef() == Ref.THIS) { + return compiledClass.thisClass(); + } + //TODO other cases + throw new RuntimeException("shouldn't be here"); + } } diff --git a/src/main/java/nl/sander/beejava/ConstantPoolCreator.java b/src/main/java/nl/sander/beejava/ConstantPoolCreator.java index 927360f..d1b417f 100644 --- a/src/main/java/nl/sander/beejava/ConstantPoolCreator.java +++ b/src/main/java/nl/sander/beejava/ConstantPoolCreator.java @@ -1,7 +1,7 @@ package nl.sander.beejava; import nl.sander.beejava.constantpool.ConstantPool; -import nl.sander.beejava.constantpool.entry.NodeConstant; +import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; import java.util.Set; @@ -13,33 +13,33 @@ public class ConstantPoolCreator { private int index; // the current index that will be assigned to a constant pool entry. It needs to be unique for each entry. // References to other elements in the pool are made through indexes, so they have to be valid to guarantee that the class can be loaded by the JVM. - public ConstantPool createConstantPool(Set constantTree) { + public ConstantPool createConstantPool(Set constantTree) { constantPool = new ConstantPool(); index = 0; updateToplevelElements(constantTree); return constantPool; } - private void updateToplevelElements(Set children) { - for (NodeConstant child : children) { + private void updateToplevelElements(Set children) { + for (ConstantPoolEntry child : children) { addToPool(child); updateChildElements(child.getChildren()); // first the complete toplevel element including it's children, then next toplevel element } } - private void updateChildElements(Set children) { + private void updateChildElements(Set children) { // first all direct children - for (NodeConstant child : children) { + for (ConstantPoolEntry child : children) { addToPool(child); } // then further lineage - for (NodeConstant child : children) { + for (ConstantPoolEntry child : children) { updateChildElements(child.getChildren()); } } - private void addToPool(NodeConstant entry) { + private void addToPool(ConstantPoolEntry entry) { index += 1; entry.setIndex(index); constantPool.add(entry); diff --git a/src/main/java/nl/sander/beejava/ConstantTreeCreator.java b/src/main/java/nl/sander/beejava/ConstantTreeCreator.java deleted file mode 100644 index db10258..0000000 --- a/src/main/java/nl/sander/beejava/ConstantTreeCreator.java +++ /dev/null @@ -1,121 +0,0 @@ -package nl.sander.beejava; - -import nl.sander.beejava.api.BeeClass; -import nl.sander.beejava.api.CodeLine; -import nl.sander.beejava.api.Ref; -import nl.sander.beejava.constantpool.entry.*; - -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * Builds a set of a tree of constant pool entries that refer to each other. - *

- * A client must supply a {@link BeeClass} containing a set of {@link CodeLine}s that is assumed to be correct. - * It doesn't check if a valid state is reached. - */ -/* So the name isn't entirely correct. Waiting for inspiration. - * also TODO make sure entries aren't duplicates - */ -public class ConstantTreeCreator { - private final Set constantTree = new LinkedHashSet<>(); - private BeeClass beeClass; - private ClassEntry thisClass; - private ClassEntry superClass; - - - /** - * Creates a Set of nested entries that make up a single reference. For instance a class reference whose name is a utf8 reference. - * 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 - * @return a Set of constant pool entries - */ - public Set createConstantTree(BeeClass beeClass) { - constantTree.clear(); - this.beeClass = beeClass; - beeClass.getConstructors().forEach(this::updateConstantTree); - // TODO update constantTree for fields ? - // TODO update constantTree for methods - - constantTree.add(getThisClassRef(beeClass)); - return constantTree; - } - - /* - * might be null if no methods refer to _this_ - */ - private ClassEntry getThisClassRef(BeeClass beeClass) { - if (thisClass == null) { - thisClass = new ClassEntry(new Utf8Entry(internalName(beeClass.getName()))); - } - return thisClass; - } - - - public ClassEntry getThisClass() { - return thisClass; - } - - public ClassEntry getSuperClass() { - return superClass; - } - - private void updateConstantTree(ContainsCode codeContainer) { - codeContainer.getCode().forEach(this::updateConstantTree); - } - - /* - * scan code line for items that need adding to the constant pool - */ - private void updateConstantTree(CodeLine codeline) { - if (codeline.hasMethod()) { - addMethod(codeline); - } - - if (codeline.hasField()) { - addField(codeline); - } - } - - private void addMethod(CodeLine codeline) { - constantTree.add(new MethodRefEntry(getOrCreateClassEntry(codeline), createMethodNameAndType(codeline))); - } - - private void addField(CodeLine codeline) { - constantTree.add(new FieldRefEntry(getOrCreateClassEntry(codeline), createFieldNameAndType(codeline))); - } - - private NameAndTypeEntry createMethodNameAndType(CodeLine codeline) { - return new NameAndTypeEntry(new Utf8Entry(codeline.getMethodName()), new Utf8Entry(codeline.getMethodSignature())); - } - - private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) { - return new NameAndTypeEntry(new Utf8Entry(codeline.getField().getName()), new Utf8Entry(TypeMapper.map(codeline.getField().getType()))); - } - - private ClassEntry getOrCreateClassEntry(CodeLine codeline) { - if (codeline.getRef() == Ref.SUPER) { - if (superClass == null) { - superClass = createClassEntry(beeClass.getSuperClass().getName()); - } - return superClass; - } else if (codeline.getRef() == Ref.THIS) { - if (thisClass == null) { - thisClass = createClassEntry(beeClass.getName()); - } - return thisClass; - } - //TODO other cases - throw new RuntimeException("shouldn't be here"); - } - - private ClassEntry createClassEntry(String name) { - return new ClassEntry(new Utf8Entry(internalName(name))); - } - - private String internalName(String name) { - return name.replaceAll("\\.", "/"); - } - -} diff --git a/src/main/java/nl/sander/beejava/api/BeeClass.java b/src/main/java/nl/sander/beejava/api/BeeClass.java index 9c9212b..ec2f161 100644 --- a/src/main/java/nl/sander/beejava/api/BeeClass.java +++ b/src/main/java/nl/sander/beejava/api/BeeClass.java @@ -67,6 +67,10 @@ public class BeeClass { return superClass; } + public Set> getInterfaces() { + return interfaces; + } + public Set getFields() { return fields; } diff --git a/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java b/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java index cbc968b..f8a29bb 100644 --- a/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java +++ b/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java @@ -1,14 +1,13 @@ package nl.sander.beejava.constantpool; -import nl.sander.beejava.constantpool.entry.NodeConstant; +import nl.sander.beejava.constantpool.entry.ConstantPoolEntry; import nl.sander.beejava.util.ByteBuf; import java.util.ArrayList; -import java.util.List; -public class ConstantPool extends ArrayList{ +public class ConstantPool extends ArrayList{ - public int getIndex(NodeConstant entry) { + public int getIndex(ConstantPoolEntry entry) { for (int i = 0; i < size(); i++) { if (get(i) == entry) { return i + 1; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ClassEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/ClassEntry.java index 218e88f..4cdea81 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ClassEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ClassEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class ClassEntry extends NodeConstant { +public class ClassEntry extends ConstantPoolEntry { private static final byte TAG = 7; private final Utf8Entry name; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java similarity index 83% rename from src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java rename to src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java index d059a30..780ba83 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPoolEntry.java @@ -4,12 +4,12 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; -public abstract class NodeConstant { - protected final Set children; // TODO decide whether or not to keep this. Could also make getChildren abstract and make it return a new list every time +public abstract class ConstantPoolEntry { + protected final Set children; // TODO decide whether or not to keep this. Could also make getChildren abstract and make it return a new list every time // TODO to save storage. getChildren should only be called once, so it is probably more efficient like that private int index; // the index of the entry is not known until after creation of the complete tree, so cannot be final, but it should not be updated. - protected NodeConstant(NodeConstant... children) { + protected ConstantPoolEntry(ConstantPoolEntry... children) { this.children = new LinkedHashSet<>(); this.children.addAll(Arrays.asList(children)); // java8 way destroys order, not desastrous, but I like to preserve it. } @@ -37,7 +37,7 @@ public abstract class NodeConstant { this.index = index; } - public Set getChildren() { + public Set getChildren() { return children; } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/DoubleEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/DoubleEntry.java index a2f3214..75ad5e1 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/DoubleEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/DoubleEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class DoubleEntry extends LeafConstant { +public class DoubleEntry extends LeafConstantPoolEntry { private static final byte TAG = 6; private final double doubleVal; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/DynamicEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/DynamicEntry.java index 4c81d4e..e65babd 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/DynamicEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/DynamicEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class DynamicEntry extends NodeConstant { +public class DynamicEntry extends ConstantPoolEntry { private static final byte TAG = 17; private final int bootstrapMethodIndex; // TODO private final NameAndTypeEntry nameAndType; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/FieldRefEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/FieldRefEntry.java index 034af5a..c4fd172 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/FieldRefEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/FieldRefEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class FieldRefEntry extends NodeConstant { +public class FieldRefEntry extends ConstantPoolEntry { private static final byte TAG = 9; private final ClassEntry classEntry; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java index 8162512..be5a3ac 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/FloatEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class FloatEntry extends LeafConstant { +public class FloatEntry extends LeafConstantPoolEntry { private static final byte TAG = 4; private final float floatVal; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java index f55f6fc..80455a4 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/IntegerEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class IntegerEntry extends LeafConstant { +public class IntegerEntry extends LeafConstantPoolEntry { private static final byte TAG = 3; private final int intVal; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/InterfaceMethodRefEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/InterfaceMethodRefEntry.java index 70c9aac..fdbf54d 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/InterfaceMethodRefEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/InterfaceMethodRefEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class InterfaceMethodRefEntry extends NodeConstant { +public class InterfaceMethodRefEntry extends ConstantPoolEntry { private static final byte TAG = 11; private final ClassEntry classEntry; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/InvokeDynamicEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/InvokeDynamicEntry.java index 15aa829..8ca4e83 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/InvokeDynamicEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/InvokeDynamicEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class InvokeDynamicEntry extends NodeConstant { +public class InvokeDynamicEntry extends ConstantPoolEntry { private static final byte TAG = 18; private final int bootstrapMethodAttrIndex; //?? diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/LeafConstant.java b/src/main/java/nl/sander/beejava/constantpool/entry/LeafConstantPoolEntry.java similarity index 62% rename from src/main/java/nl/sander/beejava/constantpool/entry/LeafConstant.java rename to src/main/java/nl/sander/beejava/constantpool/entry/LeafConstantPoolEntry.java index fb73e65..72411f6 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/LeafConstant.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/LeafConstantPoolEntry.java @@ -6,9 +6,9 @@ import java.util.Set; /** * Is a constant without children */ -public abstract class LeafConstant extends NodeConstant { +public abstract class LeafConstantPoolEntry extends ConstantPoolEntry { @Override - public Set getChildren() { + public Set getChildren() { return Collections.emptySet(); } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/LongEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/LongEntry.java index 057ad8d..83aa546 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/LongEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/LongEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class LongEntry extends LeafConstant { +public class LongEntry extends LeafConstantPoolEntry { private static final byte TAG = 5; private final long longVal; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/MethodHandleEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/MethodHandleEntry.java index de8d1ca..a596a6b 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/MethodHandleEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/MethodHandleEntry.java @@ -1,7 +1,7 @@ package nl.sander.beejava.constantpool.entry; //TODO implement later -public class MethodHandleEntry extends NodeConstant { +public class MethodHandleEntry extends ConstantPoolEntry { private static final byte TAG = 15; private final int referenceKind; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/MethodRefEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/MethodRefEntry.java index 909e471..91533d5 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/MethodRefEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/MethodRefEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class MethodRefEntry extends NodeConstant { +public class MethodRefEntry extends ConstantPoolEntry { private static final byte TAG = 10; private final ClassEntry classRef; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/MethodTypeEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/MethodTypeEntry.java index 2cedb9d..c658869 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/MethodTypeEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/MethodTypeEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class MethodTypeEntry extends NodeConstant { +public class MethodTypeEntry extends ConstantPoolEntry { private static final byte TAG = 16; private final Utf8Entry methodDescriptor; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ModuleEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/ModuleEntry.java index aa84d41..db5e4ce 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ModuleEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ModuleEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class ModuleEntry extends NodeConstant { +public class ModuleEntry extends ConstantPoolEntry { private static final byte TAG = 19; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/NameAndTypeEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/NameAndTypeEntry.java index 6057be4..31a9976 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/NameAndTypeEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/NameAndTypeEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class NameAndTypeEntry extends NodeConstant { +public class NameAndTypeEntry extends ConstantPoolEntry { private static final byte TAG = 12; private final Utf8Entry name; private final Utf8Entry descriptor; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/PackageEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/PackageEntry.java index 7b8a563..1e74ef0 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/PackageEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/PackageEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class PackageEntry extends NodeConstant { +public class PackageEntry extends ConstantPoolEntry { private static final byte TAG = 20; private final Utf8Entry name; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/StringEntry.java b/src/main/java/nl/sander/beejava/constantpool/entry/StringEntry.java index 71183d2..f34e2b1 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/StringEntry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/StringEntry.java @@ -1,6 +1,6 @@ package nl.sander.beejava.constantpool.entry; -public class StringEntry extends NodeConstant { +public class StringEntry extends ConstantPoolEntry { private static final byte TAG = 8; private final Utf8Entry utf8; diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/Utf8Entry.java b/src/main/java/nl/sander/beejava/constantpool/entry/Utf8Entry.java index 6017124..f9fb06b 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/Utf8Entry.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/Utf8Entry.java @@ -2,7 +2,7 @@ package nl.sander.beejava.constantpool.entry; import java.nio.charset.StandardCharsets; -public class Utf8Entry extends LeafConstant { +public class Utf8Entry extends LeafConstantPoolEntry { private static final byte TAG = 1; private final String value; diff --git a/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java b/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java new file mode 100644 index 0000000..a7f3018 --- /dev/null +++ b/src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java @@ -0,0 +1,15 @@ +package nl.sander.beejava; + +import org.junit.jupiter.api.Test; + +public class BytecodeGeneratorTests { + @Test + public void testEmpty(){ + BytecodeGenerator.compile(TestData.emptyClass()); + } + + @Test + public void testInterface(){ + BytecodeGenerator.compile(TestData.emptyClassWithInterface()); + } +} diff --git a/src/test/java/nl/sander/beejava/CompilerTests.java b/src/test/java/nl/sander/beejava/CompilerTests.java index edf1c3c..dff6d77 100644 --- a/src/test/java/nl/sander/beejava/CompilerTests.java +++ b/src/test/java/nl/sander/beejava/CompilerTests.java @@ -1,10 +1,99 @@ package nl.sander.beejava; +import nl.sander.beejava.api.*; +import nl.sander.beejava.constantpool.entry.*; +import nl.sander.beejava.flags.FieldAccessFlag; +import nl.sander.beejava.flags.MethodAccessFlag; import org.junit.jupiter.api.Test; +import java.util.Iterator; +import java.util.Set; + +import static nl.sander.beejava.api.CodeLine.line; +import static nl.sander.beejava.api.Opcode.*; +import static nl.sander.beejava.flags.ClassAccessFlag.PUBLIC; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class CompilerTests { - @Test - public void test(){ - Compiler.compile(TestData.emptyClass()); + + // creates simplest class possible and checks the tree, that the ConstantTreeCreator emits + @Test // This is not a maintainable test + public void testMethodRefEntryForSuperConstructor() { + BeeClass classWithIntField = TestData.emptyClass(); + CompiledClass compiledClass = new Compiler().compile(classWithIntField); + Set constantTree = compiledClass.getConstantTree(); + assertEquals(2, constantTree.size()); + ConstantPoolEntry superConstructor = constantTree.iterator().next(); + + assertEquals(MethodRefEntry.class, superConstructor.getClass()); + MethodRefEntry methodRefEntry = (MethodRefEntry) superConstructor; + + Set methodRefEntryChildren = methodRefEntry.getChildren(); + assertEquals(2, methodRefEntryChildren.size()); + + Iterator firstChildren = methodRefEntryChildren.iterator(); + ConstantPoolEntry child1 = firstChildren.next(); + assertEquals(ClassEntry.class, child1.getClass()); + ClassEntry classEntry = (ClassEntry) child1; + + Set classEntryChildren = classEntry.getChildren(); + assertEquals(1, classEntryChildren.size()); + ConstantPoolEntry child2 = classEntryChildren.iterator().next(); + + assertEquals(Utf8Entry.class, child2.getClass()); + Utf8Entry className = (Utf8Entry) child2; + assertEquals("java/lang/Object", className.getUtf8()); + + ConstantPoolEntry child3 = firstChildren.next(); + assertEquals(NameAndTypeEntry.class, child3.getClass()); + NameAndTypeEntry nameAndTypeEntry = (NameAndTypeEntry) child3; + + Set nameAndTypeEntryChildren = nameAndTypeEntry.getChildren(); + assertEquals(2, nameAndTypeEntryChildren.size()); + Iterator nameAndTypeChildrenIterator = nameAndTypeEntryChildren.iterator(); + + ConstantPoolEntry child4 = nameAndTypeChildrenIterator.next(); + assertEquals(Utf8Entry.class, child4.getClass()); + Utf8Entry name = (Utf8Entry) child4; + assertEquals("", name.getUtf8()); + + ConstantPoolEntry child5 = nameAndTypeChildrenIterator.next(); + assertEquals(Utf8Entry.class, child5.getClass()); + Utf8Entry type = (Utf8Entry) child5; + assertEquals("()V", type.getUtf8()); } + + private BeeClass createClassWithIntField() { + BeeField intField = BeeField.builder() + .withAccessFlags(FieldAccessFlag.PRIVATE) + .withType(int.class) + .withName("intField") + .build(); + + BeeParameter intValueParameter = BeeParameter.create(int.class, "intValue"); + + BeeConstructor constructor = BeeConstructor.builder() + .withAccessFlags(MethodAccessFlag.PUBLIC) + .withFormalParameters(intValueParameter) + .withCode( + line(0, LOAD, Ref.THIS), + line(1, INVOKE, Ref.SUPER, "", "()"), + line(2, LOAD, Ref.THIS), + line(3, LOAD, intValueParameter), + line(4, PUT, intField), + line(5, RETURN)) + .build(); + + return BeeClass.builder() + .withClassFileVersion(Version.V14) + .withPackage("nl.sander.beejava.test") + .withAccessFlags(PUBLIC) + .withSimpleName("IntBean") + .withSuperClass(Object.class) + .withFields(intField) + .withConstructors(constructor) + .build(); + } + + } diff --git a/src/test/java/nl/sander/beejava/ConstantTreeCreatorTests.java b/src/test/java/nl/sander/beejava/ConstantTreeCreatorTests.java deleted file mode 100644 index cae6ee1..0000000 --- a/src/test/java/nl/sander/beejava/ConstantTreeCreatorTests.java +++ /dev/null @@ -1,98 +0,0 @@ -package nl.sander.beejava; - -import nl.sander.beejava.api.*; -import nl.sander.beejava.constantpool.entry.*; -import nl.sander.beejava.flags.FieldAccessFlag; -import nl.sander.beejava.flags.MethodAccessFlag; -import org.junit.jupiter.api.Test; - -import java.util.Iterator; -import java.util.Set; - -import static nl.sander.beejava.api.CodeLine.line; -import static nl.sander.beejava.api.Opcode.*; -import static nl.sander.beejava.flags.ClassAccessFlag.PUBLIC; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class ConstantTreeCreatorTests { - - // creates simplest class possible and checks the tree, that the ConstantTreeCreator emits - @Test // This is not a maintainable test - public void testMethodRefEntryForSuperConstructor() { - BeeClass classWithIntField = TestData.emptyClass(); - Set constantTree = new ConstantTreeCreator().createConstantTree(classWithIntField); - assertEquals(1, constantTree.size()); - NodeConstant superConstructor = constantTree.iterator().next(); - - assertEquals(MethodRefEntry.class, superConstructor.getClass()); - MethodRefEntry methodRefEntry = (MethodRefEntry) superConstructor; - - Set methodRefEntryChildren = methodRefEntry.getChildren(); - assertEquals(2, methodRefEntryChildren.size()); - - Iterator firstChildren = methodRefEntryChildren.iterator(); - NodeConstant child1 = firstChildren.next(); - assertEquals(ClassEntry.class, child1.getClass()); - ClassEntry classEntry = (ClassEntry) child1; - - Set classEntryChildren = classEntry.getChildren(); - assertEquals(1, classEntryChildren.size()); - NodeConstant child2 = classEntryChildren.iterator().next(); - - assertEquals(Utf8Entry.class, child2.getClass()); - Utf8Entry className = (Utf8Entry) child2; - assertEquals("java/lang/Object", className.getUtf8()); - - NodeConstant child3 = firstChildren.next(); - assertEquals(NameAndTypeEntry.class, child3.getClass()); - NameAndTypeEntry nameAndTypeEntry = (NameAndTypeEntry) child3; - - Set nameAndTypeEntryChildren = nameAndTypeEntry.getChildren(); - assertEquals(2, nameAndTypeEntryChildren.size()); - Iterator nameAndTypeChildrenIterator = nameAndTypeEntryChildren.iterator(); - - NodeConstant child4 = nameAndTypeChildrenIterator.next(); - assertEquals(Utf8Entry.class, child4.getClass()); - Utf8Entry name = (Utf8Entry) child4; - assertEquals("", name.getUtf8()); - - NodeConstant child5 = nameAndTypeChildrenIterator.next(); - assertEquals(Utf8Entry.class, child5.getClass()); - Utf8Entry type = (Utf8Entry) child5; - assertEquals("()V", type.getUtf8()); - } - - private BeeClass createClassWithIntField() { - BeeField intField = BeeField.builder() - .withAccessFlags(FieldAccessFlag.PRIVATE) - .withType(int.class) - .withName("intField") - .build(); - - BeeParameter intValueParameter = BeeParameter.create(int.class, "intValue"); - - BeeConstructor constructor = BeeConstructor.builder() - .withAccessFlags(MethodAccessFlag.PUBLIC) - .withFormalParameters(intValueParameter) - .withCode( - line(0, LOAD, Ref.THIS), - line(1, INVOKE, Ref.SUPER, "", "()"), - line(2, LOAD, Ref.THIS), - line(3, LOAD, intValueParameter), - line(4, PUT, intField), - line(5, RETURN)) - .build(); - - return BeeClass.builder() - .withClassFileVersion(Version.V14) - .withPackage("nl.sander.beejava.test") - .withAccessFlags(PUBLIC) - .withSimpleName("IntBean") - .withSuperClass(Object.class) - .withFields(intField) - .withConstructors(constructor) - .build(); - } - - -} diff --git a/src/test/java/nl/sander/beejava/TestData.java b/src/test/java/nl/sander/beejava/TestData.java index d9f88b2..cb133cd 100644 --- a/src/test/java/nl/sander/beejava/TestData.java +++ b/src/test/java/nl/sander/beejava/TestData.java @@ -6,12 +6,37 @@ import nl.sander.beejava.api.Ref; import nl.sander.beejava.api.Version; import nl.sander.beejava.flags.MethodAccessFlag; +import java.io.Serializable; + import static nl.sander.beejava.api.CodeLine.line; import static nl.sander.beejava.api.Opcode.*; import static nl.sander.beejava.flags.ClassAccessFlag.PUBLIC; public class TestData { public static BeeClass emptyClass() { + return BeeClass.builder() + .withClassFileVersion(Version.V14) + .withPackage("nl.sander.beejava.test") + .withAccessFlags(PUBLIC) + .withSimpleName("EmptyBean") + .withSuperClass(Object.class) // Not mandatory, like in java sourcecode + .withConstructors(getBeeConstructor()) // There's no default constructor in beejava. The user must always add them + .build(); + } + + public static BeeClass emptyClassWithInterface() { + return BeeClass.builder() + .withClassFileVersion(Version.V14) + .withPackage("nl.sander.beejava.test") + .withAccessFlags(PUBLIC) + .withSimpleName("EmptyBean") + .withSuperClass(Object.class) // Not mandatory, like in java sourcecode + .withInterfaces(Serializable.class) + .withConstructors(getBeeConstructor()) // There's no default constructor in beejava. The user must always add them + .build(); + } + + private static BeeConstructor getBeeConstructor() { BeeConstructor constructor = BeeConstructor.builder() .withAccessFlags(MethodAccessFlag.PUBLIC) .withCode( @@ -19,14 +44,6 @@ public class TestData { line(1, INVOKE, Ref.SUPER, "", "()"), line(5, RETURN)) .build(); - - return BeeClass.builder() - .withClassFileVersion(Version.V14) - .withPackage("nl.sander.beejava.test") - .withAccessFlags(PUBLIC) - .withSimpleName("EmptyBean") - .withSuperClass(Object.class) // Not mandatory, like in java sourcecode - .withConstructors(constructor) // There's no default constructor in beejava. The user must always add them - .build(); + return constructor; } } diff --git a/src/test/java/nl/sander/beejava/testclasses/EmptyBean.java b/src/test/java/nl/sander/beejava/testclasses/EmptyBean.java new file mode 100644 index 0000000..42ed855 --- /dev/null +++ b/src/test/java/nl/sander/beejava/testclasses/EmptyBean.java @@ -0,0 +1,5 @@ +package nl.sander.beejava.testclasses; + +public class EmptyBean { + +} diff --git a/src/test/java/nl/sander/beejava/testclasses/EmptyBeanWithInterface.java b/src/test/java/nl/sander/beejava/testclasses/EmptyBeanWithInterface.java new file mode 100644 index 0000000..005f537 --- /dev/null +++ b/src/test/java/nl/sander/beejava/testclasses/EmptyBeanWithInterface.java @@ -0,0 +1,7 @@ +package nl.sander.beejava.testclasses; + +import java.io.Serializable; + +public class EmptyBeanWithInterface implements Serializable { + +} diff --git a/src/test/java/nl/sander/beejava/testclasses/IntBean.java b/src/test/java/nl/sander/beejava/testclasses/IntBean.java index 4a1adb8..86d50a0 100644 --- a/src/test/java/nl/sander/beejava/testclasses/IntBean.java +++ b/src/test/java/nl/sander/beejava/testclasses/IntBean.java @@ -1,10 +1,10 @@ package nl.sander.beejava.testclasses; public class IntBean { -// private int intField; + private int intField; -// public IntBean(int intField) { -// this.intField = intField; -// } + public IntBean(int intField) { + this.intField = intField; + } }