changeset 1479:d35aa8beb997

8139919: Make CallSiteDescriptor a concrete class Reviewed-by: hannesw, lagergren, sundar
author attila
date Wed, 21 Oct 2015 10:42:20 +0200
parents e6bb9489faac
children 7cb19fa78763
files src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleCallSiteDescriptor.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java
diffstat 13 files changed, 197 insertions(+), 533 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java	Wed Oct 21 10:42:20 2015 +0200
@@ -89,30 +89,42 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.StringTokenizer;
 import jdk.internal.dynalink.support.NameCodec;
 
 /**
- * Interface for objects containing the information necessary for linking a call
- * site. This information is normally passed as parameters to bootstrap methods
- * and consists of the {@code MethodHandles.Lookup} object on the caller class
- * in which the call site occurs, the method name mentioned in the call site,
- * and the method type of the call site. {@code CallSiteDescriptor} objects are
- * used in Dynalink to capture and store these parameters for subsequent use by
- * the {@link DynamicLinker}.
+ * Call site descriptors contain all the information necessary for linking a
+ * call site. This information is normally passed as parameters to bootstrap
+ * methods and consists of the {@code MethodHandles.Lookup} object on the caller
+ * class in which the call site occurs, the method name mentioned in the call
+ * site, and the method type of the call site. {@code CallSiteDescriptor}
+ * objects are used in Dynalink to capture and store these parameters for
+ * subsequent use by the {@link DynamicLinker}.
  * <p>
  * The constructors of built-in {@link RelinkableCallSite} implementations all
  * take a call site descriptor.
  * <p>
- * Call site descriptors must be immutable.
+ * Call site descriptors must be immutable. You can use this class as-is or you
+ * can subclass it, especially if you need to add further information to the
+ * descriptors (typically, values passed in additional parameters to the
+ * bootstrap method) or want to cache results of name tokenization. Since the
+ * descriptors must be immutable, you can set up a cache for equivalent
+ * descriptors to have the call sites share them.
  */
-public interface CallSiteDescriptor {
+public class CallSiteDescriptor {
+    private final MethodHandles.Lookup lookup;
+    private final String name;
+    private final MethodType methodType;
+
     /**
-     * A runtime permission to invoke the {@link #getLookup()} method. It is
-     * named {@code "dynalink.getLookup"}.
+     * The name of a runtime permission to invoke the {@link #getLookup()}
+     * method.
      */
-    public static final RuntimePermission GET_LOOKUP_PERMISSION =
-            new RuntimePermission("dynalink.getLookup");
+    public static final String GET_LOOKUP_PERMISSION_NAME = "dynalink.getLookup";
+
+    private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(GET_LOOKUP_PERMISSION_NAME);
 
     /**
      * The index of the name token that will carry the operation scheme prefix,
@@ -146,67 +158,138 @@
     public static final String OPERATOR_DELIMITER = "|";
 
     /**
+     * Creates a new call site descriptor.
+     * @param lookup the lookup object describing the class the call site belongs to.
+     * @param name the name of the method at the call site.
+     * @param methodType the method type of the call site.
+     */
+    public CallSiteDescriptor(final Lookup lookup, final String name, final MethodType methodType) {
+        this.lookup = Objects.requireNonNull(lookup, "lookup");
+        this.name = Objects.requireNonNull(name, "name");
+        this.methodType = Objects.requireNonNull(methodType, "methodType");
+    }
+
+    /**
      * Returns the number of tokens in the name of the method at the call site.
      * Method names are tokenized with the {@link #TOKEN_DELIMITER} character
      * character, e.g. {@code "dyn:getProp:color"} would be the name used to
      * describe a method that retrieves the property named "color" on the object
-     * it is invoked on.
+     * it is invoked on. This method will count the tokens in the name on every
+     * invocation. Subclasses can override this method with a more efficient
+     * implementation that caches the tokens.
      * @return the number of tokens in the name of the method at the call site.
      */
-    public int getNameTokenCount();
+    public int getNameTokenCount() {
+        return getNameTokenizer().countTokens();
+    }
 
     /**
      * Returns the <i>i<sup>th</sup></i> token in the method name at the call
      * site. Method names are tokenized with the {@link #TOKEN_DELIMITER}
-     * character.
+     * character. This method will tokenize the name on every invocation.
+     * Subclasses can override this method with a more efficient implementation
+     * that caches the tokens.
      * @param i the index of the token. Must be between 0 (inclusive) and
      * {@link #getNameTokenCount()} (exclusive).
-     * @throws IllegalArgumentException if the index is outside the allowed
+     * @throws NoSuchElementException if the index is outside the allowed
      * range.
      * @return the <i>i<sup>th</sup></i> token in the method name at the call
      * site.
      */
-    public String getNameToken(int i);
+    public String getNameToken(final int i) {
+        final StringTokenizer tok = getNameTokenizer();
+        for (int j = 0; j < i; ++j) {
+            tok.nextToken();
+        }
+        final String token = tok.nextToken();
+        return (i > 1 ? NameCodec.decode(token) : token).intern();
+    }
+
+    private StringTokenizer getNameTokenizer() {
+        return getNameTokenizer(name);
+    }
+
+    private static StringTokenizer getNameTokenizer(final String name) {
+        return new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
+    }
 
     /**
      * Returns the full (untokenized) name of the method at the call site.
      * @return the full (untokenized) name of the method at the call site.
      */
-    public String getName();
+    public final String getName() {
+        return name;
+    }
 
     /**
      * The type of the method at the call site.
      *
      * @return type of the method at the call site.
      */
-    public MethodType getMethodType();
+    public final MethodType getMethodType() {
+        return methodType;
+    }
 
     /**
      * Returns the lookup that should be used to find method handles to set as
      * targets of the call site described by this descriptor. When creating
      * descriptors from a {@link java.lang.invoke} bootstrap method, it should
-     * be the lookup passed to the bootstrap. An implementation should use
-     * {@link #checkLookup(MethodHandles.Lookup)} to ensure the necessary
-     * security properties.
+     * be the lookup passed to the bootstrap.
      * @return the lookup that should be used to find method handles to set as
      * targets of the call site described by this descriptor.
      * @throws SecurityException if the lookup isn't the
      * {@link MethodHandles#publicLookup()} and a security manager is present,
-     * and a check for {@code RuntimePermission("dynalink.getLookup")}
-     * (a canonical instance of which is available as
-     * {@link #GET_LOOKUP_PERMISSION}) fails.
+     * and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
      */
-    public Lookup getLookup();
+    public final Lookup getLookup() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null && lookup != MethodHandles.publicLookup()) {
+            sm.checkPermission(GET_LOOKUP_PERMISSION);
+        }
+        return lookup;
+    }
+
+    /**
+     * Returns the value of {@link #getLookup()} without a security check. Can
+     * be used by subclasses to access the lookup quickly.
+     * @return same as returned value of {@link #getLookup()}.
+     */
+    protected final Lookup getLookupPrivileged() {
+        return lookup;
+    }
 
     /**
      * Creates a new call site descriptor from this descriptor, which is
-     * identical to this, except it changes the method type.
+     * identical to this, except it changes the method type. Subclasses must
+     * override the
      *
      * @param newMethodType the new method type
      * @return a new call site descriptor, with the method type changed.
      */
-    public CallSiteDescriptor changeMethodType(MethodType newMethodType);
+    public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
+        final CallSiteDescriptor changed = Objects.requireNonNull(
+                changeMethodTypeInternal(newMethodType),
+                "changeMethodTypeInternal() must not return null.");
 
+        if (getClass() != changed.getClass()) {
+            throw new RuntimeException(
+                    "changeMethodTypeInternal() must return an object of the same class it is invoked on.");
+        }
+
+        return changed;
+    }
+
+    /**
+     * Creates a new call site descriptor from this descriptor, which is
+     * identical to this, except it changes the method type. Subclasses must
+     * override this method to return an object of their exact class.
+     *
+     * @param newMethodType the new method type
+     * @return a new call site descriptor, with the method type changed.
+     */
+    protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
+        return new CallSiteDescriptor(lookup, name, newMethodType);
+    }
 
     /**
      * Tokenizes a composite operation name of this descriptor along
@@ -215,7 +298,7 @@
      * {@code ["getElem", "getProp", "getMethod"]}.
      * @return a list of operator tokens.
      */
-    public default List<String> tokenizeOperators() {
+    public final List<String> tokenizeOperators() {
         final String ops = getNameToken(CallSiteDescriptor.OPERATOR);
         final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
         final int count = tok.countTokens();
@@ -230,29 +313,6 @@
     }
 
     /**
-     * Checks if the current access context is granted the
-     * {@code RuntimePermission("dynalink.getLookup")} permission, if the
-     * system contains a security manager, and the passed lookup is not the
-     * {@link MethodHandles#publicLookup()}. This method should be used in all
-     * implementations of {@link #getLookup()} method to ensure that only
-     * code with permission can retrieve the lookup object.
-     * @param lookup the lookup being checked for access
-     * @return the passed in lookup if there's either no security manager in
-     * the system, or the passed lookup is the public lookup, or the current
-     * access context is granted the relevant permission.
-     * @throws SecurityException if the system contains a security manager, and
-     * the passed lookup is not the public lookup, and the current access
-     * context is not granted the relevant permission.
-     */
-    public static Lookup checkLookup(final Lookup lookup) {
-        final SecurityManager sm = System.getSecurityManager();
-        if (sm != null && lookup != MethodHandles.publicLookup()) {
-            sm.checkPermission(GET_LOOKUP_PERMISSION);
-        }
-        return lookup;
-    }
-
-    /**
      * Tokenizes the composite name along {@link #TOKEN_DELIMITER} characters,
      * as well as {@link NameCodec#decode(String) demangles} and interns the
      * tokens. The first two tokens are not demangled as they are supposed to
@@ -263,7 +323,7 @@
      * @return an array of unmangled, interned tokens.
      */
     public static String[] tokenizeName(final String name) {
-        final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
+        final StringTokenizer tok = getNameTokenizer(name);
         final String[] tokens = new String[tok.countTokens()];
         for(int i = 0; i < tokens.length; ++i) {
             String token = tok.nextToken();
@@ -274,4 +334,60 @@
         }
         return tokens;
     }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        } else if (obj == null) {
+            return false;
+        } else if (obj.getClass() != getClass()) {
+            return false;
+        }
+        final CallSiteDescriptor other = (CallSiteDescriptor)obj;
+        return name.equals(other.name) && methodType.equals(other.methodType) &&
+                lookupsEqual(lookup, other.lookup);
+    }
+
+    /**
+     * Compares two lookup objects for value-based equality. They are considered
+     * equal if they have the same
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}.
+     * @param l1 first lookup
+     * @param l2 second lookup
+     * @return true if the two lookups are equal, false otherwise.
+     */
+    private static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
+        return l1.lookupClass() == l2.lookupClass() && l1.lookupModes() == l2.lookupModes();
+    }
+
+    @Override
+    public int hashCode() {
+        return name.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(lookup);
+    }
+
+    /**
+     * Returns a value-based hash code for the passed lookup object. It is
+     * based on the lookup object's
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()} values.
+     * @param lookup the lookup object.
+     * @return a hash code for the object..
+     */
+    protected static int lookupHashCode(final Lookup lookup) {
+        return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
+    }
+
+    /**
+     * Returns the string representation of this call site descriptor, of the
+     * format {@code name(parameterTypes)returnType@lookup}.
+     */
+    @Override
+    public String toString() {
+        final String mt = methodType.toString();
+        final String l = lookup.toString();
+        final StringBuilder b = new StringBuilder(name.length() + mt.length() + 1 + l.length());
+        return b.append(name).append(mt).append("@").append(l).toString();
+    }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java	Wed Oct 21 10:42:20 2015 +0200
@@ -96,7 +96,6 @@
 import jdk.internal.dynalink.linker.support.Lookup;
 import jdk.internal.dynalink.linker.support.SimpleLinkRequest;
 import jdk.internal.dynalink.support.ChainedCallSite;
-import jdk.internal.dynalink.support.SimpleCallSiteDescriptor;
 import jdk.internal.dynalink.support.SimpleRelinkableCallSite;
 
 /**
@@ -124,7 +123,7 @@
  *     }
  *
  *     public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
- *         return dynamicLinker.link(new SimpleRelinkableCallSite(new SimpleCallSiteDescriptor(lookup, name, type)));
+ *         return dynamicLinker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(lookup, name, type)));
  *     }
  * }
  * </pre>
@@ -153,12 +152,7 @@
  * <li>You also need to provide {@link CallSiteDescriptor}s to your call sites.
  * They are immutable objects that contain all the information about the call
  * site: the class performing the lookups, the name of the method being invoked,
- * and the method signature. The library provides a
- * {@link SimpleCallSiteDescriptor}, or you can create your own descriptor
- * classes, especially if you need to add further information to them
- * (typically, values passed in additional parameters to the bootstrap method).
- * Since they are specified to be immutable, you can set up a cache for
- * equivalent descriptors to have the call sites share them.</li>
+ * and the method signature.</li>
  *
  * </ul>
  */
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Wed Oct 21 10:42:20 2015 +0200
@@ -107,7 +107,7 @@
 class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
     private static final AccessControlContext GET_LOOKUP_CONTEXT =
             AccessControlContextFactory.createAccessControlContext(
-                    CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+                    CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
 
     // Typed as "AccessibleObject" as it can be either a method or a constructor.
     // If we were Java8-only, we could use java.lang.reflect.Executable
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Wed Oct 21 10:42:20 2015 +0200
@@ -232,8 +232,7 @@
 
     private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT =
             AccessControlContextFactory.createAccessControlContext(
-                    new RuntimePermission("getClassLoader"),
-                    CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+                    "getClassLoader", CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
 
     private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) {
         return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java	Wed Oct 21 10:42:20 2015 +0200
@@ -145,7 +145,7 @@
  *     public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
  *         return dynamicLinker.link(
  *             new SimpleRelinkableCallSite(
- *                 new SimpleCallSiteDescriptor(lookup, name, type)));
+ *                 new CallSiteDescriptor(lookup, name, type)));
  *     }
  * }
  * </pre>
@@ -166,9 +166,7 @@
  * are two implementations already provided by the library.</li>
  * <li>Finally, Dynalink uses {@link jdk.internal.dynalink.CallSiteDescriptor} objects to
  * preserve the parameters to the bootstrap method as it will need them whenever
- * it needs to relink a call site. Again,
- * {@link jdk.internal.dynalink.support.SimpleCallSiteDescriptor} is a simple
- * implementation already provided by the library.</li>
+ * it needs to relink a call site.</li>
  * </ul>
  * <p>What can you already do with the above setup? {@code DynamicLinkerFactory}
  * by default creates a {@code DynamicLinker} that can link Java objects with the
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Wed Oct 21 10:41:54 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file, and Oracle licenses the original version of this file under the BSD
- * license:
- */
-/*
-   Copyright 2009-2013 Attila Szegedi
-
-   Licensed under both the Apache License, Version 2.0 (the "Apache License")
-   and the BSD License (the "BSD License"), with licensee being free to
-   choose either of the two at their discretion.
-
-   You may not use this file except in compliance with either the Apache
-   License or the BSD License.
-
-   If you choose to use this file in compliance with the Apache License, the
-   following notice applies to you:
-
-       You may obtain a copy of the Apache License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing, software
-       distributed under the License is distributed on an "AS IS" BASIS,
-       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-       implied. See the License for the specific language governing
-       permissions and limitations under the License.
-
-   If you choose to use this file in compliance with the BSD License, the
-   following notice applies to you:
-
-       Redistribution and use in source and binary forms, with or without
-       modification, are permitted provided that the following conditions are
-       met:
-       * Redistributions of source code must retain the above copyright
-         notice, this list of conditions and the following disclaimer.
-       * Redistributions in binary form must reproduce the above copyright
-         notice, this list of conditions and the following disclaimer in the
-         documentation and/or other materials provided with the distribution.
-       * Neither the name of the copyright holder nor the names of
-         contributors may be used to endorse or promote products derived from
-         this software without specific prior written permission.
-
-       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package jdk.internal.dynalink.support;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.util.Objects;
-import jdk.internal.dynalink.CallSiteDescriptor;
-
-/**
- * A base class for call site descriptor implementations. Provides
- * reconstruction of the name from the tokens, as well as generally useful
- * {@code equals}, {@code hashCode}, and {@code toString} methods. In order to
- * both prevent unprivileged access to its internal {@link MethodHandles.Lookup}
- * object, and at the same time not force privileged access to it from
- * {@code equals}, {@code hashCode}, and {@code toString} methods, subclasses
- * must implement {@link #lookupEquals(AbstractCallSiteDescriptor)},
- * {@link #lookupHashCode()} and {@link #lookupToString()} methods.
- * Additionally, {@link #equalsInKind(AbstractCallSiteDescriptor)} should be
- * overridden instead of {@link #equals(Object)} to compare descriptors in
- * subclasses; it is only necessary if they have implementation-specific
- * properties other than the standard name, type, and lookup.
- * @param <T> The call site descriptor subclass
- */
-public abstract class AbstractCallSiteDescriptor<T extends AbstractCallSiteDescriptor<T>> implements CallSiteDescriptor {
-
-    @Override
-    public String getName() {
-        return appendName(new StringBuilder(getNameLength())).toString();
-    }
-
-    /**
-     * Checks if this call site descriptor is equality to another object. It is
-     * considered equal iff and only if they belong to the exact same class, and
-     * have the same name, method type, and lookup. Subclasses with additional
-     * properties should override
-     * {@link #equalsInKind(AbstractCallSiteDescriptor)} instead of this method.
-     * @param obj the object checked for equality
-     * @return true if they are equal, false otherwise
-     */
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean equals(final Object obj) {
-        return obj != null && obj.getClass() == getClass() && equalsInKind((T)obj);
-    }
-
-    /**
-     * Returns true if this call site descriptor is equal to the passed,
-     * non-null call site descriptor of the same class.
-     * @param csd the other call site descriptor.
-     * @return true if they are equal.
-     */
-    protected boolean equalsInKind(final T csd) {
-        if(csd == this) {
-            return true;
-        }
-        final int ntc = getNameTokenCount();
-        if(ntc != csd.getNameTokenCount()) {
-            return false;
-        }
-        for(int i = ntc; i-- > 0;) { // Reverse order as variability is higher at the end
-            if(!Objects.equals(getNameToken(i), csd.getNameToken(i))) {
-                return false;
-            }
-        }
-        if(!getMethodType().equals(csd.getMethodType())) {
-            return false;
-        }
-        return lookupEquals(csd);
-    }
-
-    /**
-     * Returns true if this call site descriptor's lookup is equal to the other
-     * call site descriptor's lookup. Typical implementation should try to
-     * obtain the other lookup directly without going through privileged
-     * {@link #getLookup()} (e.g. by reading the field as the type system
-     * enforces that they are of the same class) and then delegate to
-     * {@link #lookupsEqual(MethodHandles.Lookup, MethodHandles.Lookup)}.
-     * @param other the other lookup
-     * @return true if the lookups are equal
-     */
-    protected abstract boolean lookupEquals(T other);
-
-    /**
-     * Compares two lookup objects for value-based equality. They are considered
-     * equal if they have the same
-     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
-     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}.
-     * @param l1 first lookup
-     * @param l2 second lookup
-     * @return true if the two lookups are equal, false otherwise.
-     */
-    protected static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
-        if(l1 == l2) {
-            return true;
-        } else if (l1 == null || l2 == null) {
-            return false;
-        } else if(l1.lookupClass() != l2.lookupClass()) {
-            return false;
-        }
-        return l1.lookupModes() == l2.lookupModes();
-    }
-
-    @Override
-    public int hashCode() {
-        int h = lookupHashCode();
-        final int c = getNameTokenCount();
-        for(int i = 0; i < c; ++i) {
-            h = h * 31 + getNameToken(i).hashCode();
-        }
-        return h * 31 + getMethodType().hashCode();
-    }
-
-    /**
-     * Return the hash code of this call site descriptor's {@link Lookup}
-     * object. Typical implementation should delegate to
-     * {@link #lookupHashCode(MethodHandles.Lookup)}.
-     * @return the hash code of this call site descriptor's {@link Lookup}
-     * object.
-     */
-    protected abstract int lookupHashCode();
-
-    /**
-     * Returns a value-based hash code for the passed lookup object. It is
-     * based on the lookup object's
-     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
-     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()} values.
-     * @param lookup the lookup object.
-     * @return a hash code for the object. Returns 0 for null.
-     */
-    protected static int lookupHashCode(final Lookup lookup) {
-        return lookup != null ? lookup.lookupClass().hashCode() + 31 * lookup.lookupModes() : 0;
-    }
-
-    @Override
-    public String toString() {
-        final String mt = getMethodType().toString();
-        final String l = lookupToString();
-        final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength());
-        return appendName(b).append(mt).append("@").append(l).toString();
-    }
-
-    /**
-     * Return a string representation of this call site descriptor's
-     * {@link Lookup} object. Typically will return
-     * {@link java.lang.invoke.MethodHandles.Lookup#toString()}.
-     * @return a string representation of this call site descriptor's
-     * {@link Lookup} object.
-     */
-    protected abstract String lookupToString();
-
-    private int getNameLength() {
-        final int c = getNameTokenCount();
-        int l = 0;
-        for(int i = 0; i < c; ++i) {
-            l += getNameToken(i).length();
-        }
-        return l +  c - 1;
-    }
-
-    private StringBuilder appendName(final StringBuilder b) {
-        b.append(getNameToken(0));
-        final int c = getNameTokenCount();
-        for(int i = 1; i < c; ++i) {
-            b.append(':').append(getNameToken(i));
-        }
-        return b;
-    }
-}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/SimpleCallSiteDescriptor.java	Wed Oct 21 10:41:54 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file, and Oracle licenses the original version of this file under the BSD
- * license:
- */
-/*
-   Copyright 2015 Attila Szegedi
-
-   Licensed under both the Apache License, Version 2.0 (the "Apache License")
-   and the BSD License (the "BSD License"), with licensee being free to
-   choose either of the two at their discretion.
-
-   You may not use this file except in compliance with either the Apache
-   License or the BSD License.
-
-   If you choose to use this file in compliance with the Apache License, the
-   following notice applies to you:
-
-       You may obtain a copy of the Apache License at
-
-           http://www.apache.org/licenses/LICENSE-2.0
-
-       Unless required by applicable law or agreed to in writing, software
-       distributed under the License is distributed on an "AS IS" BASIS,
-       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-       implied. See the License for the specific language governing
-       permissions and limitations under the License.
-
-   If you choose to use this file in compliance with the BSD License, the
-   following notice applies to you:
-
-       Redistribution and use in source and binary forms, with or without
-       modification, are permitted provided that the following conditions are
-       met:
-       * Redistributions of source code must retain the above copyright
-         notice, this list of conditions and the following disclaimer.
-       * Redistributions in binary form must reproduce the above copyright
-         notice, this list of conditions and the following disclaimer in the
-         documentation and/or other materials provided with the distribution.
-       * Neither the name of the copyright holder nor the names of
-         contributors may be used to endorse or promote products derived from
-         this software without specific prior written permission.
-
-       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
-       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
-       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-package jdk.internal.dynalink.support;
-
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
-import java.util.Objects;
-import jdk.internal.dynalink.CallSiteDescriptor;
-
-/**
- * A simple implementation of the call site descriptor. It stores the lookup, the name, and the method type.
-  * Even if you roll your own implementation of {@link CallSiteDescriptor}, you might want to use
-  * {@link CallSiteDescriptor#checkLookup(MethodHandles.Lookup)} as a ready-made utility method to ensure you're handing
-  * out lookup objects securely.
- */
-public class SimpleCallSiteDescriptor extends AbstractCallSiteDescriptor<SimpleCallSiteDescriptor> {
-    private final Lookup lookup;
-    private final String[] tokenizedName;
-    private final MethodType methodType;
-
-    /**
-     * Creates a new simple call site descriptor.
-     * @param lookup the lookup at the call site, as passed to the bootstrap method. Must not be null.
-     * @param name the name of the operation at the call site, as passed to the bootstrap method. Must not be null.
-     * @param methodType the signature of operation at the call site, as passed to the bootstrap method. Must not be null.
-     */
-    public SimpleCallSiteDescriptor(final Lookup lookup, final String name, final MethodType methodType) {
-        this(Objects.requireNonNull(lookup, "lookup"),
-                CallSiteDescriptor.tokenizeName(Objects.requireNonNull(name, "name")),
-                Objects.requireNonNull(methodType, "methodType"));
-    }
-
-    private SimpleCallSiteDescriptor(final Lookup lookup, final String[] tokenizedName, final MethodType methodType) {
-        this.lookup = lookup;
-        this.tokenizedName = tokenizedName;
-        this.methodType = methodType;
-    }
-
-    @Override
-    public int getNameTokenCount() {
-        return tokenizedName.length;
-    }
-
-    @Override
-    public String getNameToken(final int i) {
-        try {
-            return tokenizedName[i];
-        } catch(final ArrayIndexOutOfBoundsException e) {
-            throw new IllegalArgumentException(e.getMessage());
-        }
-    }
-
-    @Override
-    public MethodType getMethodType() {
-        return methodType;
-    }
-
-    @Override
-    public final Lookup getLookup() {
-        return CallSiteDescriptor.checkLookup(lookup);
-    }
-
-    @Override
-    public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
-        return new SimpleCallSiteDescriptor(lookup, tokenizedName, newMethodType);
-    }
-
-    @Override
-    protected boolean lookupEquals(final SimpleCallSiteDescriptor other) {
-        return AbstractCallSiteDescriptor.lookupsEqual(lookup, other.lookup);
-    }
-
-    @Override
-    protected int lookupHashCode() {
-        return AbstractCallSiteDescriptor.lookupHashCode(lookup);
-    }
-
-    @Override
-    protected String lookupToString() {
-        return lookup.toString();
-    }
-}
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Oct 21 10:42:20 2015 +0200
@@ -128,7 +128,7 @@
     private static final Object LAZY_PROTOTYPE = new Object();
 
     private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
-            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
 
     private static PropertyMap createStrictModeMap(final PropertyMap map) {
         final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java	Wed Oct 21 10:42:20 2015 +0200
@@ -96,7 +96,7 @@
                 CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;
 
         final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(
-                NashornCallSiteDescriptor.getLookupPrivileged(descriptor), opName,
+                NashornCallSiteDescriptor.getLookupInternal(descriptor), opName,
                 type.changeParameterType(0, adapterClass), 0);
 
         // Delegate to BeansLinker
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Wed Oct 21 10:42:20 2015 +0200
@@ -109,7 +109,7 @@
                 final MethodType callType = desc.getMethodType();
                 // drop callee (Undefined ScriptFunction) and change the request to be dyn:callMethod:<name>
                 final NashornCallSiteDescriptor newDesc = NashornCallSiteDescriptor.get(
-                        NashornCallSiteDescriptor.getLookupPrivileged(desc), "dyn:callMethod:" + name,
+                        NashornCallSiteDescriptor.getLookupInternal(desc), "dyn:callMethod:" + name,
                         desc.getMethodType().dropParameterTypes(1, 2),
                         NashornCallSiteDescriptor.getFlags(desc));
                 final GuardedInvocation gi = getGuardedInvocation(beansLinker,
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Oct 21 10:42:20 2015 +0200
@@ -34,7 +34,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import jdk.internal.dynalink.CallSiteDescriptor;
-import jdk.internal.dynalink.support.AbstractCallSiteDescriptor;
 import jdk.nashorn.internal.ir.debug.NashornTextifier;
 import jdk.nashorn.internal.runtime.AccessControlContextFactory;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
@@ -44,7 +43,7 @@
  * we can have a more compact representation, as we know that we're always only using {@code "dyn:*"} operations; also
  * we're storing flags in an additional primitive field.
  */
-public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<NashornCallSiteDescriptor> {
+public final class NashornCallSiteDescriptor extends CallSiteDescriptor {
     /** Flags that the call site references a scope variable (it's an identifier reference or a var declaration, not a
      * property access expression. */
     public static final int CALLSITE_SCOPE         = 1 << 0;
@@ -109,12 +108,10 @@
     };
 
     private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
-            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
 
-    private final MethodHandles.Lookup lookup;
     private final String operator;
     private final String operand;
-    private final MethodType methodType;
     private final int flags;
 
     /**
@@ -161,12 +158,12 @@
         assert "dyn".equals(tokenizedName[0]);
         assert tokenizedName[1] != null;
         // TODO: see if we can move mangling/unmangling into Dynalink
-        return get(lookup, tokenizedName[1], tokenizedName.length == 3 ? tokenizedName[2].intern() : null,
+        return get(lookup, name, tokenizedName[1], tokenizedName.length == 3 ? tokenizedName[2].intern() : null,
                 methodType, flags);
     }
 
-    private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String operator, final String operand, final MethodType methodType, final int flags) {
-        final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operator, operand, methodType, flags);
+    private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name, final String operator, final String operand, final MethodType methodType, final int flags) {
+        final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, name, operator, operand, methodType, flags);
         // Many of these call site descriptors are identical (e.g. every getter for a property color will be
         // "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them.
         final ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
@@ -174,12 +171,11 @@
         return canonical != null ? canonical : csd;
     }
 
-    private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final String operator, final String operand,
+    private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final String name, final String operator, final String operand,
             final MethodType methodType, final int flags) {
-        this.lookup = lookup;
+        super(lookup, name, methodType);
         this.operator = operator;
         this.operand = operand;
-        this.methodType = methodType;
         this.flags = flags;
     }
 
@@ -197,34 +193,25 @@
             if(operand != null) {
                 return operand;
             }
-            break;
-        default:
-            break;
         }
         throw new IndexOutOfBoundsException(String.valueOf(i));
     }
 
-    @Override
-    public Lookup getLookup() {
-        return CallSiteDescriptor.checkLookup(lookup);
-    }
-
-    static Lookup getLookupPrivileged(final CallSiteDescriptor csd) {
+    static Lookup getLookupInternal(final CallSiteDescriptor csd) {
         if (csd instanceof NashornCallSiteDescriptor) {
-            return ((NashornCallSiteDescriptor)csd).lookup;
+            return ((NashornCallSiteDescriptor)csd).getLookupPrivileged();
         }
-        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->csd.getLookup(),
-                GET_LOOKUP_PERMISSION_CONTEXT);
+        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->csd.getLookup(), GET_LOOKUP_PERMISSION_CONTEXT);
     }
 
     @Override
-    protected boolean equalsInKind(final NashornCallSiteDescriptor csd) {
-        return super.equalsInKind(csd) && flags == csd.flags;
+    public boolean equals(final Object obj) {
+        return super.equals(obj) && flags == ((NashornCallSiteDescriptor)obj).flags;
     }
 
     @Override
-    public MethodType getMethodType() {
-        return methodType;
+    public int hashCode() {
+        return super.hashCode() ^ flags;
     }
 
     /**
@@ -458,23 +445,7 @@
     }
 
     @Override
-    public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
-        return get(lookup, operator, operand, newMethodType, flags);
-    }
-
-
-    @Override
-    protected boolean lookupEquals(final NashornCallSiteDescriptor other) {
-        return AbstractCallSiteDescriptor.lookupsEqual(lookup, other.lookup);
-    }
-
-    @Override
-    protected int lookupHashCode() {
-        return AbstractCallSiteDescriptor.lookupHashCode(lookup);
-    }
-
-    @Override
-    protected String lookupToString() {
-        return lookup.toString();
+    public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
+        return get(getLookupPrivileged(), getName(), operator, operand, newMethodType, flags);
     }
 }
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java	Wed Oct 21 10:42:20 2015 +0200
@@ -67,7 +67,7 @@
  */
 final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
     private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
-            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION);
+            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
 
     private static final ClassValue<MethodHandle> ARRAY_CONVERTERS = new ClassValue<MethodHandle>() {
         @Override
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java	Wed Oct 21 10:41:54 2015 +0200
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java	Wed Oct 21 10:42:20 2015 +0200
@@ -82,7 +82,7 @@
                 // Change this link request into a link request on the adapter class.
                 final Object[] args = request.getArguments();
                 args[0] = JavaAdapterFactory.getAdapterClassFor(new Class<?>[] { receiverClass }, null,
-                        NashornCallSiteDescriptor.getLookupPrivileged(request.getCallSiteDescriptor()));
+                        NashornCallSiteDescriptor.getLookupInternal(request.getCallSiteDescriptor()));
                 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.