Skip to content

Commit

Permalink
Optimize checksum-based hash functions on non-array ByteBuffers by at…
Browse files Browse the repository at this point in the history
… least an order of magnitude, at least for Java 9+.

RELNOTES=`hash`: Optimized `Checksum`-based hash functions for Java 9+.
PiperOrigin-RevId: 606354141
  • Loading branch information
lowasser authored and Google Java Core Libraries committed Feb 12, 2024
1 parent 345cd11 commit afb35a5
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions guava/src/com/google/common/hash/ChecksumHashFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.errorprone.annotations.Immutable;
import com.google.j2objc.annotations.J2ObjCIncompatible;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.nio.ByteBuffer;
import java.util.zip.Checksum;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
* {@link HashFunction} adapter for {@link Checksum} instances.
Expand Down Expand Up @@ -74,6 +80,14 @@ protected void update(byte[] bytes, int off, int len) {
checksum.update(bytes, off, len);
}

@Override
@J2ObjCIncompatible
protected void update(ByteBuffer b) {
if (!ChecksumMethodHandles.updateByteBuffer(checksum, b)) {
super.update(b);
}
}

@Override
public HashCode hash() {
long value = checksum.getValue();
Expand All @@ -90,5 +104,47 @@ public HashCode hash() {
}
}

@J2ObjCIncompatible
@SuppressWarnings("unused")
private static final class ChecksumMethodHandles {
private static final @Nullable MethodHandle UPDATE_BB = updateByteBuffer();

@IgnoreJRERequirement // https://github.com/mojohaus/animal-sniffer/issues/67
static boolean updateByteBuffer(Checksum cs, ByteBuffer bb) {
if (UPDATE_BB != null) {
try {
UPDATE_BB.invokeExact(cs, bb);
} catch (Error t) {
throw t;
} catch (Throwable t) {
throw new AssertionError(t);
}
return true;
} else {
return false;
}
}

private static @Nullable MethodHandle updateByteBuffer() {
try {
Class<?> clazz = Class.forName("java.util.zip.Checksum");
return MethodHandles.lookup()
.findVirtual(clazz, "update", MethodType.methodType(void.class, ByteBuffer.class));
} catch (ClassNotFoundException e) {
throw new AssertionError(e);
} catch (IllegalAccessException e) {
// That API is public.
throw newLinkageError(e);
} catch (NoSuchMethodException e) {
// Only introduced in Java 9.
return null;
}
}

private static LinkageError newLinkageError(Throwable cause) {
return new LinkageError(cause.toString(), cause);
}
}

private static final long serialVersionUID = 0L;
}

0 comments on commit afb35a5

Please sign in to comment.