Skip to content

Commit

Permalink
[memory] Deduplicate new Strings #2054
Browse files Browse the repository at this point in the history
Reduces memory used by type hierarchy / call hierarchy.
Stored for example in ResolvedBinaryType.uniqueKey

#2054
  • Loading branch information
EcljpseB0T authored and jukzi committed Mar 5, 2024
1 parent fe3ee68 commit b16f949
Show file tree
Hide file tree
Showing 41 changed files with 268 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
import org.eclipse.jdt.internal.compiler.util.Util;

public class AnnotationInfo extends ClassFileStruct implements IBinaryAnnotation {
Expand Down Expand Up @@ -57,7 +58,7 @@ public class AnnotationInfo extends ClassFileStruct implements IBinaryAnnotation
private void decodeAnnotation() {
this.readOffset = 0;
int utf8Offset = this.constantPoolOffsets[u2At(0)] - this.structOffset;
this.typename = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.typename = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
int numberOfPairs = u2At(2);
// u2 type_index + u2 num_member_value_pair
this.readOffset += 4;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,49 +48,47 @@
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
import org.eclipse.jdt.internal.compiler.util.JRTUtil;
import org.eclipse.jdt.internal.compiler.util.Util;

public class ClassFileReader extends ClassFileStruct implements IBinaryType {

private int accessFlags;
private final int accessFlags;
private final char[] classFileName;
private char[] className;
private int classNameIndex;
private int constantPoolCount;
private final char[] className;
private final int classNameIndex;
private final int constantPoolCount;
private AnnotationInfo[] annotations;
private TypeAnnotationInfo[] typeAnnotations;
private FieldInfo[] fields;
private ModuleInfo moduleDeclaration;
public char[] moduleName;
private int fieldsCount;
private final int fieldsCount;

// initialized in case the .class file is a nested type
private InnerClassInfo innerInfo;
private InnerClassInfo[] innerInfos;
private char[][] interfaceNames;
private int interfacesCount;
private char[][] permittedSubtypesNames;
private final char[][] interfaceNames;
private final int interfacesCount;
private final char[][] permittedSubtypesNames;
private int permittedSubtypesCount;
private MethodInfo[] methods;
private int methodsCount;
private char[] signature;
private final int methodsCount;
private final char[] signature;
private char[] sourceName;
private char[] sourceFileName;
private char[] superclassName;
private final char[] sourceFileName;
private final char[] superclassName;
private long tagBits;
private long version;
private char[] enclosingTypeName;
private final long version;
private final char[] enclosingTypeName;
private char[][][] missingTypeNames;
private int enclosingNameAndTypeIndex;
private char[] enclosingMethod;
private char[] nestHost;
private int nestMembersCount;
private char[][] nestMembers;
private boolean isRecord;
private int recordComponentsCount;
private RecordComponentInfo[] recordComponents;
URI path;
private URI path;
private static String printTypeModifiers(int modifiers) {
java.io.StringWriter out = new java.io.StringWriter();
java.io.PrintWriter print = new java.io.PrintWriter(out);
Expand Down Expand Up @@ -327,14 +325,15 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
}
}
// Read and validate access flags
this.accessFlags = u2At(readOffset);
int accessFlag = u2At(readOffset);
readOffset += 2;

// Read the classname, use exception handlers to catch bad format
this.classNameIndex = u2At(readOffset);
if (this.classNameIndex != 0) {
this.className = getConstantClassNameAt(this.classNameIndex);
if (this.classNameIndex == 0) {
throw new IllegalArgumentException("No ClassName"); //$NON-NLS-1$
}
this.className = CharDeduplication.intern(getConstantClassNameAt(this.classNameIndex));
readOffset += 2;

// Read the superclass name, can be null for java.lang.Object
Expand All @@ -343,10 +342,12 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
// if superclassNameIndex is equals to 0 there is no need to set a value for the
// field this.superclassName. null is fine.
if (superclassNameIndex != 0) {
this.superclassName = getConstantClassNameAt(superclassNameIndex);
this.superclassName = CharDeduplication.intern(getConstantClassNameAt(superclassNameIndex));
if (CharOperation.equals(this.superclassName, TypeConstants.CharArray_JAVA_LANG_RECORD_SLASH)) {
this.accessFlags |= ExtraCompilerModifiers.AccRecord;
accessFlag |= ExtraCompilerModifiers.AccRecord;
}
} else {
this.superclassName = null;
}

// Read the interfaces, use exception handlers to catch bad format
Expand All @@ -355,9 +356,11 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
if (this.interfacesCount != 0) {
this.interfaceNames = new char[this.interfacesCount][];
for (int i = 0; i < this.interfacesCount; i++) {
this.interfaceNames[i] = getConstantClassNameAt(u2At(readOffset));
this.interfaceNames[i] = CharDeduplication.intern(getConstantClassNameAt(u2At(readOffset)));
readOffset += 2;
}
} else {
this.interfaceNames = null;
}
// Read the fields, use exception handlers to catch bad format
this.fieldsCount = u2At(readOffset);
Expand All @@ -376,7 +379,7 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
readOffset += 2;
if (this.methodsCount != 0) {
this.methods = new MethodInfo[this.methodsCount];
boolean isAnnotationType = (this.accessFlags & ClassFileConstants.AccAnnotation) != 0;
boolean isAnnotationType = (accessFlag & ClassFileConstants.AccAnnotation) != 0;
for (int i = 0; i < this.methodsCount; i++) {
this.methods[i] = isAnnotationType
? AnnotationMethodInfo.createAnnotationMethod(this.reference, this.constantPoolOffsets, readOffset, this.version)
Expand All @@ -388,6 +391,10 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
// Read the attributes
int attributesCount = u2At(readOffset);
readOffset += 2;
char[] enclosingTypeNam = null;
char[] sourceFileNam = null;
char[] signatur = null;
char[][] permittedSubtypesNam = null;

for (int i = 0; i < attributesCount; i++) {
int utf8Offset = this.constantPoolOffsets[u2At(readOffset)];
Expand All @@ -401,13 +408,13 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
if (CharOperation.equals(attributeName, AttributeNamesConstants.EnclosingMethodName)) {
utf8Offset =
this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(readOffset + 6)] + 1)];
this.enclosingTypeName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
enclosingTypeNam = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
this.enclosingNameAndTypeIndex = u2At(readOffset + 8);
}
break;
case 'D' :
if (CharOperation.equals(attributeName, AttributeNamesConstants.DeprecatedName)) {
this.accessFlags |= ClassFileConstants.AccDeprecated;
accessFlag |= ClassFileConstants.AccDeprecated;
}
break;
case 'I' :
Expand All @@ -428,7 +435,7 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
if (this.innerInfo != null) {
char[] enclosingType = this.innerInfo.getEnclosingTypeName();
if (enclosingType != null) {
this.enclosingTypeName = enclosingType;
enclosingTypeNam = enclosingType;
}
}
}
Expand All @@ -442,18 +449,18 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
case 'o' :
if (CharOperation.equals(attributeName, AttributeNamesConstants.SourceName)) {
utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)];
this.sourceFileName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
sourceFileNam = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
break;
case 'y' :
if (CharOperation.equals(attributeName, AttributeNamesConstants.SyntheticName)) {
this.accessFlags |= ClassFileConstants.AccSynthetic;
accessFlag |= ClassFileConstants.AccSynthetic;
}
break;
case 'i' :
if (CharOperation.equals(attributeName, AttributeNamesConstants.SignatureName)) {
utf8Offset = this.constantPoolOffsets[u2At(readOffset + 6)];
this.signature = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
signatur = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
}
}
Expand Down Expand Up @@ -496,17 +503,19 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
if (CharOperation.equals(attributeName, AttributeNamesConstants.NestHost)) {
utf8Offset =
this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(readOffset + 6)] + 1)];
this.nestHost = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
@SuppressWarnings("unused")
char[] nestHos = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
} else if (CharOperation.equals(attributeName, AttributeNamesConstants.NestMembers)) {
int offset = readOffset + 6;
this.nestMembersCount = u2At(offset);
if (this.nestMembersCount != 0) {
int nestMembersCount = u2At(offset);
if (nestMembersCount != 0) {
offset += 2;
this.nestMembers = new char[this.nestMembersCount][];
for (int j = 0; j < this.nestMembersCount; j++) {
/** unused */
char[][] nestMember = new char[nestMembersCount][];
for (int j = 0; j < nestMembersCount; j++) {
utf8Offset =
this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(offset)] + 1)];
this.nestMembers[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
nestMember[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
offset += 2;
}
}
Expand All @@ -517,13 +526,13 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
int offset = readOffset + 6;
this.permittedSubtypesCount = u2At(offset);
if (this.permittedSubtypesCount != 0) {
this.accessFlags |= ExtraCompilerModifiers.AccSealed;
accessFlag |= ExtraCompilerModifiers.AccSealed;
offset += 2;
this.permittedSubtypesNames = new char[this.permittedSubtypesCount][];
permittedSubtypesNam = new char[this.permittedSubtypesCount][];
for (int j = 0; j < this.permittedSubtypesCount; j++) {
utf8Offset =
this.constantPoolOffsets[u2At(this.constantPoolOffsets[u2At(offset)] + 1)];
this.permittedSubtypesNames[j] = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
permittedSubtypesNam[j] = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
offset += 2;
}
}
Expand All @@ -536,6 +545,11 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit
this.moduleDeclaration.setAnnotations(this.annotations, this.tagBits, fullyInitialize);
this.annotations = null;
}
this.accessFlags = accessFlag;
this.enclosingTypeName = enclosingTypeNam;
this.sourceFileName = sourceFileNam;
this.signature = signatur;
this.permittedSubtypesNames= permittedSubtypesNam;
if (fullyInitialize) {
initialize();
}
Expand Down Expand Up @@ -566,10 +580,6 @@ private void decodeRecords(int readOffset, char[] attributeName) {
}
}

public char[] getNestHost() {
return this.nestHost;
}

@Override
public ExternalAnnotationStatus getExternalAnnotationStatus() {
return ExternalAnnotationStatus.NOT_EEA_CONFIGURED;
Expand Down Expand Up @@ -708,7 +718,7 @@ public char[] getEnclosingMethod() {
utf8Offset = this.constantPoolOffsets[u2At(nameAndTypeOffset + 3)];
buffer.append(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));

this.enclosingMethod = String.valueOf(buffer).toCharArray();
this.enclosingMethod = CharDeduplication.intern(buffer.toString().toCharArray());
}
return this.enclosingMethod;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
import org.eclipse.jdt.internal.compiler.util.CharDeduplication;
import org.eclipse.jdt.internal.compiler.util.Util;

@SuppressWarnings("rawtypes")
Expand Down Expand Up @@ -191,7 +192,7 @@ public char[] getGenericSignature() {
if (this.signatureUtf8Offset != -1) {
if (this.signature == null) {
// decode the signature
this.signature = utf8At(this.signatureUtf8Offset + 3, u2At(this.signatureUtf8Offset + 1));
this.signature = CharDeduplication.intern(utf8At(this.signatureUtf8Offset + 3, u2At(this.signatureUtf8Offset + 1)));
}
return this.signature;
}
Expand Down Expand Up @@ -221,7 +222,7 @@ public char[] getName() {
if (this.name == null) {
// read the name
int utf8Offset = this.constantPoolOffsets[u2At(2)] - this.structOffset;
this.name = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.name = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
return this.name;
}
Expand All @@ -245,7 +246,7 @@ public char[] getTypeName() {
if (this.descriptor == null) {
// read the signature
int utf8Offset = this.constantPoolOffsets[u2At(4)] - this.structOffset;
this.descriptor = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.descriptor = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
return this.descriptor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.eclipse.jdt.internal.compiler.classfmt;

import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
import org.eclipse.jdt.internal.compiler.util.CharDeduplication;

/**
* Describes one entry in the classes table of the InnerClasses attribute.
Expand Down Expand Up @@ -48,7 +49,7 @@ public char[] getEnclosingTypeName() {
this.constantPoolOffsets[u2At(
this.constantPoolOffsets[this.outerClassNameIndex] - this.structOffset + 1)]
- this.structOffset;
this.outerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.outerClassName = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
this.readOuterClassName = true;

Expand All @@ -72,7 +73,7 @@ public char[] getName() {
if (this.innerClassNameIndex != 0) {
int classOffset = this.constantPoolOffsets[this.innerClassNameIndex] - this.structOffset;
int utf8Offset = this.constantPoolOffsets[u2At(classOffset + 1)] - this.structOffset;
this.innerClassName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.innerClassName = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
this.readInnerClassName = true;
}
Expand All @@ -88,7 +89,7 @@ public char[] getSourceName() {
if (!this.readInnerName) {
if (this.innerNameIndex != 0) {
int utf8Offset = this.constantPoolOffsets[this.innerNameIndex] - this.structOffset;
this.innerName = utf8At(utf8Offset + 3, u2At(utf8Offset + 1));
this.innerName = CharDeduplication.intern(utf8At(utf8Offset + 3, u2At(utf8Offset + 1)));
}
this.readInnerName = true;
}
Expand Down

0 comments on commit b16f949

Please sign in to comment.