Skip to content

Commit

Permalink
ModuleAccess.getEVERYONE_MODULE & getALL_UNNAMED_MODULE
Browse files Browse the repository at this point in the history
  • Loading branch information
Karlatemp committed Jun 13, 2021
1 parent b09501d commit 2e3e9ae
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@
public interface ModuleAccess {
boolean isSupport();

/**
* special Module to mean "everyone"
* <p>
* Only used for {@link #addExports(Object, String, Object)}, {@link #addOpens(Object, String, Object)}
*
* @since 1.6.0
*/
Object getEVERYONE_MODULE();

/**
* special Module to mean "all unnamed modules"
* <p>
* Only used for {@link #addExports(Object, String, Object)}, {@link #addOpens(Object, String, Object)}
*
* @since 1.6.0
*/
Object getALL_UNNAMED_MODULE();

/**
* klass.getModule()
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ public Object getModule(Class<?> klass) {
throw new UnsupportedOperationException();
}

@Override
public Object getEVERYONE_MODULE() {
throw new UnsupportedOperationException();
}

@Override
public Object getALL_UNNAMED_MODULE() {
throw new UnsupportedOperationException();
}

@Override
public Package definePackage(ClassLoader cl, String name, Object module) {
throw new UnsupportedOperationException();
Expand Down Expand Up @@ -83,6 +93,16 @@ public boolean isSupport() {
return false;
}

@Override
public Object getEVERYONE_MODULE() {
return null;
}

@Override
public Object getALL_UNNAMED_MODULE() {
return null;
}

@Override
public Object getModule(Class<?> klass) {
return null;
Expand Down
25 changes: 25 additions & 0 deletions api/src/main/java/io/github/karlatemp/unsafeaccessor/Root.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.util.function.Consumer;

/**
* JVM Root Access.
Expand Down Expand Up @@ -177,4 +178,28 @@ public static ModuleAccess getModuleAccess() {
getUnsafe();
return Secret.MACCESS;
}

static class ObjectInitializer {
static Consumer<Object> initializer;

static Consumer<Object> initializer() {
if (initializer != null) return initializer;
synchronized (ObjectInitializer.class) {
if (initializer != null) return initializer;
initializer = UsfAccessor.allocateObjectInitializer();
}
return initializer;
}
}

/**
* Do nothing
*
* @since 1.6.0
*/
public static void initializeObject(Object instance) {
if (instance == null) return;
Unsafe.getUnsafe0().ensureClassInitialized(instance.getClass());
ObjectInitializer.initializer().accept(instance);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
package io.github.karlatemp.unsafeaccessor;

import java.util.function.Consumer;

// internal
public class UsfAccessor {
static abstract class UsfAccessorSpi {
abstract Object allocateUnsafe();

abstract Consumer<Object> allocateObjectInitializer();
}

static UsfAccessorSpi spi;

static UsfAccessorSpi spi() {
if (spi != null) return spi;
synchronized (UsfAccessorSpi.class) {
if (spi != null) return spi;
try {
// in module :impl.loader
Class<?> impl = Class.forName("io.github.karlatemp.unsafeaccessor.UsfAccessorImpl");
return spi = impl.asSubclass(UsfAccessorSpi.class).getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new UnsupportedOperationException(e);
}
}
}

// Internal service for load Unsafe.
protected static Object allocateUnsafe() {
try {
// in module :impl.loader
Class<?> impl = Class.forName("io.github.karlatemp.unsafeaccessor.UsfAccessorImpl");
return impl.getDeclaredMethod("allocateUnsafe").invoke(null);
} catch (Exception e) {
throw new UnsupportedOperationException(e);
}
return spi().allocateUnsafe();
}

protected static Consumer<Object> allocateObjectInitializer() {
return spi().allocateObjectInitializer();
}
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "A bridge for access jdk.internal.misc.Unsafe"

allprojects {
group 'io.github.karlatemp'
version '1.5.0'
version '1.6.0'
repositories {
mavenCentral()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.github.karlatemp.unsafeaccessor.codegen;

import io.github.karlatemp.unsafeaccessor.CodeGenUtils;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;

import java.util.Base64;

public class GenObjectInitializer {
public static void main(String[] args) throws Throwable {
ClassNode newClass = new ClassNode();
newClass.visit(
Opcodes.V1_8,
0,
"io/github/karlatemp/unsafeaccessor/ObjectInitializerHolder",
null,
"java/lang/Object",
null
);
CodeGenUtils.genCons(newClass);
MethodVisitor code = newClass.visitMethod(Opcodes.ACC_STATIC, "code", "()[B", null, null);
code.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Base64", "getDecoder", "()Ljava/util/Base64$Decoder;", false);
{
ClassNode initializer = new ClassNode();
initializer.visit(
Opcodes.V1_8,
0,
"io/github/karlatemp/unsafeaccessor/ObjectInitializerImpl",
null,
"jdk/internal/reflect/MagicAccessorImpl",
new String[]{"java/util/function/Consumer"}
);
CodeGenUtils.genCons(initializer);
MethodVisitor accept = initializer.visitMethod(Opcodes.ACC_PUBLIC, "accept", "(Ljava/lang/Object;)V", null, null);
accept.visitVarInsn(Opcodes.ALOAD, 0);
accept.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
accept.visitInsn(Opcodes.RETURN);
accept.visitMaxs(2, 2);
byte[] bytecode = CodeGenUtils.toBytecode(initializer);
code.visitLdcInsn(Base64.getEncoder().encodeToString(bytecode));
}
code.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Base64$Decoder", "decode", "(Ljava/lang/String;)[B", false);
code.visitInsn(Opcodes.ARETURN);
code.visitMaxs(3, 3);

CodeGenUtils.save(newClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,28 @@
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;

@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "rawtypes"})
class ModuleAccessImpl$JDK9 implements ModuleAccess {
private static Object EVERYONE_MODULE;
private static Object ALL_UNNAMED_MODULE;
private static final Supplier<UnsafeAccess> SUPPLIER;

private static Object findModule(String name) {
try {
return (Module) SUPPLIER.get().getTrustedIn(Module.class)
.findStaticGetter(Module.class, name, Module.class)
.invoke();
} catch (Throwable throwable) {
return throwable;
}
}

static {
((Consumer<Object>) ModuleAccessImpl$JDK9.class.getClassLoader())
.accept(new ModuleAccessImpl$JDK9());
ClassLoader classLoader = ModuleAccessImpl$JDK9.class.getClassLoader();
SUPPLIER = (Supplier<UnsafeAccess>) ((Supplier) classLoader).get();
((Consumer<Object>) classLoader).accept(new ModuleAccessImpl$JDK9());
}

@Override
Expand All @@ -30,6 +46,26 @@ public Object getModule(Class<?> klass) {
return klass.getModule();
}

@Override
public Object getALL_UNNAMED_MODULE() {
if (ALL_UNNAMED_MODULE == null) {
ALL_UNNAMED_MODULE = findModule("ALL_UNNAMED_MODULE");
}
if (ALL_UNNAMED_MODULE instanceof Throwable)
throw new UnsupportedOperationException((Throwable) ALL_UNNAMED_MODULE);
return ALL_UNNAMED_MODULE;
}

@Override
public Object getEVERYONE_MODULE() {
if (EVERYONE_MODULE == null) {
EVERYONE_MODULE = findModule("EVERYONE_MODULE");
}
if (EVERYONE_MODULE instanceof Throwable)
throw new UnsupportedOperationException((Throwable) EVERYONE_MODULE);
return EVERYONE_MODULE;
}

@Override
public Object newModuleBuilder(
String mn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ JLA, findSS(), findJLMA()
data = replace(data, "Lio/github/karlatemp/unsafeaccessor/ModuleAccessImpl$JDK9;", "L" + targetJvmName + ";");

data = doRemap(data, ACCESS_CLASSES);
env = (Supplier) () -> UnsafeAccess.INSTANCE;

Class.forName(loader.define(data).getName(), true, loader);
Root.Secret.MACCESS = (ModuleAccess) env;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package io.github.karlatemp.unsafeaccessor;

class UsfAccessorImpl {
static Object allocateUnsafe() throws Exception {
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

@SuppressWarnings("unchecked")
class UsfAccessorImpl extends UsfAccessor.UsfAccessorSpi {
Object allocateUnsafe() {
try {
Class.forName("java.lang.Module");
Root.Secret.MACCESS = new ModuleAccessImpl.PendingInit();
Expand All @@ -16,4 +22,50 @@ static Object allocateUnsafe() throws Exception {
return new SunMiscUnsafeImpl();
}
}

static Class<?> findC(ClassLoader cl, String... names) {
List<Throwable> throwables = new ArrayList<>();
for (String n : names) {
try {
return Class.forName(n, false, cl);
} catch (ClassNotFoundException e) {
throwables.add(e);
}
}
NoClassDefFoundError error = new NoClassDefFoundError();
for (Throwable t : throwables) error.addSuppressed(t);
throw error;
}

@Override
Consumer<Object> allocateObjectInitializer() {
byte[] code = ObjectInitializerHolder.code();
Class<?> MagicAccessorImpl = findC(
null,
"jdk.internal.reflect.MagicAccessorImpl",
"sun.reflect.MagicAccessorImpl"
);
Class<? extends ClassLoader> DelegatingClassLoader = findC(
null,
"jdk.internal.reflect.DelegatingClassLoader",
"sun.reflect.DelegatingClassLoader"
).asSubclass(ClassLoader.class);
if (!MagicAccessorImpl.getName().equals("jdk.internal.reflect.MagicAccessorImpl")) {
code = BytecodeUtil.replace(code,
"jdk/internal/reflect/MagicAccessorImpl",
MagicAccessorImpl.getName().replace('.', '/')
);
}
try {
Constructor<? extends ClassLoader> constructor = DelegatingClassLoader.getDeclaredConstructor(ClassLoader.class);
Root.OpenAccess.openAccess0(constructor, true);
ClassLoader delegate = constructor.newInstance(ClassLoader.getSystemClassLoader());
Class<?> klass = Unsafe.getUnsafe0().defineClass(null, code, 0, code.length, delegate, null);
Constructor<?> constructor1 = klass.getDeclaredConstructor();
Root.OpenAccess.openAccess0(constructor1, true);
return (Consumer<Object>) constructor1.newInstance();
} catch (Exception e) {
throw new UnsupportedOperationException(e);
}
}
}
Loading

0 comments on commit 2e3e9ae

Please sign in to comment.