Commit a3ac07fc authored by Eric Bruneton's avatar Eric Bruneton

Merge branch 'fix-performance-regression' into 'master'

Fix the performance regression from 6.1 by splitting the generic cache into specific ones.

See merge request !217
parents 63729dc5 2b202158
Pipeline #2845 passed with stage
in 6 minutes and 44 seconds
......@@ -109,11 +109,16 @@ public class ClassReader {
private final int[] cpInfoOffsets;
/**
* The value of each cp_info entry of the ClassFile's constant_pool array, <i>for Constant_Utf8
* and Constant_Dynamic constants only</i>. The value of constant pool entry i is given by
* cpInfoValues[i]. This cache avoids multiple parsing of those constant pool items.
* The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids
* multiple parsing of a given CONSTANT_Utf8 constant pool item.
*/
private final Object[] cpInfoValues;
private final String[] constantUtf8Values;
/**
* The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This
* cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item.
*/
private final ConstantDynamic[] constantDynamicValues;
/**
* The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
......@@ -168,7 +173,7 @@ public class ClassReader {
*/
ClassReader(
final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
this.b = classFileBuffer;
b = classFileBuffer;
// Check the class' major_version. This field is after the magic and minor_version fields, which
// use 4 and 2 bytes respectively.
if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V12) {
......@@ -179,7 +184,7 @@ public class ClassReader {
// minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
int constantPoolCount = readUnsignedShort(classFileOffset + 8);
cpInfoOffsets = new int[constantPoolCount];
cpInfoValues = new Object[constantPoolCount];
constantUtf8Values = new String[constantPoolCount];
// Compute the offset of each constant pool entry, as well as a conservative estimate of the
// maximum length of the constant pool strings. The first constant pool entry is after the
// magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
......@@ -187,16 +192,13 @@ public class ClassReader {
int currentCpInfoIndex = 1;
int currentCpInfoOffset = classFileOffset + 10;
int currentMaxStringLength = 0;
boolean hasBootstrapMethods = false;
boolean hasConstantDynamic = false;
boolean hasConstantInvokeDynamic = 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:
......@@ -205,6 +207,14 @@ public class ClassReader {
case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
cpInfoSize = 5;
break;
case Symbol.CONSTANT_DYNAMIC_TAG:
cpInfoSize = 5;
hasConstantDynamic = true;
break;
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
cpInfoSize = 5;
hasConstantInvokeDynamic = true;
break;
case Symbol.CONSTANT_LONG_TAG:
case Symbol.CONSTANT_DOUBLE_TAG:
cpInfoSize = 9;
......@@ -234,13 +244,18 @@ public class ClassReader {
}
currentCpInfoOffset += cpInfoSize;
}
this.maxStringLength = currentMaxStringLength;
maxStringLength = currentMaxStringLength;
// The Classfile's access_flags field is just after the last constant pool entry.
this.header = currentCpInfoOffset;
header = currentCpInfoOffset;
// Allocate the cache of ConstantDynamic values, if there is at least one.
constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null;
// Read the BootstrapMethods attribute, if any (only get the offset of each method).
this.bootstrapMethodOffsets =
hasBootstrapMethods ? readBootstrapMethodsAttribute(currentMaxStringLength) : null;
bootstrapMethodOffsets =
(hasConstantDynamic | hasConstantInvokeDynamic)
? readBootstrapMethodsAttribute(currentMaxStringLength)
: null;
}
/**
......@@ -3402,14 +3417,13 @@ public class ClassReader {
* @return the String corresponding to the specified CONSTANT_Utf8 entry.
*/
final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) {
String value = (String) cpInfoValues[constantPoolEntryIndex];
String value = constantUtf8Values[constantPoolEntryIndex];
if (value != null) {
return value;
}
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
value = readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
cpInfoValues[constantPoolEntryIndex] = value;
return value;
return constantUtf8Values[constantPoolEntryIndex] =
readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
}
/**
......@@ -3515,7 +3529,7 @@ public class ClassReader {
*/
private ConstantDynamic readConstantDynamic(
final int constantPoolEntryIndex, final char[] charBuffer) {
ConstantDynamic constantDynamic = (ConstantDynamic) cpInfoValues[constantPoolEntryIndex];
ConstantDynamic constantDynamic = constantDynamicValues[constantPoolEntryIndex];
if (constantDynamic != null) {
return constantDynamic;
}
......@@ -3531,9 +3545,8 @@ public class ClassReader {
bootstrapMethodArguments[i] = readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
bootstrapMethodOffset += 2;
}
constantDynamic = new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments);
cpInfoValues[constantPoolEntryIndex] = constantDynamic;
return constantDynamic;
return constantDynamicValues[constantPoolEntryIndex] =
new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments);
}
/**
......
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