< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java

Print this page
rev 58565 : 8238358: Implementation of JEP 371: Hidden Classes
Reviewed-by: duke
Contributed-by: mandy.chung@oracle.com, lois.foltan@oracle.com, david.holmes@oracle.com, harold.seigel@oracle.com, serguei.spitsyn@oracle.com, alex.buckley@oracle.com, jamsheed.c.m@oracle.com

*** 23,33 **** * questions. */ package jdk.nashorn.internal.runtime; ! import static jdk.internal.org.objectweb.asm.Opcodes.V1_7; import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION; import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore; --- 23,33 ---- * questions. */ package jdk.nashorn.internal.runtime; ! import static jdk.internal.org.objectweb.asm.Opcodes.*; import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; import static jdk.nashorn.internal.codegen.CompilerConstants.CREATE_PROGRAM_FUNCTION; import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
*** 39,48 **** --- 39,49 ---- import java.io.InputStream; import java.io.IOException; import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; + import java.lang.invoke.MethodHandles.Lookup.ClassOption; import java.lang.invoke.MethodType; import java.lang.invoke.SwitchPoint; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.module.Configuration;
*** 65,75 **** import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.util.Collection; import java.util.HashMap; - import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; --- 66,75 ----
*** 82,95 **** import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.script.ScriptEngine; import jdk.dynalink.DynamicLinker; import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassWriter; ! import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ClassFilter; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.WeakValueCache; import jdk.nashorn.internal.codegen.Compiler; --- 82,97 ---- import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.script.ScriptEngine; + import jdk.dynalink.DynamicLinker; import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.ClassWriter; ! import jdk.internal.org.objectweb.asm.FieldVisitor; ! import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ClassFilter; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.WeakValueCache; import jdk.nashorn.internal.codegen.Compiler;
*** 106,116 **** import jdk.nashorn.internal.runtime.logging.DebugLogger; import jdk.nashorn.internal.runtime.logging.Loggable; import jdk.nashorn.internal.runtime.logging.Logger; import jdk.nashorn.internal.runtime.options.LoggingOption.LoggerInfo; import jdk.nashorn.internal.runtime.options.Options; - import jdk.internal.misc.Unsafe; /** * This class manages the global state of execution. Context is immutable. */ public final class Context { --- 108,117 ----
*** 316,340 **** } private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>(); private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller { - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static final String ANONYMOUS_HOST_CLASS_NAME = Compiler.SCRIPTS_PACKAGE.replace('/', '.') + ".AnonymousHost"; private static final byte[] ANONYMOUS_HOST_CLASS_BYTES = getAnonymousHostClassBytes(); ! private final Class<?> hostClass; private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource, final Class<?> hostClass) { super(context, codeSource); ! this.hostClass = hostClass; } @Override public Class<?> install(final String className, final byte[] bytecode) { ANONYMOUS_INSTALLED_SCRIPT_COUNT.increment(); ! return UNSAFE.defineAnonymousClass(hostClass, bytecode, null); } @Override public CodeInstaller getOnDemandCompilationInstaller() { // This code loader can be indefinitely reused for on-demand recompilations for the same code source. --- 317,380 ---- } private final WeakValueCache<CodeSource, Class<?>> anonymousHostClasses = new WeakValueCache<>(); private static final class AnonymousContextCodeInstaller extends ContextCodeInstaller { private static final String ANONYMOUS_HOST_CLASS_NAME = Compiler.SCRIPTS_PACKAGE.replace('/', '.') + ".AnonymousHost"; private static final byte[] ANONYMOUS_HOST_CLASS_BYTES = getAnonymousHostClassBytes(); ! private final MethodHandles.Lookup hostLookup; private AnonymousContextCodeInstaller(final Context context, final CodeSource codeSource, final Class<?> hostClass) { super(context, codeSource); ! this.hostLookup = (MethodHandles.Lookup)staticFieldValue(hostClass, "LOOKUP"); ! } ! ! private static Object staticFieldValue(Class<?> c, String name) { ! try { ! return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() { ! @Override ! public Object run() throws Exception { ! Field f = c.getDeclaredField(name); ! return f.get(null); ! } ! }); ! } catch (PrivilegedActionException e) { ! throw new InternalError(e.getCause()); ! } } @Override public Class<?> install(final String className, final byte[] bytecode) { + try { ANONYMOUS_INSTALLED_SCRIPT_COUNT.increment(); ! // Workaround: define it as a hidden nestmate so that the hostLookup can find private members ! return hostLookup.defineHiddenClass(bytecode, true, ClassOption.NESTMATE).lookupClass(); ! } catch (IllegalAccessException e) { ! throw new InternalError(e); ! } ! } ! ! @Override ! public void initialize(final Collection<Class<?>> classes, final Source source, final Object[] constants) { ! AccessController.doPrivileged(new PrivilegedAction<Void>() { ! @Override ! public Void run() { ! for (final Class<?> clazz : classes) { ! try { ! //use reflection to write source and constants table to installed classes ! MethodHandle sourceField = hostLookup.findStaticSetter(clazz, SOURCE.symbolName(), Source.class); ! sourceField.invokeExact(source); ! MethodHandle constantsField = hostLookup.findStaticSetter(clazz, CONSTANTS.symbolName(), Object[].class); ! constantsField.invokeExact(constants); ! } catch (Throwable e) { ! throw new RuntimeException(e); ! } ! } ! return null; ! } ! }); } @Override public CodeInstaller getOnDemandCompilationInstaller() { // This code loader can be indefinitely reused for on-demand recompilations for the same code source.
*** 348,359 **** // produces named classes. return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader()); } private static byte[] getAnonymousHostClassBytes() { final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ! cw.visit(V1_7, Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT, ANONYMOUS_HOST_CLASS_NAME.replace('.', '/'), null, "java/lang/Object", null); cw.visitEnd(); return cw.toByteArray(); } } --- 388,418 ---- // produces named classes. return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader()); } private static byte[] getAnonymousHostClassBytes() { + // Workaround: define a host class in a non-exported package. + // This should be replaced when there is a mechanism to define + // a hidden class in a given package of a given module. final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); ! final String cn = ANONYMOUS_HOST_CLASS_NAME.replace('.', '/'); ! cw.visit(V13, ACC_PUBLIC|ACC_INTERFACE |ACC_ABSTRACT, cn, null, "java/lang/Object", null); ! { ! FieldVisitor fv = cw.visitField(ACC_PUBLIC|ACC_STATIC|ACC_FINAL, "LOOKUP", ! "Ljava/lang/invoke/MethodHandles$Lookup;", null, null); ! fv.visitEnd(); ! } ! { ! MethodVisitor mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); ! mv.visitCode(); ! mv.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", ! "()Ljava/lang/invoke/MethodHandles$Lookup;", false); ! mv.visitFieldInsn(PUTSTATIC, cn, "LOOKUP", "Ljava/lang/invoke/MethodHandles$Lookup;"); ! mv.visitInsn(RETURN); ! mv.visitMaxs(0, 0); ! mv.visitEnd(); ! } cw.visitEnd(); return cw.toByteArray(); } }
< prev index next >