8139919: Make CallSiteDescriptor a concrete class

Reviewed-by: hannesw, lagergren, sundar
This commit is contained in:
Attila Szegedi 2015-10-21 10:42:20 +02:00
parent b49c5c8b09
commit df445c6578
13 changed files with 197 additions and 533 deletions

View File

@ -89,30 +89,42 @@ import java.lang.invoke.MethodType;
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,
@ -145,68 +157,139 @@ public interface CallSiteDescriptor {
*/
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 @@ public interface CallSiteDescriptor {
* {@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();
@ -229,29 +312,6 @@ public interface CallSiteDescriptor {
return Arrays.asList(tokens);
}
/**
* 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
@ -263,7 +323,7 @@ public interface CallSiteDescriptor {
* @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 @@ public interface CallSiteDescriptor {
}
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();
}
}

View File

@ -96,7 +96,6 @@ import jdk.internal.dynalink.linker.LinkerServices;
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 @@ import jdk.internal.dynalink.support.SimpleRelinkableCallSite;
* }
*
* 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 @@ import jdk.internal.dynalink.support.SimpleRelinkableCallSite;
* <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>
*/

View File

@ -107,7 +107,7 @@ import jdk.internal.dynalink.linker.support.Lookup;
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

View File

@ -232,8 +232,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
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>() {

View File

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

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -128,7 +128,7 @@ public class ScriptFunction extends ScriptObject {
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;

View File

@ -96,7 +96,7 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
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

View File

@ -109,7 +109,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
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,

View File

@ -34,7 +34,6 @@ import java.security.PrivilegedAction;
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 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* 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 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<
};
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 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<
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 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<
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 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<
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 @@ public final class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor<
}
@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);
}
}

View File

@ -67,7 +67,7 @@ import jdk.nashorn.internal.runtime.Undefined;
*/
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

View File

@ -82,7 +82,7 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
// 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.