8158131: Nashorn should not use jdk.internal.module.Modules API

Reviewed-by: hannesw, mhaupt, alanb
This commit is contained in:
Athijegannathan Sundararajan 2016-05-31 13:04:26 +05:30
parent 4bc1c3af53
commit 4489e7f18c
8 changed files with 452 additions and 81 deletions

View File

@ -39,14 +39,21 @@ import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
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;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.reflect.Field;
import java.lang.reflect.Layer;
import java.lang.reflect.Modifier;
import java.lang.reflect.Module;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
@ -60,9 +67,12 @@ 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;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
@ -128,6 +138,11 @@ public final class Context {
*/
public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection";
/**
* Permission to create a new Module
*/
public static final String NASHORN_CREATE_MODULE = "nashorn.createModule";
/**
* Permission to enable nashorn debug mode.
*/
@ -337,7 +352,7 @@ public final class Context {
return new NamedContextCodeInstaller(context, codeSource, context.createNewLoader());
}
private static final byte[] getAnonymousHostClassBytes() {
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();
@ -486,7 +501,6 @@ public final class Context {
/** Optional class filter to use for Java classes. Can be null. */
private final ClassFilter classFilter;
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
private static final ConcurrentMap<String, Class<?>> structureClasses = new ConcurrentHashMap<>();
@ -508,8 +522,10 @@ public final class Context {
private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt();
private static final AccessControlContext CREATE_LOADER_ACC_CTXT = createPermAccCtxt("createClassLoader");
private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(NASHORN_CREATE_GLOBAL);
private static final AccessControlContext GET_LOADER_ACC_CTXT = createPermAccCtxt("getClassLoader");
static {
final ClassLoader myLoader = Context.class.getClassLoader();
sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
@Override
public StructureLoader run() {
@ -791,7 +807,7 @@ public final class Context {
// Nashorn extension: any 'eval' is unconditionally strict when -strict is specified.
boolean strictFlag = strict || this._strict;
Class<?> clazz = null;
Class<?> clazz;
try {
clazz = compile(source, new ThrowErrorManager(), strictFlag, true);
} catch (final ParserException e) {
@ -1281,6 +1297,78 @@ public final class Context {
return getContextTrusted().dynamicLinker;
}
/**
* Creates a module layer with one module that is defined to the given class
* loader.
*
* @param descriptor the module descriptor for the newly created module
* @param loader the class loader of the module
* @return the new Module
*/
public static Module createModule(final ModuleDescriptor descriptor, final ClassLoader loader) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission(NASHORN_CREATE_MODULE));
}
return createModuleTrusted(descriptor, loader);
}
/**
* Creates a module layer with one module that is defined to the given class
* loader.
*
* @param descriptor the module descriptor for the newly created module
* @param loader the class loader of the module
* @return the new Module
*/
static Module createModuleTrusted(final ModuleDescriptor descriptor, final ClassLoader loader) {
return createModuleTrusted(Layer.boot(), descriptor, loader);
}
/**
* Creates a module layer with one module that is defined to the given class
* loader.
*
* @param parent the parent layer of the new module
* @param descriptor the module descriptor for the newly created module
* @param loader the class loader of the module
* @return the new Module
*/
static Module createModuleTrusted(final Layer parent, final ModuleDescriptor descriptor, final ClassLoader loader) {
final String mn = descriptor.name();
final ModuleReference mref = new ModuleReference(descriptor, null, () -> {
IOException ioe = new IOException("<dynamic module>");
throw new UncheckedIOException(ioe);
});
final ModuleFinder finder = new ModuleFinder() {
@Override
public Optional<ModuleReference> find(String name) {
if (name.equals(mn)) {
return Optional.of(mref);
} else {
return Optional.empty();
}
}
@Override
public Set<ModuleReference> findAll() {
return Set.of(mref);
}
};
final Configuration cf = parent.configuration()
.resolveRequires(finder, ModuleFinder.of(), Set.of(mn));
final PrivilegedAction<Layer> pa = () -> parent.defineModules(cf, name -> loader);
final Layer layer = AccessController.doPrivileged(pa, GET_LOADER_ACC_CTXT);
final Module m = layer.findModule(mn).get();
assert m.getLayer() == layer;
return m;
}
static Context getContextTrustedOrNull() {
final Global global = Context.getGlobal();
return global == null ? null : getContext(global);

View File

@ -26,19 +26,22 @@
package jdk.nashorn.internal.runtime;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Module;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.Permission;
import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.Permissions;
import java.security.SecureClassLoader;
import java.util.HashSet;
import java.util.Set;
import jdk.internal.module.Modules;
/**
* Superclass for Nashorn class loader classes.
@ -55,15 +58,14 @@ abstract class NashornLoader extends SecureClassLoader {
protected static final String RUNTIME_LINKER_PKG_INTERNAL = "jdk/nashorn/internal/runtime/linker";
protected static final String SCRIPTS_PKG_INTERNAL = "jdk/nashorn/internal/scripts";
protected static final Module nashornModule = NashornLoader.class.getModule();
static final Module NASHORN_MODULE = Context.class.getModule();
private static final Permission[] SCRIPT_PERMISSIONS;
private static final Set<String> scriptsPkgSet = new HashSet<>();
private static final String MODULE_MANIPULATOR_NAME = SCRIPTS_PKG + ".ModuleGraphManipulator";
private static final byte[] MODULE_MANIPULATOR_BYTES = readModuleManipulatorBytes();
static {
scriptsPkgSet.add(SCRIPTS_PKG);
/*
* Generated classes get access to runtime, runtime.linker, objects, scripts packages.
* Note that the actual scripts can not access these because Java.type, Packages
@ -80,23 +82,42 @@ abstract class NashornLoader extends SecureClassLoader {
};
}
// addExport Method object on ModuleGraphManipulator
// class loaded by this loader
private Method addModuleExport;
NashornLoader(final ClassLoader parent) {
super(parent);
}
protected static Module defineModule(final String moduleName, final ClassLoader loader) {
return Modules.defineModule(loader, moduleName, scriptsPkgSet);
void loadModuleManipulator() {
final Class<?> clazz = defineClass(MODULE_MANIPULATOR_NAME,
MODULE_MANIPULATOR_BYTES, 0, MODULE_MANIPULATOR_BYTES.length);
// force class initialization so that <clinit> runs!
try {
Class.forName(MODULE_MANIPULATOR_NAME, true, this);
} catch (final Exception ex) {
throw new RuntimeException(ex);
}
final PrivilegedAction<Void> pa = () -> {
try {
addModuleExport = clazz.getDeclaredMethod("addExport", Module.class);
addModuleExport.setAccessible(true);
} catch (final NoSuchMethodException | SecurityException ex) {
throw new RuntimeException(ex);
}
return null;
};
AccessController.doPrivileged(pa);
}
protected static void addReadsModule(final Module from, final Module to) {
Modules.addReads(from, to);
}
protected static void addModuleExports(final Module from, final String pkg, final Module to) {
if (to == null) {
Modules.addExportsToAll(from, pkg);
} else {
Modules.addExports(from, pkg, to);
final void addModuleExport(final Module to) {
try {
addModuleExport.invoke(null, to);
} catch (final IllegalAccessException |
IllegalArgumentException |
InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
@ -194,5 +215,17 @@ abstract class NashornLoader extends SecureClassLoader {
throw new IllegalArgumentException("file");
}
}
private static byte[] readModuleManipulatorBytes() {
final PrivilegedAction<byte[]> pa = () -> {
final String res = "/"+ MODULE_MANIPULATOR_NAME.replace('.', '/') + ".class";
try (InputStream in = NashornLoader.class.getResourceAsStream(res)) {
return in.readAllBytes();
} catch (IOException exp) {
throw new UncheckedIOException(exp);
}
};
return AccessController.doPrivileged(pa);
}
}

View File

@ -25,6 +25,7 @@
package jdk.nashorn.internal.runtime;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Module;
import java.security.CodeSource;
import java.util.Objects;
@ -52,35 +53,43 @@ final class ScriptLoader extends NashornLoader {
this.context = context;
// new scripts module, it's specific exports and read-edges
scriptModule = defineModule("jdk.scripting.nashorn.scripts", this);
addModuleExports(scriptModule, SCRIPTS_PKG, nashornModule);
addReadsModule(scriptModule, nashornModule);
addReadsModule(scriptModule, Object.class.getModule());
scriptModule = createModule("jdk.scripting.nashorn.scripts");
// specific exports from nashorn to new scripts module
nashornModule.addExports(OBJECTS_PKG, scriptModule);
nashornModule.addExports(RUNTIME_PKG, scriptModule);
nashornModule.addExports(RUNTIME_ARRAYS_PKG, scriptModule);
nashornModule.addExports(RUNTIME_LINKER_PKG, scriptModule);
nashornModule.addExports(SCRIPTS_PKG, scriptModule);
NASHORN_MODULE.addExports(OBJECTS_PKG, scriptModule);
NASHORN_MODULE.addExports(RUNTIME_PKG, scriptModule);
NASHORN_MODULE.addExports(RUNTIME_ARRAYS_PKG, scriptModule);
NASHORN_MODULE.addExports(RUNTIME_LINKER_PKG, scriptModule);
NASHORN_MODULE.addExports(SCRIPTS_PKG, scriptModule);
// nashorn needs to read scripts module methods,fields
nashornModule.addReads(scriptModule);
NASHORN_MODULE.addReads(scriptModule);
}
private Module createModule(final String moduleName) {
final Module structMod = context.getSharedLoader().getModule();
final ModuleDescriptor descriptor
= new ModuleDescriptor.Builder(moduleName)
.requires(NASHORN_MODULE.getName())
.requires(structMod.getName())
.conceals(SCRIPTS_PKG)
.build();
final Module mod = Context.createModuleTrusted(structMod.getLayer(), descriptor, this);
loadModuleManipulator();
return mod;
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
checkPackageAccess(name);
if (name.startsWith(NASHORN_PKG_PREFIX)) {
final StructureLoader sharedCl = context.getSharedLoader();
final Class<?> cl = sharedCl.loadClass(name);
if (! structureAccessAdded) {
if (cl.getClassLoader() == sharedCl) {
structureAccessAdded = true;
final Module structModule = sharedCl.getModule();
addModuleExports(structModule, SCRIPTS_PKG, scriptModule);
addReadsModule(scriptModule, structModule);
}
if (!structureAccessAdded && cl.getClassLoader() == sharedCl) {
structureAccessAdded = true;
sharedCl.addModuleExport(scriptModule);
}
return cl;
}

View File

@ -30,6 +30,7 @@ import static jdk.nashorn.internal.codegen.Compiler.binaryName;
import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_DUAL_FIELD_PREFIX;
import static jdk.nashorn.internal.codegen.CompilerConstants.JS_OBJECT_SINGLE_FIELD_PREFIX;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.Module;
import java.security.ProtectionDomain;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
@ -50,17 +51,26 @@ final class StructureLoader extends NashornLoader {
super(parent);
// new structures module, it's exports, read edges
structuresModule = defineModule("jdk.scripting.nashorn.structures", this);
addModuleExports(structuresModule, SCRIPTS_PKG, nashornModule);
addReadsModule(structuresModule, nashornModule);
addReadsModule(structuresModule, Object.class.getModule());
structuresModule = createModule("jdk.scripting.nashorn.structures");
// specific exports from nashorn to the structures module
nashornModule.addExports(SCRIPTS_PKG, structuresModule);
nashornModule.addExports(RUNTIME_PKG, structuresModule);
NASHORN_MODULE.addExports(SCRIPTS_PKG, structuresModule);
NASHORN_MODULE.addExports(RUNTIME_PKG, structuresModule);
// nashorn has to read fields from classes of the new module
nashornModule.addReads(structuresModule);
NASHORN_MODULE.addReads(structuresModule);
}
private Module createModule(final String moduleName) {
final ModuleDescriptor descriptor
= new ModuleDescriptor.Builder(moduleName)
.requires(NASHORN_MODULE.getName())
.conceals(SCRIPTS_PKG)
.build();
final Module mod = Context.createModuleTrusted(descriptor, this);
loadModuleManipulator();
return mod;
}
/**
@ -90,7 +100,7 @@ final class StructureLoader extends NashornLoader {
return isDualFieldStructure(name) || isSingleFieldStructure(name);
}
protected Module getModule() {
Module getModule() {
return structuresModule;
}

View File

@ -31,12 +31,24 @@ import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_VARARGS;
import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.ARRAYLENGTH;
import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.D2F;
import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.GOTO;
import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
import static jdk.internal.org.objectweb.asm.Opcodes.IF_ICMPGE;
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.I2B;
import static jdk.internal.org.objectweb.asm.Opcodes.I2S;
import static jdk.internal.org.objectweb.asm.Opcodes.POP;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
@ -62,6 +74,12 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -69,6 +87,7 @@ import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.commons.InstructionAdapter;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.linker.AdaptationResult.Outcome;
@ -136,6 +155,9 @@ import jdk.internal.reflect.CallerSensitive;
* implemented securely.
*/
final class JavaAdapterBytecodeGenerator {
private static final Module NASHORN_MODULE = Context.class.getModule();
private static final Module JAVA_BASE_MODULE = Object.class.getModule();
// Field names in adapters
private static final String GLOBAL_FIELD_NAME = "global";
private static final String DELEGATE_FIELD_NAME = "delegate";
@ -211,6 +233,17 @@ final class JavaAdapterBytecodeGenerator {
private static final String FINALIZER_DELEGATE_NAME = "$$nashornFinalizerDelegate";
private static final String FINALIZER_DELEGATE_METHOD_DESCRIPTOR = Type.getMethodDescriptor(Type.VOID_TYPE, OBJECT_TYPE);
// adapter class may need module read-edges from other modules.
// We generate a class to add those required module read-edges.
// This is the name of the module read edge adder class.
static final String MODULES_READ_ADDER_INTERNAL = ADAPTER_PACKAGE_INTERNAL + "$ModulesReadAdder";
static final String MODULES_READ_ADDER = MODULES_READ_ADDER_INTERNAL.replace('/', '.');
// module add read method
static final String MODULES_ADD_READS = "addReads";
// .class bytes of module add reader class. Lazily generated and cached.
private static byte[] MODULES_READ_ADDER_BYRES;
/**
* Collection of methods we never override: Object.clone(), Object.finalize().
*/
@ -307,6 +340,21 @@ final class JavaAdapterBytecodeGenerator {
return autoConvertibleFromFunction;
}
static synchronized byte[] getModulesAddReadsBytes() {
if (MODULES_READ_ADDER_BYRES == null) {
// lazily generate module read edge adder class
MODULES_READ_ADDER_BYRES = generateModulesReadAdderClass();
}
return MODULES_READ_ADDER_BYRES;
}
private void addAccessedModule(Module m) {
if (m != null && m != JAVA_BASE_MODULE && m != NASHORN_MODULE) {
accessedModules.add(m);
}
}
private static String getGeneratedClassName(final Class<?> superType, final List<Class<?>> interfaces) {
// The class we use to primarily name our adapter is either the superclass, or if it is Object (meaning we're
// just implementing interfaces or extending Object), then the first implemented interface or Object.
@ -1086,10 +1134,7 @@ final class JavaAdapterBytecodeGenerator {
*/
private void gatherMethods(final Class<?> type) throws AdaptationException {
if (Modifier.isPublic(type.getModifiers())) {
final Module module = type.getModule();
if (module != null) {
accessedModules.add(module);
}
addAccessedModule(type.getModule());
final Method[] typeMethods = type.isInterface() ? type.getMethods() : type.getDeclaredMethods();
@ -1117,16 +1162,12 @@ final class JavaAdapterBytecodeGenerator {
for (final Class<?> pt : typeMethod.getParameterTypes()) {
if (pt.isPrimitive()) continue;
final Module ptMod = pt.getModule();
if (ptMod != null) {
accessedModules.add(ptMod);
}
addAccessedModule(pt.getModule());
}
final Class<?> rt = typeMethod.getReturnType();
if (!rt.isPrimitive()) {
final Module rtMod = rt.getModule();
if (rtMod != null) accessedModules.add(rtMod);
addAccessedModule(rt.getModule());
}
final MethodInfo mi = new MethodInfo(typeMethod);
@ -1211,7 +1252,95 @@ final class JavaAdapterBytecodeGenerator {
return e.isAnnotationPresent(CallerSensitive.class);
}
private static final Call lookupServiceMethod(final String name, final Class<?> rtype, final Class<?>... ptypes) {
private static Call lookupServiceMethod(final String name, final Class<?> rtype, final Class<?>... ptypes) {
return staticCallNoLookup(JavaAdapterServices.class, name, rtype, ptypes);
}
/*
* Generate a class that adds module read edges from adapter module to the
* modules of the reference types used by the generated adapter class.
*/
private static byte[] generateModulesReadAdderClass() {
final ClassWriter cw = new ClassWriter(0);
MethodVisitor mv;
// make the class package private
cw.visit(Opcodes.V1_7, ACC_SUPER | ACC_FINAL, MODULES_READ_ADDER_INTERNAL,
null, "java/lang/Object", null);
// private static final Module MY_MODULE;
{
FieldVisitor fv = cw.visitField(ACC_PRIVATE | ACC_FINAL | ACC_STATIC,
"MY_MODULE", "Ljava/lang/reflect/Module;", null, null);
fv.visitEnd();
}
/*
* private static void addReads(Module[] modules) {
* for (Module m : mods) {
* MY_MODULE.addRead(m);
* }
* }
*/
{
mv = cw.visitMethod(ACC_PRIVATE | ACC_STATIC,
MODULES_ADD_READS,
"([Ljava/lang/reflect/Module;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ASTORE, 1);
mv.visitVarInsn(ALOAD, 1);
mv.visitInsn(ARRAYLENGTH);
mv.visitVarInsn(ISTORE, 2);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, 3);
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitFrame(Opcodes.F_APPEND, 3,
new Object[]{"[Ljava/lang/reflect/Module;",
Opcodes.INTEGER, Opcodes.INTEGER}, 0, null);
mv.visitVarInsn(ILOAD, 3);
mv.visitVarInsn(ILOAD, 2);
Label l1 = new Label();
mv.visitJumpInsn(IF_ICMPGE, l1);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ILOAD, 3);
mv.visitInsn(AALOAD);
mv.visitVarInsn(ASTORE, 4);
mv.visitFieldInsn(GETSTATIC, MODULES_READ_ADDER_INTERNAL,
"MY_MODULE", "Ljava/lang/reflect/Module;");
mv.visitVarInsn(ALOAD, 4);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/reflect/Module",
"addReads", "(Ljava/lang/reflect/Module;)Ljava/lang/reflect/Module;", false);
mv.visitInsn(POP);
mv.visitIincInsn(3, 1);
mv.visitJumpInsn(GOTO, l0);
mv.visitLabel(l1);
mv.visitFrame(Opcodes.F_CHOP, 3, null, 0, null);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 5);
mv.visitEnd();
}
/*
* static {
* MY_MODULE = ThisClass.class.getModule();
* }
*/
{
mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv.visitCode();
mv.visitLdcInsn(Type.getType("L" + MODULES_READ_ADDER_INTERNAL + ";"));
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class",
"getModule", "()Ljava/lang/reflect/Module;", false);
mv.visitFieldInsn(PUTSTATIC, MODULES_READ_ADDER_INTERNAL,
"MY_MODULE", "Ljava/lang/reflect/Module;");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}

View File

@ -25,6 +25,9 @@
package jdk.nashorn.internal.runtime.linker;
import java.lang.module.ModuleDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Module;
import java.security.AccessControlContext;
import java.security.AccessController;
@ -42,7 +45,6 @@ import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.internal.module.Modules;
/**
* This class encapsulates the bytecode of the adapter class and can be used to load it into the JVM as an actual Class.
@ -52,14 +54,12 @@ import jdk.internal.module.Modules;
* class are normally created by {@code JavaAdapterBytecodeGenerator}.
*/
final class JavaAdapterClassLoader {
private static final Module nashornModule = JavaAdapterClassLoader.class.getModule();
private static final Set<String> adapterPkgs = new HashSet<>();
static {
adapterPkgs.add(JavaAdapterBytecodeGenerator.ADAPTER_PACKAGE);
}
private static final Module NASHORN_MODULE = Context.class.getModule();
private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader");
private static final AccessControlContext GET_CONTEXT_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_GET_CONTEXT);
private static final AccessControlContext CREATE_MODULE_ACC_CTXT = ClassAndLoader.createPermAccCtxt(Context.NASHORN_CREATE_MODULE);
private static final Collection<String> VISIBLE_INTERNAL_CLASS_NAMES = Collections.unmodifiableCollection(new HashSet<>(
Arrays.asList(JavaAdapterServices.class.getName(), ScriptObject.class.getName(), ScriptFunction.class.getName(), JSType.class.getName())));
@ -93,12 +93,19 @@ final class JavaAdapterClassLoader {
}, CREATE_LOADER_ACC_CTXT);
}
private static void addExports(final Module from, final String pkg, final Module to) {
if (to == null) {
Modules.addExportsToAll(from, pkg);
} else {
Modules.addExports(from, pkg, to);
}
private static Module createAdapterModule(final ClassLoader loader) {
final ModuleDescriptor descriptor =
new ModuleDescriptor.Builder("jdk.scripting.nashorn.javaadapters")
.requires(NASHORN_MODULE.getName())
.exports(JavaAdapterBytecodeGenerator.ADAPTER_PACKAGE)
.build();
return AccessController.doPrivileged(new PrivilegedAction<Module>() {
@Override
public Module run() {
return Context.createModule(descriptor, loader);
}
}, CREATE_MODULE_ACC_CTXT);
}
// Note that the adapter class is created in the protection domain of the class/interface being
@ -113,23 +120,44 @@ final class JavaAdapterClassLoader {
private final ClassLoader myLoader = getClass().getClassLoader();
// new adapter module
private final Module adapterModule = Modules.defineModule(this, "jdk.scripting.nashorn.javaadapters", adapterPkgs);
private final Module adapterModule = createAdapterModule(this);
{
// new adapter module exports and read-edges
addExports(adapterModule, JavaAdapterBytecodeGenerator.ADAPTER_PACKAGE, null);
Modules.addReads(adapterModule, nashornModule);
Modules.addReads(adapterModule, Object.class.getModule());
for (Module mod : accessedModules) {
Modules.addReads(adapterModule, mod);
// new adapter module read-edges
if (!accessedModules.isEmpty()) {
// There are modules accessed from this adapter. We need to add module-read
// edges to those from the adapter module. We do this by generating a
// package-private class, loading it with this adapter class loader and
// then calling a private static method on it.
final byte[] buf = JavaAdapterBytecodeGenerator.getModulesAddReadsBytes();
final Class<?> addReader = defineClass(
JavaAdapterBytecodeGenerator.MODULES_READ_ADDER, buf, 0, buf.length);
final PrivilegedAction<Method> pa = () -> {
try {
final Method m = addReader.getDeclaredMethod(
JavaAdapterBytecodeGenerator.MODULES_ADD_READS, Module[].class);
m.setAccessible(true);
return m;
} catch (final NoSuchMethodException | SecurityException ex) {
throw new RuntimeException(ex);
}
};
final Method addReads = AccessController.doPrivileged(pa);
try {
addReads.invoke(null, (Object)accessedModules.toArray(new Module[0]));
} catch (final IllegalAccessException | IllegalArgumentException |
InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
// specific exports from nashorn to the new adapter module
nashornModule.addExports("jdk.nashorn.internal.runtime", adapterModule);
nashornModule.addExports("jdk.nashorn.internal.runtime.linker", adapterModule);
NASHORN_MODULE.addExports("jdk.nashorn.internal.runtime", adapterModule);
NASHORN_MODULE.addExports("jdk.nashorn.internal.runtime.linker", adapterModule);
// nashorn should be be able to read methods of classes loaded in adapter module
nashornModule.addReads(adapterModule);
NASHORN_MODULE.addReads(adapterModule);
}
@Override

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.linker;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Modifier;
import jdk.internal.module.Modules;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.StandardOperation;
@ -93,7 +92,6 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
NashornCallSiteDescriptor.getLookupInternal(request.getCallSiteDescriptor());
args[0] = JavaAdapterFactory.getAdapterClassFor(new Class<?>[] { receiverClass }, null, lookup);
Modules.addReads(lookup.lookupClass().getModule(), ((StaticClass)args[0]).getRepresentedClass().getModule());
final LinkRequest adapterRequest = request.replaceArguments(request.getCallSiteDescriptor(), args);
final GuardedInvocation gi = checkNullConstructor(delegate(linkerServices, adapterRequest), receiverClass);
// Finally, modify the guard to test for the original abstract class.

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.scripts;
import java.lang.reflect.Module;
import jdk.nashorn.api.scripting.JSObject;
/**
* Nashorn's StructureLoader and ScriptLoader instances load
* this class in the respective dynamic modules created. This
* class is never loaded by Nashorn's own class loader. The
* .class bytes of this class are loaded as resource by the
* {@link jdk.nashorn.internal.runtime.NashornLoader} class. This class
* exists in this package because nashorn structures and scripts
* modules use this package name for the only exported package
* from those modules.
*
* Note that this class may be dynamically generated at runtime.
* But, this java source is used for ease of reading.
*/
final class ModuleGraphManipulator {
private ModuleGraphManipulator() {}
private static final Module MY_MODULE;
private static final String MY_PKG_NAME;
static {
final Class<?> myClass = ModuleGraphManipulator.class;
MY_MODULE = myClass.getModule();
final String myName = myClass.getName();
MY_PKG_NAME = myName.substring(0, myName.lastIndexOf('.'));
// nashorn's module is the module of the class loader of current class
final Module nashornModule = myClass.getClassLoader().getClass().getModule();
// Make sure this class was not loaded by Nashorn's own loader!
if (MY_MODULE == nashornModule) {
throw new IllegalStateException(myClass + " loaded by wrong loader!");
}
// From this module add a qualified export to nashorn module
MY_MODULE.addExports(MY_PKG_NAME, nashornModule);
}
// The following method is reflectively invoked from Nashorn
// to add required module export edges. Because this package
// itself is qualified exported only to nashorn and this
// method is private, unsafe calls are not possible.
private static void addExport(final Module otherMod) {
MY_MODULE.addExports(MY_PKG_NAME, otherMod);
}
}