API draft, constant pool creator working in principle. A working test
This commit is contained in:
parent
e9e66f6291
commit
9aad0e55c6
44 changed files with 1545 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.idea/
|
||||
target/
|
||||
.DS_Store
|
||||
*.iml
|
||||
54
javap/nl.sander.beejava.testclasses.IntBean_javap.txt
Normal file
54
javap/nl.sander.beejava.testclasses.IntBean_javap.txt
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
Classfile /Users/Shautvast/IdeaProjects/beejava/target/test-classes/nl/sander/beejava/testclasses/IntBean.class
|
||||
Last modified 2 Oct 2020; size 369 bytes
|
||||
SHA-256 checksum ef66d886f52e768d038ec9e87724671c6a748ea0cd62b1b117c5cfb31bcdb153
|
||||
Compiled from "IntBean.java"
|
||||
public class nl.sander.beejava.testclasses.IntBean
|
||||
minor version: 0
|
||||
major version: 58
|
||||
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
|
||||
this_class: #8 // nl/sander/beejava/testclasses/IntBean
|
||||
super_class: #2 // java/lang/Object
|
||||
interfaces: 0, fields: 1, 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 = Fieldref #8.#9 // nl/sander/beejava/testclasses/IntBean.intField:I
|
||||
#8 = Class #10 // nl/sander/beejava/testclasses/IntBean
|
||||
#9 = NameAndType #11:#12 // intField:I
|
||||
#10 = Utf8 nl/sander/beejava/testclasses/IntBean
|
||||
#11 = Utf8 intField
|
||||
#12 = Utf8 I
|
||||
#13 = Utf8 (I)V
|
||||
#14 = Utf8 Code
|
||||
#15 = Utf8 LineNumberTable
|
||||
#16 = Utf8 LocalVariableTable
|
||||
#17 = Utf8 this
|
||||
#18 = Utf8 Lnl/sander/beejava/testclasses/IntBean;
|
||||
#19 = Utf8 SourceFile
|
||||
#20 = Utf8 IntBean.java
|
||||
{
|
||||
public nl.sander.beejava.testclasses.IntBean(int);
|
||||
descriptor: (I)V
|
||||
flags: (0x0001) ACC_PUBLIC
|
||||
Code:
|
||||
stack=2, locals=2, args_size=2
|
||||
0: aload_0
|
||||
1: invokespecial #1 // Method java/lang/Object."<init>":()V
|
||||
4: aload_0
|
||||
5: iload_1
|
||||
6: putfield #7 // Field intField:I
|
||||
9: return
|
||||
LineNumberTable:
|
||||
line 6: 0
|
||||
line 7: 4
|
||||
line 8: 9
|
||||
LocalVariableTable:
|
||||
Start Length Slot Name Signature
|
||||
0 10 0 this Lnl/sander/beejava/testclasses/IntBean;
|
||||
0 10 1 intField I
|
||||
}
|
||||
SourceFile: "IntBean.java"
|
||||
50
pom.xml
Normal file
50
pom.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<name>beejava</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>14</source>
|
||||
<target>14</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<groupId>nl.sander</groupId>
|
||||
<artifactId>beejava</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>15</maven.compiler.source>
|
||||
<maven.compiler.target>15</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.10.19</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
123
src/main/java/nl/sander/beejava/BeeClass.java
Normal file
123
src/main/java/nl/sander/beejava/BeeClass.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.flags.ClassAccessFlag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class BeeClass {
|
||||
private final Version classFileVersion;
|
||||
private final BeePackage beePackage;
|
||||
private final Set<ClassAccessFlag> accessFlags = new HashSet<>();
|
||||
private final String name;
|
||||
private final Class<?> superClass;
|
||||
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||
private final Set<BeeField> fields = new HashSet<>();
|
||||
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||
|
||||
private BeeClass(Version classFileVersion,
|
||||
BeePackage beePackage, Set<ClassAccessFlag> accessFlags, String name, Class<?> superClass,
|
||||
Set<Class<?>> interfaces, Set<BeeField> fields, Set<BeeConstructor> constructors) {
|
||||
this.classFileVersion = classFileVersion;
|
||||
this.beePackage = beePackage;
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
this.name = name;
|
||||
this.superClass = superClass;
|
||||
this.interfaces.addAll(interfaces);
|
||||
this.fields.addAll(fields);
|
||||
this.constructors.addAll(constructors);
|
||||
}
|
||||
|
||||
public static BeeClass.Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Version getClassFileVersion() {
|
||||
return classFileVersion;
|
||||
}
|
||||
|
||||
public BeePackage getPackage() {
|
||||
return beePackage;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Set<BeeConstructor> getConstructors() {
|
||||
return constructors;
|
||||
}
|
||||
|
||||
public Set<ClassAccessFlag> getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public Class<?> getSuperClass() {
|
||||
return superClass;
|
||||
}
|
||||
|
||||
public Set<BeeField> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Version version;
|
||||
private final Set<ClassAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Set<Class<?>> interfaces = new HashSet<>();
|
||||
private final Set<BeeField> fields = new HashSet<>();
|
||||
private final Set<BeeConstructor> constructors = new HashSet<>();
|
||||
private BeePackage beePackage;
|
||||
private Class<?> superClass = Object.class;
|
||||
private String name;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
public Builder withClassFileVersion(Version version){
|
||||
this.version=version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeClass.Builder withPackage(String beePackage) {
|
||||
this.beePackage = new BeePackage(beePackage);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeClass.Builder withAccessFlags(ClassAccessFlag... accessFlags) {
|
||||
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeClass.Builder withName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withSuperClass(Class<?> superClass) {
|
||||
this.superClass = superClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withInterfaces(Class<?>... interfaces) {
|
||||
this.interfaces.addAll(Arrays.asList(interfaces));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withFields(BeeField... fields) {
|
||||
this.fields.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withConstructors(BeeConstructor... constructors) {
|
||||
this.constructors.addAll(Arrays.asList(constructors));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeClass build() {
|
||||
return new BeeClass(version, beePackage, accessFlags, name, superClass, interfaces, fields, constructors);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
85
src/main/java/nl/sander/beejava/BeeConstructor.java
Normal file
85
src/main/java/nl/sander/beejava/BeeConstructor.java
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.flags.MethodAccessFlag;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BeeConstructor implements ContainsCode{
|
||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Set<BeeParameter> formalParameters = new HashSet<>();
|
||||
private final List<CodeLine> code = new LinkedList<>();
|
||||
|
||||
private BeeConstructor(Set<MethodAccessFlag> accessFlags,
|
||||
List<BeeParameter> formalParameters,
|
||||
List<CodeLine> code) {
|
||||
this.formalParameters.addAll(formalParameters);
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
this.code.addAll(code);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
Set<MethodAccessFlag> getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
Set<BeeParameter> getFormalParameters() {
|
||||
return formalParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodeLine> getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BeeConstructor{" +
|
||||
"formalParameters=" + formalParameters +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BeeConstructor that = (BeeConstructor) o;
|
||||
return formalParameters.equals(that.formalParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(formalParameters);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Set<MethodAccessFlag> accessFlags = new HashSet<>();
|
||||
private final List<BeeParameter> formalParameters = new LinkedList<>();
|
||||
private final List<CodeLine> code = new LinkedList<>();
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder withFormalParameters(BeeParameter... formalParameters) {
|
||||
this.formalParameters.addAll(Arrays.asList(formalParameters));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withAccessFlags(MethodAccessFlag... accessFlags) {
|
||||
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withCode(CodeLine... lines) {
|
||||
this.code.addAll(Arrays.asList(lines));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeConstructor build() {
|
||||
return new BeeConstructor(accessFlags, formalParameters, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/main/java/nl/sander/beejava/BeeField.java
Normal file
79
src/main/java/nl/sander/beejava/BeeField.java
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.flags.FieldAccessFlag;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class BeeField {
|
||||
|
||||
private final Set<FieldAccessFlag> accessFlags = new HashSet<>();
|
||||
private final Class<?> type;
|
||||
private final String name;
|
||||
|
||||
private BeeField(Set<FieldAccessFlag> accessFlags, Class<?> type, String name) {
|
||||
this.accessFlags.addAll(accessFlags);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static BeeField.Builder builder(){
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public Set<FieldAccessFlag> getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BeeField beeField = (BeeField) o;
|
||||
return name.equals(beeField.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Set<FieldAccessFlag> accessFlags = new HashSet<>();
|
||||
private Class<?> type;
|
||||
private String name;
|
||||
|
||||
private Builder(){
|
||||
|
||||
}
|
||||
|
||||
public BeeField.Builder withAccessFlags(FieldAccessFlag... accessFlags) {
|
||||
this.accessFlags.addAll(Arrays.asList(accessFlags));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeField.Builder withType(Class<?> type) {
|
||||
this.type=type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeField.Builder withName(String name) {
|
||||
this.name=name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BeeField build() {
|
||||
return new BeeField(accessFlags, type, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/main/java/nl/sander/beejava/BeePackage.java
Normal file
10
src/main/java/nl/sander/beejava/BeePackage.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
class BeePackage {
|
||||
|
||||
private final String name;
|
||||
|
||||
BeePackage(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
38
src/main/java/nl/sander/beejava/BeeParameter.java
Normal file
38
src/main/java/nl/sander/beejava/BeeParameter.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class BeeParameter {
|
||||
private final Class<?> type;
|
||||
private final String name;
|
||||
|
||||
private BeeParameter(Class<?> type, String name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static BeeParameter create(Class<?> type, String name) {
|
||||
return new BeeParameter(type, Objects.requireNonNull(name));
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BeeParameter that = (BeeParameter) o;
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
107
src/main/java/nl/sander/beejava/CodeLine.java
Normal file
107
src/main/java/nl/sander/beejava/CodeLine.java
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
|
||||
class CodeLine {
|
||||
private final int linenumber;
|
||||
private final Opcode opcode;
|
||||
private Ref ref;
|
||||
private BeeParameter parameter;
|
||||
private String methodName;
|
||||
private String inputSignature;
|
||||
private String outputSignature;
|
||||
private BeeField field;
|
||||
|
||||
CodeLine(int linenumber, Opcode opcode) {
|
||||
this.linenumber = linenumber;
|
||||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, Ref ref) {
|
||||
return new CodeLine(nr, opcode).withRef(ref);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, Ref ref, String methodNameRef, String inputSignature) {
|
||||
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(inputSignature).withVoidOutput();
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, Ref ref, String methodNameRef, String inputSignature, String outputSignature) {
|
||||
return new CodeLine(nr, opcode).withRef(ref).withMethodName(methodNameRef).withInput(inputSignature).withOutput(outputSignature);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode) {
|
||||
return new CodeLine(nr, opcode);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, BeeParameter parameter) {
|
||||
return new CodeLine(nr, opcode).withParameter(parameter);
|
||||
}
|
||||
|
||||
public static CodeLine line(int nr, Opcode opcode, BeeField intField) {
|
||||
return new CodeLine(nr, opcode).withRef(Ref.THIS).withField(intField);
|
||||
}
|
||||
|
||||
private CodeLine withRef(Ref ref) {
|
||||
this.ref = ref;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withInput(String inputSignature) {
|
||||
this.inputSignature = inputSignature;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withVoidOutput() {
|
||||
return withOutput("V");
|
||||
}
|
||||
|
||||
private CodeLine withOutput(String outputSignature) {
|
||||
this.outputSignature = outputSignature;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withParameter(BeeParameter parameter) {
|
||||
this.parameter = parameter;
|
||||
return this;
|
||||
}
|
||||
|
||||
private CodeLine withField(BeeField field) {
|
||||
this.field = field;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return methodName;
|
||||
}
|
||||
|
||||
boolean hasMethod() {
|
||||
return methodName != null;
|
||||
}
|
||||
|
||||
String getMethodSignature() {
|
||||
return inputSignature + outputSignature;
|
||||
}
|
||||
|
||||
Ref getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
||||
boolean hasField() {
|
||||
return field != null;
|
||||
}
|
||||
|
||||
BeeField getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
BeeParameter getParameter() {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
38
src/main/java/nl/sander/beejava/Compiler.java
Normal file
38
src/main/java/nl/sander/beejava/Compiler.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.constantpool.ConstantPool;
|
||||
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||
import nl.sander.beejava.util.ByteBuf;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class Compiler {
|
||||
|
||||
private final BeeClass beeClass; // maybe not a member?
|
||||
private final ConstantTreeCreator constantTreeCreator = new ConstantTreeCreator();
|
||||
private final ConstantPoolCreator constantPoolCreator = new ConstantPoolCreator();
|
||||
|
||||
public Compiler(BeeClass beeClass) {
|
||||
this.beeClass = beeClass;
|
||||
}
|
||||
|
||||
public static byte[] compile(BeeClass beeClass) {
|
||||
Compiler compiler = new Compiler(beeClass);
|
||||
return compiler.doCompile();
|
||||
}
|
||||
|
||||
private byte[] doCompile() {
|
||||
ByteBuf buf = new ByteBuf();
|
||||
buf.add(0xCA, 0xFE, 0xBA, 0xBE);
|
||||
buf.add(beeClass.getClassFileVersion().getMinor());
|
||||
buf.add(beeClass.getClassFileVersion().getMajor());
|
||||
|
||||
Set<ConstantPoolEntry> constantTree = constantTreeCreator.createConstantTree(beeClass);
|
||||
ConstantPool constantPool = constantPoolCreator.createConstantPool(constantTree);
|
||||
|
||||
buf.add(constantPool.getBytes());
|
||||
return buf.toBytes();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
47
src/main/java/nl/sander/beejava/ConstantPoolCreator.java
Normal file
47
src/main/java/nl/sander/beejava/ConstantPoolCreator.java
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import nl.sander.beejava.constantpool.ConstantPool;
|
||||
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Transforms the hierachical constant tree into a flat datastructure. The walks the tree adding indexes to each element.
|
||||
*/
|
||||
public class ConstantPoolCreator {
|
||||
private ConstantPool constantPool;
|
||||
private int index;
|
||||
|
||||
public ConstantPool createConstantPool(Set<ConstantPoolEntry> constantTree) {
|
||||
constantPool = new ConstantPool();
|
||||
constantPool.add(null); // dummy element to align it's index with the indexes in the elements themselves
|
||||
index = 0;
|
||||
updateToplevelElements(constantTree);
|
||||
return constantPool;
|
||||
}
|
||||
|
||||
private void updateToplevelElements(Set<ConstantPoolEntry> 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<ConstantPoolEntry> children) {
|
||||
// first all direct children
|
||||
for (ConstantPoolEntry child : children) {
|
||||
addToPool(child);
|
||||
}
|
||||
// then further lineage
|
||||
for (ConstantPoolEntry child : children) {
|
||||
updateChildElements(child.getChildren());
|
||||
}
|
||||
}
|
||||
|
||||
private void addToPool(ConstantPoolEntry entry) {
|
||||
index += 1;
|
||||
entry.setIndex(index);
|
||||
constantPool.add(entry);
|
||||
}
|
||||
}
|
||||
78
src/main/java/nl/sander/beejava/ConstantTreeCreator.java
Normal file
78
src/main/java/nl/sander/beejava/ConstantTreeCreator.java
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
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<ConstantPoolEntry> constantTree = new LinkedHashSet<>();
|
||||
private BeeClass beeClass;
|
||||
|
||||
public Set<ConstantPoolEntry> createConstantTree(BeeClass beeClass) {
|
||||
constantTree.clear();
|
||||
this.beeClass = beeClass;
|
||||
beeClass.getConstructors().forEach(this::updateConstantTree);
|
||||
// TODO update constantTree for fields ?
|
||||
// TODO update constantTree for methods
|
||||
return constantTree;
|
||||
}
|
||||
|
||||
private void updateConstantTree(ContainsCode codeContainer) {
|
||||
codeContainer.getCode().forEach(this::updateConstantTree);
|
||||
}
|
||||
|
||||
// TODO construct multi root tree
|
||||
private void updateConstantTree(CodeLine codeline) {
|
||||
if (codeline.hasMethod()){
|
||||
addMethodRef(codeline);
|
||||
}
|
||||
|
||||
if (codeline.hasField()) {
|
||||
addFieldRef(codeline);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethodRef(CodeLine codeline) {
|
||||
constantTree.add(new MethodRefEntry(createClassName(codeline), createMethodNameAndType(codeline)));
|
||||
}
|
||||
|
||||
private void addFieldRef(CodeLine codeline) {
|
||||
constantTree.add(new FieldRefEntry(createClassName(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 createClassName(CodeLine codeline) {
|
||||
return new ClassEntry(new Utf8Entry(internalName(getNameOfClass(codeline))));
|
||||
}
|
||||
|
||||
private String getNameOfClass(CodeLine codeline) {
|
||||
if (codeline.getRef() == Ref.SUPER) {
|
||||
return beeClass.getSuperClass().getName();
|
||||
} else if (codeline.getRef() == Ref.THIS) {
|
||||
return beeClass.getPackage() + "." + beeClass.getName();
|
||||
}
|
||||
throw new RuntimeException("shouldn't be here");
|
||||
}
|
||||
|
||||
private String internalName(String name) {
|
||||
return name.replaceAll("\\.", "/");
|
||||
}
|
||||
|
||||
}
|
||||
8
src/main/java/nl/sander/beejava/ContainsCode.java
Normal file
8
src/main/java/nl/sander/beejava/ContainsCode.java
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ContainsCode {
|
||||
|
||||
List<CodeLine> getCode();
|
||||
}
|
||||
69
src/main/java/nl/sander/beejava/Opcode.java
Normal file
69
src/main/java/nl/sander/beejava/Opcode.java
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
public enum Opcode {
|
||||
LOAD("load"),
|
||||
STORE("store"),
|
||||
CONST("const"),
|
||||
NEWARRAY("new"),
|
||||
RETURN("return"),
|
||||
ARRAYLENGTH("length"),
|
||||
THROW("throw"),
|
||||
PUSH("push"),
|
||||
CHECKCAST("checkcast"),
|
||||
ADD("add"),
|
||||
COMPARE("cmp"),
|
||||
DIVIDE("div"),
|
||||
MULTIPLY("mul"),
|
||||
NEGATE("neg"),
|
||||
REMAINDER("rem"),
|
||||
SUBTRACT("sub"),
|
||||
DUPLICATE("dup"),
|
||||
DUPLICATE_DOWN("dup_x1"),
|
||||
DUPLICATE2("dup2"),
|
||||
DUPLICATE2_DOWN("dup2_x1"),
|
||||
GET("get"),
|
||||
GOTO("goto"),
|
||||
GOTO_W("goto_w"),
|
||||
TO_DOUBLE("2d"),
|
||||
TO_INT("2i"),
|
||||
TO_LONG("2l"),
|
||||
TO_BYTE("2b"),
|
||||
TO_CHAR("2c"),
|
||||
TO_FLOAT("2f"),
|
||||
TO_SHORT("2s"),
|
||||
AND("and"),
|
||||
IF_EQUAL("ifeq"),
|
||||
IF_NOT_EQUAL("ifneq"),
|
||||
IF_LESS_THAN("iflt"),
|
||||
IF_GREATER_OR_EQUAL("ifge"),
|
||||
IF_GREATER_THAN("ifgt"),
|
||||
IF_LESS_OR_EQUAL("ifle"),
|
||||
IF_NOT_NULL("ifnotnull"),
|
||||
IF_NULL("ifnull"),
|
||||
INCREMENT("inc"),
|
||||
INSTANCEOF("instanceof"),
|
||||
INVOKE("invoke"),
|
||||
OR("or"),
|
||||
SHIFT_LEFT("shr"),
|
||||
SHIFT_RIGHT("shl"),
|
||||
LOGICAL_SHIFT_RIGHT("ushr"),
|
||||
XOR("xor"),
|
||||
LOOKUPSWITCH("lookupswitch"),
|
||||
MONITORENTER("monitorenter"),
|
||||
MONITOREXIT("monitorexit"),
|
||||
MULTIANEWARRAY("multinewarray"),
|
||||
NEW("new"),
|
||||
NOP("nop"),
|
||||
POP("pop"),
|
||||
POP2("pop2"),
|
||||
PUT("put"),
|
||||
SWAP("swap"),
|
||||
TABLESWITCH("tableswitch"),
|
||||
WIDE("wide");
|
||||
|
||||
private final String name;
|
||||
|
||||
Opcode(String name) {
|
||||
this.name=name;
|
||||
}
|
||||
}
|
||||
22
src/main/java/nl/sander/beejava/Output.java
Normal file
22
src/main/java/nl/sander/beejava/Output.java
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
/**
|
||||
* Only used to contain void return
|
||||
*/
|
||||
public final class Output {
|
||||
|
||||
public static final Output VOID =new Output();
|
||||
|
||||
private Output() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return getClass() == obj.getClass();
|
||||
}
|
||||
}
|
||||
10
src/main/java/nl/sander/beejava/Ref.java
Normal file
10
src/main/java/nl/sander/beejava/Ref.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
/**
|
||||
* used to indicate this, super, or none of those, in which case it's class
|
||||
*/
|
||||
public enum Ref {
|
||||
THIS,
|
||||
SUPER,
|
||||
CLASS
|
||||
}
|
||||
20
src/main/java/nl/sander/beejava/TypeMapper.java
Normal file
20
src/main/java/nl/sander/beejava/TypeMapper.java
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class TypeMapper {
|
||||
private static final Map<Class<?>, String> MAP = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
MAP.put(int.class, "I");
|
||||
}
|
||||
|
||||
public static String map(Class<?> type) {
|
||||
return Optional.ofNullable(MAP.get(type))
|
||||
.orElseThrow(() -> new RuntimeException("Type " + type.getName() + " not found")); //this MUST not happen -> TODO map all types
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
34
src/main/java/nl/sander/beejava/Version.java
Normal file
34
src/main/java/nl/sander/beejava/Version.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
public enum Version {
|
||||
V1_0_2(45),
|
||||
V1_1(45),
|
||||
V1_2(46),
|
||||
V1_3(47),
|
||||
V1_4(48),
|
||||
V5_0(49),
|
||||
V6(50),
|
||||
V7(51),
|
||||
V8(52),
|
||||
V9(53),
|
||||
V10(54),
|
||||
V11(55),
|
||||
V12(56),
|
||||
V13(57),
|
||||
V14(58),
|
||||
V15(59);
|
||||
|
||||
private final int major;
|
||||
|
||||
Version(int major) {
|
||||
this.major = major;
|
||||
}
|
||||
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
public int getMinor(){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package nl.sander.beejava.constantpool;
|
||||
|
||||
import nl.sander.beejava.constantpool.entry.ConstantPoolEntry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConstantPool {
|
||||
private final List<ConstantPoolEntry> entries=new ArrayList<>();
|
||||
|
||||
public int getIndex(ConstantPoolEntry entry){
|
||||
for (int i=0; i<entries.size(); i++){
|
||||
if (entries.get(i)==entry){
|
||||
return i+1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void add(int index, ConstantPoolEntry entry){
|
||||
entries.add(index, entry);
|
||||
}
|
||||
|
||||
public void add(ConstantPoolEntry entry){
|
||||
entries.add(entry);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return new byte[]{};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class ClassEntry extends ConstantPoolEntry {
|
||||
private final Utf8Entry name;
|
||||
|
||||
public ClassEntry(Utf8Entry name) {
|
||||
super(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getNameIndex() {
|
||||
return name.getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassEntry{" +
|
||||
"nameIndex=" + getNameIndex() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class ConstantPoolEntry {
|
||||
protected final Set<ConstantPoolEntry> children;
|
||||
private int index;
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public Set<ConstantPoolEntry> getChildren() {
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class DoubleEntry extends LeafEntry {
|
||||
private final double doubleVal;
|
||||
|
||||
public DoubleEntry(double doubleVal) {
|
||||
this.doubleVal = doubleVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class FieldRefEntry extends ConstantPoolEntry {
|
||||
private final ClassEntry classEntry;
|
||||
private final NameAndTypeEntry nameAndTypeEntry;
|
||||
|
||||
public FieldRefEntry(ClassEntry classEntry, NameAndTypeEntry nameAndTypeEntry) {
|
||||
super(classEntry, nameAndTypeEntry);
|
||||
this.classEntry = classEntry;
|
||||
this.nameAndTypeEntry = nameAndTypeEntry;
|
||||
}
|
||||
|
||||
public int getClassIndex() {
|
||||
return classEntry.getIndex();
|
||||
}
|
||||
|
||||
public int getNameAndTypeIndex() {
|
||||
return nameAndTypeEntry.getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FieldRefEntry{" +
|
||||
"classIndex=" + getClassIndex() +
|
||||
", nameAndTypeIndex=" + getNameAndTypeIndex() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class FloatEntry extends LeafEntry {
|
||||
private final float floatVal;
|
||||
|
||||
public FloatEntry(float floatVal) {
|
||||
this.floatVal = floatVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FloatEntry{" +
|
||||
"floatVal=" + floatVal +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class IntEntry extends LeafEntry {
|
||||
private final int intVal;
|
||||
|
||||
public IntEntry(int integer) {
|
||||
this.intVal = integer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntEntry{" +
|
||||
"intVal=" + intVal +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class InterfaceMethodRefEntry extends ConstantPoolEntry {
|
||||
private final ClassEntry classEntry;
|
||||
private final NameAndTypeEntry nameAndTypeEntry;
|
||||
|
||||
public InterfaceMethodRefEntry(ClassEntry classEntry, NameAndTypeEntry nameAndTypeEntry) {
|
||||
super(classEntry,nameAndTypeEntry);
|
||||
this.classEntry = classEntry;
|
||||
this.nameAndTypeEntry = nameAndTypeEntry;
|
||||
}
|
||||
|
||||
public int getClassIndex(){
|
||||
return classEntry.getIndex();
|
||||
}
|
||||
|
||||
public int getNameAndTypeIndex(){
|
||||
return nameAndTypeEntry.getIndex();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
//package nl.sander.beejava.constantpool.entry;
|
||||
//
|
||||
//public class InvokeDynamicEntry extends ConstantPoolEntry {
|
||||
// private final int bootstrapMethodAttrIndex; //??
|
||||
// private final NameAndTypeEntry nameAndTypeEntry;
|
||||
//
|
||||
//
|
||||
//
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return "InvokeDynamicEntry{" +
|
||||
// "bootstrapMethodAttrIndex=" + bootstrapMethodAttrIndex +
|
||||
// ", nameAndTypeIndex=" + nameAndTypeIndex +
|
||||
// '}';
|
||||
// }
|
||||
//}
|
||||
//TODO implement later
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class LeafEntry extends ConstantPoolEntry {
|
||||
@Override
|
||||
public Set<ConstantPoolEntry> getChildren() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class LongEntry extends LeafEntry {
|
||||
|
||||
private final long longVal;
|
||||
|
||||
public LongEntry(long longVal) {
|
||||
this.longVal = longVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LongEntry{" +
|
||||
"longVal=" + longVal +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
//package nl.sander.beejava.constantpool.entry;
|
||||
//
|
||||
//public class MethodHandleEntry extends ConstantPoolEntry {
|
||||
// private final int referenceKind;
|
||||
// private final int referenceIndex;
|
||||
//
|
||||
// public MethodHandleEntry(int referenceKind, int referenceIndex) {
|
||||
// this.referenceKind = referenceKind;
|
||||
// this.referenceIndex = referenceIndex;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return "MethodHandleEntry{" +
|
||||
// "referenceKind=" + referenceKind +
|
||||
// ", referenceIndex=" + referenceIndex +
|
||||
// '}';
|
||||
// }
|
||||
//}
|
||||
|
||||
//TODO implement later
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class MethodRefEntry extends ConstantPoolEntry {
|
||||
private final ClassEntry classEntry;
|
||||
private final NameAndTypeEntry nameAndTypeEntry;
|
||||
|
||||
public MethodRefEntry(ClassEntry classEntry, NameAndTypeEntry nameAndTypeEntry) {
|
||||
super(classEntry,nameAndTypeEntry);
|
||||
this.classEntry = classEntry;
|
||||
this.nameAndTypeEntry = nameAndTypeEntry;
|
||||
}
|
||||
|
||||
public int getClassIndex() {
|
||||
return classEntry.getIndex();
|
||||
}
|
||||
|
||||
public int getNameAndTypeIndex() {
|
||||
return nameAndTypeEntry.getIndex();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//package nl.sander.beejava.constantpool.entry;
|
||||
//
|
||||
//public class MethodTypeEntry extends ConstantPoolEntry {
|
||||
// private final int descriptorIndex;
|
||||
//
|
||||
// public MethodTypeEntry(int descriptorIndex) {
|
||||
// this.descriptorIndex = descriptorIndex;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String toString() {
|
||||
// return "MethodTypeEntry{" +
|
||||
// "descriptorIndex=" + descriptorIndex +
|
||||
// '}';
|
||||
// }
|
||||
//}
|
||||
|
||||
//TODO implement when I know that this is
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class ModuleEntry extends ConstantPoolEntry {
|
||||
|
||||
private final Utf8Entry nameEntry;
|
||||
|
||||
public ModuleEntry(Utf8Entry nameEntry) {
|
||||
super(nameEntry);
|
||||
this.nameEntry = nameEntry;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class NameAndTypeEntry extends ConstantPoolEntry {
|
||||
private final Utf8Entry name;
|
||||
private final Utf8Entry type;
|
||||
|
||||
public NameAndTypeEntry(Utf8Entry name, Utf8Entry type) {
|
||||
super(name,type);
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public int getNameIndex() {
|
||||
return name.getIndex();
|
||||
}
|
||||
|
||||
public int getTypeIndex() {
|
||||
return type.getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NameAndTypeEntry{" +
|
||||
"nameIndex=" + getNameIndex() +
|
||||
", typeIndex=" + getTypeIndex() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class PackageEntry extends ConstantPoolEntry {
|
||||
private final Utf8Entry name;
|
||||
|
||||
public PackageEntry(Utf8Entry name) {
|
||||
super(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getNameIndex() {
|
||||
return name.getIndex();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class StringEntry extends ConstantPoolEntry {
|
||||
private final Utf8Entry utf8;
|
||||
|
||||
public StringEntry(Utf8Entry utf8) {
|
||||
this.utf8 = utf8;
|
||||
}
|
||||
|
||||
public int getUtf8Index() {
|
||||
return utf8.getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StringEntry{" +
|
||||
"utf8Index=" + getUtf8Index() +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package nl.sander.beejava.constantpool.entry;
|
||||
|
||||
public class Utf8Entry extends LeafEntry {
|
||||
private final String stringVal;
|
||||
|
||||
public Utf8Entry(String utf8) {
|
||||
this.stringVal = utf8;
|
||||
}
|
||||
|
||||
public String getUtf8() {
|
||||
return stringVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Utf8Entry{" +
|
||||
"stringVal='" + stringVal + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
12
src/main/java/nl/sander/beejava/flags/AccessFlag.java
Normal file
12
src/main/java/nl/sander/beejava/flags/AccessFlag.java
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package nl.sander.beejava.flags;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface AccessFlag {
|
||||
|
||||
int getBytecode();
|
||||
|
||||
default int getCombineBytecode(Set<AccessFlag> accessflags) {
|
||||
return accessflags.stream().mapToInt(AccessFlag::getBytecode).sum();
|
||||
}
|
||||
}
|
||||
26
src/main/java/nl/sander/beejava/flags/ClassAccessFlag.java
Normal file
26
src/main/java/nl/sander/beejava/flags/ClassAccessFlag.java
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
package nl.sander.beejava.flags;
|
||||
|
||||
import nl.sander.beejava.flags.AccessFlag;
|
||||
|
||||
public enum ClassAccessFlag implements AccessFlag {
|
||||
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
||||
FINAL(0x0010), // Declared final; no subclasses allowed.
|
||||
SUPER(0x0020), // Treat superclass methods specially when invoked by the invokespecial instruction.
|
||||
INTERFACE(0x0200), // Is an interface, not a class.
|
||||
ABSTRACT(0x0400), // Declared abstract; must not be instantiated.
|
||||
SYNTHETIC(0x1000), // Declared synthetic; not present in the source code.
|
||||
ANNOTATION(0x2000), // Declared as an annotation type.
|
||||
ENUM(0x4000), // Declared as an enum type.
|
||||
MODULE(0x8000); // Is a module, not a class or interface.
|
||||
|
||||
private final int bytecode;
|
||||
|
||||
ClassAccessFlag(int bytecode) {
|
||||
this.bytecode=bytecode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytecode() {
|
||||
return bytecode;
|
||||
}
|
||||
}
|
||||
25
src/main/java/nl/sander/beejava/flags/FieldAccessFlag.java
Normal file
25
src/main/java/nl/sander/beejava/flags/FieldAccessFlag.java
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package nl.sander.beejava.flags;
|
||||
|
||||
import nl.sander.beejava.flags.AccessFlag;
|
||||
|
||||
public enum FieldAccessFlag implements AccessFlag {
|
||||
PUBLIC(0x0001), // Declared public; may be accessed from outside itspackage.
|
||||
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the samenest (§5.4.4).
|
||||
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
||||
STATIC(0x0008), // Declared static.
|
||||
FINAL(0x0010), // Declared final; never directly assigned to afterobject construction (JLS §17.5).
|
||||
VOLATILE(0x0040), // Declared volatile; cannot be cached.
|
||||
ACC_TRANSIENT(0x0080), // Declared transient; not written or read by apersistent object manager.
|
||||
SYNTHETIC(0x1000), // Declared synthetic; not present in the source code.
|
||||
ENUM(0x4000); //Declared as an element of an enum.
|
||||
|
||||
private final int bytecode;
|
||||
|
||||
FieldAccessFlag(int bytecode) {
|
||||
this.bytecode = bytecode;
|
||||
}
|
||||
|
||||
public int getBytecode() {
|
||||
return bytecode;
|
||||
}
|
||||
}
|
||||
28
src/main/java/nl/sander/beejava/flags/MethodAccessFlag.java
Normal file
28
src/main/java/nl/sander/beejava/flags/MethodAccessFlag.java
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package nl.sander.beejava.flags;
|
||||
|
||||
import nl.sander.beejava.flags.AccessFlag;
|
||||
|
||||
public enum MethodAccessFlag implements AccessFlag {
|
||||
PUBLIC(0x0001), // Declared public; may be accessed from outside its package.
|
||||
PRIVATE(0x0002), // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4).
|
||||
PROTECTED(0x0004), // Declared protected; may be accessed within subclasses.
|
||||
STATIC(0x0008), // Declared static.
|
||||
FINAL(0x0010), // Declared final; must not be overridden (§5.4.5).
|
||||
SYNCHRONIZED(0x0020), // Declared synchronized; invocation is wrapped by a monitor use.
|
||||
BRIDGE(0x0040), // A bridge method, generated by the compiler.
|
||||
VARARGS(0x0080), //Declared with variable number of arguments.
|
||||
NATIVE(0x0100), //Declared native; implemented in a language other than the Java programming language.
|
||||
ABSTRACT(0x0400), // Declared abstract; no implementation is provided.
|
||||
STRICT(0x0800), // Declared strictfp; floating-point mode is FP-strict.
|
||||
SYNTHETIC(0x1000); // Declared synthetic; not present in the source code.
|
||||
|
||||
private final int bytecode;
|
||||
|
||||
MethodAccessFlag(int bytecode) {
|
||||
this.bytecode = bytecode;
|
||||
}
|
||||
|
||||
public int getBytecode() {
|
||||
return bytecode;
|
||||
}
|
||||
}
|
||||
86
src/main/java/nl/sander/beejava/util/ByteBuf.java
Normal file
86
src/main/java/nl/sander/beejava/util/ByteBuf.java
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package nl.sander.beejava.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.*;
|
||||
|
||||
/**
|
||||
* storage like ArrayList, with bytebuffer instead of array
|
||||
*/
|
||||
public class ByteBuf {
|
||||
|
||||
private ByteBuffer data;
|
||||
|
||||
public ByteBuf() {
|
||||
this(64);
|
||||
}
|
||||
|
||||
public ByteBuf(final int initialSize) {
|
||||
data = ByteBuffer.allocate(initialSize);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public String toString(Charset charset) {
|
||||
data.flip();
|
||||
|
||||
CharsetDecoder decoder = charset.newDecoder(); // decode is not threadsafe, might put it in threadlocal
|
||||
// but I don't think this (newDecoder()+config) is expensive
|
||||
|
||||
decoder.onMalformedInput(CodingErrorAction.REPLACE)
|
||||
.onUnmappableCharacter(CodingErrorAction.REPLACE);
|
||||
|
||||
try {
|
||||
return decoder.decode(data).toString();
|
||||
} catch (CharacterCodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
data.clear();
|
||||
}
|
||||
|
||||
public void add(final byte c) {
|
||||
if (data.remaining() == 0) {
|
||||
enlarge(1);
|
||||
}
|
||||
data.put(c);
|
||||
}
|
||||
|
||||
public void add(final byte[] bytes) {
|
||||
if (data.remaining() < bytes.length) {
|
||||
enlarge(bytes.length);
|
||||
}
|
||||
data.put(bytes);
|
||||
}
|
||||
|
||||
public void add(final int... ints) {
|
||||
if (data.remaining() < ints.length) {
|
||||
enlarge(ints.length);
|
||||
}
|
||||
byte[] bytes = new byte[ints.length];
|
||||
for (int i = 0; i < ints.length; i++) {
|
||||
bytes[i] = (byte) (i & 0xFF);
|
||||
}
|
||||
add(bytes);
|
||||
}
|
||||
|
||||
private void enlarge(final int size) {
|
||||
final int length1 = 2 * data.limit();
|
||||
final int length2 = data.limit() + size;
|
||||
ByteBuffer newData = ByteBuffer.allocate(Math.max(length1, length2));
|
||||
data.flip();
|
||||
newData.put(data);
|
||||
data = newData;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return data.limit() - data.remaining();
|
||||
}
|
||||
|
||||
public byte[] toBytes() {
|
||||
return data.array();
|
||||
}
|
||||
}
|
||||
114
src/test/java/nl/sander/beejava/ConstantTeeTests.java
Normal file
114
src/test/java/nl/sander/beejava/ConstantTeeTests.java
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package nl.sander.beejava;
|
||||
|
||||
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.CodeLine.line;
|
||||
import static nl.sander.beejava.Opcode.*;
|
||||
import static nl.sander.beejava.flags.ClassAccessFlag.PUBLIC;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ConstantTeeTests {
|
||||
@Test
|
||||
public void testMethodRefEntryForSuperConstructor() {
|
||||
BeeClass classWithIntField = createEmptyClass();
|
||||
Set<ConstantPoolEntry> constantTree = new ConstantTreeCreator().createConstantTree(classWithIntField);
|
||||
assertEquals(1, 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 createEmptyClass() {
|
||||
BeeConstructor constructor = BeeConstructor.builder()
|
||||
.withAccessFlags(MethodAccessFlag.PUBLIC)
|
||||
.withCode(
|
||||
line(0, LOAD, Ref.THIS),
|
||||
line(1, INVOKE, Ref.SUPER, "<init>", "()"),
|
||||
line(5, RETURN))
|
||||
.build();
|
||||
|
||||
return BeeClass.builder()
|
||||
.withClassFileVersion(Version.V14)
|
||||
.withPackage("nl.sander.beejava.test")
|
||||
.withAccessFlags(PUBLIC)
|
||||
.withName("EmptyBean")
|
||||
.withSuperClass(Object.class)
|
||||
.withConstructors(constructor)
|
||||
.build();
|
||||
}
|
||||
|
||||
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)
|
||||
.withName("IntBean")
|
||||
.withSuperClass(Object.class)
|
||||
.withFields(intField)
|
||||
.withConstructors(constructor)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
10
src/test/java/nl/sander/beejava/testclasses/IntBean.java
Normal file
10
src/test/java/nl/sander/beejava/testclasses/IntBean.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package nl.sander.beejava.testclasses;
|
||||
|
||||
public class IntBean {
|
||||
// private int intField;
|
||||
|
||||
// public IntBean(int intField) {
|
||||
// this.intField = intField;
|
||||
// }
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue