implemented some basic getBytes methods to create bytecode for constantpool

This commit is contained in:
Sander Hautvast 2020-11-09 12:40:34 +01:00
parent 7968d27814
commit c6db240f47
20 changed files with 147 additions and 71 deletions

View file

@ -1,27 +1,30 @@
package nl.sander.beejava.constantpool; package nl.sander.beejava.constantpool;
import nl.sander.beejava.constantpool.entry.NodeConstant; import nl.sander.beejava.constantpool.entry.NodeConstant;
import nl.sander.beejava.util.ByteBuf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class ConstantPool { public class ConstantPool {
private final List<NodeConstant> entries=new ArrayList<>(); private final List<NodeConstant> entries = new ArrayList<>();
public int getIndex(NodeConstant entry){ public int getIndex(NodeConstant entry) {
for (int i=0; i<entries.size(); i++){ for (int i = 0; i < entries.size(); i++) {
if (entries.get(i)==entry){ if (entries.get(i) == entry) {
return i+1; return i + 1;
} }
} }
return -1; return -1;
} }
public void add(NodeConstant entry){ public void add(NodeConstant entry) {
entries.add(entry); entries.add(entry);
} }
public byte[] getBytes() { public byte[] getBytes() {
return new byte[]{}; ByteBuf bytes = new ByteBuf();
entries.forEach(entry -> bytes.add(entry.getBytes()));
return bytes.toBytes();
} }
} }

View file

@ -1,6 +1,7 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantClass extends NodeConstant { public class ConstantClass extends NodeConstant {
private static final byte TAG = 7;
private final ConstantUtf8 name; private final ConstantUtf8 name;
public ConstantClass(ConstantUtf8 name) { public ConstantClass(ConstantUtf8 name) {
@ -20,7 +21,7 @@ public class ConstantClass extends NodeConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 7; return new byte[]{TAG, upperFraction(getNameIndex()), lowerFraction(getNameIndex())};
} }
} }

View file

@ -1,6 +1,7 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantDouble extends LeafConstant { public class ConstantDouble extends LeafConstant {
private static final byte TAG = 6;
private final double doubleVal; private final double doubleVal;
public ConstantDouble(double doubleVal) { public ConstantDouble(double doubleVal) {
@ -8,7 +9,10 @@ public class ConstantDouble extends LeafConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 6; long bits = Double.doubleToRawLongBits(doubleVal);
return new byte[]{TAG, rshift(bits, 56), rshift(bits, 48), rshift(bits, 40), rshift(bits, 32),
rshift(bits, 24), rshift(bits, 16), rshift(bits, 8), (byte) (bits & 0xFF)};
} }
} }

View file

@ -1,6 +1,7 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantDynamic extends NodeConstant { public class ConstantDynamic extends NodeConstant {
private static final byte TAG = 17;
private final int bootstrapMethodIndex; // TODO private final int bootstrapMethodIndex; // TODO
private final ConstantNameAndType nameAndType; private final ConstantNameAndType nameAndType;
@ -10,11 +11,11 @@ public class ConstantDynamic extends NodeConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 17; return new byte[]{TAG};
} }
public int getNameAndTypeIndex(){ public int getNameAndTypeIndex() {
return nameAndType.getIndex(); return nameAndType.getIndex();
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantFieldRef extends NodeConstant { public class ConstantFieldRef extends NodeConstant {
private static final byte TAG = 9;
private final ConstantClass constantClass; private final ConstantClass constantClass;
private final ConstantNameAndType constantNameAndType; private final ConstantNameAndType constantNameAndType;
@ -27,7 +29,8 @@ public class ConstantFieldRef extends NodeConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 9; return new byte[]{TAG};
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantFloat extends LeafConstant { public class ConstantFloat extends LeafConstant {
private static final byte TAG = 4;
private final float floatVal; private final float floatVal;
public ConstantFloat(float floatVal) { public ConstantFloat(float floatVal) {
@ -15,7 +17,8 @@ public class ConstantFloat extends LeafConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 4; long bits = Float.floatToRawIntBits(floatVal);
return new byte[]{TAG, (byte) (bits >>> 24), (byte) (bits >>> 16), (byte) (bits >>> 8), (byte) (bits & 0xFF)};
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantInteger extends LeafConstant { public class ConstantInteger extends LeafConstant {
private static final byte TAG = 3;
private final int intVal; private final int intVal;
public ConstantInteger(int integer) { public ConstantInteger(int integer) {
@ -15,7 +17,7 @@ public class ConstantInteger extends LeafConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 3; return new byte[]{TAG, (byte) (intVal >>> 24), (byte) (intVal >>> 16), (byte) (intVal >>> 8), (byte) (intVal & 0xFF)};
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantInterfaceMethodRef extends NodeConstant { public class ConstantInterfaceMethodRef extends NodeConstant {
private static final byte TAG = 11;
private final ConstantClass constantClass; private final ConstantClass constantClass;
private final ConstantNameAndType constantNameAndType; private final ConstantNameAndType constantNameAndType;
@ -10,16 +12,17 @@ public class ConstantInterfaceMethodRef extends NodeConstant {
this.constantNameAndType = constantNameAndType; this.constantNameAndType = constantNameAndType;
} }
public int getClassIndex(){ public int getClassIndex() {
return constantClass.getIndex(); return constantClass.getIndex();
} }
public int getNameAndTypeIndex(){ public int getNameAndTypeIndex() {
return constantNameAndType.getIndex(); return constantNameAndType.getIndex();
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 11; return new byte[]{TAG};
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantInvokeDynamic extends NodeConstant { public class ConstantInvokeDynamic extends NodeConstant {
private static final byte TAG = 18;
private final int bootstrapMethodAttrIndex; //?? private final int bootstrapMethodAttrIndex; //??
private final ConstantNameAndType constantNameAndType; private final ConstantNameAndType constantNameAndType;
@ -18,9 +20,9 @@ public class ConstantInvokeDynamic extends NodeConstant {
'}'; '}';
} }
@Override
public int getTag() { public byte[] getBytes() {
return 18; return new byte[]{TAG};
} }
} }
//TODO implement later //TODO implement later

View file

@ -2,6 +2,7 @@ package nl.sander.beejava.constantpool.entry;
public class ConstantLong extends LeafConstant { public class ConstantLong extends LeafConstant {
private static final byte TAG = 5;
private final long longVal; private final long longVal;
public ConstantLong(long longVal) { public ConstantLong(long longVal) {
@ -16,7 +17,10 @@ public class ConstantLong extends LeafConstant {
} }
@Override @Override
public int getTag() { public byte[] getBytes() {
return 5; return new byte[]{TAG, rshift(longVal, 56), rshift(longVal, 48), rshift(longVal, 40), rshift(longVal, 32),
rshift(longVal, 24), rshift(longVal, 16), rshift(longVal, 8), (byte) (longVal & 0xFF)};
} }
} }

View file

@ -2,6 +2,8 @@ package nl.sander.beejava.constantpool.entry;
//TODO implement later //TODO implement later
public class ConstantMethodHandle extends NodeConstant { public class ConstantMethodHandle extends NodeConstant {
private static final byte TAG = 15;
private final int referenceKind; private final int referenceKind;
// only 1 of these can be present: // only 1 of these can be present:
@ -25,8 +27,7 @@ public class ConstantMethodHandle extends NodeConstant {
return 0; //TODO implement return 0; //TODO implement
} }
@Override public byte[] getBytes() {
public int getTag() { return new byte[]{TAG};
return 15;
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantMethodRef extends NodeConstant { public class ConstantMethodRef extends NodeConstant {
private static final byte TAG = 10;
private final ConstantClass constantClass; private final ConstantClass constantClass;
private final ConstantNameAndType constantNameAndType; private final ConstantNameAndType constantNameAndType;
@ -18,8 +20,8 @@ public class ConstantMethodRef extends NodeConstant {
return constantNameAndType.getIndex(); return constantNameAndType.getIndex();
} }
@Override
public int getTag() { public byte[] getBytes() {
return 10; return new byte[]{TAG};
} }
} }

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantMethodType extends NodeConstant { public class ConstantMethodType extends NodeConstant {
private static final byte TAG = 16;
private final ConstantUtf8 methodDescriptor; private final ConstantUtf8 methodDescriptor;
public ConstantMethodType(ConstantUtf8 methodDescriptor) { public ConstantMethodType(ConstantUtf8 methodDescriptor) {
@ -14,8 +16,8 @@ public class ConstantMethodType extends NodeConstant {
'}'; '}';
} }
@Override
public int getTag() { public byte[] getBytes() {
return 16; return new byte[]{TAG};
} }
} }

View file

@ -2,6 +2,8 @@ package nl.sander.beejava.constantpool.entry;
public class ConstantModule extends NodeConstant { public class ConstantModule extends NodeConstant {
private static final byte TAG = 19;
private final ConstantUtf8 nameEntry; private final ConstantUtf8 nameEntry;
public ConstantModule(ConstantUtf8 nameEntry) { public ConstantModule(ConstantUtf8 nameEntry) {
@ -9,8 +11,11 @@ public class ConstantModule extends NodeConstant {
this.nameEntry = nameEntry; this.nameEntry = nameEntry;
} }
@Override public int getNameIndex() {
public int getTag() { return nameEntry.getIndex();
return 19; }
public byte[] getBytes() {
return new byte[]{TAG, upperFraction(getNameIndex()), lowerFraction(getNameIndex())};
} }
} }

View file

@ -1,13 +1,14 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantNameAndType extends NodeConstant { public class ConstantNameAndType extends NodeConstant {
private static final byte TAG = 12;
private final ConstantUtf8 name; private final ConstantUtf8 name;
private final ConstantUtf8 type; private final ConstantUtf8 descriptor;
public ConstantNameAndType(ConstantUtf8 name, ConstantUtf8 type) { public ConstantNameAndType(ConstantUtf8 name, ConstantUtf8 descriptor) {
super(name,type); super(name, descriptor);
this.name = name; this.name = name;
this.type = type; this.descriptor = descriptor;
} }
@ -15,20 +16,19 @@ public class ConstantNameAndType extends NodeConstant {
return name.getIndex(); return name.getIndex();
} }
public int getTypeIndex() { public int getDescriptorIndex() {
return type.getIndex(); return descriptor.getIndex();
} }
@Override @Override
public String toString() { public String toString() {
return "NameAndTypeEntry{" + return "NameAndTypeEntry{" +
"nameIndex=" + getNameIndex() + "nameIndex=" + getNameIndex() +
", typeIndex=" + getTypeIndex() + ", typeIndex=" + getDescriptorIndex() +
'}'; '}';
} }
@Override public byte[] getBytes() {
public int getTag() { return new byte[]{TAG, upperFraction(getNameIndex()), lowerFraction(getNameIndex()), upperFraction(getDescriptorIndex()), lowerFraction(getDescriptorIndex())};
return 12;
} }
} }

View file

@ -1,6 +1,7 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantPackage extends NodeConstant { public class ConstantPackage extends NodeConstant {
private static final byte TAG = 20;
private final ConstantUtf8 name; private final ConstantUtf8 name;
public ConstantPackage(ConstantUtf8 name) { public ConstantPackage(ConstantUtf8 name) {
@ -12,8 +13,7 @@ public class ConstantPackage extends NodeConstant {
return name.getIndex(); return name.getIndex();
} }
@Override public byte[] getBytes() {
public int getTag() { return new byte[]{TAG, upperFraction(getNameIndex()), lowerFraction(getNameIndex())};
return 20;
} }
} }

View file

@ -1,6 +1,7 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
public class ConstantString extends NodeConstant { public class ConstantString extends NodeConstant {
private static final byte TAG = 8;
private final ConstantUtf8 utf8; private final ConstantUtf8 utf8;
public ConstantString(ConstantUtf8 utf8) { public ConstantString(ConstantUtf8 utf8) {
@ -18,8 +19,7 @@ public class ConstantString extends NodeConstant {
'}'; '}';
} }
@Override public byte[] getBytes() {
public int getTag() { return new byte[]{TAG, upperFraction(getUtf8Index()), lowerFraction(getUtf8Index())};
return 8;
} }
} }

View file

@ -1,6 +1,9 @@
package nl.sander.beejava.constantpool.entry; package nl.sander.beejava.constantpool.entry;
import java.nio.charset.StandardCharsets;
public class ConstantUtf8 extends LeafConstant { public class ConstantUtf8 extends LeafConstant {
private static final byte TAG = 1;
private final String value; private final String value;
public ConstantUtf8(String utf8) { public ConstantUtf8(String utf8) {
@ -18,8 +21,13 @@ public class ConstantUtf8 extends LeafConstant {
'}'; '}';
} }
@Override public byte[] getBytes() {
public int getTag() { byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
return 1; byte[] bytes = new byte[utf8Bytes.length + 3];
bytes[0] = TAG;
bytes[1] = upperFraction(bytes.length);
bytes[2] = lowerFraction(bytes.length);
System.arraycopy(utf8Bytes, 0, bytes, 3, utf8Bytes.length);
return bytes;
} }
} }

View file

@ -6,7 +6,7 @@ import java.util.Set;
public abstract class NodeConstant { public abstract class NodeConstant {
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<NodeConstant> 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 NodeConstant(NodeConstant... children) {
@ -14,11 +14,20 @@ public abstract class NodeConstant {
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.
} }
/* /**
* The tag that indicates the entry type in the bytecode. * return the bytes that end up in the class file.
* §4.4 Table 4.4-A. Constant pool tags
*/ */
public abstract int getTag(); public abstract byte[] getBytes();
/**
* Convenience for test. The TAG is always the first byte of the getBytes array
* see §4.4 Table 4.4-A. Constant pool tags
*
* @return a byte indicating the type of the constant
*/
byte getTag(){
return getBytes()[0];
}
public int getIndex() { public int getIndex() {
return index; return index;
@ -32,4 +41,27 @@ public abstract class NodeConstant {
return children; return children;
} }
/**
* returns lower 8 bits as byte
*
* @param u16 is assumed to be 16 bits unsigned integer
* @return lower 8 bits as byte
*/
protected byte lowerFraction(int u16) {
return (byte) (u16 & 0xFF);
}
/**
* returns upper 8 bits as byte
*
* @param u16 is assumed to be 16 bits unsigned integer
* @return upper 8 bits as byte
*/
protected byte upperFraction(int u16) {
return (byte) (u16 << 8);
}
protected byte rshift(long bits, int positions) {
return (byte) (bits >>> positions);
}
} }

View file

@ -10,17 +10,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
public class TagCorrectnessTest { public class TagCorrectnessTest {
@Test @Test
public void testSpec() { public void testSpec() {
assertEquals(7, classEntry().getTag()); assertEquals(1, utf8().getTag());
assertEquals(9, fieldRef().getTag());
assertEquals(10, new ConstantMethodRef(classEntry(), nameAndType()).getTag());
assertEquals(11, new ConstantInterfaceMethodRef(classEntry(), nameAndType()).getTag());
assertEquals(8, new ConstantString(utf8()).getTag());
assertEquals(3, new ConstantInteger(0).getTag()); assertEquals(3, new ConstantInteger(0).getTag());
assertEquals(4, new ConstantFloat(0).getTag()); assertEquals(4, new ConstantFloat(0).getTag());
assertEquals(5, new ConstantLong(0).getTag()); assertEquals(5, new ConstantLong(0).getTag());
assertEquals(6, new ConstantDouble(0).getTag()); assertEquals(6, new ConstantDouble(0).getTag());
assertEquals(7, classEntry().getTag());
assertEquals(8, new ConstantString(utf8()).getTag());
assertEquals(9, fieldRef().getTag());
assertEquals(10, new ConstantMethodRef(classEntry(), nameAndType()).getTag());
assertEquals(11, new ConstantInterfaceMethodRef(classEntry(), nameAndType()).getTag());
assertEquals(12, nameAndType().getTag()); assertEquals(12, nameAndType().getTag());
assertEquals(1, utf8().getTag());
assertEquals(15, new ConstantMethodHandle(0).getTag()); //TODO assertEquals(15, new ConstantMethodHandle(0).getTag()); //TODO
assertEquals(16, new ConstantMethodType(utf8()).getTag()); //TODO assertEquals(16, new ConstantMethodType(utf8()).getTag()); //TODO
assertEquals(17, new ConstantDynamic(0, nameAndType()).getTag()); //TODO assertEquals(17, new ConstantDynamic(0, nameAndType()).getTag()); //TODO