Commit f52a21ff authored by Remi Forax's avatar Remi Forax

Merge branch 'compute-bootstrap-methods-only-if-necessary' into 'master'

Crawl the class attributes to find the bootstrap methods only if necessary

See merge request !200
parents 875e510f 968a4141
Pipeline #2703 passed with stage
in 7 minutes and 28 seconds
......@@ -187,19 +187,22 @@ public class ClassReader {
int currentCpInfoIndex = 1;
int currentCpInfoOffset = classFileOffset + 10;
int currentMaxStringLength = 0;
boolean hasBootstrapMethods = false;
// The offset of the other entries depend on the total size of all the previous entries.
while (currentCpInfoIndex < constantPoolCount) {
cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1;
int cpInfoSize;
switch (classFileBuffer[currentCpInfoOffset]) {
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
case Symbol.CONSTANT_DYNAMIC_TAG:
hasBootstrapMethods = true;
// fallthrough
case Symbol.CONSTANT_FIELDREF_TAG:
case Symbol.CONSTANT_METHODREF_TAG:
case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
case Symbol.CONSTANT_INTEGER_TAG:
case Symbol.CONSTANT_FLOAT_TAG:
case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
case Symbol.CONSTANT_DYNAMIC_TAG:
cpInfoSize = 5;
break;
case Symbol.CONSTANT_LONG_TAG:
......@@ -236,29 +239,8 @@ public class ClassReader {
this.header = currentCpInfoOffset;
// Read the BootstrapMethods attribute, if any (only get the offset of each method).
int currentAttributeOffset = getFirstAttributeOffset();
int[] currentBootstrapMethodOffsets = null;
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, new char[maxStringLength]);
int attributeLength = readInt(currentAttributeOffset + 2);
currentAttributeOffset += 6;
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// Read the num_bootstrap_methods field and create an array of this size.
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
// Compute and store the offset of each 'bootstrap_methods' array field entry.
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
currentBootstrapMethodOffset +=
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
}
}
currentAttributeOffset += attributeLength;
}
this.bootstrapMethodOffsets = currentBootstrapMethodOffsets;
this.bootstrapMethodOffsets =
hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null;
}
/**
......@@ -3222,6 +3204,41 @@ public class ClassReader {
return currentOffset + 2;
}
/**
* Reads the BootstrapMethods attribute to compute the offset of each bootstrap method.
*
* @param maxStringLength a conservative estimate of the maximum length of the strings contained
* in the constant pool of the class.
* @return the offsets of the bootstrap methods or null.
*/
private int[] readBootstrapMethodsAttribute(final int maxStringLength) {
char[] charBuffer = new char[maxStringLength];
int currentAttributeOffset = getFirstAttributeOffset();
int[] currentBootstrapMethodOffsets = null;
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, charBuffer);
int attributeLength = readInt(currentAttributeOffset + 2);
currentAttributeOffset += 6;
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// Read the num_bootstrap_methods field and create an array of this size.
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
// Compute and store the offset of each 'bootstrap_methods' array field entry.
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
currentBootstrapMethodOffset +=
4 + readUnsignedShort(currentBootstrapMethodOffset + 2) * 2;
}
return currentBootstrapMethodOffsets;
}
currentAttributeOffset += attributeLength;
}
return null;
}
/**
* Reads a non standard JVMS 'attribute' structure in {@link #b}.
*
......
......@@ -203,6 +203,7 @@ final class SymbolTable {
// method calls below), and to account for bootstrap method entries.
entries = new Entry[constantPoolCount * 2];
char[] charBuffer = new char[classReader.getMaxStringLength()];
boolean hasBootstrapMethods = false;
int itemIndex = 1;
while (itemIndex < constantPoolCount) {
int itemOffset = classReader.getItem(itemIndex);
......@@ -252,6 +253,7 @@ final class SymbolTable {
break;
case Symbol.CONSTANT_DYNAMIC_TAG:
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
hasBootstrapMethods = true;
nameAndTypeItemOffset =
classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
addConstantDynamicOrInvokeDynamicReference(
......@@ -276,7 +278,23 @@ final class SymbolTable {
(itemTag == Symbol.CONSTANT_LONG_TAG || itemTag == Symbol.CONSTANT_DOUBLE_TAG) ? 2 : 1;
}
// Copy the BootstrapMethods 'bootstrap_methods' array binary content, if any.
// Copy the BootstrapMethods, if any.
if (hasBootstrapMethods) {
copyBootstrapMethods(classReader, charBuffer);
}
}
/**
* Read the BootstrapMethods 'bootstrap_methods' array binary content and add them as entries of
* the SymbolTable.
*
* @param classReader the ClassReader whose bootstrap methods must be copied to initialize the
* SymbolTable.
* @param charBuffer a buffer used to read strings in the constant pool.
*/
private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
// Find attributOffset of the 'bootstrap_methods' array.
byte[] inputBytes = classReader.b;
int currentAttributeOffset = classReader.getFirstAttributeOffset();
for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment