created CompiledClass and refactored code into it. Added Interfaces to bytecode
This commit is contained in:
parent
3e699d0754
commit
8eda63261b
35 changed files with 440 additions and 319 deletions
|
|
@ -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."<init>":()V
|
||||||
|
#2 = Class #4 // java/lang/Object
|
||||||
|
#3 = NameAndType #5:#6 // "<init>":()V
|
||||||
|
#4 = Utf8 java/lang/Object
|
||||||
|
#5 = Utf8 <init>
|
||||||
|
#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."<init>":()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"
|
||||||
6
pom.xml
6
pom.xml
|
|
@ -7,7 +7,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-bytecodeGenerator-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>14</source>
|
<source>14</source>
|
||||||
<target>14</target>
|
<target>14</target>
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>15</maven.compiler.source>
|
<maven.bytecodeGenerator.source>15</maven.bytecodeGenerator.source>
|
||||||
<maven.compiler.target>15</maven.compiler.target>
|
<maven.bytecodeGenerator.target>15</maven.bytecodeGenerator.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
|
||||||
64
src/main/java/nl/sander/beejava/BytecodeGenerator.java
Normal file
64
src/main/java/nl/sander/beejava/BytecodeGenerator.java
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
80
src/main/java/nl/sander/beejava/CompiledClass.java
Normal file
80
src/main/java/nl/sander/beejava/CompiledClass.java
Normal file
|
|
@ -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<ConstantPoolEntry> constantTree = new LinkedHashSet<>();
|
||||||
|
private final Set<ClassEntry> 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<ConstantPoolEntry> getConstantTree() {
|
||||||
|
return constantTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ClassEntry> 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("\\.", "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,64 +1,83 @@
|
||||||
package nl.sander.beejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.beejava.api.BeeClass;
|
import nl.sander.beejava.api.BeeClass;
|
||||||
import nl.sander.beejava.constantpool.ConstantPool;
|
import nl.sander.beejava.api.CodeLine;
|
||||||
import nl.sander.beejava.constantpool.entry.NodeConstant;
|
import nl.sander.beejava.api.Ref;
|
||||||
import nl.sander.beejava.flags.ClassAccessFlag;
|
import nl.sander.beejava.constantpool.entry.*;
|
||||||
import nl.sander.beejava.util.ByteBuf;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a set of a tree of constant pool entries that refer to each other.
|
||||||
|
* <p>
|
||||||
|
* 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 {
|
public class Compiler {
|
||||||
|
private CompiledClass compiledClass;
|
||||||
|
|
||||||
private final BeeClass beeClass; // maybe not a member?
|
/**
|
||||||
private final ConstantTreeCreator constantTreeCreator = new ConstantTreeCreator();
|
* Creates a Set of nested entries that make up a single reference. For instance a class reference whose name is a utf8 reference.
|
||||||
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
|
* 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) {
|
compiledClass.setThisClass();
|
||||||
this.beeClass = beeClass;
|
compiledClass.setInterfaces();
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] compile(BeeClass beeClass) {
|
return compiledClass;
|
||||||
Compiler compiler = new Compiler(beeClass);
|
|
||||||
return compiler.doCompile();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] doCompile() {
|
|
||||||
ByteBuf buf = new ByteBuf();
|
|
||||||
buf.addU8(0xCA, 0xFE, 0xBA, 0xBE);
|
|
||||||
buf.addU16(beeClass.getClassFileVersion().getMinor());
|
|
||||||
buf.addU16(beeClass.getClassFileVersion().getMajor());
|
|
||||||
|
|
||||||
Set<NodeConstant> 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);
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateConstantPool(ContainsCode codeContainer) {
|
||||||
|
codeContainer.getCode().forEach(this::updateConstantPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scan code line for items that need adding to the constant pool
|
||||||
|
*/
|
||||||
|
private void updateConstantPool(CodeLine codeline) {
|
||||||
|
if (codeline.hasMethod()) {
|
||||||
|
addMethod(codeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package nl.sander.beejava;
|
package nl.sander.beejava;
|
||||||
|
|
||||||
import nl.sander.beejava.constantpool.ConstantPool;
|
import nl.sander.beejava.constantpool.ConstantPool;
|
||||||
import nl.sander.beejava.constantpool.entry.NodeConstant;
|
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||||
|
|
||||||
import java.util.Set;
|
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.
|
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.
|
// 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<NodeConstant> constantTree) {
|
public ConstantPool createConstantPool(Set<ConstantPoolEntry> constantTree) {
|
||||||
constantPool = new ConstantPool();
|
constantPool = new ConstantPool();
|
||||||
index = 0;
|
index = 0;
|
||||||
updateToplevelElements(constantTree);
|
updateToplevelElements(constantTree);
|
||||||
return constantPool;
|
return constantPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateToplevelElements(Set<NodeConstant> children) {
|
private void updateToplevelElements(Set<ConstantPoolEntry> children) {
|
||||||
for (NodeConstant child : children) {
|
for (ConstantPoolEntry child : children) {
|
||||||
addToPool(child);
|
addToPool(child);
|
||||||
updateChildElements(child.getChildren());
|
updateChildElements(child.getChildren());
|
||||||
// first the complete toplevel element including it's children, then next toplevel element
|
// first the complete toplevel element including it's children, then next toplevel element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChildElements(Set<NodeConstant> children) {
|
private void updateChildElements(Set<ConstantPoolEntry> children) {
|
||||||
// first all direct children
|
// first all direct children
|
||||||
for (NodeConstant child : children) {
|
for (ConstantPoolEntry child : children) {
|
||||||
addToPool(child);
|
addToPool(child);
|
||||||
}
|
}
|
||||||
// then further lineage
|
// then further lineage
|
||||||
for (NodeConstant child : children) {
|
for (ConstantPoolEntry child : children) {
|
||||||
updateChildElements(child.getChildren());
|
updateChildElements(child.getChildren());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToPool(NodeConstant entry) {
|
private void addToPool(ConstantPoolEntry entry) {
|
||||||
index += 1;
|
index += 1;
|
||||||
entry.setIndex(index);
|
entry.setIndex(index);
|
||||||
constantPool.add(entry);
|
constantPool.add(entry);
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
* <p>
|
|
||||||
* 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<NodeConstant> 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<NodeConstant> 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("\\.", "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -67,6 +67,10 @@ public class BeeClass {
|
||||||
return superClass;
|
return superClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<Class<?>> getInterfaces() {
|
||||||
|
return interfaces;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<BeeField> getFields() {
|
public Set<BeeField> getFields() {
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
package nl.sander.beejava.constantpool;
|
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 nl.sander.beejava.util.ByteBuf;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ConstantPool extends ArrayList<NodeConstant>{
|
public class ConstantPool extends ArrayList<ConstantPoolEntry>{
|
||||||
|
|
||||||
public int getIndex(NodeConstant entry) {
|
public int getIndex(ConstantPoolEntry entry) {
|
||||||
for (int i = 0; i < size(); i++) {
|
for (int i = 0; i < size(); i++) {
|
||||||
if (get(i) == entry) {
|
if (get(i) == entry) {
|
||||||
return i + 1;
|
return i + 1;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class ClassEntry extends NodeConstant {
|
public class ClassEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 7;
|
private static final byte TAG = 7;
|
||||||
private final Utf8Entry name;
|
private final Utf8Entry name;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public abstract class NodeConstant {
|
public abstract class ConstantPoolEntry {
|
||||||
protected final Set<NodeConstant> children; // TODO decide whether or not to keep this. Could also make getChildren abstract and make it return a new list every time
|
protected final Set<ConstantPoolEntry> 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
|
// 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.
|
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 = new LinkedHashSet<>();
|
||||||
this.children.addAll(Arrays.asList(children)); // java8 way destroys order, not desastrous, but I like to preserve it.
|
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;
|
this.index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<NodeConstant> getChildren() {
|
public Set<ConstantPoolEntry> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class DoubleEntry extends LeafConstant {
|
public class DoubleEntry extends LeafConstantPoolEntry {
|
||||||
private static final byte TAG = 6;
|
private static final byte TAG = 6;
|
||||||
private final double doubleVal;
|
private final double doubleVal;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class DynamicEntry extends NodeConstant {
|
public class DynamicEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 17;
|
private static final byte TAG = 17;
|
||||||
private final int bootstrapMethodIndex; // TODO
|
private final int bootstrapMethodIndex; // TODO
|
||||||
private final NameAndTypeEntry nameAndType;
|
private final NameAndTypeEntry nameAndType;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class FieldRefEntry extends NodeConstant {
|
public class FieldRefEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 9;
|
private static final byte TAG = 9;
|
||||||
|
|
||||||
private final ClassEntry classEntry;
|
private final ClassEntry classEntry;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class FloatEntry extends LeafConstant {
|
public class FloatEntry extends LeafConstantPoolEntry {
|
||||||
private static final byte TAG = 4;
|
private static final byte TAG = 4;
|
||||||
|
|
||||||
private final float floatVal;
|
private final float floatVal;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class IntegerEntry extends LeafConstant {
|
public class IntegerEntry extends LeafConstantPoolEntry {
|
||||||
private static final byte TAG = 3;
|
private static final byte TAG = 3;
|
||||||
|
|
||||||
private final int intVal;
|
private final int intVal;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class InterfaceMethodRefEntry extends NodeConstant {
|
public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 11;
|
private static final byte TAG = 11;
|
||||||
|
|
||||||
private final ClassEntry classEntry;
|
private final ClassEntry classEntry;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class InvokeDynamicEntry extends NodeConstant {
|
public class InvokeDynamicEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 18;
|
private static final byte TAG = 18;
|
||||||
|
|
||||||
private final int bootstrapMethodAttrIndex; //??
|
private final int bootstrapMethodAttrIndex; //??
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import java.util.Set;
|
||||||
/**
|
/**
|
||||||
* Is a constant without children
|
* Is a constant without children
|
||||||
*/
|
*/
|
||||||
public abstract class LeafConstant extends NodeConstant {
|
public abstract class LeafConstantPoolEntry extends ConstantPoolEntry {
|
||||||
@Override
|
@Override
|
||||||
public Set<NodeConstant> getChildren() {
|
public Set<ConstantPoolEntry> getChildren() {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class LongEntry extends LeafConstant {
|
public class LongEntry extends LeafConstantPoolEntry {
|
||||||
|
|
||||||
private static final byte TAG = 5;
|
private static final byte TAG = 5;
|
||||||
private final long longVal;
|
private final long longVal;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
//TODO implement later
|
//TODO implement later
|
||||||
public class MethodHandleEntry extends NodeConstant {
|
public class MethodHandleEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 15;
|
private static final byte TAG = 15;
|
||||||
|
|
||||||
private final int referenceKind;
|
private final int referenceKind;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class MethodRefEntry extends NodeConstant {
|
public class MethodRefEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 10;
|
private static final byte TAG = 10;
|
||||||
|
|
||||||
private final ClassEntry classRef;
|
private final ClassEntry classRef;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class MethodTypeEntry extends NodeConstant {
|
public class MethodTypeEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 16;
|
private static final byte TAG = 16;
|
||||||
|
|
||||||
private final Utf8Entry methodDescriptor;
|
private final Utf8Entry methodDescriptor;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class ModuleEntry extends NodeConstant {
|
public class ModuleEntry extends ConstantPoolEntry {
|
||||||
|
|
||||||
private static final byte TAG = 19;
|
private static final byte TAG = 19;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class NameAndTypeEntry extends NodeConstant {
|
public class NameAndTypeEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 12;
|
private static final byte TAG = 12;
|
||||||
private final Utf8Entry name;
|
private final Utf8Entry name;
|
||||||
private final Utf8Entry descriptor;
|
private final Utf8Entry descriptor;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class PackageEntry extends NodeConstant {
|
public class PackageEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 20;
|
private static final byte TAG = 20;
|
||||||
private final Utf8Entry name;
|
private final Utf8Entry name;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package nl.sander.beejava.constantpool.entry;
|
package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
public class StringEntry extends NodeConstant {
|
public class StringEntry extends ConstantPoolEntry {
|
||||||
private static final byte TAG = 8;
|
private static final byte TAG = 8;
|
||||||
private final Utf8Entry utf8;
|
private final Utf8Entry utf8;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package nl.sander.beejava.constantpool.entry;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
public class Utf8Entry extends LeafConstant {
|
public class Utf8Entry extends LeafConstantPoolEntry {
|
||||||
private static final byte TAG = 1;
|
private static final byte TAG = 1;
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
|
|
|
||||||
15
src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
Normal file
15
src/test/java/nl/sander/beejava/BytecodeGeneratorTests.java
Normal file
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,99 @@
|
||||||
package nl.sander.beejava;
|
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 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 {
|
public class CompilerTests {
|
||||||
@Test
|
|
||||||
public void test(){
|
// creates simplest class possible and checks the tree, that the ConstantTreeCreator emits
|
||||||
Compiler.compile(TestData.emptyClass());
|
@Test // This is not a maintainable test
|
||||||
|
public void testMethodRefEntryForSuperConstructor() {
|
||||||
|
BeeClass classWithIntField = TestData.emptyClass();
|
||||||
|
CompiledClass compiledClass = new Compiler().compile(classWithIntField);
|
||||||
|
Set<ConstantPoolEntry> constantTree = compiledClass.getConstantTree();
|
||||||
|
assertEquals(2, constantTree.size());
|
||||||
|
ConstantPoolEntry superConstructor = constantTree.iterator().next();
|
||||||
|
|
||||||
|
assertEquals(MethodRefEntry.class, superConstructor.getClass());
|
||||||
|
MethodRefEntry methodRefEntry = (MethodRefEntry) superConstructor;
|
||||||
|
|
||||||
|
Set<ConstantPoolEntry> methodRefEntryChildren = methodRefEntry.getChildren();
|
||||||
|
assertEquals(2, methodRefEntryChildren.size());
|
||||||
|
|
||||||
|
Iterator<ConstantPoolEntry> firstChildren = methodRefEntryChildren.iterator();
|
||||||
|
ConstantPoolEntry child1 = firstChildren.next();
|
||||||
|
assertEquals(ClassEntry.class, child1.getClass());
|
||||||
|
ClassEntry classEntry = (ClassEntry) child1;
|
||||||
|
|
||||||
|
Set<ConstantPoolEntry> 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<ConstantPoolEntry> nameAndTypeEntryChildren = nameAndTypeEntry.getChildren();
|
||||||
|
assertEquals(2, nameAndTypeEntryChildren.size());
|
||||||
|
Iterator<ConstantPoolEntry> nameAndTypeChildrenIterator = nameAndTypeEntryChildren.iterator();
|
||||||
|
|
||||||
|
ConstantPoolEntry child4 = nameAndTypeChildrenIterator.next();
|
||||||
|
assertEquals(Utf8Entry.class, child4.getClass());
|
||||||
|
Utf8Entry name = (Utf8Entry) child4;
|
||||||
|
assertEquals("<init>", 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, "<init>", "()"),
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<NodeConstant> constantTree = new ConstantTreeCreator().createConstantTree(classWithIntField);
|
|
||||||
assertEquals(1, constantTree.size());
|
|
||||||
NodeConstant superConstructor = constantTree.iterator().next();
|
|
||||||
|
|
||||||
assertEquals(MethodRefEntry.class, superConstructor.getClass());
|
|
||||||
MethodRefEntry methodRefEntry = (MethodRefEntry) superConstructor;
|
|
||||||
|
|
||||||
Set<NodeConstant> methodRefEntryChildren = methodRefEntry.getChildren();
|
|
||||||
assertEquals(2, methodRefEntryChildren.size());
|
|
||||||
|
|
||||||
Iterator<NodeConstant> firstChildren = methodRefEntryChildren.iterator();
|
|
||||||
NodeConstant child1 = firstChildren.next();
|
|
||||||
assertEquals(ClassEntry.class, child1.getClass());
|
|
||||||
ClassEntry classEntry = (ClassEntry) child1;
|
|
||||||
|
|
||||||
Set<NodeConstant> 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<NodeConstant> nameAndTypeEntryChildren = nameAndTypeEntry.getChildren();
|
|
||||||
assertEquals(2, nameAndTypeEntryChildren.size());
|
|
||||||
Iterator<NodeConstant> nameAndTypeChildrenIterator = nameAndTypeEntryChildren.iterator();
|
|
||||||
|
|
||||||
NodeConstant child4 = nameAndTypeChildrenIterator.next();
|
|
||||||
assertEquals(Utf8Entry.class, child4.getClass());
|
|
||||||
Utf8Entry name = (Utf8Entry) child4;
|
|
||||||
assertEquals("<init>", 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, "<init>", "()"),
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -6,12 +6,37 @@ import nl.sander.beejava.api.Ref;
|
||||||
import nl.sander.beejava.api.Version;
|
import nl.sander.beejava.api.Version;
|
||||||
import nl.sander.beejava.flags.MethodAccessFlag;
|
import nl.sander.beejava.flags.MethodAccessFlag;
|
||||||
|
|
||||||
|
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.ClassAccessFlag.PUBLIC;
|
||||||
|
|
||||||
public class TestData {
|
public class TestData {
|
||||||
public static BeeClass emptyClass() {
|
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()
|
BeeConstructor constructor = BeeConstructor.builder()
|
||||||
.withAccessFlags(MethodAccessFlag.PUBLIC)
|
.withAccessFlags(MethodAccessFlag.PUBLIC)
|
||||||
.withCode(
|
.withCode(
|
||||||
|
|
@ -19,14 +44,6 @@ public class TestData {
|
||||||
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||||
line(5, RETURN))
|
line(5, RETURN))
|
||||||
.build();
|
.build();
|
||||||
|
return constructor;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package nl.sander.beejava.testclasses;
|
||||||
|
|
||||||
|
public class EmptyBean {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package nl.sander.beejava.testclasses;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class EmptyBeanWithInterface implements Serializable {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package nl.sander.beejava.testclasses;
|
package nl.sander.beejava.testclasses;
|
||||||
|
|
||||||
public class IntBean {
|
public class IntBean {
|
||||||
// private int intField;
|
private int intField;
|
||||||
|
|
||||||
// public IntBean(int intField) {
|
public IntBean(int intField) {
|
||||||
// this.intField = intField;
|
this.intField = intField;
|
||||||
// }
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue