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;
import nl.sander.beejava.constantpool.entry.NodeConstant;
import nl.sander.beejava.util.ByteBuf;
import java.util.ArrayList;
import java.util.List;
public class ConstantPool {
private final List<NodeConstant> entries=new ArrayList<>();
private final List<NodeConstant> entries = new ArrayList<>();
public int getIndex(NodeConstant entry){
for (int i=0; i<entries.size(); i++){
if (entries.get(i)==entry){
return i+1;
public int getIndex(NodeConstant entry) {
for (int i = 0; i < entries.size(); i++) {
if (entries.get(i) == entry) {
return i + 1;
}
}
return -1;
}
public void add(NodeConstant entry){
public void add(NodeConstant entry) {
entries.add(entry);
}
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;
public class ConstantClass extends NodeConstant {
private static final byte TAG = 7;
private final ConstantUtf8 name;
public ConstantClass(ConstantUtf8 name) {
@ -20,7 +21,7 @@ public class ConstantClass extends NodeConstant {
}
@Override
public int getTag() {
return 7;
public byte[] getBytes() {
return new byte[]{TAG, upperFraction(getNameIndex()), lowerFraction(getNameIndex())};
}
}

View file

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

View file

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

View file

@ -1,6 +1,8 @@
package nl.sander.beejava.constantpool.entry;
public class ConstantFloat extends LeafConstant {
private static final byte TAG = 4;
private final float floatVal;
public ConstantFloat(float floatVal) {
@ -15,7 +17,8 @@ public class ConstantFloat extends LeafConstant {
}
@Override
public int getTag() {
return 4;
public byte[] getBytes() {
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;
public class ConstantInteger extends LeafConstant {
private static final byte TAG = 3;
private final int intVal;
public ConstantInteger(int integer) {
@ -15,7 +17,7 @@ public class ConstantInteger extends LeafConstant {
}
@Override
public int getTag() {
return 3;
public byte[] getBytes() {
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;
public class ConstantInterfaceMethodRef extends NodeConstant {
private static final byte TAG = 11;
private final ConstantClass constantClass;
private final ConstantNameAndType constantNameAndType;
@ -10,16 +12,17 @@ public class ConstantInterfaceMethodRef extends NodeConstant {
this.constantNameAndType = constantNameAndType;
}
public int getClassIndex(){
public int getClassIndex() {
return constantClass.getIndex();
}
public int getNameAndTypeIndex(){
public int getNameAndTypeIndex() {
return constantNameAndType.getIndex();
}
@Override
public int getTag() {
return 11;
public byte[] getBytes() {
return new byte[]{TAG};
}
}

View file

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

View file

@ -2,6 +2,7 @@ package nl.sander.beejava.constantpool.entry;
public class ConstantLong extends LeafConstant {
private static final byte TAG = 5;
private final long longVal;
public ConstantLong(long longVal) {
@ -16,7 +17,10 @@ public class ConstantLong extends LeafConstant {
}
@Override
public int getTag() {
return 5;
public byte[] getBytes() {
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
public class ConstantMethodHandle extends NodeConstant {
private static final byte TAG = 15;
private final int referenceKind;
// only 1 of these can be present:
@ -25,8 +27,7 @@ public class ConstantMethodHandle extends NodeConstant {
return 0; //TODO implement
}
@Override
public int getTag() {
return 15;
public byte[] getBytes() {
return new byte[]{TAG};
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,9 @@
package nl.sander.beejava.constantpool.entry;
import java.nio.charset.StandardCharsets;
public class ConstantUtf8 extends LeafConstant {
private static final byte TAG = 1;
private final String value;
public ConstantUtf8(String utf8) {
@ -18,8 +21,13 @@ public class ConstantUtf8 extends LeafConstant {
'}';
}
@Override
public int getTag() {
return 1;
public byte[] getBytes() {
byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
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

@ -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.
}
/*
* The tag that indicates the entry type in the bytecode.
* §4.4 Table 4.4-A. Constant pool tags
/**
* return the bytes that end up in the class file.
*/
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() {
return index;
@ -32,4 +41,27 @@ public abstract class NodeConstant {
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 {
@Test
public void testSpec() {
assertEquals(7, classEntry().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(1, utf8().getTag());
assertEquals(3, new ConstantInteger(0).getTag());
assertEquals(4, new ConstantFloat(0).getTag());
assertEquals(5, new ConstantLong(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(1, utf8().getTag());
assertEquals(15, new ConstantMethodHandle(0).getTag()); //TODO
assertEquals(16, new ConstantMethodType(utf8()).getTag()); //TODO
assertEquals(17, new ConstantDynamic(0, nameAndType()).getTag()); //TODO