Skip to content

Commit

Permalink
chore: switch to use MethodHandles#defineHiddenClass, but needs some …
Browse files Browse the repository at this point in the history
…more work for GA
  • Loading branch information
mworzala committed Jul 30, 2024
1 parent 0b69a01 commit f68420b
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 27 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ java {
tasks.test {
useJUnitPlatform()

jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
// jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
}

nexusPublishing {
Expand Down
49 changes: 29 additions & 20 deletions src/main/java/net/hollowcube/mql/jit/AsmUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;

public final class AsmUtil {
Expand Down Expand Up @@ -64,30 +65,38 @@ public static void convert(Class<?> to, Class<?> from, MethodVisitor mv) {

@SuppressWarnings("all")
public static Class<?> loadClass(String className, byte[] b) {
// Override defineClass (as it is protected) and define the class.
Class<?> clazz = null;
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> cls = (Class<?>) Class.forName("java.lang.ClassLoader");
java.lang.reflect.Method method =
cls.getDeclaredMethod(
"defineClass",
new Class[]{String.class, byte[].class, int.class, int.class});

// Protected method invocation.
method.setAccessible(true);
try {
Object[] args =
new Object[]{className, b, 0, b.length};
clazz = (Class<?>) method.invoke(loader, args);
} finally {
method.setAccessible(false);
}
var lookup = MethodHandles.lookup();
var a = lookup.defineHiddenClass(b, true);
return a.lookupClass();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
throw new RuntimeException(e);
}
return clazz;
// Override defineClass (as it is protected) and define the class.
// Class<?> clazz = null;
// try {
// ClassLoader loader = ClassLoader.getSystemClassLoader();
// Class<?> cls = (Class<?>) Class.forName("java.lang.ClassLoader");
// java.lang.reflect.Method method =
// cls.getDeclaredMethod(
// "defineClass",
// new Class[]{String.class, byte[].class, int.class, int.class});
//
// // Protected method invocation.
// method.setAccessible(true);
// try {
// Object[] args =
// new Object[]{className, b, 0, b.length};
// clazz = (Class<?>) method.invoke(loader, args);
// } finally {
// method.setAccessible(false);
// }
// } catch (Exception e) {
// e.printStackTrace();
// System.exit(1);
// }
// return clazz;
}

public static @NotNull String prettyPrintEvalMethod(byte[] bytecode) {
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/net/hollowcube/mql/jit/MqlCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
Expand All @@ -32,14 +34,16 @@ public class MqlCompiler<T> {
private static final AtomicInteger COUNTER = new AtomicInteger();
private static final ClassInfo MATH_CI = new ClassInfo(MqlMath.class, true);

private final MethodHandles.Lookup lookup;
private final Class<?> scriptInterface;
private final Class<?>[] generics;

private Method evalMethod;
private ParamInfo[] evalMethodParams;
private String evalFnDescriptor;

public MqlCompiler(Class<T> scriptInterface, Class<?>... generics) {
public MqlCompiler(@NotNull MethodHandles.Lookup lookup, Class<T> scriptInterface, Class<?>... generics) {
this.lookup = lookup;
this.scriptInterface = scriptInterface;
this.generics = generics;
parseScriptInterface();
Expand Down Expand Up @@ -67,7 +71,8 @@ public byte[] compileBytecode(String className, String script) {
for (Class<?> generic : generics)
sig.append(AsmUtil.toDescriptor(generic));
sig.append(">;");
scriptClass.visit(V17, ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, className, sig.toString(),
var targetPackage = scriptInterface.getPackageName().replace('.', '/');
scriptClass.visit(V17, ACC_PUBLIC | ACC_FINAL | ACC_SYNTHETIC, targetPackage + "/" + className, sig.toString(),
AsmUtil.toName(Object.class), new String[]{AsmUtil.toName(scriptInterface)});

// Generate required synthetics
Expand Down
4 changes: 3 additions & 1 deletion src/test/java/net/hollowcube/mql/jit/TestCompilation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import java.lang.invoke.MethodHandles;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestCompilation {
Expand Down Expand Up @@ -68,7 +70,7 @@ public void callQueryInnerCall() {
}

private void check(@NotNull Class<?> script, @NotNull String source, @NotNull String expected) {
var compiler = new MqlCompiler<>(script);
var compiler = new MqlCompiler<>(MethodHandles.lookup(), script);
byte[] bytecode = compiler.compileBytecode("mql$test", source);

var str = AsmUtil.prettyPrintEvalMethod(bytecode);
Expand Down
4 changes: 3 additions & 1 deletion src/test/java/net/hollowcube/mql/jit/TestExecution.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import java.lang.invoke.MethodHandles;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestExecution {
Expand Down Expand Up @@ -44,7 +46,7 @@ public void math() {
}

private <T> T compile(@NotNull Class<T> scriptInterface, @NotNull String source) {
var compiler = new MqlCompiler<>(scriptInterface);
var compiler = new MqlCompiler<>(MethodHandles.lookup(), scriptInterface);
Class<T> scriptClass = compiler.compile(source);

try {
Expand Down
6 changes: 4 additions & 2 deletions src/test/java/net/hollowcube/mql/jit/TestRegression.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import java.lang.invoke.MethodHandles;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestRegression {
Expand Down Expand Up @@ -81,15 +83,15 @@ private void parse(String input, String expected) {
}

private void compile(@NotNull Class<?> script, @NotNull String source, @NotNull String expected) {
var compiler = new MqlCompiler<>(script);
var compiler = new MqlCompiler<>(MethodHandles.lookup(), script);
byte[] bytecode = compiler.compileBytecode("mql$test", source);

var str = AsmUtil.prettyPrintEvalMethod(bytecode);
assertEquals(expected, str);
}

private <T> T execute(@NotNull Class<T> scriptInterface, @NotNull String source) {
var compiler = new MqlCompiler<>(scriptInterface);
var compiler = new MqlCompiler<>(MethodHandles.lookup(), scriptInterface);
Class<T> scriptClass = compiler.compile(source);

try {
Expand Down

0 comments on commit f68420b

Please sign in to comment.