diff --git a/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java b/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java index 3ac6e0a..2d37b1a 100644 --- a/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java +++ b/src/main/java/nl/sander/beejava/constantpool/ConstantPool.java @@ -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 entries=new ArrayList<>(); + private final List entries = new ArrayList<>(); - public int getIndex(NodeConstant entry){ - for (int i=0; i bytes.add(entry.getBytes())); + return bytes.toBytes(); } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantClass.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantClass.java index 528a521..9861f69 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantClass.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantClass.java @@ -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())}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDouble.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDouble.java index 100eac7..7e64468 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDouble.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDouble.java @@ -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)}; } + } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDynamic.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDynamic.java index 85093d2..c2f4286 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDynamic.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantDynamic.java @@ -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(); } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFieldRef.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFieldRef.java index c93e5e1..7ec925b 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFieldRef.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFieldRef.java @@ -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}; } + } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFloat.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFloat.java index 44483b5..2256513 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFloat.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantFloat.java @@ -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)}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInteger.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInteger.java index 201af2b..a3452c1 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInteger.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInteger.java @@ -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)}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInterfaceMethodRef.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInterfaceMethodRef.java index 9cd3c0d..9800a44 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInterfaceMethodRef.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInterfaceMethodRef.java @@ -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}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInvokeDynamic.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInvokeDynamic.java index 187599a..788a049 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInvokeDynamic.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantInvokeDynamic.java @@ -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 \ No newline at end of file diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantLong.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantLong.java index c951987..b5ce2dd 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantLong.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantLong.java @@ -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)}; } + + } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodHandle.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodHandle.java index 74f5c3c..e0b70e5 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodHandle.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodHandle.java @@ -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}; } } \ No newline at end of file diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodRef.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodRef.java index 9181c00..01fedca 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodRef.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodRef.java @@ -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}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodType.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodType.java index 57efdb6..d35caaa 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodType.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantMethodType.java @@ -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}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantModule.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantModule.java index 1dfdb93..385d551 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantModule.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantModule.java @@ -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())}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantNameAndType.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantNameAndType.java index 3b083b7..7153f93 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantNameAndType.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantNameAndType.java @@ -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())}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPackage.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPackage.java index fd7150f..2c2426f 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPackage.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantPackage.java @@ -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())}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantString.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantString.java index d38fc6d..7f9831b 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantString.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantString.java @@ -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())}; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantUtf8.java b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantUtf8.java index 4c5a948..f343386 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/ConstantUtf8.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/ConstantUtf8.java @@ -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; } } diff --git a/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java b/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java index 23c39e8..a5d6a75 100644 --- a/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java +++ b/src/main/java/nl/sander/beejava/constantpool/entry/NodeConstant.java @@ -6,7 +6,7 @@ import java.util.Set; public abstract class NodeConstant { protected final Set 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. 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. } - /* - * 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); + } } diff --git a/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java b/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java index c917317..6a54a48 100644 --- a/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java +++ b/src/test/java/nl/sander/beejava/constantpool/entry/TagCorrectnessTest.java @@ -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