From ddd2344009e3f1f38c2242355adc4378b4fd3fb0 Mon Sep 17 00:00:00 2001 From: Michael Pfaff Date: Sat, 10 Aug 2024 15:07:54 -0400 Subject: [PATCH] Introduce an API exposing some OpenJDK internals --- .../dev/pfaff/jdk/JavaInternalAccess.java | 90 +++++++++++++++++++ .../internal/access/JavaLangInvokeAccess.java | 9 ++ src/java.base/share/classes/module-info.java | 2 + 3 files changed, 101 insertions(+) create mode 100644 src/java.base/share/classes/dev/pfaff/jdk/JavaInternalAccess.java diff --git a/src/java.base/share/classes/dev/pfaff/jdk/JavaInternalAccess.java b/src/java.base/share/classes/dev/pfaff/jdk/JavaInternalAccess.java new file mode 100644 index 0000000000000..f55653686153b --- /dev/null +++ b/src/java.base/share/classes/dev/pfaff/jdk/JavaInternalAccess.java @@ -0,0 +1,90 @@ +package dev.pfaff.jdk; + +import jdk.internal.access.SharedSecrets; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.CallerSensitiveAdapter; +import jdk.internal.reflect.Reflection; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.lang.invoke.MethodHandles.Lookup; + +/** + * Provides access to internal OpenJDK APIs. + */ +public final class JavaInternalAccess { + @Stable + private static volatile boolean RESTRICTED; + + private static final JavaInternalAccess INSTANCE = new JavaInternalAccess(); + + private JavaInternalAccess() {} + + /** + * @return the instance + * @throws SecurityException if access has been restricted by a call to {@link #restrictAccess()} + */ + public static JavaInternalAccess getInstance() { + if (RESTRICTED) { + throw new SecurityException("Access is restricted"); + } + return INSTANCE; + } + + /** + * Restricts access to {@link JavaInternalAccess} by blocking future calls to {@link #getInstance()}. + */ + public void restrictAccess() { + if (!RESTRICTED) RESTRICTED = true; + } + + /** + * Creates a new {@link Lookup lookup object} with trusted access, which + * reports the specified class as its {@link Lookup#lookupClass() lookupClass}. + * + * @return the new {@link Lookup lookup object} + */ + @CallerSensitive + @ForceInline // to ensure Reflection.getCallerClass optimization + public Lookup trustedLookup() { + final Class c = Reflection.getCallerClass(); + if (c == null) { + throw new IllegalCallerException("no caller frame"); + } + return SharedSecrets.getJavaLangInvokeAccess().makeTrustedLookup(c); + } + + // Caller-sensitive adapter method for reflective invocation + @CallerSensitiveAdapter + private Lookup trustedLookup(Class caller) { + if (caller.getClassLoader() == null) { + throw new InternalError("calling trustedLookup() reflectively is not supported: "+caller); + } + return SharedSecrets.getJavaLangInvokeAccess().makeTrustedLookup(caller); + } + + /** + * Updates module m1 to export a package to module m2. If m1 already + * exports or opens the package to m2, this operation has no effect. + * + * @param m1 the module to update + * @param pkg the package to export or open + * @param m2 the module export or open to + */ + public void addExports(Module m1, String pkg, Module m2) { + SharedSecrets.getJavaLangAccess().addExports(m1, pkg, m2); + } + + /** + * Updates module m1 to open a package to module m2. If m1 already opens + * the package to m2, this operation has no effect. If m1 already exports + * the package to m2, the export will be promoted to an open. + * + * @param m1 the module to update + * @param pkg the package to export or open + * @param m2 the module export or open to + */ + public void addOpens(Module m1, String pkg, Module m2) { + SharedSecrets.getJavaLangAccess().addOpens(m1, pkg, m2); + } +} diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java index 563870381febf..aa767c8fbe3e2 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java @@ -170,4 +170,13 @@ public interface JavaLangInvokeAccess { * This method should only be used by ReflectionFactory::newConstructorForSerialization. */ MethodHandle serializableConstructor(Class decl, Constructor ctorToCall) throws IllegalAccessException; + + /** + * Creates a new {@link Lookup lookup object} with trusted access, which + * reports the specified class as its {@link Lookup#lookupClass() lookupClass}. + * + * @param lookupClass lookup class + * @return the new {@link Lookup lookup object} + */ + Lookup makeTrustedLookup(Class lookupClass); } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 52c1029dd3d52..e4da43881742a 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -374,6 +374,8 @@ exports sun.util.resources to jdk.localedata; + exports dev.pfaff.jdk; + // the service types defined by the APIs in this module uses java.lang.System.LoggerFinder;