fixed a bug with wrong utf-8 length and added uniqueness checks. Improved the design
This commit is contained in:
parent
d17883701d
commit
78cfcd411f
27 changed files with 567 additions and 133 deletions
|
|
@ -0,0 +1,93 @@
|
|||
Classfile /Users/Shautvast/IdeaProjects/beejava/target/test-classes/nl/sander/beejava/testclasses/BeanWithClassReferences.class
|
||||
Last modified 10 Nov 2020; size 655 bytes
|
||||
SHA-256 checksum 1bb4b80be80051827e68106c7ec72140696f105df82dfc28147eaaff73a9b667
|
||||
Compiled from "BeanWithClassReferences.java"
|
||||
public class nl.sander.beejava.testclasses.BeanWithClassReferences
|
||||
minor version: 0
|
||||
major version: 58
|
||||
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
|
||||
this_class: #23 // nl/sander/beejava/testclasses/BeanWithClassReferences
|
||||
super_class: #2 // java/lang/Object
|
||||
interfaces: 0, fields: 0, methods: 3, 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 = Fieldref #8.#9 // java/lang/System.out:Ljava/io/PrintStream;
|
||||
#8 = Class #10 // java/lang/System
|
||||
#9 = NameAndType #11:#12 // out:Ljava/io/PrintStream;
|
||||
#10 = Utf8 java/lang/System
|
||||
#11 = Utf8 out
|
||||
#12 = Utf8 Ljava/io/PrintStream;
|
||||
#13 = String #14 // 1
|
||||
#14 = Utf8 1
|
||||
#15 = Methodref #16.#17 // java/io/PrintStream.println:(Ljava/lang/String;)V
|
||||
#16 = Class #18 // java/io/PrintStream
|
||||
#17 = NameAndType #19:#20 // println:(Ljava/lang/String;)V
|
||||
#18 = Utf8 java/io/PrintStream
|
||||
#19 = Utf8 println
|
||||
#20 = Utf8 (Ljava/lang/String;)V
|
||||
#21 = String #22 // 2
|
||||
#22 = Utf8 2
|
||||
#23 = Class #24 // nl/sander/beejava/testclasses/BeanWithClassReferences
|
||||
#24 = Utf8 nl/sander/beejava/testclasses/BeanWithClassReferences
|
||||
#25 = Utf8 Code
|
||||
#26 = Utf8 LineNumberTable
|
||||
#27 = Utf8 LocalVariableTable
|
||||
#28 = Utf8 this
|
||||
#29 = Utf8 Lnl/sander/beejava/testclasses/BeanWithClassReferences;
|
||||
#30 = Utf8 print1
|
||||
#31 = Utf8 print2
|
||||
#32 = Utf8 SourceFile
|
||||
#33 = Utf8 BeanWithClassReferences.java
|
||||
{
|
||||
public nl.sander.beejava.testclasses.BeanWithClassReferences();
|
||||
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 3: 0
|
||||
LocalVariableTable:
|
||||
Start Length Slot Name Signature
|
||||
0 5 0 this Lnl/sander/beejava/testclasses/BeanWithClassReferences;
|
||||
|
||||
public void print1();
|
||||
descriptor: ()V
|
||||
flags: (0x0001) ACC_PUBLIC
|
||||
Code:
|
||||
stack=2, locals=1, args_size=1
|
||||
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
|
||||
3: ldc #13 // String 1
|
||||
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
|
||||
8: return
|
||||
LineNumberTable:
|
||||
line 6: 0
|
||||
line 7: 8
|
||||
LocalVariableTable:
|
||||
Start Length Slot Name Signature
|
||||
0 9 0 this Lnl/sander/beejava/testclasses/BeanWithClassReferences;
|
||||
|
||||
public void print2();
|
||||
descriptor: ()V
|
||||
flags: (0x0001) ACC_PUBLIC
|
||||
Code:
|
||||
stack=2, locals=1, args_size=1
|
||||
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
|
||||
3: ldc #21 // String 2
|
||||
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
|
||||
8: return
|
||||
LineNumberTable:
|
||||
line 10: 0
|
||||
line 11: 8
|
||||
LocalVariableTable:
|
||||
Start Length Slot Name Signature
|
||||
0 9 0 this Lnl/sander/beejava/testclasses/BeanWithClassReferences;
|
||||
}
|
||||
SourceFile: "BeanWithClassReferences.java"
|
||||
14
pom.xml
14
pom.xml
|
|
@ -7,7 +7,15 @@
|
|||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-bytecodeGenerator-plugin</artifactId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>15</source>
|
||||
<target>15</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>14</source>
|
||||
<target>14</target>
|
||||
|
|
@ -21,8 +29,8 @@
|
|||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.bytecodeGenerator.source>15</maven.bytecodeGenerator.source>
|
||||
<maven.bytecodeGenerator.target>15</maven.bytecodeGenerator.target>
|
||||
<maven.compiler.source>14</maven.compiler.source>
|
||||
<maven.compiler.target>14</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,31 +8,30 @@ 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 CompiledClass compiledClass; // maybe not a member?
|
||||
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
|
||||
|
||||
public BytecodeGenerator(BeeClass beeClass) {
|
||||
this.beeClass = beeClass;
|
||||
public BytecodeGenerator(CompiledClass compiledClass) {
|
||||
this.compiledClass = compiledClass;
|
||||
}
|
||||
|
||||
public static byte[] compile(BeeClass beeClass) {
|
||||
BytecodeGenerator bytecodeGenerator = new BytecodeGenerator(beeClass);
|
||||
return bytecodeGenerator.doCompile();
|
||||
public static byte[] generate(CompiledClass compiledClass) {
|
||||
BytecodeGenerator bytecodeGenerator = new BytecodeGenerator(compiledClass);
|
||||
return bytecodeGenerator.generate();
|
||||
}
|
||||
|
||||
private byte[] doCompile() {
|
||||
private byte[] generate() {
|
||||
ByteBuf buf = new ByteBuf();
|
||||
buf.addU8(0xCA, 0xFE, 0xBA, 0xBE);
|
||||
buf.addU16(beeClass.getClassFileVersion().getMinor());
|
||||
buf.addU16(beeClass.getClassFileVersion().getMajor());
|
||||
buf.addU16(compiledClass.getBeeClass().getClassFileVersion().getMinor());
|
||||
buf.addU16(compiledClass.getBeeClass().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(ClassAccessFlag.getSum(compiledClass.getBeeClass().getAccessFlags()));
|
||||
buf.addU16(compiledClass.geThisIndex());
|
||||
buf.addU16(compiledClass.getSuperIndex());
|
||||
buf.addU16(compiledClass.getInterfaces().size());
|
||||
|
|
|
|||
|
|
@ -3,80 +3,63 @@ 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 {
|
||||
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) {
|
||||
CompiledClass(BeeClass beeClass) {
|
||||
this.beeClass = beeClass;
|
||||
}
|
||||
|
||||
public int getSuperIndex() {
|
||||
int getSuperIndex() {
|
||||
return superClass.getIndex();
|
||||
}
|
||||
|
||||
public int geThisIndex() {
|
||||
int geThisIndex() {
|
||||
return thisClass.getIndex();
|
||||
}
|
||||
|
||||
public ClassEntry addSuperClass() {
|
||||
void setSuperClass(ClassEntry newSuperClass) {
|
||||
if (superClass == null) {
|
||||
superClass = createClassEntry(beeClass.getSuperClass().getName());
|
||||
superClass = newSuperClass;
|
||||
}
|
||||
return superClass;
|
||||
}
|
||||
|
||||
public ClassEntry addThisClass() {
|
||||
if (thisClass == null) {
|
||||
thisClass = createClassEntry(internalName(beeClass.getName()));
|
||||
}
|
||||
return thisClass;
|
||||
}
|
||||
|
||||
public Set<ConstantPoolEntry> getConstantTree() {
|
||||
Set<ConstantPoolEntry> getConstantTree() {
|
||||
return constantTree;
|
||||
}
|
||||
|
||||
public Set<ClassEntry> getInterfaces() {
|
||||
Set<ClassEntry> getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
public void addInterface(ClassEntry interfaceEntry) {
|
||||
void addConstantPoolEntry(ConstantPoolEntry entry) {
|
||||
constantTree.add(entry); // no duplicates
|
||||
}
|
||||
|
||||
void addInterface(ClassEntry interfaceEntry) {
|
||||
interfaces.add(interfaceEntry);
|
||||
}
|
||||
|
||||
public void addConstantPoolEntry(ConstantPoolEntry interfaceEntry) {
|
||||
constantTree.add(interfaceEntry);
|
||||
BeeClass getBeeClass() {
|
||||
return beeClass;
|
||||
}
|
||||
|
||||
public void addInterfaces() {
|
||||
beeClass.getInterfaces().forEach(interfase -> {
|
||||
ClassEntry interfaceEntry = new ClassEntry(new Utf8Entry(internalName(interfase.getName())));
|
||||
addInterface(interfaceEntry);
|
||||
addConstantPoolEntry(interfaceEntry);
|
||||
});
|
||||
ClassEntry getThisClass() {
|
||||
return thisClass;
|
||||
}
|
||||
|
||||
public void addFields() {
|
||||
beeClass.getFields().forEach(field -> {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
private ClassEntry createClassEntry(String name) {
|
||||
return new ClassEntry(new Utf8Entry(internalName(name)));
|
||||
}
|
||||
|
||||
private String internalName(String name) {
|
||||
return name.replaceAll("\\.", "/");
|
||||
public void setThisClass(ClassEntry newThisClass) {
|
||||
if (thisClass == null) {
|
||||
thisClass = newThisClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ 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.*;
|
||||
|
||||
/**
|
||||
* Builds a set of a tree of constant pool entries that refer to each other.
|
||||
|
|
@ -15,7 +13,13 @@ import nl.sander.beejava.constantpool.entry.*;
|
|||
* also TODO make sure entries aren't duplicates
|
||||
*/
|
||||
public class Compiler {
|
||||
private CompiledClass compiledClass;
|
||||
private final CompiledClass compiledClass;
|
||||
private final ConstantPoolEntryCreator constantPoolEntryCreator;
|
||||
|
||||
Compiler(CompiledClass compiledClass) {
|
||||
this.compiledClass = 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.
|
||||
|
|
@ -24,15 +28,18 @@ public class Compiler {
|
|||
* @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);
|
||||
public static CompiledClass compile(BeeClass beeClass) {
|
||||
return new Compiler(new CompiledClass(beeClass)).compile();
|
||||
}
|
||||
|
||||
CompiledClass compile() {
|
||||
compiledClass.getBeeClass().getConstructors().forEach(this::updateConstantPool);
|
||||
// TODO update constant pool for fields ?
|
||||
// TODO update constant pool for methods
|
||||
|
||||
compiledClass.addThisClass();
|
||||
compiledClass.addInterfaces();
|
||||
compiledClass.addFields();
|
||||
constantPoolEntryCreator.addThisClass();
|
||||
constantPoolEntryCreator.addInterfaces();
|
||||
constantPoolEntryCreator.addFields();
|
||||
|
||||
return compiledClass;
|
||||
}
|
||||
|
|
@ -43,43 +50,21 @@ public class Compiler {
|
|||
}
|
||||
|
||||
/*
|
||||
* scan code line for items that need adding to the constant pool
|
||||
* Scan code line for items that need adding to the constant pool
|
||||
*
|
||||
* Constantpool uniqueness is maintained in two ways:
|
||||
* 1. ConstantPoolEntryCreator.getOrCreateMethodRefEntry (and other methods) return a tree of entries.
|
||||
* Sub-entries are kept in cache by the ConstantPoolEntryCreator and it returns a cached entry over a new one, if deemed equal.
|
||||
* 2. the root node (also in aforementioned cache) is not symmetric because it is the only one that can be added to The compiledClass.
|
||||
* So Compiled class also contains a set of unique root nodes.
|
||||
*/
|
||||
private void updateConstantPool(CodeLine codeline) {
|
||||
if (codeline.hasMethod()) {
|
||||
addMethodToConstantPool(codeline);
|
||||
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateMethodRefEntry(codeline));
|
||||
}
|
||||
|
||||
if (codeline.hasField()) {
|
||||
addFieldToConstantPool(codeline);
|
||||
compiledClass.addConstantPoolEntry(constantPoolEntryCreator.getOrCreateFieldRefEntry(codeline));
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethodToConstantPool(CodeLine codeline) {
|
||||
compiledClass.addConstantPoolEntry(new MethodRefEntry(getOrCreateClassEntry(codeline), createMethodNameAndType(codeline)));
|
||||
}
|
||||
|
||||
private void addFieldToConstantPool(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.addSuperClass();
|
||||
|
||||
} else if (codeline.getRef() == Ref.THIS) {
|
||||
return compiledClass.addThisClass();
|
||||
}
|
||||
//TODO other cases
|
||||
throw new RuntimeException("shouldn't be here");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,96 @@
|
|||
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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for creating unique constant pool entries
|
||||
*/
|
||||
class ConstantPoolEntryCreator {
|
||||
private final Map<Integer, ConstantPoolEntry> cache = new HashMap<>();
|
||||
private final CompiledClass compiledClass;
|
||||
|
||||
public ConstantPoolEntryCreator(CompiledClass compiledClass) {
|
||||
this.compiledClass = compiledClass;
|
||||
}
|
||||
|
||||
FieldRefEntry getOrCreateFieldRefEntry(CodeLine codeLine) {
|
||||
return cache(new FieldRefEntry(getOrCreateClassEntry(codeLine), createFieldNameAndType(codeLine)));
|
||||
}
|
||||
|
||||
MethodRefEntry getOrCreateMethodRefEntry(CodeLine codeline) {
|
||||
ClassEntry classEntry = getOrCreateClassEntry(codeline);
|
||||
NameAndTypeEntry nameAndType = getOrCreateMethodNameAndType(codeline);
|
||||
return cache(new MethodRefEntry(classEntry, nameAndType));
|
||||
}
|
||||
|
||||
private NameAndTypeEntry createFieldNameAndType(CodeLine codeline) {
|
||||
return cache(new NameAndTypeEntry(cache(new Utf8Entry(codeline.getField().getName())), cache(new Utf8Entry(TypeMapper.map(codeline.getField().getType())))));
|
||||
}
|
||||
|
||||
private NameAndTypeEntry getOrCreateMethodNameAndType(CodeLine codeline) {
|
||||
return new NameAndTypeEntry(
|
||||
cache(new Utf8Entry(codeline.getMethodName())),
|
||||
cache(new Utf8Entry(codeline.getMethodSignature())));
|
||||
}
|
||||
|
||||
private ClassEntry getOrCreateClassEntry(CodeLine codeline) {
|
||||
if (codeline.getRef() == Ref.SUPER) { //this and super are rather special
|
||||
ClassEntry superClass = getClassEntry(compiledClass.getBeeClass().getSuperClass().getName());
|
||||
compiledClass.setSuperClass(superClass);
|
||||
return superClass;
|
||||
|
||||
} else if (codeline.getRef() == Ref.THIS) {
|
||||
addThisClass();
|
||||
return compiledClass.getThisClass();
|
||||
}
|
||||
//TODO other cases
|
||||
throw new RuntimeException("shouldn't be here");
|
||||
}
|
||||
|
||||
void addThisClass(){
|
||||
ClassEntry classEntry = getClassEntry(compiledClass.getBeeClass().getName());
|
||||
compiledClass.setThisClass(classEntry);
|
||||
}
|
||||
|
||||
private ClassEntry getClassEntry(String externalClassName) {
|
||||
return cache(new ClassEntry(cache(new Utf8Entry(internalName(externalClassName)))));
|
||||
}
|
||||
|
||||
public void addInterfaces() {
|
||||
compiledClass.getBeeClass().getInterfaces().forEach(interfase -> {
|
||||
ClassEntry interfaceEntry = cache(new ClassEntry(cache(new Utf8Entry(internalName(interfase.getName())))));
|
||||
compiledClass.addInterface(interfaceEntry);
|
||||
compiledClass.addConstantPoolEntry(interfaceEntry);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addFields() {
|
||||
compiledClass.getBeeClass().getFields().forEach(field -> {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
private String internalName(String name) {
|
||||
return name.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
<T extends ConstantPoolEntry> T cache(T newEntry) {
|
||||
// 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
|
||||
int hash = newEntry.hashCode();
|
||||
return (T) cache.computeIfAbsent(hash, k -> newEntry);
|
||||
// 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.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ClassEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 7;
|
||||
private final Utf8Entry name;
|
||||
|
|
@ -24,4 +26,17 @@ public class ClassEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getNameIndex()), lowerByte(getNameIndex())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ClassEntry that = (ClassEntry) o;
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class DoubleEntry extends LeafConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public class DoubleEntry extends LeafEntry {
|
||||
private static final byte TAG = 6;
|
||||
private final double doubleVal;
|
||||
|
||||
|
|
@ -15,4 +17,16 @@ public class DoubleEntry extends LeafConstantPoolEntry {
|
|||
getByte(bits, 24), getByte(bits, 16), getByte(bits, 8), (byte) (bits & 0xFF)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
DoubleEntry that = (DoubleEntry) o;
|
||||
return Double.compare(that.doubleVal, doubleVal) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(doubleVal);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DynamicEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 17;
|
||||
private final int bootstrapMethodIndex; // TODO
|
||||
|
|
@ -18,4 +20,18 @@ public class DynamicEntry extends ConstantPoolEntry {
|
|||
public int getNameAndTypeIndex() {
|
||||
return nameAndType.getIndex();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public boolean equals(Object o) {
|
||||
// if (this == o) return true;
|
||||
// if (o == null || getClass() != o.getClass()) return false;
|
||||
// DynamicEntry that = (DynamicEntry) o;
|
||||
// return bootstrapMethodIndex == that.bootstrapMethodIndex &&
|
||||
// nameAndType.equals(that.nameAndType);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public int hashCode() {
|
||||
// return Objects.hash(bootstrapMethodIndex, nameAndType);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class FieldRefEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 9;
|
||||
|
||||
|
|
@ -33,4 +35,17 @@ public class FieldRefEntry extends ConstantPoolEntry {
|
|||
return new byte[]{TAG};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FieldRefEntry that = (FieldRefEntry) o;
|
||||
return classEntry.equals(that.classEntry) &&
|
||||
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(classEntry, nameAndTypeEntry);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class FloatEntry extends LeafConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public class FloatEntry extends LeafEntry {
|
||||
private static final byte TAG = 4;
|
||||
|
||||
private final float floatVal;
|
||||
|
|
@ -16,6 +18,19 @@ public class FloatEntry extends LeafConstantPoolEntry {
|
|||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
FloatEntry that = (FloatEntry) o;
|
||||
return Float.compare(that.floatVal, floatVal) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(floatVal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
long bits = Float.floatToRawIntBits(floatVal);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class IntegerEntry extends LeafConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public class IntegerEntry extends LeafEntry {
|
||||
private static final byte TAG = 3;
|
||||
|
||||
private final int intVal;
|
||||
|
|
@ -20,4 +22,17 @@ public class IntegerEntry extends LeafConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, (byte) (intVal >>> 24), (byte) (intVal >>> 16), (byte) (intVal >>> 8), (byte) (intVal & 0xFF)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
IntegerEntry that = (IntegerEntry) o;
|
||||
return intVal == that.intVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(intVal);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 11;
|
||||
|
||||
|
|
@ -25,4 +27,18 @@ public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
InterfaceMethodRefEntry that = (InterfaceMethodRefEntry) o;
|
||||
return classEntry.equals(that.classEntry) &&
|
||||
nameAndTypeEntry.equals(that.nameAndTypeEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(classEntry, nameAndTypeEntry);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,5 +24,7 @@ public class InvokeDynamicEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG};
|
||||
}
|
||||
|
||||
// TODO equals and hashcode
|
||||
}
|
||||
//TODO implement later
|
||||
|
|
@ -6,7 +6,7 @@ import java.util.Set;
|
|||
/**
|
||||
* Is a constant without children
|
||||
*/
|
||||
public abstract class LeafConstantPoolEntry extends ConstantPoolEntry {
|
||||
public abstract class LeafEntry extends ConstantPoolEntry {
|
||||
@Override
|
||||
public Set<ConstantPoolEntry> getChildren() {
|
||||
return Collections.emptySet();
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class LongEntry extends LeafConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public class LongEntry extends LeafEntry {
|
||||
|
||||
private static final byte TAG = 5;
|
||||
private final long longVal;
|
||||
|
|
@ -22,5 +24,16 @@ public class LongEntry extends LeafConstantPoolEntry {
|
|||
getByte(longVal, 24), getByte(longVal, 16), getByte(longVal, 8), (byte) (longVal & 0xFF)};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
LongEntry longEntry = (LongEntry) o;
|
||||
return longVal == longEntry.longVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(longVal);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,4 +30,6 @@ public class MethodHandleEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG};
|
||||
}
|
||||
|
||||
//TODO equals and hashcode
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MethodRefEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 10;
|
||||
|
||||
|
|
@ -24,4 +26,28 @@ public class MethodRefEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getClassIndex()), lowerByte(getClassIndex()), upperByte(getNameAndTypeIndex()), lowerByte(getNameAndTypeIndex())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MethodRefEntry that = (MethodRefEntry) o;
|
||||
return classRef.equals(that.classRef) &&
|
||||
nameAndType.equals(that.nameAndType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(classRef, nameAndType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodRefEntry{" +
|
||||
"classIndex=" + getClassIndex() +
|
||||
", nameAndTypeIndex=" + getNameAndTypeIndex() +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MethodTypeEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 16;
|
||||
|
||||
|
|
@ -9,15 +11,27 @@ public class MethodTypeEntry extends ConstantPoolEntry {
|
|||
this.methodDescriptor = methodDescriptor;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
MethodTypeEntry that = (MethodTypeEntry) o;
|
||||
return methodDescriptor.equals(that.methodDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(methodDescriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MethodTypeEntry{" +
|
||||
"methodDescriptor=" + methodDescriptor +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ModuleEntry extends ConstantPoolEntry {
|
||||
|
||||
private static final byte TAG = 19;
|
||||
|
|
@ -18,4 +20,24 @@ public class ModuleEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getNameIndex()), lowerByte(getNameIndex())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
ModuleEntry that = (ModuleEntry) o;
|
||||
return nameEntry.equals(that.nameEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(nameEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModuleEntry{" +
|
||||
"nameEntryIndex" + getNameIndex() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class NameAndTypeEntry extends ConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public final class NameAndTypeEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 12;
|
||||
private final Utf8Entry name;
|
||||
private final Utf8Entry descriptor;
|
||||
|
|
@ -20,6 +22,24 @@ public class NameAndTypeEntry extends ConstantPoolEntry {
|
|||
return descriptor.getIndex();
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getNameIndex()), lowerByte(getNameIndex()), upperByte(getDescriptorIndex()), lowerByte(getDescriptorIndex())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NameAndTypeEntry that = (NameAndTypeEntry) o;
|
||||
return name.equals(that.name) &&
|
||||
descriptor.equals(that.descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NameAndTypeEntry{" +
|
||||
|
|
@ -28,7 +48,4 @@ public class NameAndTypeEntry extends ConstantPoolEntry {
|
|||
'}';
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getNameIndex()), lowerByte(getNameIndex()), upperByte(getDescriptorIndex()), lowerByte(getDescriptorIndex())};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class PackageEntry extends ConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public final class PackageEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 20;
|
||||
private final Utf8Entry name;
|
||||
|
||||
|
|
@ -16,4 +18,24 @@ public class PackageEntry extends ConstantPoolEntry {
|
|||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getNameIndex()), lowerByte(getNameIndex())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PackageEntry that = (PackageEntry) o;
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PackageEntry{" +
|
||||
"nameIndex=" + getNameIndex() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class StringEntry extends ConstantPoolEntry {
|
||||
import java.util.Objects;
|
||||
|
||||
public final class StringEntry extends ConstantPoolEntry {
|
||||
private static final byte TAG = 8;
|
||||
private final Utf8Entry utf8;
|
||||
|
||||
|
|
@ -12,14 +14,27 @@ public class StringEntry extends ConstantPoolEntry {
|
|||
return utf8.getIndex();
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getUtf8Index()), lowerByte(getUtf8Index())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
StringEntry that = (StringEntry) o;
|
||||
return utf8.equals(that.utf8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(utf8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StringEntry{" +
|
||||
"utf8Index=" + getUtf8Index() +
|
||||
'}';
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{TAG, upperByte(getUtf8Index()), lowerByte(getUtf8Index())};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Utf8Entry extends LeafConstantPoolEntry {
|
||||
public final class Utf8Entry extends LeafEntry {
|
||||
private static final byte TAG = 1;
|
||||
private final String value;
|
||||
|
||||
|
|
@ -14,20 +15,33 @@ public class Utf8Entry extends LeafConstantPoolEntry {
|
|||
return value;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] bytes = new byte[utf8Bytes.length + 3];
|
||||
bytes[0] = TAG;
|
||||
bytes[1] = upperByte(utf8Bytes.length);
|
||||
bytes[2] = lowerByte(utf8Bytes.length);
|
||||
System.arraycopy(utf8Bytes, 0, bytes, 3, utf8Bytes.length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Utf8Entry utf8Entry = (Utf8Entry) o;
|
||||
return value.equals(utf8Entry.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Utf8Entry{" +
|
||||
"value='" + value + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] bytes = new byte[utf8Bytes.length + 3];
|
||||
bytes[0] = TAG;
|
||||
bytes[1] = upperByte(bytes.length);
|
||||
bytes[2] = lowerByte(bytes.length);
|
||||
System.arraycopy(utf8Bytes, 0, bytes, 3, utf8Bytes.length);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,23 @@ package nl.sander.beejava;
|
|||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BytecodeGeneratorTests {
|
||||
@Test
|
||||
public void testEmpty(){
|
||||
BytecodeGenerator.compile(TestData.emptyClass());
|
||||
public void testEmpty() throws IOException {
|
||||
byte[] bytecode = BytecodeGenerator.generate(Compiler.compile(TestData.emptyClass()));
|
||||
File dir = new File("target/nl/sander/beejava/test");
|
||||
dir.mkdirs();
|
||||
try (FileOutputStream outputStream = new FileOutputStream(new File(dir, "EmptyBean.class"))) {
|
||||
outputStream.write(bytecode);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInterface() {
|
||||
BytecodeGenerator.compile(TestData.emptyClassWithInterface());
|
||||
BytecodeGenerator.generate(Compiler.compile(TestData.emptyClassWithInterface()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@ 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 {
|
||||
|
|
@ -20,7 +16,7 @@ public class CompilerTests {
|
|||
@Test // This is not a maintainable test
|
||||
public void testMethodRefEntryForSuperConstructor() {
|
||||
BeeClass classWithIntField = TestData.emptyClass();
|
||||
CompiledClass compiledClass = new Compiler().compile(classWithIntField);
|
||||
CompiledClass compiledClass = Compiler.compile(classWithIntField);
|
||||
Set<ConstantPoolEntry> constantTree = compiledClass.getConstantTree();
|
||||
assertEquals(2, constantTree.size());
|
||||
ConstantPoolEntry superConstructor = constantTree.iterator().next();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package nl.sander.beejava.testclasses;
|
||||
|
||||
public class BeanWithClassReferences {
|
||||
|
||||
public void print1(){
|
||||
System.out.println("1");
|
||||
}
|
||||
|
||||
public void print2(){
|
||||
System.out.println("2");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue