--- old/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java 2020-04-15 18:50:58.000000000 +0530 +++ /dev/null 2020-04-15 18:50:58.000000000 +0530 @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2010, 2013, 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.runtime.linker; - -import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; - -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.Permissions; -import java.security.PrivilegedAction; -import java.security.ProtectionDomain; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - * A tuple of a class loader and a single class representative of the classes that can be loaded through it. Its - * equals/hashCode is defined in terms of the identity of the class loader. The rationale for this class is that it - * couples a class loader with a random representative class coming from that loader - this representative class is then - * used to determine if one loader can see the other loader's classes. - */ -final class ClassAndLoader { - static AccessControlContext createPermAccCtxt(final String... permNames) { - final Permissions perms = new Permissions(); - for (final String permName : permNames) { - perms.add(new RuntimePermission(permName)); - } - return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); - } - - private static final AccessControlContext GET_LOADER_ACC_CTXT = createPermAccCtxt("getClassLoader"); - - private final Class representativeClass; - // Don't access this directly; most of the time, use getRetrievedLoader(), or if you know what you're doing, - // getLoader(). - private ClassLoader loader; - // We have mild affinity against eagerly retrieving the loader, as we need to do it in a privileged block. For - // the most basic case of looking up an already-generated adapter info for a single type, we avoid it. - private boolean loaderRetrieved; - - ClassAndLoader(final Class representativeClass, final boolean retrieveLoader) { - this.representativeClass = representativeClass; - if(retrieveLoader) { - retrieveLoader(); - } - } - - Class getRepresentativeClass() { - return representativeClass; - } - - boolean canSee(final ClassAndLoader other) { - try { - final Class otherClass = other.getRepresentativeClass(); - return Class.forName(otherClass.getName(), false, getLoader()) == otherClass; - } catch (final ClassNotFoundException e) { - return false; - } - } - - ClassLoader getLoader() { - if(!loaderRetrieved) { - retrieveLoader(); - } - return getRetrievedLoader(); - } - - ClassLoader getRetrievedLoader() { - assert loaderRetrieved; - return loader; - } - - private void retrieveLoader() { - loader = representativeClass.getClassLoader(); - loaderRetrieved = true; - } - - @Override - public boolean equals(final Object obj) { - return obj instanceof ClassAndLoader && ((ClassAndLoader)obj).getRetrievedLoader() == getRetrievedLoader(); - } - - @Override - public int hashCode() { - return System.identityHashCode(getRetrievedLoader()); - } - - /** - * Given a list of types that define the superclass/interfaces for an adapter class, returns a single type from the - * list that will be used to attach the adapter to its ClassValue. The first type in the array that is defined in a - * class loader that can also see all other types is returned. If there is no such loader, an exception is thrown. - * @param types the input types - * @return the first type from the array that is defined in a class loader that can also see all other types. - */ - static ClassAndLoader getDefiningClassAndLoader(final Class[] types) { - // Short circuit the cheap case - if(types.length == 1) { - return new ClassAndLoader(types[0], false); - } - - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ClassAndLoader run() { - return getDefiningClassAndLoaderPrivileged(types); - } - }, GET_LOADER_ACC_CTXT); - } - - static ClassAndLoader getDefiningClassAndLoaderPrivileged(final Class[] types) { - final Collection maximumVisibilityLoaders = getMaximumVisibilityLoaders(types); - - final Iterator it = maximumVisibilityLoaders.iterator(); - if(maximumVisibilityLoaders.size() == 1) { - // Fortunate case - single maximally specific class loader; return its representative class. - return it.next(); - } - - // Ambiguity; throw an error. - assert maximumVisibilityLoaders.size() > 1; // basically, can't be zero - final StringBuilder b = new StringBuilder(); - b.append(it.next().getRepresentativeClass().getCanonicalName()); - while(it.hasNext()) { - b.append(", ").append(it.next().getRepresentativeClass().getCanonicalName()); - } - throw typeError("extend.ambiguous.defining.class", b.toString()); - } - - /** - * Given an array of types, return a subset of their class loaders that are maximal according to the - * "can see other loaders' classes" relation, which is presumed to be a partial ordering. - * @param types types - * @return a collection of maximum visibility class loaders. It is guaranteed to have at least one element. - */ - private static Collection getMaximumVisibilityLoaders(final Class[] types) { - final List maximumVisibilityLoaders = new LinkedList<>(); - outer: for(final ClassAndLoader maxCandidate: getClassLoadersForTypes(types)) { - final Iterator it = maximumVisibilityLoaders.iterator(); - while(it.hasNext()) { - final ClassAndLoader existingMax = it.next(); - final boolean candidateSeesExisting = maxCandidate.canSee(existingMax); - final boolean exitingSeesCandidate = existingMax.canSee(maxCandidate); - if(candidateSeesExisting) { - if(!exitingSeesCandidate) { - // The candidate sees the the existing maximum, so drop the existing one as it's no longer maximal. - it.remove(); - } - // NOTE: there's also the anomalous case where both loaders see each other. Not sure what to do - // about that one, as two distinct class loaders both seeing each other's classes is weird and - // violates the assumption that the relation "sees others' classes" is a partial ordering. We'll - // just not do anything, and treat them as incomparable; hopefully some later class loader that - // comes along can eliminate both of them, if it can not, we'll end up with ambiguity anyway and - // throw an error at the end. - } else if(exitingSeesCandidate) { - // Existing sees the candidate, so drop the candidate. - continue outer; - } - } - // If we get here, no existing maximum visibility loader could see the candidate, so the candidate is a new - // maximum. - maximumVisibilityLoaders.add(maxCandidate); - } - return maximumVisibilityLoaders; - } - - private static Collection getClassLoadersForTypes(final Class[] types) { - final Map classesAndLoaders = new LinkedHashMap<>(); - for(final Class c: types) { - final ClassAndLoader cl = new ClassAndLoader(c, true); - if(!classesAndLoaders.containsKey(cl)) { - classesAndLoaders.put(cl, cl); - } - } - return classesAndLoaders.keySet(); - } -}