< 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 >