Skip to content

Instantly share code, notes, and snippets.

@Maldivia
Created May 21, 2019 12:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Maldivia/560779a886c187da63c6908be5573ac6 to your computer and use it in GitHub Desktop.
Save Maldivia/560779a886c187da63c6908be5573ac6 to your computer and use it in GitHub Desktop.
JDK8 vresion of Lazy initialization
package app1;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import sun.misc.Unsafe;
import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.util.function.Supplier;
public abstract class Lazy8<T> implements Supplier<T> {
static Object site(MethodHandles.Lookup caller,
String invokedName,
MethodType invokedType,
MethodHandle handle,
Object target) throws Throwable {
Object value = handle.invokeExact((Supplier)target);
return new ConstantCallSite(MethodHandles.constant(Object.class, value));
}
private static final String MARKER = "LAZY_MARKER";
public static <T> Lazy8<T> let(Supplier<T> init) {
ClassWriter cw = new ClassWriter(Opcodes.ASM7);
String lazyName = Lazy8.class.getName().replace('.', '/');
cw.visit(Opcodes.V1_8, 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.visitInvokeDynamicInsn("get", "()Ljava/lang/Object;",
new Handle(Opcodes.H_INVOKESTATIC,
lazyName,
"site",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;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);
System.out.println(cpSize);
Object[] cp = new Object[cpSize];
cp[markerIndex] = init;
Class<?> aClass = unsafe.defineAnonymousClass(Lazy.class, bytes, cp);
return (Lazy8<T>) aClass.newInstance();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment