Skip to content

Instantly share code, notes, and snippets.

@Maldivia
Last active May 21, 2019 12:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Maldivia/513d2bb27738ab957339d13af2bb5e19 to your computer and use it in GitHub Desktop.
Save Maldivia/513d2bb27738ab957339d13af2bb5e19 to your computer and use it in GitHub Desktop.
Lazy init class using Unsafe anonymous class and Constant Dynamic from JDK11
package app1;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.function.Supplier;
public abstract class Lazy<T> implements Supplier<T> {
private static final String MARKER = "LAZY_MARKER";
public static <T> Lazy<T> let(Supplier<T> init) {
ClassWriter cw = new ClassWriter(Opcodes.ASM7);
String lazyName = Lazy.class.getName().replace('.', '/');
cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, lazyName + "$Impl", null, lazyName, null);
var mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, lazyName, "<init>", "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "get", "()Ljava/lang/Object;", null, null);
mv.visitCode();
mv.visitLdcInsn(new ConstantDynamic("get",
"Ljava/lang/Object;",
new Handle(Opcodes.H_INVOKESTATIC,
"java/lang/invoke/ConstantBootstraps",
"invoke",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
false),
new Handle(Opcodes.H_INVOKEINTERFACE,
"java/util/function/Supplier",
"get",
"()Ljava/lang/Object;",
true),
MARKER));
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
int markerIndex = cw.newConst(MARKER);
cw.visitEnd();
byte[] bytes = cw.toByteArray();
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
int cpSize = ((bytes[8] & 0xff) << 8) + (bytes[9] & 0xff);
Object[] cp = new Object[cpSize];
cp[markerIndex] = init;
Class<?> aClass = unsafe.defineAnonymousClass(Lazy.class, bytes, cp);
return (Lazy<T>) aClass.newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
package app1;
public class MiscTest11 {
public static void main(String[] args) throws Exception {
Lazy<String> hello = Lazy.let(MiscTest11::hello);
System.out.println(hello.get());
System.out.println(hello.get());
System.out.println(hello.get());
Lazy<String> world = Lazy.let(MiscTest11::world);
System.out.println(world.get());
System.out.println(world.get());
System.out.println(world.get());
world = Lazy.let(MiscTest11::world);
System.out.println(world.get());
System.out.println(world.get());
System.out.println(world.get());
}
private static String hello() {
System.out.println("init hello string");
return "Hello";
}
private static String world() {
System.out.println("init world string");
return "World";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment