8139919: Make CallSiteDescriptor a concrete class
Reviewed-by: hannesw, lagergren, sundar
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/DynamicLinker.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/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/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornLinker.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornStaticClassLinker.java Wed Oct 21 10:41:54 2015 +0200
+++ b/nashorn/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.