internal: use LambdaMetafactory to generate java.util.zip.CRC32C instances (#595)

currently we have written a lambda (turns into anonymous class) which
invokes a MethodHandle for the java.util.zip.CRC32C constructor as the
Supplier<Checksum> implementation.

This has 2 layers of misdirection. The Supplier implementation spun up
by the jvm calls the anonymous lambda class, which then calls the
MethodHandle invoke. This leads to stack traces like:

use LambdaMetafactory to generate a Supplier<Checksum> which calls the
java.util.zip.CRC32C

Co-authored-by: bo8979 <bo8979@cerner.com>
This commit is contained in:
Brett Okken 2024-09-10 14:22:02 -05:00 committed by GitHub
parent 341377bfed
commit 01368fe0d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 22 additions and 15 deletions

View File

@ -4,6 +4,7 @@
package org.xerial.snappy; package org.xerial.snappy;
import java.io.IOException; import java.io.IOException;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
@ -37,21 +38,27 @@ final class SnappyFramed
Supplier<Checksum> supplier = null; Supplier<Checksum> supplier = null;
try try
{ {
final Class crc32cClazz = Class.forName("java.util.zip.CRC32C"); final Class<?> crc32cClazz = Class.forName("java.util.zip.CRC32C");
final MethodHandles.Lookup lookup = MethodHandles.publicLookup(); // using LambdaMetafactory requires a caller sensitive lookup
final MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle conHandle = lookup.findConstructor(crc32cClazz, MethodType.methodType(void.class));
final MethodHandle conHandle = lookup.findConstructor(crc32cClazz, MethodType.methodType(void.class)) // use LambdaMetafactory to generate an implementation of Supplier<Checksum> which invokes
.asType(MethodType.methodType(Checksum.class)); // the java.util.zip.CRC32C default constructor
supplier = () -> { supplier = (Supplier<Checksum>) LambdaMetafactory.metafactory(lookup,
try // method name on Supplier
{ "get",
return (Checksum) conHandle.invokeExact(); // functional interface to be created by factory
} MethodType.methodType(Supplier.class),
catch (Throwable e) // type of the functional interface
{ // uses a generic, so erasure to Object
throw new IllegalStateException(e); MethodType.methodType(Object.class),
} // the method handle to call
}; conHandle,
// type as used at call site
MethodType.methodType(Checksum.class))
.getTarget()
.invoke();
} }
catch(Throwable t) catch(Throwable t)
{ {