Skip to content

Commit

Permalink
Remove reliance on JDK internals in ClassFactory (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
PaintNinja authored Aug 20, 2024
1 parent 6d0589d commit 6fb1fcc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,30 @@
package net.minecraftforge.eventbus.testjar.benchmarks;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.invoke.MethodHandles;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper;

import net.minecraftforge.unsafe.UnsafeHacks;

public class ClassFactory<T> {
public final class ClassFactory<T> {
private final Mapper<T> mapper;
private final String binaryName;
private final String name;
private final byte[] data;
private final Method define;
private final MethodHandles.Lookup lookup;
private int count;

public ClassFactory(String name, Mapper<T> mapper) {
/**
* @param clazz The class to create new derivations of
* @param lookup {@code MethodHandles.lookup()} for defining the new classes
* @param mapper A function to apply on newly defined classes
*/
public ClassFactory(Class<?> clazz, MethodHandles.Lookup lookup, Mapper<T> mapper) {
this.mapper = mapper;
this.name = name;
this.binaryName = name.replace('.', '/');
this.binaryName = clazz.getName().replace('.', '/');
this.data = readData(this.binaryName);
this.define = getAccess();
this.lookup = lookup;
}

private static byte[] readData(String name) {
Expand All @@ -40,24 +41,13 @@ private static byte[] readData(String name) {
}
}

private static Method getAccess() {
try {
var define = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
UnsafeHacks.setAccessible(define);
return define;
} catch (Exception e) {
return sneak(e);
}
}

public T create() {
count++;
var newName = this.binaryName + "$New" + count;

var renamer = new Remapper() {
@Override
public String map(String internalName) {
if (internalName.equals(binaryName)) return newName;
if (internalName.equals(binaryName)) return binaryName + "$New" + count;
return BenchmarkManager.rename(internalName);
}
};
Expand All @@ -66,9 +56,8 @@ public String map(String internalName) {
var writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
reader.accept(new ClassRemapper(writer, renamer), 0);
try {
var cl = Thread.currentThread().getContextClassLoader();
var newData = writer.toByteArray();
var newCls = (Class<?>)define.invoke(cl, this.name + "$New" + count, newData, 0, newData.length);
var newCls = (Class<?>) lookup.defineClass(newData);
return mapper.apply(newCls);
} catch (Exception e) {
return sneak(e);
Expand All @@ -77,10 +66,11 @@ public String map(String internalName) {

@SuppressWarnings("unchecked")
private static <E extends Throwable, R> R sneak(Throwable e) throws E {
throw (E)e;
throw (E) e;
}

public static interface Mapper<T> {
@FunctionalInterface
public interface Mapper<T> {
T apply(Class<?> cls) throws Exception;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package net.minecraftforge.eventbus.testjar.subscribers;


import java.lang.invoke.MethodHandles;
import java.util.function.Consumer;

import net.minecraftforge.eventbus.api.IEventBus;
Expand All @@ -26,9 +27,13 @@ public void onResultEvent(ResultEvent event) { }
public void onSimpleEvent(EventWithData event) { }

public static class Factory {
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>("net.minecraftforge.eventbus.testjar.subscribers.SubscriberDynamic", cls -> {
var inst = cls.getConstructor().newInstance();
return bus -> bus.register(inst);
});
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>(
SubscriberDynamic.class,
MethodHandles.lookup(),
cls -> {
var inst = cls.getConstructor().newInstance();
return bus -> bus.register(inst);
}
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package net.minecraftforge.eventbus.testjar.subscribers;

import java.lang.invoke.MethodHandles;
import java.util.function.Consumer;

import net.minecraftforge.eventbus.api.IEventBus;
Expand All @@ -29,6 +30,10 @@ public static void onSimpleEvent(EventWithData event) { }

public static class Factory {
@SuppressWarnings("unchecked")
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>("net.minecraftforge.eventbus.testjar.subscribers.SubscriberLambda", cls -> (Consumer<IEventBus>)cls.getDeclaredField("register").get(null));
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>(
SubscriberLambda.class,
MethodHandles.lookup(),
cls -> (Consumer<IEventBus>) cls.getDeclaredField("register").get(null)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package net.minecraftforge.eventbus.testjar.subscribers;


import java.lang.invoke.MethodHandles;
import java.util.function.Consumer;

import net.minecraftforge.eventbus.api.IEventBus;
Expand All @@ -26,6 +27,10 @@ public static void onResultEvent(ResultEvent event) { }
public static void onSimpleEvent(EventWithData event) { }

public static class Factory {
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>("net.minecraftforge.eventbus.testjar.subscribers.SubscriberStatic", cls -> bus -> bus.register(cls));
public static final ClassFactory<Consumer<IEventBus>> REGISTER = new ClassFactory<>(
SubscriberStatic.class,
MethodHandles.lookup(),
cls -> bus -> bus.register(cls)
);
}
}

0 comments on commit 6fb1fcc

Please sign in to comment.