HMember: flatten array into fields to reduce memory footprint

This commit is contained in:
Tagir Valeev
2018-04-15 13:21:47 +07:00
parent 2e246f08b5
commit 1360cb1031
2 changed files with 33 additions and 14 deletions
@@ -150,7 +150,7 @@ public class BytecodeAnalysisIndex extends ScalarIndexExtension<HMember> {
@Override
public void save(@NotNull DataOutput out, HMember value) throws IOException {
out.write(value.myBytes);
out.write(value.asBytes());
}
@Override
@@ -279,7 +279,7 @@ public class BytecodeAnalysisIndex extends ScalarIndexExtension<HMember> {
}
private static void writeKey(@NotNull DataOutput out, EKey key, MessageDigest md) throws IOException {
out.write(key.member.hashed(md).myBytes);
out.write(key.member.hashed(md).asBytes());
int rawDirKey = key.negated ? -key.dirKey : key.dirKey;
DataInputOutputUtil.writeINT(out, rawDirKey);
out.writeBoolean(key.stable);
@@ -19,8 +19,8 @@ import com.intellij.openapi.vfs.CharsetToolkit;
import one.util.streamex.IntStreamEx;
import org.jetbrains.annotations.NotNull;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Arrays;
import static com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter.getMessageDigest;
@@ -29,41 +29,60 @@ import static com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConve
*/
public final class HMember implements MemberDescriptor {
// how many bytes are taken from class fqn digest
private static final int CLASS_HASH_SIZE = 10;
private static final int CLASS_HASH_SIZE = Long.BYTES+Short.BYTES;
// how many bytes are taken from signature digest
private static final int SIGNATURE_HASH_SIZE = 4;
private static final int SIGNATURE_HASH_SIZE = Integer.BYTES;
static final int HASH_SIZE = CLASS_HASH_SIZE + SIGNATURE_HASH_SIZE;
@NotNull
final byte[] myBytes;
final long myClassHi;
final short myClassLo;
final int myMethod;
HMember(Member method, MessageDigest md) {
if (md == null) {
md = getMessageDigest();
}
byte[] classDigest = md.digest(method.internalClassName.getBytes(CharsetToolkit.UTF8_CHARSET));
ByteBuffer classBuffer = ByteBuffer.wrap(classDigest);
myClassHi = classBuffer.getLong();
myClassLo = classBuffer.getShort();
md.update(method.methodName.getBytes(CharsetToolkit.UTF8_CHARSET));
md.update(method.methodDesc.getBytes(CharsetToolkit.UTF8_CHARSET));
byte[] sigDigest = md.digest();
myBytes = new byte[HASH_SIZE];
System.arraycopy(classDigest, 0, myBytes, 0, CLASS_HASH_SIZE);
System.arraycopy(sigDigest, 0, myBytes, CLASS_HASH_SIZE, SIGNATURE_HASH_SIZE);
myMethod = ByteBuffer.wrap(sigDigest).getInt();
}
public HMember(@NotNull byte[] bytes) {
myBytes = bytes;
ByteBuffer buffer = ByteBuffer.wrap(bytes);
myClassHi = buffer.getLong();
myClassLo = buffer.getShort();
myMethod = buffer.getInt();
}
@NotNull
byte[] asBytes() {
ByteBuffer bytes = ByteBuffer.allocate(HASH_SIZE);
bytes.putLong(myClassHi).putShort(myClassLo).putInt(myMethod);
return bytes.array();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return Arrays.equals(myBytes, ((HMember)o).myBytes);
HMember that = (HMember)o;
return that.myClassHi == myClassHi && that.myClassLo == myClassLo && that.myMethod == myMethod;
}
@Override
public int hashCode() {
return Arrays.hashCode(myBytes);
// Must work as Arrays.hashCode(asBytes()) to preserve compatibility with old caches
int result = 1;
for (int i = Long.BYTES - 1; i >= 0; i--) result = result * 31 + (byte)((myClassHi >>> (i * 8)) & 0xFF);
for (int i = Short.BYTES - 1; i >= 0; i--) result = result * 31 + (byte)((myClassLo >>> (i * 8)) & 0xFF);
for (int i = Integer.BYTES - 1; i >= 0; i--) result = result * 31 + (byte)((myMethod >>> (i * 8)) & 0xFF);
return result;
}
@NotNull
@@ -73,7 +92,7 @@ public final class HMember implements MemberDescriptor {
}
public String toString() {
return bytesToString(myBytes);
return bytesToString(asBytes());
}
static String bytesToString(byte[] key) {