
mockit.external.asm.BootstrapMethods Maven / Gradle / Ivy
Go to download
JMockit is a Java toolkit for automated developer testing.
It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external
APIs; JUnit (4 & 5) and TestNG test runners are supported.
It also contains an advanced code coverage tool.
package mockit.external.asm;
/**
* Generates the "BootstrapMethods" attribute in a class file being written by a {@link ClassWriter}.
*/
final class BootstrapMethods
{
private final ConstantPoolGeneration constantPool;
/**
* The number of entries in the BootstrapMethods attribute.
*/
private int bootstrapMethodsCount;
/**
* The BootstrapMethods attribute.
*/
private ByteVector bootstrapMethods;
BootstrapMethods(ConstantPoolGeneration constantPool) { this.constantPool = constantPool; }
Item addInvokeDynamicReference(String name, String desc, Handle bsm, Object... bsmArgs) {
ByteVector methods = bootstrapMethods;
if (methods == null) {
methods = bootstrapMethods = new ByteVector();
}
int position = methods.length; // record current position
int hashCode = bsm.hashCode();
Item handleItem = constantPool.newHandleItem(bsm);
methods.putShort(handleItem.index);
int argsLength = bsmArgs.length;
methods.putShort(argsLength);
hashCode = putBSMArgs(hashCode, bsmArgs);
byte[] data = methods.data;
int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
hashCode &= 0x7FFFFFFF;
Item bsmItem = getBSMItem(position, hashCode, data, length);
int bsmIndex;
if (bsmItem != null) {
bsmIndex = bsmItem.index;
methods.length = position; // revert to old position
}
else {
bsmIndex = bootstrapMethodsCount++;
bsmItem = new Item(bsmIndex);
bsmItem.set(position, hashCode);
constantPool.put(bsmItem);
}
// Now, create the InvokeDynamic constant.
Item result = constantPool.createInvokeDynamicConstant(name, desc, bsmIndex);
return result;
}
private int putBSMArgs(int hashCode, Object[] bsmArgs) {
ByteVector methods = bootstrapMethods;
for (int i = 0; i < bsmArgs.length; i++) {
Object bsmArg = bsmArgs[i];
hashCode ^= bsmArg.hashCode();
Item constItem = constantPool.newConstItem(bsmArg);
methods.putShort(constItem.index);
}
return hashCode;
}
private Item getBSMItem(int position, int hashCode, byte[] data, int length) {
Item bsmItem = constantPool.getItem(hashCode);
loop:
while (bsmItem != null) {
if (bsmItem.type != ConstantPoolItemType.BSM || bsmItem.hashCode != hashCode) {
bsmItem = bsmItem.next;
continue;
}
// Because the data encode the size of the argument we don't need to test if these size are equals.
int resultPosition = bsmItem.intVal;
for (int p = 0; p < length; p++) {
if (data[position + p] != data[resultPosition + p]) {
bsmItem = bsmItem.next;
continue loop;
}
}
break;
}
return bsmItem;
}
boolean hasMethods() { return bootstrapMethods != null; }
int getSize() {
constantPool.newUTF8("BootstrapMethods");
return 8 + bootstrapMethods.length;
}
void put(ByteVector out) {
if (hasMethods()) {
out.putShort(constantPool.newUTF8("BootstrapMethods"));
out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount);
out.putByteVector(bootstrapMethods);
}
}
/**
* Copies the bootstrap method data from the given {@link ClassReader}.
*/
void copyBootstrapMethods(ClassReader cr, Item[] items, char[] c) {
// Finds the "BootstrapMethods" attribute.
int u = cr.getAttributesStartIndex();
boolean found = false;
for (int i = cr.readUnsignedShort(u); i > 0; i--) {
String attrName = cr.readUTF8(u + 2, c);
if ("BootstrapMethods".equals(attrName)) {
found = true;
break;
}
u += 6 + cr.readInt(u + 4);
}
if (!found) {
return;
}
// Copies the bootstrap methods in the class writer.
bootstrapMethodsCount = cr.readUnsignedShort(u + 8);
for (int j = 0, v = u + 10; j < bootstrapMethodsCount; j++) {
int position = v - u - 10;
int hashCode = cr.readConst(cr.readUnsignedShort(v), c).hashCode();
for (int k = cr.readUnsignedShort(v + 2); k > 0; k--) {
hashCode ^= cr.readConst(cr.readUnsignedShort(v + 4), c).hashCode();
v += 2;
}
v += 4;
Item item = new Item(j);
item.set(position, hashCode & 0x7FFFFFFF);
int index = item.hashCode % items.length;
item.next = items[index];
items[index] = item;
}
int attrSize = cr.readInt(u + 4);
bootstrapMethods = new ByteVector(attrSize + 62);
bootstrapMethods.putByteArray(cr.b, u + 10, attrSize - 2);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy