io.github.jdcmp.codegen.Internals Maven / Gradle / Ivy
package io.github.jdcmp.codegen;
import io.github.jdcmp.api.documentation.ThreadSafe;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
@ThreadSafe
final class Internals {
private static final Logger LOGGER = Logger.getLogger(Internals.class.getName());
private static final FallbackStrategy FIELD_FINDER_STRATEGIES;
private static final FallbackStrategy FIELD_ACCESS_STRATEGIES;
static {
ArrayList strategies = new ArrayList<>(2);
add(strategies, TrustedLookupFieldFinder.class, TrustedLookupFieldFinder::new);
add(strategies, PlainFieldFinder.class, PlainFieldFinder::new);
FIELD_FINDER_STRATEGIES = FallbackStrategy.of(strategies);
}
static {
ArrayList strategies = new ArrayList<>(2);
add(strategies, UnsafeFieldSetter.class, UnsafeFieldSetter::new);
add(strategies, PlainFieldSetter.class, PlainFieldSetter::new);
FIELD_ACCESS_STRATEGIES = FallbackStrategy.of(strategies);
}
private static void add(ArrayList list, Class extends T> clazz, Supplier factory) {
try {
list.add(factory.get());
} catch (Exception e) {
LOGGER.log(Level.FINE, "Class for Field handling is unavailable: " + clazz, e);
}
}
public static void setStaticFieldVolatile(Class> clazz, String fieldName, Object value) {
Field field = FIELD_FINDER_STRATEGIES.apply(ff -> ff.findStatic(clazz, fieldName));
FIELD_ACCESS_STRATEGIES.consume(fa -> fa.setStatic(field, value));
}
public static MethodHandle superUnreflect(Method method) {
return TrustedLookup.unreflect(method);
}
static final class Unsafe {
private static final Class> CLASS = OptionalClass.UNSAFE.load();
private static final Object INSTANCE = SingletonFinder.findInstance(CLASS);
static Object getInstance() {
return INSTANCE;
}
static final class Method extends AbstractMethod {
static final Method STATIC_FIELD_BASE = of("staticFieldBase", Object.class, Field.class);
static final Method STATIC_FIELD_OFFSET = of("staticFieldOffset", long.class, Field.class);
static final Method PUT_OBJECT_VOLATILE = of("putObjectVolatile", void.class, Object.class, long.class, Object.class);
static final Method ALLOCATE_INSTANCE = of("allocateInstance", Object.class, Class.class);
static final Method DEFINE_ANONYMOUS_CLASS = of("defineAnonymousClass", Class.class, Class.class, byte[].class, Object[].class);
private static Method of(String methodName, Class> returnType, Class>... parameterTypes) {
return new Method(methodName, MethodType.methodType(returnType, parameterTypes));
}
private Method(String methodName, MethodType methodType) {
super(OptionalClass.UNSAFE, methodName, methodType);
}
}
}
static final class ReflectionFactory {
private static final Object INSTANCE = SingletonFinder.findInstance(OptionalClass.REFLECTION_FACTORY.load());
public static Object getInstance() {
return INSTANCE;
}
static final class Method extends AbstractMethod {
static final Method NEW_CONSTRUCTOR_FOR_SERIALIZATION = of("newConstructorForSerialization", Constructor.class, Class.class);
static final Method NEW_CONSTRUCTOR_FOR_SERIALIZATION_CONSTRUCTOR = of("newConstructorForSerialization", Constructor.class, Class.class, Constructor.class);
private static Method of(String methodName, Class> returnType, Class>... parameterTypes) {
return new Method(methodName, MethodType.methodType(returnType, parameterTypes));
}
private Method(String methodName, MethodType methodType) {
super(OptionalClass.REFLECTION_FACTORY, methodName, methodType);
}
}
}
static final class Lookup {
static final class Method extends AbstractMethod {
static final Method DEFINE_CLASS = of("defineClass", Class.class, byte[].class);
static final Method ACCESS_CLASS = of("accessClass", Class.class, Class.class);
private static Method of(String methodName, Class> returnType, Class>... parameterTypes) {
return new Method(methodName, MethodType.methodType(returnType, parameterTypes));
}
Method(String methodName, MethodType methodType) {
super(OptionalClass.LOOKUP, methodName, methodType);
}
}
}
abstract static class AbstractMethod implements EnumeratedMethod {
private final OptionalClass methodDeclaringClass;
private final String methodName;
private final MethodType methodType;
protected AbstractMethod(OptionalClass methodDeclaringClass, String methodName, MethodType methodType) {
this.methodDeclaringClass = Objects.requireNonNull(methodDeclaringClass);
this.methodName = Objects.requireNonNull(methodName);
this.methodType = Objects.requireNonNull(methodType);
}
@Override
public OptionalClass getMethodDeclaringClass() {
return methodDeclaringClass;
}
@Override
public String getMethodName() {
return methodName;
}
@Override
public MethodType getMethodType() {
return methodType;
}
}
enum OptionalClass {
UNSAFE("sun.misc.Unsafe"),
REFLECTION_FACTORY("sun.reflect.ReflectionFactory"),
LOOKUP("java.lang.invoke.MethodHandles$Lookup"),
CLASS_OPTION("java.lang.invoke.MethodHandles$Lookup$ClassOption");
private final String className;
OptionalClass(String className) {
this.className = Objects.requireNonNull(className);
}
public String getClassName() {
return className;
}
public Class> load() {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
private static final class MethodHandleFinder {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
public static MethodHandle find(MethodHandleMetadata info) {
OptionalClass declaringClass = info.getMethodDeclaringClass();
String methodName = info.getMethodName();
MethodType methodType = info.getMethodType();
try {
Class> clazz = declaringClass.load();
return LOOKUP.findVirtual(clazz, methodName, methodType);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Failed to find method: " + declaringClass.getClassName() + "." + methodName + methodType);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private interface EnumeratedMethod extends MethodHandleMetadata, MethodHandleResolver {
@Override
default MethodHandle find() {
return MethodHandleFinder.find(this);
}
default Optional tryFind() {
try {
return Optional.of(find());
} catch (Exception e) {
return Optional.empty();
}
}
}
private interface MethodHandleMetadata {
OptionalClass getMethodDeclaringClass();
String getMethodName();
MethodType getMethodType();
}
private interface MethodHandleResolver {
MethodHandle find();
Optional tryFind();
}
private static final class SingletonFinder {
static Object findInstance(Class> clazz) {
try {
for (Field field : clazz.getDeclaredFields()) {
if (field.getType() == clazz && Modifier.isStatic(field.getModifiers())) {
field.setAccessible(true);
Object object = field.get(null);
if (object != null) {
return object;
}
}
}
} catch (Exception e) {
throw new RuntimeException("Failed to find field containing instance of class: " + clazz, e);
}
throw new RuntimeException("Failed to find field containing instance of class: " + clazz);
}
}
/**
* No longer works in Java 17+ (missing sun.misc.Unsafe.defineAnonymousClass)
*/
static final class TrustedLookup {
// A minimalistic class with "static Lookup get() { return Lookup.IMPL_LOOKUP; }", compressed and encoded in base64
private static final String ACCESSOR = "eNqNjT0OglAQhGcFRQQNVzDBKBWNVlbGRiMEC60NwgsK"
+ "hGf4O5extPAAHsoIWljKNN9OZnf2+bo/AEwxIMxCt3TN2E0C85yUPGKmzfIT91du4scs0/VdWmQ58y3Oo+Ky8DyWZTyVQATtd+oc"
+ "Q+blEgSCELCcYEwM60/zt3FOGDValCARlLW9tQ6W42z2W8K44QsVMnoyulAI4pL7DEO0IKIWVVkbnYr9ymkVa4k3qNfPhDd4rFKr";
public static MethodHandle unreflect(Method method) {
try {
return get().unreflect(method);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static MethodHandles.Lookup get() {
try {
byte[] bytes = getClassBytes();
Class> accessorClass = (Class>) Holder.DEFINE_ANONYMOUS_CLASS.invokeExact(MethodHandles.class, bytes, (Object[]) null);
Method accessorMethod = accessorClass.getDeclaredMethod("get");
return (MethodHandles.Lookup) accessorMethod.invoke(null);
} catch (@SuppressWarnings("removal") RuntimeException | ThreadDeath e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private static byte[] getClassBytes() throws IOException {
byte[] bytes = new byte[301];
try (InflaterInputStream iis = new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(ACCESSOR)))) {
if (iis.read(bytes) != 301) {
throw new RuntimeException();
}
}
return bytes;
}
private static final class Holder {
private static final MethodHandle DEFINE_ANONYMOUS_CLASS;
static {
Object unsafe = Unsafe.getInstance();
DEFINE_ANONYMOUS_CLASS = Unsafe.Method.DEFINE_ANONYMOUS_CLASS.find().bindTo(unsafe);
}
}
}
@ThreadSafe
interface FieldFinder {
Field findStatic(Class> clazz, String fieldName) throws Throwable;
}
@ThreadSafe
static final class PlainFieldFinder implements FieldFinder {
@Override
public Field findStatic(Class> clazz, String fieldName) throws Throwable {
return clazz.getDeclaredField(fieldName);
}
}
@ThreadSafe
static final class TrustedLookupFieldFinder implements FieldFinder {
TrustedLookupFieldFinder() {
Utils.initializeClass(Holder.class);
}
@Override
public Field findStatic(Class> clazz, String fieldName) throws Throwable {
Field[] fields = (Field[]) Holder.GET_DECLARED_FIELDS_0.invokeExact(clazz, false);
for (Field field : fields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
throw new NoSuchFieldException("No field " + fieldName + " in class " + clazz);
}
private static final class Holder {
static final MethodHandle GET_DECLARED_FIELDS_0;
static {
try {
MethodHandles.Lookup lookup = TrustedLookup.get();
MethodType methodType = MethodType.methodType(Field[].class, boolean.class);
GET_DECLARED_FIELDS_0 = lookup.findSpecial(Class.class, "getDeclaredFields0", methodType, Class.class);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
}
}
@ThreadSafe
interface FieldSetter {
void setStatic(Field field, Object value) throws Throwable;
}
static final class UnsafeFieldSetter implements FieldSetter {
UnsafeFieldSetter() {
Utils.initializeClass(Holder.class);
}
@Override
public void setStatic(Field field, Object value) throws Throwable {
Object base = Holder.STATIC_FIELD_BASE.invokeExact(field);
long offset = (long) Holder.STATIC_FIELD_OFFSET.invokeExact(field);
Holder.PUT_OBJECT_VOLATILE.invokeExact(base, offset, value);
}
private static final class Holder {
private static final MethodHandle STATIC_FIELD_BASE;
private static final MethodHandle STATIC_FIELD_OFFSET;
private static final MethodHandle PUT_OBJECT_VOLATILE;
static {
Class> unsafeClass = OptionalClass.UNSAFE.load();
Object unsafeInstance = SingletonFinder.findInstance(unsafeClass);
STATIC_FIELD_BASE = Unsafe.Method.STATIC_FIELD_BASE.find().bindTo(unsafeInstance);
STATIC_FIELD_OFFSET = Unsafe.Method.STATIC_FIELD_OFFSET.find().bindTo(unsafeInstance);
PUT_OBJECT_VOLATILE = Unsafe.Method.PUT_OBJECT_VOLATILE.find().bindTo(unsafeInstance);
}
}
}
static final class PlainFieldSetter implements FieldSetter {
@Override
public void setStatic(Field field, Object value) throws Throwable {
int modifiers = field.getModifiers();
if (Modifier.isFinal(modifiers)) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.set(field, modifiers & ~Modifier.FINAL);
}
field.setAccessible(true);
field.set(null, value);
}
}
private Internals() {
throw new AssertionError("No instances");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy