This commit is contained in:
Lana Steuck 2015-10-22 11:12:39 -07:00
commit 3e9bab356e
116 changed files with 3958 additions and 3798 deletions

View File

@ -51,7 +51,11 @@ import javax.tools.ToolProvider;
*/
final class PackagesHelper {
// JavaCompiler may be null on certain platforms (eg. JRE)
private static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
private static final JavaCompiler compiler;
static {
// Use javac only if security manager is not around!
compiler = System.getSecurityManager() == null? ToolProvider.getSystemJavaCompiler() : null;
}
/**
* Is Java package properties helper available?

View File

@ -83,92 +83,205 @@
package jdk.internal.dynalink;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import java.util.Objects;
/**
* An immutable descriptor of a call site. It is an immutable object that contains all the information about a call
* site: the class performing the lookups, the name of the method being invoked, and the method signature. The library
* has a default {@link CallSiteDescriptorFactory} for descriptors that you can use, or you can create your own
* descriptor classes, especially if you need to add further information (values passed in additional parameters to the
* bootstrap method) to them. Call site descriptors are used in this library in place of passing a real call site to
* guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in
* {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site
* descriptors consider using {@link CallSiteDescriptorFactory#tokenizeName(String)} in your implementation.
* 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 dynamic operation at 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. 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. 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 {
/**
* The index of the name token that will carry the operation scheme prefix (usually, "dyn").
*/
public static final int SCHEME = 0;
/**
* The index of the name token that will usually carry the operation name.
*/
public static final int OPERATOR=1;
/**
* The index of the name token that will usually carry a name of an operand (of a property, method, etc.)
*/
public static final int NAME_OPERAND=2;
public class CallSiteDescriptor {
private final MethodHandles.Lookup lookup;
private final Operation operation;
private final MethodType methodType;
/**
* Character used to delimit tokens in an call site name.
* The name of a runtime permission to invoke the {@link #getLookup()}
* method.
*/
public static final String TOKEN_DELIMITER = ":";
public static final String GET_LOOKUP_PERMISSION_NAME = "dynalink.getLookup";
private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(GET_LOOKUP_PERMISSION_NAME);
/**
* Character used to delimit operation names in a composite operation specification.
* Creates a new call site descriptor.
* @param lookup the lookup object describing the class the call site belongs to.
* @param operation the dynamic operation at the call site.
* @param methodType the method type of the call site.
*/
public static final String OPERATOR_DELIMITER = "|";
public CallSiteDescriptor(final Lookup lookup, final Operation operation, final MethodType methodType) {
this.lookup = Objects.requireNonNull(lookup, "lookup");
this.operation = Objects.requireNonNull(operation, "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
* colon ":" character, i.e. "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.
* @return the number of tokens in the name of the method at the call site.
* Returns the operation at the call site.
* @return the operation at the call site.
*/
public int getNameTokenCount();
/**
* Returns the <i>i<sup>th</sup></i> token in the method name at the call site. Method names are tokenized with the
* colon ":" character.
* @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 range.
* @return the <i>i<sup>th</sup></i> token in the method name at the call site. The returned strings are interned.
*/
public String getNameToken(int i);
/**
* Returns the name of the method at the call site. Note that the object internally only stores the tokenized name,
* and has to reconstruct the full name from tokens on each invocation.
* @return the name of the method at the call site.
*/
public String getName();
public final Operation getOperation() {
return operation;
}
/**
* 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 passed to the bootstrap method. If the lookup isn't the public lookup, the
* implementation must check the {@code RuntimePermission("dynalink.getLookup")} permission if a security
* manager is present.
* @return the lookup passed to the bootstrap method.
* 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.
* @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")} 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;
}
/**
* Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method
* type.
* 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. Invokes
* {@link #changeMethodTypeInternal(MethodType)} and checks that it returns
* a descriptor of the same class as this descriptor.
*
* @param newMethodType the new method type
* @return a new call site descriptor, with the method type changed.
* @throws RuntimeException if {@link #changeMethodTypeInternal(MethodType)}
* returned a descriptor of different class than this object.
* @throws NullPointerException if {@link #changeMethodTypeInternal(MethodType)}
* returned null.
*/
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.
*/
public CallSiteDescriptor changeMethodType(MethodType newMethodType);
protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
return new CallSiteDescriptor(lookup, operation, newMethodType);
}
/**
* Returns true if this call site descriptor is equal to the passed object.
* It is considered equal if the other object is of the exact same class,
* their operations and method types are equal, and their lookups have the
* same {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
* {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}.
*/
@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 operation.equals(other.operation) &&
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();
}
/**
* Returns a value-based hash code of this call site descriptor computed
* from its operation, method type, and lookup object's lookup class and
* lookup modes.
* @return value-based hash code for this call site descriptor.
*/
@Override
public int hashCode() {
return operation.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..
*/
private 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 String o = operation.toString();
final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length());
return b.append(o).append(mt).append('@').append(l).toString();
}
}

View File

@ -81,16 +81,19 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
/**
* A dual map that can either strongly or weakly reference a given class depending on whether the class is visible from
@ -98,7 +101,10 @@ import java.util.concurrent.ConcurrentMap;
*
* @param <T> the type of the values in the map
*/
public abstract class ClassMap<T> {
abstract class ClassMap<T> {
private static final AccessControlContext GET_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext("getClassLoader");
private final ConcurrentMap<Class<?>, T> map = new ConcurrentHashMap<>();
private final Map<Class<?>, Reference<T>> weakMap = new WeakHashMap<>();
private final ClassLoader classLoader;
@ -109,7 +115,7 @@ public abstract class ClassMap<T> {
*
* @param classLoader the classloader that determines strong referenceability.
*/
protected ClassMap(final ClassLoader classLoader) {
ClassMap(final ClassLoader classLoader) {
this.classLoader = classLoader;
}
@ -120,7 +126,7 @@ public abstract class ClassMap<T> {
* @param clazz the class to compute the value for
* @return the return value. Must not be null.
*/
protected abstract T computeValue(Class<?> clazz);
abstract T computeValue(Class<?> clazz);
/**
* Returns the value associated with the class
@ -128,7 +134,7 @@ public abstract class ClassMap<T> {
* @param clazz the class
* @return the value associated with the class
*/
public T get(final Class<?> clazz) {
T get(final Class<?> clazz) {
// Check in fastest first - objects we're allowed to strongly reference
final T v = map.get(clazz);
if(v != null) {
@ -149,15 +155,15 @@ public abstract class ClassMap<T> {
final T newV = computeValue(clazz);
assert newV != null;
final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
final Boolean canReferenceDirectly = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public ClassLoader run() {
return clazz.getClassLoader();
public Boolean run() {
return InternalTypeUtilities.canReferenceDirectly(classLoader, clazz.getClassLoader());
}
}, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
}, GET_CLASS_LOADER_CONTEXT);
// If allowed to strongly reference, put it in the fast map
if(Guards.canReferenceDirectly(classLoader, clazzLoader)) {
if(canReferenceDirectly) {
final T oldV = map.putIfAbsent(clazz, newV);
return oldV != null ? oldV : newV;
}

View File

@ -0,0 +1,297 @@
/*
* 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;
import java.util.Arrays;
import java.util.Objects;
/**
* Describes an operation that is composed of at least two other operations. The
* component operations are treated as alternatives to each other in order of
* preference. The semantics of the composite operation is "first successful".
* That is, a composite of {@code GET_PROPERTY|GET_ELEMENT:color} should be
* interpreted as <i>get the property named "color" on the object, but if the
* property does not exist, then get the collection element named "color"
* instead</i>.
* <p>
* Composite operations are helpful in implementation of languages that
* don't distinguish between one or more of the property, method, and element
* namespaces, or when expressing operations against objects that can be
* considered both ordinary objects and collections, e.g. Java
* {@link java.util.Map} objects. A composite operation
* {@code GET_PROPERTY|GET_ELEMENT:empty} against a Java map will always match
* the {@link java.util.Map#isEmpty()} property, but
* {@code GET_ELEMENT|GET_PROPERTY:empty} will actually match a map element with
* key {@code "empty"} if the map contains that key, and only fall back to the
* {@code isEmpty()} property getter if the map does not contain the key. If
* the source language mandates this semantics, it can be easily achieved using
* composite operations.
* <p>
* Even if the language itself doesn't distinguish between some of the
* namespaces, it can be helpful to map different syntaxes to different
* compositions. E.g. the source expression {@code obj.color} could map to
* {@code GET_PROPERTY|GET_ELEMENT|GET_METHOD:color}, but a different source
* expression that looks like collection element access {@code obj[key]} could
* be expressed instead as {@code GET_ELEMENT|GET_PROPERTY|GET_METHOD}.
* Finally, if the retrieved value is subsequently called, then it makes sense
* to bring {@code GET_METHOD} to the front of the list: the getter part of the
* source expression {@code obj.color()} should be
* {@code GET_METHOD|GET_PROPERTY|GET_ELEMENT:color} and the one for
* {@code obj[key]()} should be {@code GET_METHOD|GET_ELEMENT|GET_PROPERTY}.
* <p>
* The elements of a composite operation can not be composites or named
* operations, but rather simple operations such are elements of
* {@link StandardOperation}. A composite operation itself can serve as the base
* operation of a named operation, though; a typical way to construct e.g. the
* {@code GET_ELEMENT|GET_PROPERTY:empty} from above would be:
* <pre>
* Operation getElementOrPropertyEmpty = new NamedOperation(
* new CompositeOperation(
* StandardOperation.GET_ELEMENT,
* StandardOperation.GET_PROPERTY),
* "empty");
* </pre>
* <p>
* Not all compositions make sense. Typically, any combination in any order of
* standard getter operations {@code GET_PROPERTY}, {@code GET_ELEMENT}, and
* {@code GET_METHOD} make sense, as do combinations of {@code SET_PROPERTY} and
* {@code SET_ELEMENT}; other standard operations should not be combined. The
* constructor will allow any combination of operations, though.
*/
public class CompositeOperation implements Operation {
private final Operation[] operations;
/**
* Constructs a new composite operation.
* @param operations the components for this composite operation. The passed
* array will be cloned.
* @throws IllegalArgumentException if less than two components are
* specified, or any component is itself a {@link CompositeOperation} or a
* {@link NamedOperation}.
* @throws NullPointerException if either the operations array or any of its
* elements are {@code null}.
*/
public CompositeOperation(final Operation... operations) {
Objects.requireNonNull(operations, "operations array is null");
if (operations.length < 2) {
throw new IllegalArgumentException("Must have at least two operations");
}
final Operation[] clonedOps = operations.clone();
for(int i = 0; i < clonedOps.length; ++i) {
final Operation op = clonedOps[i];
if (op == null) {
throw new NullPointerException("operations[" + i + "] is null");
} else if (op instanceof NamedOperation) {
throw new IllegalArgumentException("operations[" + i + "] is a NamedOperation");
} else if (op instanceof CompositeOperation) {
throw new IllegalArgumentException("operations[" + i + "] is a CompositeOperation");
}
}
this.operations = clonedOps;
}
/**
* Returns the component operations in this composite operation. The
* returned array is a copy and changes to it don't have effect on this
* object.
* @return the component operations in this composite operation.
*/
public Operation[] getOperations() {
return operations.clone();
}
/**
* Returns the number of component operations in this composite operation.
* @return the number of component operations in this composite operation.
*/
public int getOperationCount() {
return operations.length;
}
/**
* Returns the i-th component operation in this composite operation.
* @param i the operation index
* @return the i-th component operation in this composite operation.
* @throws IndexOutOfBoundsException if the index is out of range.
*/
public Operation getOperation(final int i) {
try {
return operations[i];
} catch (final ArrayIndexOutOfBoundsException e) {
throw new IndexOutOfBoundsException(Integer.toString(i));
}
}
/**
* Returns true if this composite operation contains an operation equal to
* the specified operation.
* @param operation the operation being searched for. Must not be null.
* @return true if the if this composite operation contains an operation
* equal to the specified operation.
*/
public boolean contains(final Operation operation) {
Objects.requireNonNull(operation);
for(final Operation component: operations) {
if (component.equals(operation)) {
return true;
}
}
return false;
}
/**
* Returns true if the other object is also a composite operation and their
* component operations are equal.
* @param obj the object to compare to
* @return true if this object is equal to the other one, false otherwise.
*/
@Override
public boolean equals(final Object obj) {
if (obj == null || obj.getClass() != CompositeOperation.class) {
return false;
}
return Arrays.equals(operations, ((CompositeOperation)obj).operations);
}
/**
* Returns the hash code of this composite operation. Defined to be equal
* to {@code java.util.Arrays.hashCode(operations)}.
*/
@Override
public int hashCode() {
return Arrays.hashCode(operations);
};
/**
* Returns the string representation of this composite operation. Defined to
* be the {@code toString} of its component operations, each separated by
* the vertical line character (e.g. {@code "GET_PROPERTY|GET_ELEMENT"}).
* @return the string representation of this composite operation.
*/
@Override
public String toString() {
final StringBuilder b = new StringBuilder();
b.append(operations[0]);
for(int i = 1; i < operations.length; ++i) {
b.append('|').append(operations[i]);
}
return b.toString();
}
/**
* Returns the components of the passed operation if it is a composite
* operation, otherwise returns an array containing the operation itself.
* This allows for returning an array of component even if it is not known
* whether the operation is itself a composite (treating a non-composite
* operation as if it were a single-element composite of itself).
* @param op the operation whose components are retrieved.
* @return if the passed operation is a composite operation, returns its
* {@link #getOperations()}, otherwise returns the operation itself.
*/
public static Operation[] getOperations(final Operation op) {
return op instanceof CompositeOperation
? ((CompositeOperation)op).operations.clone()
: new Operation[] { op };
}
/**
* Returns true if the specified potentially composite operation is a
* {@link CompositeOperation} and contains an operation equal to the
* specified operation. If {@code composite} is not a
* {@link CompositeOperation}, then the two operations are compared for
* equality.
* @param composite the potentially composite operation. Must not be null.
* @param operation the operation being searched for. Must not be null.
* @return true if the if the passed operation is a
* {@link CompositeOperation} and contains a component operation equal to
* the specified operation, or if it is not a {@link CompositeOperation} and
* is equal to {@code operation}.
*/
public static boolean contains(final Operation composite, final Operation operation) {
if (composite instanceof CompositeOperation) {
return ((CompositeOperation)composite).contains(operation);
}
return composite.equals(Objects.requireNonNull(operation));
}
}

View File

@ -1,141 +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;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
/**
* A convenience default bootstrapper that exposes static bootstrap methods which language runtimes that need the very
* default behavior can use with minimal setup. When first referenced, it will create a dynamic linker with default
* settings for the {@link DynamicLinkerFactory}, and its bootstrap methods will create {@link MonomorphicCallSite} for
* all call sites. It has two bootstrap methods: one creates call sites that use the
* {@link MethodHandles#publicLookup()} as the lookup for all call sites and disregard the one passed in as the caller,
* and one that just uses the passed caller as the lookup scope. Using the public lookup one is advised if your language
* runtime has no concept of interacting with Java visibility scopes, as it results in a more lightweight runtime
* information.
*/
public class DefaultBootstrapper {
private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
private DefaultBootstrapper() {
}
/**
* Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do
* this). In case your language runtime doesn't have a concept of interaction with Java access scopes, you might
* want to consider using
* {@link #publicBootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead.
*
* @param caller the caller's lookup
* @param name the name of the method at the call site
* @param type the method signature at the call site
* @return a new {@link MonomorphicCallSite} linked with the default dynamic linker.
*/
public static CallSite bootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) {
return bootstrapInternal(caller, name, type);
}
/**
* Use this method as your bootstrap method (see the documentation of the java.lang.invoke package for how to do
* this) when your language runtime doesn't have a concept of interaction with Java access scopes. If you need to
* preserve the different caller Lookup objects in the call sites, use
* {@link #bootstrap(java.lang.invoke.MethodHandles.Lookup, String, MethodType)} instead
*
* @param caller the caller's lookup. It is ignored as the call sites will be created with
* {@link MethodHandles#publicLookup()} instead.
* @param name the name of the method at the call site
* @param type the method signature at the call site
* @return a new {@link MonomorphicCallSite} linked with the default dynamic linker.
*/
public static CallSite publicBootstrap(final MethodHandles.Lookup caller, final String name, final MethodType type) {
return bootstrapInternal(MethodHandles.publicLookup(), name, type);
}
private static CallSite bootstrapInternal(final MethodHandles.Lookup caller, final String name, final MethodType type) {
return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(caller, name, type)));
}
}

View File

@ -87,26 +87,31 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.util.List;
import java.util.Objects;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardedInvocationTransformer;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.LinkRequestImpl;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
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.SimpleRelinkableCallSite;
/**
* The linker for {@link RelinkableCallSite} objects. Users of it (scripting
* frameworks and language runtimes) have to create a linker using the
* {@link DynamicLinkerFactory} and invoke its link method from the invokedynamic
* bootstrap methods to set the target of all the call sites in the code they
* generate. Usual usage would be to create one class per language runtime to
* contain one linker instance as:
*
* The linker for {@link RelinkableCallSite} objects. A dynamic linker is a main
* objects when using Dynalink, it coordinates linking of call sites with
* linkers of available language runtimes that are represented by
* {@link GuardingDynamicLinker} objects (you only need to deal with these if
* you are yourself implementing a language runtime with its own object model
* and/or type conversions). To use Dynalink, you have to create one or more
* dynamic linkers using a {@link DynamicLinkerFactory}. Subsequently, you need
* to invoke its {@link #link(RelinkableCallSite)} method from
* {@code invokedynamic} bootstrap methods to let it manage all the call sites
* they create. Usual usage would be to create at least one class per language
* runtime to contain one linker instance as:
* <pre>
*
* class MyLanguageRuntime {
* private static final GuardingDynamicLinker myLanguageLinker = new MyLanguageLinker();
* private static final DynamicLinker dynamicLinker = createDynamicLinker();
@ -118,33 +123,44 @@ import jdk.internal.dynalink.support.RuntimeContextLinkRequestImpl;
* }
*
* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
* return dynamicLinker.link(new MonomorphicCallSite(CallSiteDescriptorFactory.create(lookup, name, type)));
* return dynamicLinker.link(
* new SimpleRelinkableCallSite(
* new CallSiteDescriptor(lookup, parseOperation(name), type)));
* }
*
* private static Operation parseOperation(String name) {
* ...
* }
* }
* </pre>
*
* Note how there are three components you will need to provide here:
* The above setup of one static linker instance is often too simple. You will
* often have your language runtime have a concept of some kind of
* "context class loader" and you will want to create one dynamic linker per
* such class loader, to ensure it incorporates linkers for all other language
* runtimes visible to that class loader (see
* {@link DynamicLinkerFactory#setClassLoader(ClassLoader)}).
* <p>
* There are three components you need to provide in the above example:
* <ul>
*
* <li>You're expected to provide a {@link GuardingDynamicLinker} for your own
* language. If your runtime doesn't have its own language and/or object model
* (i.e., it's a generic scripting shell), you don't need to implement a dynamic
* linker; you would simply not invoke the {@code setPrioritizedLinker} method
* on the factory, or even better, simply use {@link DefaultBootstrapper}.</li>
* <li>You are expected to provide a {@link GuardingDynamicLinker} for your own
* language. If your runtime doesn't have its own object model or type
* conversions, you don't need to implement a {@code GuardingDynamicLinker}; you
* would simply not invoke the {@code setPrioritizedLinker} method on the factory.</li>
*
* <li>The performance of the programs can depend on your choice of the class to
* represent call sites. The above example used {@link MonomorphicCallSite}, but
* you might want to use {@link ChainedCallSite} instead. You'll need to
* experiment and decide what fits your language runtime the best. You can
* subclass either of these or roll your own if you need to.</li>
* represent call sites. The above example used
* {@link SimpleRelinkableCallSite}, but you might want to use
* {@link ChainedCallSite} instead. You'll need to experiment and decide what
* fits your runtime the best. You can further subclass either of these or
* implement your own.</li>
*
* <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 has a default {@link CallSiteDescriptorFactory}
* for descriptors that you can use, or you can create your own descriptor
* classes, especially if you need to add further information (values passed in
* additional parameters to the bootstrap method) to them.</li>
* site: the class performing the lookups, the operation being invoked, and the
* method signature. You will have to supply your own scheme to encode and
* decode operations in the call site name or static parameters, that is why
* in the above example the {@code parseOperation} method is left unimplemented.</li>
*
* </ul>
*/
@ -157,8 +173,7 @@ public final class DynamicLinker {
private static final String INVOKE_PACKAGE_PREFIX = "java.lang.invoke.";
private final LinkerServices linkerServices;
private final GuardedInvocationFilter prelinkFilter;
private final int runtimeContextArgCount;
private final GuardedInvocationTransformer prelinkTransformer;
private final boolean syncOnRelink;
private final int unstableRelinkThreshold;
@ -166,20 +181,17 @@ public final class DynamicLinker {
* Creates a new dynamic linker.
*
* @param linkerServices the linkerServices used by the linker, created by the factory.
* @param prelinkFilter see {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter)}
* @param runtimeContextArgCount see {@link DynamicLinkerFactory#setRuntimeContextArgCount(int)}
* @param prelinkTransformer see {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer)}
* @param syncOnRelink see {@link DynamicLinkerFactory#setSyncOnRelink(boolean)}
* @param unstableRelinkThreshold see {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}
*/
DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationFilter prelinkFilter, final int runtimeContextArgCount,
DynamicLinker(final LinkerServices linkerServices, final GuardedInvocationTransformer prelinkTransformer,
final boolean syncOnRelink, final int unstableRelinkThreshold) {
if(runtimeContextArgCount < 0) {
throw new IllegalArgumentException("runtimeContextArgCount < 0");
}
if(unstableRelinkThreshold < 0) {
throw new IllegalArgumentException("unstableRelinkThreshold < 0");
}
this.linkerServices = linkerServices;
this.prelinkFilter = prelinkFilter;
this.runtimeContextArgCount = runtimeContextArgCount;
this.prelinkTransformer = prelinkTransformer;
this.syncOnRelink = syncOnRelink;
this.unstableRelinkThreshold = unstableRelinkThreshold;
}
@ -202,12 +214,13 @@ public final class DynamicLinker {
}
/**
* Returns the object representing the lower level linker services of this
* class that are normally exposed to individual language-specific linkers.
* While as a user of this class you normally only care about the
* {@link #link(RelinkableCallSite)} method, in certain circumstances you
* might want to use the lower level services directly; either to lookup
* specific method handles, to access the type converters, and so on.
* Returns the object representing the linker services of this class that
* are normally exposed to individual {@link GuardingDynamicLinker
* language-specific linkers}. While as a user of this class you normally
* only care about the {@link #link(RelinkableCallSite)} method, in certain
* circumstances you might want to use the lower level services directly;
* either to lookup specific method handles, to access the type converters,
* and so on.
*
* @return the object representing the linker services of this class.
*/
@ -244,10 +257,7 @@ public final class DynamicLinker {
final CallSiteDescriptor callSiteDescriptor = callSite.getDescriptor();
final boolean unstableDetectionEnabled = unstableRelinkThreshold > 0;
final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold;
final LinkRequest linkRequest =
runtimeContextArgCount == 0 ?
new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) :
new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount);
final LinkRequest linkRequest = new SimpleLinkRequest(callSiteDescriptor, callSiteUnstable, arguments);
GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest);
@ -256,21 +266,9 @@ public final class DynamicLinker {
throw new NoSuchDynamicMethodException(callSiteDescriptor.toString());
}
// If our call sites have a runtime context, and the linker produced a context-stripped invocation, adapt the
// produced invocation into contextual invocation (by dropping the context...)
if(runtimeContextArgCount > 0) {
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodHandle invocation = guardedInvocation.getInvocation();
if(invocation.type().parameterCount() == origType.parameterCount() - runtimeContextArgCount) {
final List<Class<?>> prefix = origType.parameterList().subList(1, runtimeContextArgCount + 1);
final MethodHandle guard = guardedInvocation.getGuard();
guardedInvocation = guardedInvocation.dropArguments(1, prefix);
}
}
// Make sure we filter the invocation before linking it into the call site. This is typically used to match the
// Make sure we transform the invocation before linking it into the call site. This is typically used to match the
// return type of the invocation to the call site.
guardedInvocation = prelinkFilter.filter(guardedInvocation, linkRequest, linkerServices);
guardedInvocation = prelinkTransformer.filter(guardedInvocation, linkRequest, linkerServices);
Objects.requireNonNull(guardedInvocation);
int newRelinkCount = relinkCount;
@ -290,11 +288,12 @@ public final class DynamicLinker {
}
/**
* Returns a stack trace element describing the location of the call site
* currently being linked on the current thread. The operation internally
* creates a Throwable object and inspects its stack trace, so it's
* potentially expensive. The recommended usage for it is in writing
* diagnostics code.
* Returns a stack trace element describing the location of the
* {@code invokedynamic} call site currently being linked on the current
* thread. The operation is potentially expensive as it needs to generate a
* stack trace to inspect it and is intended for use in diagnostics code.
* For "free-floating" call sites (not associated with an
* {@code invokedynamic} instruction), the result is not well-defined.
*
* @return a stack trace element describing the location of the call site
* currently being linked, or null if it is not invoked while a call

View File

@ -83,43 +83,59 @@
package jdk.internal.dynalink;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Supplier;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardedInvocationTransformer;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter;
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodHandleTransformer;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.support.AutoDiscovery;
import jdk.internal.dynalink.support.BottomGuardingDynamicLinker;
import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider;
import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker;
import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.DefaultPrelinkFilter;
import jdk.internal.dynalink.support.LinkerServicesImpl;
import jdk.internal.dynalink.support.TypeConverterFactory;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.CompositeGuardingDynamicLinker;
import jdk.internal.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.linker.support.DefaultInternalObjectFilter;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* A factory class for creating {@link DynamicLinker}s. The usual dynamic linker is a linker composed of all
* {@link GuardingDynamicLinker}s known and pre-created by the caller as well as any
* {@link AutoDiscovery automatically discovered} guarding linkers and the standard fallback
* {@link BeansLinker} and a {@link DefaultPrelinkFilter}. See {@link DynamicLinker} documentation for tips on
* how to use this class.
* A factory class for creating {@link DynamicLinker} objects. Dynamic linkers
* are the central objects in Dynalink; these are composed of several
* {@link GuardingDynamicLinker} objects and coordinate linking of call sites
* with them. The usual dynamic linker is a linker
* composed of all {@link GuardingDynamicLinker} objects explicitly pre-created
* by the user of the factory and configured with
* {@link #setPrioritizedLinkers(List)}, as well as any
* {@link #setClassLoader(ClassLoader) automatically discovered} ones, and
* finally the ones configured with {@link #setFallbackLinkers(List)}; this last
* category usually includes {@link BeansLinker}.
*/
public final class DynamicLinkerFactory {
private static final AccessControlContext GET_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext("getClassLoader");
/**
* Default value for {@link #setUnstableRelinkThreshold(int) unstable relink threshold}.
* Default value for {@link #setUnstableRelinkThreshold(int) unstable relink
* threshold}.
*/
public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8;
@ -128,18 +144,40 @@ public final class DynamicLinkerFactory {
private List<? extends GuardingDynamicLinker> prioritizedLinkers;
private List<? extends GuardingDynamicLinker> fallbackLinkers;
private int runtimeContextArgCount = 0;
private boolean syncOnRelink = false;
private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;
private GuardedInvocationFilter prelinkFilter;
private GuardedInvocationTransformer prelinkTransformer;
private MethodTypeConversionStrategy autoConversionStrategy;
private MethodHandleTransformer internalObjectsFilter;
private List<ServiceConfigurationError> autoLoadingErrors = Collections.emptyList();
/**
* Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
* context class loader at the time of {@link #createLinker()} invocation will be used.
* Creates a new dynamic linker factory with default configuration. Upon
* creation, the factory can be configured using various {@code setXxx()}
* methods and used to create one or more dynamic linkers according to its
* current configuration using {@link #createLinker()}.
*/
public DynamicLinkerFactory() {
}
/**
* Sets the class loader for automatic discovery of available guarding
* dynamic linkers. {@link GuardingDynamicLinkerExporter} implementations
* available through this class loader will be automatically instantiated
* using the {@link ServiceLoader} mechanism and the linkers they provide
* will be incorporated into {@code DynamicLinker}s that this factory
* creates. This allows for cross-language interoperability where call sites
* belonging to this language runtime can be linked by linkers from these
* automatically discovered runtimes if their native objects are passed to
* this runtime. If class loader is not set explicitly by invoking this
* method, then the thread context class loader of the thread invoking
* {@link #createLinker()} will be used. If this method is invoked
* explicitly with null then {@link ServiceLoader#loadInstalled(Class)} will
* be used to load the linkers.
*
* @param classLoader the class loader used for the autodiscovery of available linkers.
* @param classLoader the class loader used for the automatic discovery of
* available linkers.
*/
public void setClassLoader(final ClassLoader classLoader) {
this.classLoader = classLoader;
@ -147,90 +185,84 @@ public final class DynamicLinkerFactory {
}
/**
* Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
* for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
* autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
* linkers, it will be ignored and the explicit prioritized instance will be used.
* Sets the prioritized guarding dynamic linkers. Language runtimes using
* Dynalink will usually have at least one linker for their own language.
* These linkers will be consulted first by the resulting dynamic linker
* when it is linking call sites, before any autodiscovered and fallback
* linkers. If the factory also autodiscovers a linker class matching one
* of the prioritized linkers, the autodiscovered class will be ignored and
* the explicit prioritized instance will be used.
*
* @param prioritizedLinkers the list of prioritized linkers. Null can be passed to indicate no prioritized linkers
* (this is also the default value).
* @param prioritizedLinkers the list of prioritized linkers. Can be null.
* @throws NullPointerException if any of the list elements are null.
*/
public void setPrioritizedLinkers(final List<? extends GuardingDynamicLinker> prioritizedLinkers) {
this.prioritizedLinkers =
prioritizedLinkers == null ? null : new ArrayList<>(prioritizedLinkers);
this.prioritizedLinkers = copyListRequireNonNullElements(prioritizedLinkers);
}
/**
* Sets the prioritized linkers. Language runtimes using this framework will usually precreate at least the linker
* for their own language. These linkers will be consulted first in the resulting dynamic linker, before any
* autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the prioritized
* linkers, it will be ignored and the explicit prioritized instance will be used.
* Sets the prioritized guarding dynamic linkers. Identical to calling
* {@link #setPrioritizedLinkers(List)} with
* {@code Arrays.asList(prioritizedLinkers)}.
*
* @param prioritizedLinkers a list of prioritized linkers.
* @param prioritizedLinkers an array of prioritized linkers. Can be null.
* @throws NullPointerException if any of the array elements are null.
*/
public void setPrioritizedLinkers(final GuardingDynamicLinker... prioritizedLinkers) {
setPrioritizedLinkers(Arrays.asList(prioritizedLinkers));
setPrioritizedLinkers(prioritizedLinkers == null ? null : Arrays.asList(prioritizedLinkers));
}
/**
* Sets a single prioritized linker. Identical to calling {@link #setPrioritizedLinkers(List)} with a single-element
* list.
* Sets a single prioritized linker. Identical to calling
* {@link #setPrioritizedLinkers(List)} with a single-element list.
*
* @param prioritizedLinker the single prioritized linker. Must not be null.
* @throws IllegalArgumentException if null is passed.
* @throws NullPointerException if null is passed.
*/
public void setPrioritizedLinker(final GuardingDynamicLinker prioritizedLinker) {
if(prioritizedLinker == null) {
throw new IllegalArgumentException("prioritizedLinker == null");
}
this.prioritizedLinkers = Collections.singletonList(prioritizedLinker);
this.prioritizedLinkers = Collections.singletonList(Objects.requireNonNull(prioritizedLinker));
}
/**
* Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
* autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
* linkers, it will be ignored and the explicit fallback instance will be used.
* Sets the fallback guarding dynamic linkers. These linkers will be
* consulted last by the resulting dynamic linker when it is linking call
* sites, after any autodiscovered and prioritized linkers. If the factory
* also autodiscovers a linker class matching one of the fallback linkers,
* the autodiscovered class will be ignored and the explicit fallback
* instance will be used.
*
* @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
* fallback linkers.
* @param fallbackLinkers the list of fallback linkers. Can be empty to
* indicate the caller wishes to set no fallback linkers. Note that if this
* method is not invoked explicitly or is passed null, then the factory
* will create an instance of {@link BeansLinker} to serve as the default
* fallback linker.
* @throws NullPointerException if any of the list elements are null.
*/
public void setFallbackLinkers(final List<? extends GuardingDynamicLinker> fallbackLinkers) {
this.fallbackLinkers = fallbackLinkers == null ? null : new ArrayList<>(fallbackLinkers);
this.fallbackLinkers = copyListRequireNonNullElements(fallbackLinkers);
}
/**
* Sets the fallback linkers. These linkers will be consulted last in the resulting composite linker, after any
* autodiscovered linkers. If the framework also autodiscovers a linker of the same class as one of the fallback
* linkers, it will be ignored and the explicit fallback instance will be used.
* Sets the fallback guarding dynamic linkers. Identical to calling
* {@link #setFallbackLinkers(List)} with
* {@code Arrays.asList(fallbackLinkers)}.
*
* @param fallbackLinkers the list of fallback linkers. Can be empty to indicate the caller wishes to set no
* fallback linkers. If it is left as null, the standard fallback {@link BeansLinker} will be used.
* @param fallbackLinkers an array of fallback linkers. Can be empty to
* indicate the caller wishes to set no fallback linkers. Note that if this
* method is not invoked explicitly or is passed null, then the factory
* will create an instance of {@link BeansLinker} to serve as the default
* fallback linker.
* @throws NullPointerException if any of the array elements are null.
*/
public void setFallbackLinkers(final GuardingDynamicLinker... fallbackLinkers) {
setFallbackLinkers(Arrays.asList(fallbackLinkers));
setFallbackLinkers(fallbackLinkers == null ? null : Arrays.asList(fallbackLinkers));
}
/**
* Sets the number of arguments in the call sites that represent the stack context of the language runtime creating
* the linker. If the language runtime uses no context information passed on stack, then it should be zero
* (the default value). If it is set to nonzero value, then every dynamic call site emitted by this runtime must
* have the argument list of the form: {@code (this, contextArg1[, contextArg2[, ...]], normalArgs)}. It is
* advisable to only pass one context-specific argument, though, of an easily recognizable, runtime specific type
* encapsulating the runtime thread local state.
*
* @param runtimeContextArgCount the number of language runtime context arguments in call sites.
*/
public void setRuntimeContextArgCount(final int runtimeContextArgCount) {
if(runtimeContextArgCount < 0) {
throw new IllegalArgumentException("runtimeContextArgCount < 0");
}
this.runtimeContextArgCount = runtimeContextArgCount;
}
/**
* Sets whether the linker created by this factory will invoke {@link MutableCallSite#syncAll(MutableCallSite[])}
* after a call site is relinked. Defaults to false. You probably want to set it to true if your runtime supports
* multithreaded execution of dynamically linked code.
* Sets whether the dynamic linker created by this factory will invoke
* {@link MutableCallSite#syncAll(MutableCallSite[])} after a call site is
* relinked. Defaults to false. You probably want to set it to true if your
* runtime supports multithreaded execution of dynamically linked code.
* @param syncOnRelink true for invoking sync on relink, false otherwise.
*/
public void setSyncOnRelink(final boolean syncOnRelink) {
@ -238,10 +270,12 @@ public final class DynamicLinkerFactory {
}
/**
* Sets the unstable relink threshold; the number of times a call site is relinked after which it will be
* considered unstable, and subsequent link requests for it will indicate this.
* @param unstableRelinkThreshold the new threshold. Must not be less than zero. The value of zero means that
* call sites will never be considered unstable.
* Sets the unstable relink threshold; the number of times a call site is
* relinked after which it will be considered unstable, and subsequent link
* requests for it will indicate this.
* @param unstableRelinkThreshold the new threshold. Must not be less than
* zero. The value of zero means that call sites will never be considered
* unstable.
* @see LinkRequest#isCallSiteUnstable()
*/
public void setUnstableRelinkThreshold(final int unstableRelinkThreshold) {
@ -252,52 +286,85 @@ public final class DynamicLinkerFactory {
}
/**
* Set the pre-link filter. This is a {@link GuardedInvocationFilter} that will get the final chance to modify the
* guarded invocation after it has been created by a component linker and before the dynamic linker links it into
* the call site. It is normally used to adapt the return value type of the invocation to the type of the call site.
* When not set explicitly, {@link DefaultPrelinkFilter} will be used.
* @param prelinkFilter the pre-link filter for the dynamic linker.
* Set the pre-link transformer. This is a
* {@link GuardedInvocationTransformer} that will get the final chance to
* modify the guarded invocation after it has been created by a component
* linker and before the dynamic linker links it into the call site. It is
* normally used to adapt the return value type of the invocation to the
* type of the call site. When not set explicitly, a default pre-link
* transformer will be used that simply calls
* {@link GuardedInvocation#asType(LinkerServices, MethodType)}. Customized
* pre-link transformers are rarely needed; they are mostly used as a
* building block for implementing advanced techniques such as code
* deoptimization strategies.
* @param prelinkTransformer the pre-link transformer for the dynamic
* linker. Can be null to have the factory use the default transformer.
*/
public void setPrelinkFilter(final GuardedInvocationFilter prelinkFilter) {
this.prelinkFilter = prelinkFilter;
public void setPrelinkTransformer(final GuardedInvocationTransformer prelinkTransformer) {
this.prelinkTransformer = prelinkTransformer;
}
/**
* Sets an object representing the conversion strategy for automatic type conversions. After
* {@link TypeConverterFactory#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)} has
* applied all custom conversions to a method handle, it still needs to effect
* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method invocation conversions} that
* can usually be automatically applied as per
* {@link java.lang.invoke.MethodHandle#asType(java.lang.invoke.MethodType)}.
* However, sometimes language runtimes will want to customize even those conversions for their own call
* sites. A typical example is allowing unboxing of null return values, which is by default prohibited by
* ordinary {@code MethodHandles.asType}. In this case, a language runtime can install its own custom
* automatic conversion strategy, that can deal with null values. Note that when the strategy's
* {@link MethodTypeConversionStrategy#asType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType)}
* is invoked, the custom language conversions will already have been applied to the method handle, so by
* design the difference between the handle's current method type and the desired final type will always
* only be ones that can be subjected to method invocation conversions. The strategy also doesn't need to
* invoke a final {@code MethodHandle.asType()} as the converter factory will do that as the final step.
* @param autoConversionStrategy the strategy for applying method invocation conversions for the linker
* created by this factory.
* Sets an object representing the conversion strategy for automatic type
* conversions. After
* {@link LinkerServices#asType(MethodHandle, MethodType)} has applied all
* custom conversions to a method handle, it still needs to effect
* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class) method
* invocation conversions} that can usually be automatically applied as per
* {@link MethodHandle#asType(MethodType)}. However, sometimes language
* runtimes will want to customize even those conversions for their own call
* sites. A typical example is allowing unboxing of null return values,
* which is by default prohibited by ordinary
* {@code MethodHandles.asType()}. In this case, a language runtime can
* install its own custom automatic conversion strategy, that can deal with
* null values. Note that when the strategy's
* {@link MethodTypeConversionStrategy#asType(MethodHandle, MethodType)}
* is invoked, the custom language conversions will already have been
* applied to the method handle, so by design the difference between the
* handle's current method type and the desired final type will always only
* be ones that can be subjected to method invocation conversions. The
* strategy also doesn't need to invoke a final
* {@code MethodHandle.asType()} as that will be done internally as the
* final step.
* @param autoConversionStrategy the strategy for applying method invocation
* conversions for the linker created by this factory. Can be null for no
* custom strategy.
*/
public void setAutoConversionStrategy(final MethodTypeConversionStrategy autoConversionStrategy) {
this.autoConversionStrategy = autoConversionStrategy;
}
/**
* Sets a method handle transformer that is supposed to act as the implementation of this linker factory's linkers'
* services {@link LinkerServices#filterInternalObjects(java.lang.invoke.MethodHandle)} method.
* @param internalObjectsFilter a method handle transformer filtering out internal objects, or null.
* Sets a method handle transformer that is supposed to act as the
* implementation of
* {@link LinkerServices#filterInternalObjects(MethodHandle)} for linker
* services of dynamic linkers created by this factory. Some language
* runtimes can have internal objects that should not escape their scope.
* They can add a transformer here that will modify the method handle so
* that any parameters that can receive potentially internal language
* runtime objects will have a filter added on them to prevent them from
* escaping, potentially by wrapping them. The transformer can also
* potentially add an unwrapping filter to the return value.
* {@link DefaultInternalObjectFilter} is provided as a convenience class
* for easily creating such filtering transformers.
* @param internalObjectsFilter a method handle transformer filtering out
* internal objects, or null.
*/
public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) {
this.internalObjectsFilter = internalObjectsFilter;
}
/**
* Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
* the pre-link filter.
*
* Creates a new dynamic linker based on the current configuration. This
* method can be invoked more than once to create multiple dynamic linkers.
* Automatically discovered linkers are newly instantiated on every
* invocation of this method. It is allowed to change the factory's
* configuration between invocations. The method is not thread safe. After
* invocation, callers can invoke {@link #getAutoLoadingErrors()} to
* retrieve a list of {@link ServiceConfigurationError}s that occurred while
* trying to load automatically discovered linkers. These are never thrown
* from the call to this method as it makes every effort to recover from
* them and ignore the failing linkers.
* @return the new dynamic Linker
*/
public DynamicLinker createLinker() {
@ -316,8 +383,8 @@ public final class DynamicLinkerFactory {
addClasses(knownLinkerClasses, prioritizedLinkers);
addClasses(knownLinkerClasses, fallbackLinkers);
final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();
final List<GuardingDynamicLinker> discovered = AutoDiscovery.loadLinkers(effectiveClassLoader);
final List<GuardingDynamicLinker> discovered = discoverAutoLoadLinkers();
// Now, concatenate ...
final List<GuardingDynamicLinker> linkers =
new ArrayList<>(prioritizedLinkers.size() + discovered.size()
@ -336,7 +403,7 @@ public final class DynamicLinkerFactory {
final GuardingDynamicLinker composite;
switch(linkers.size()) {
case 0: {
composite = BottomGuardingDynamicLinker.INSTANCE;
composite = (r, s) -> null; // linker that can't link anything
break;
}
case 1: {
@ -356,22 +423,84 @@ public final class DynamicLinkerFactory {
}
}
if(prelinkFilter == null) {
prelinkFilter = new DefaultPrelinkFilter();
if(prelinkTransformer == null) {
prelinkTransformer = (inv, request, linkerServices) -> inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType());
}
return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,
autoConversionStrategy), composite, internalObjectsFilter), prelinkFilter, runtimeContextArgCount,
autoConversionStrategy), composite, internalObjectsFilter), prelinkTransformer,
syncOnRelink, unstableRelinkThreshold);
}
/**
* Returns a list of {@link ServiceConfigurationError}s that were
* encountered while loading automatically discovered linkers during the
* last invocation of {@link #createLinker()}. They can be any non-Dynalink
* specific service configuration issues, as well as some Dynalink-specific
* errors when an exporter that the factory tried to automatically load:
* <ul>
* <li>did not have the runtime permission named
* {@link GuardingDynamicLinkerExporter#AUTOLOAD_PERMISSION_NAME} in a
* system with a security manager, or</li>
* <li>returned null from {@link GuardingDynamicLinkerExporter#get()}, or</li>
* <li>the list returned from {@link GuardingDynamicLinkerExporter#get()}
* had a null element.</li>
* </ul>
* @return an immutable list of encountered
* {@link ServiceConfigurationError}s. Can be empty.
*/
public List<ServiceConfigurationError> getAutoLoadingErrors() {
return Collections.unmodifiableList(autoLoadingErrors);
}
private List<GuardingDynamicLinker> discoverAutoLoadLinkers() {
autoLoadingErrors = new LinkedList<>();
final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader();
final List<GuardingDynamicLinker> discovered = new LinkedList<>();
try {
final ServiceLoader<GuardingDynamicLinkerExporter> linkerLoader =
AccessController.doPrivileged((PrivilegedAction<ServiceLoader<GuardingDynamicLinkerExporter>>)()-> {
if (effectiveClassLoader == null) {
return ServiceLoader.loadInstalled(GuardingDynamicLinkerExporter.class);
}
return ServiceLoader.load(GuardingDynamicLinkerExporter.class, effectiveClassLoader);
});
for(final Iterator<GuardingDynamicLinkerExporter> it = linkerLoader.iterator(); it.hasNext();) {
try {
final GuardingDynamicLinkerExporter autoLoader = it.next();
try {
discovered.addAll(requireNonNullElements(
Objects.requireNonNull(autoLoader.get(),
()->(autoLoader.getClass().getName() + " returned null from get()")),
()->(autoLoader.getClass().getName() + " returned a list with at least one null element")));
} catch (final ServiceConfigurationError|VirtualMachineError e) {
// Don't wrap a SCE in another SCE. Also, don't ignore
// any VME (e.g. StackOverflowError or OutOfMemoryError).
throw e;
} catch (final Throwable t) {
throw new ServiceConfigurationError(t.getMessage(), t);
}
} catch (final ServiceConfigurationError e) {
// Catch SCE with an individual exporter, carry on with it.hasNext().
autoLoadingErrors.add(e);
}
}
} catch (final ServiceConfigurationError e) {
// Catch a top-level SCE; one either in ServiceLoader.load(),
// ServiceLoader.iterator(), or Iterator.hasNext().
autoLoadingErrors.add(e);
}
return discovered;
}
private static ClassLoader getThreadContextClassLoader() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
}, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
}, GET_CLASS_LOADER_CONTEXT);
}
private static void addClasses(final Set<Class<? extends GuardingDynamicLinker>> knownLinkerClasses,
@ -380,4 +509,19 @@ public final class DynamicLinkerFactory {
knownLinkerClasses.add(linker.getClass());
}
}
private static <T> List<T> copyListRequireNonNullElements(final List<T> list) {
if (list == null) {
return null;
}
return new ArrayList<>(requireNonNullElements(list, ()->"List has at least one null element"));
}
private static <T> List<T> requireNonNullElements(final List<T> list, final Supplier<String> msgSupplier) {
for(final T t: list) {
Objects.requireNonNull(t, msgSupplier);
}
return list;
}
}

View File

@ -81,9 +81,10 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.linker.GuardedInvocation;
@ -95,9 +96,7 @@ import jdk.internal.dynalink.linker.MethodHandleTransformer;
/**
* Default implementation of the {@link LinkerServices} interface.
*/
public class LinkerServicesImpl implements LinkerServices {
private static final RuntimePermission GET_CURRENT_LINK_REQUEST = new RuntimePermission("dynalink.getCurrentLinkRequest");
final class LinkerServicesImpl implements LinkerServices {
private static final ThreadLocal<LinkRequest> threadLinkRequest = new ThreadLocal<>();
private final TypeConverterFactory typeConverterFactory;
@ -112,7 +111,7 @@ public class LinkerServicesImpl implements LinkerServices {
* @param internalObjectsFilter a method handle transformer that is supposed to act as the implementation of this
* services' {@link #filterInternalObjects(java.lang.invoke.MethodHandle)} method.
*/
public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory,
LinkerServicesImpl(final TypeConverterFactory typeConverterFactory,
final GuardingDynamicLinker topLevelLinker, final MethodHandleTransformer internalObjectsFilter) {
this.typeConverterFactory = typeConverterFactory;
this.topLevelLinker = topLevelLinker;
@ -155,17 +154,11 @@ public class LinkerServicesImpl implements LinkerServices {
return internalObjectsFilter != null ? internalObjectsFilter.transform(target) : target;
}
/**
* Returns the currently processed link request, or null if the method is invoked outside of the linking process.
* @return the currently processed link request, or null.
* @throws SecurityException if the calling code doesn't have the {@code "dynalink.getCurrentLinkRequest"} runtime
* permission.
*/
public static LinkRequest getCurrentLinkRequest() {
final SecurityManager sm = System.getSecurityManager();
if(sm != null) {
sm.checkPermission(GET_CURRENT_LINK_REQUEST);
static MethodHandles.Lookup getCurrentLookup() {
final LinkRequest currentRequest = threadLinkRequest.get();
if (currentRequest != null) {
return currentRequest.getCallSiteDescriptor().getLookup();
}
return threadLinkRequest.get();
return MethodHandles.publicLookup();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -31,7 +31,7 @@
* license:
*/
/*
Copyright 2009-2013 Attila Szegedi
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
@ -81,105 +81,117 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink;
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 a generally useful {@code equals} and {@code hashCode} methods.
* Operation that associates a name with another operation. Typically used with
* operations that normally take a name or an index to bind them to a fixed
* name. E.g. {@code new NamedOperation(StandardOperation.GET_PROPERTY, "color")}
* will be a named operation for getting the property named "color" on the
* object it is applied to, and
* {@code new NamedOperation(StandardOperation.GET_ELEMENT, 3)} will be a named
* operation for getting the element at index 3 from the collection it is
* applied to. In these cases, the expected signature of the call site for the
* operation will change to no longer include the name parameter. Specifically,
* the documentation for all {@link StandardOperation} members describes how
* they are affected by being incorporated into a named operation.
*/
public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
public class NamedOperation implements Operation {
private final Operation baseOperation;
private final Object name;
@Override
public String getName() {
return appendName(new StringBuilder(getNameLength())).toString();
}
@Override
public Lookup getLookup() {
return MethodHandles.publicLookup();
}
@Override
public boolean equals(final Object obj) {
return obj instanceof CallSiteDescriptor && equals((CallSiteDescriptor)obj);
/**
* Creates a new named operation.
* @param baseOperation the base operation that is associated with a name.
* @param name the name associated with the base operation. Note that the
* name is not necessarily a string, but can be an arbitrary object. As the
* name is used for addressing, it can be an {@link Integer} when meant
* to be used as an index into an array or list etc.
* @throws NullPointerException if either {@code baseOperation} or
* {@code name} is null.
* @throws IllegalArgumentException if {@code baseOperation} is itself a
* {@code NamedOperation}.
*/
public NamedOperation(final Operation baseOperation, final Object name) {
if (baseOperation instanceof NamedOperation) {
throw new IllegalArgumentException("baseOperation is a named operation");
}
this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
this.name = Objects.requireNonNull(name, "name is null");
}
/**
* Returns true if this call site descriptor is equal to the passed call site descriptor.
* @param csd the other call site descriptor.
* @return true if they are equal.
* Returns the base operation of this named operation.
* @return the base operation of this named operation.
*/
public boolean equals(final CallSiteDescriptor csd) {
if(csd == null) {
return false;
}
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 lookupsEqual(getLookup(), csd.getLookup());
public Operation getBaseOperation() {
return baseOperation;
}
/**
* Returns the name of this named operation.
* @return the name of this named operation.
*/
public Object getName() {
return name;
}
/**
* Compares this named operation to another object. Returns true if the
* other object is also a named operation, and both their base operations
* and name are equal.
*/
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
} else if(obj.getClass() != NamedOperation.class) {
return false;
}
final NamedOperation other = (NamedOperation)obj;
return baseOperation.equals(other.baseOperation) && name.equals(other.name);
}
/**
* Returns the hash code of this named operation. It is defined to be equal
* to {@code baseOperation.hashCode() + 31 * name.hashCode()}.
*/
@Override
public int hashCode() {
final MethodHandles.Lookup lookup = getLookup();
int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
final int c = getNameTokenCount();
for(int i = 0; i < c; ++i) {
h = h * 31 + getNameToken(i).hashCode();
}
return h * 31 + getMethodType().hashCode();
return baseOperation.hashCode() + 31 * name.hashCode();
}
/**
* Returns the string representation of this named operation. It is defined
* to be equal to {@code baseOperation.toString() + ":" + name.toString()}.
*/
@Override
public String toString() {
final String mt = getMethodType().toString();
final String l = getLookup().toString();
final StringBuilder b = new StringBuilder(l.length() + 1 + mt.length() + getNameLength());
return appendName(b).append(mt).append("@").append(l).toString();
return baseOperation.toString() + ":" + name.toString();
}
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;
/**
* If the passed operation is a named operation, returns its
* {@link #getBaseOperation()}, otherwise returns the operation as is.
* @param op the operation
* @return the base operation of the passed operation.
*/
public static Operation getBaseOperation(final Operation op) {
return op instanceof NamedOperation ? ((NamedOperation)op).baseOperation : op;
}
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;
}
private static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
if(l1 == l2) {
return true;
}
if(l1.lookupClass() != l2.lookupClass()) {
return false;
}
return l1.lookupModes() == l2.lookupModes();
/**
* If the passed operation is a named operation, returns its
* {@link #getName()}, otherwise returns null. Note that a named operation
* object can never have a null name, therefore returning null is indicative
* that the passed operation is not, in fact, a named operation.
* @param op the operation
* @return the name in the passed operation, or null if it is not a named
* operation.
*/
public static Object getName(final Operation op) {
return op instanceof NamedOperation ? ((NamedOperation)op).name : null;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -31,7 +31,7 @@
* license:
*/
/*
Copyright 2009-2013 Attila Szegedi
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
@ -81,27 +81,19 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
import java.security.AccessControlContext;
import java.security.Permissions;
import java.security.ProtectionDomain;
package jdk.internal.dynalink;
/**
* This class exposes a canonical {@link AccessControlContext} with a single {@link RuntimePermission} for
* {@code "getClassLoader"} permission that is used by other parts of the code to narrow their set of permissions when
* they're retrieving class loaders in privileged blocks.
* An object that describes a dynamic operation. Dynalink defines a set of
* standard operations with the {@link StandardOperation} class, as well as a
* way to attach a fixed name to an operation using {@link NamedOperation} and
* to express a set of alternative operations using {@link CompositeOperation}.
* When presenting examples in this documentation, we will refer to standard
* operations using their name (e.g. {@code GET_PROPERTY}), to composite
* operations by separating their components with the vertical line character
* (e.g. {@code GET_PROPERTY|GET_ELEMENT}), and finally to named operations by
* separating the base operation and the name with the colon character (e.g.
* {@code GET_PROPERTY|GET_ELEMENT:color}).
*/
public class ClassLoaderGetterContextProvider {
/**
* Canonical instance of {@link AccessControlContext} with a single {@link RuntimePermission} for
* {@code "getClassLoader"} permission.
*/
public static final AccessControlContext GET_CLASS_LOADER_CONTEXT;
static {
final Permissions perms = new Permissions();
perms.add(new RuntimePermission("getClassLoader"));
GET_CLASS_LOADER_CONTEXT = new AccessControlContext(
new ProtectionDomain[] { new ProtectionDomain(null, perms) });
}
public interface Operation {
}

View File

@ -85,23 +85,37 @@ package jdk.internal.dynalink;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.VolatileCallSite;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.ChainedCallSite;
import jdk.internal.dynalink.support.SimpleRelinkableCallSite;
/**
* Interface for relinkable call sites. Language runtimes wishing to use this framework must use subclasses of
* {@link CallSite} that also implement this interface as their call sites. There is a readily usable
* {@link MonomorphicCallSite} subclass that implements monomorphic inline caching strategy as well as a
* {@link ChainedCallSite} that retains a chain of already linked method handles. The reason this is defined as an
* interface instead of a concrete, albeit abstract class is that it allows independent implementations to choose
* between {@link MutableCallSite} and {@link VolatileCallSite} as they see fit.
* Interface for call sites managed by a {@link DynamicLinker}. Users of
* Dynalink must use subclasses of {@link CallSite} that also implement this
* interface as their call site implementations. There is a readily usable
* {@link SimpleRelinkableCallSite} subclass that implements monomorphic inline
* caching strategy as well as {@link ChainedCallSite} that implements a
* polymorphic inline caching strategy and retains a chain of previously linked
* method handles. A relinkable call site will be managed by a
* {@link DynamicLinker} object after being associated with it using its
* {@link DynamicLinker#link(RelinkableCallSite)} method.
*/
public interface RelinkableCallSite {
/**
* Initializes the relinkable call site by setting a relink-and-invoke method handle. The call site
* implementation is supposed to set this method handle as its target.
* @param relinkAndInvoke a relink-and-invoke method handle supplied by the {@link DynamicLinker}.
* Invoked by dynamic linker to initialize the relinkable call site by
* setting a relink-and-invoke method handle. The call site implementation
* is supposed to set this method handle as its target using
* {@link CallSite#setTarget(MethodHandle)}. Relink-and-invoke is the
* initial method handle set by
* {@link DynamicLinker#link(RelinkableCallSite)} that will cause the call
* site to be relinked to an appropriate target on its first invocation
* based on its arguments, and that linked target will then be invoked
* (hence the name). This linking protocol effectively delays linking until
* the call site is invoked with actual arguments and thus ensures that
* linkers can make nuanced linking decisions based on those arguments and
* not just on the static method type of the call site.
* @param relinkAndInvoke a relink-and-invoke method handle supplied by
* Dynalink.
*/
public void initialize(MethodHandle relinkAndInvoke);
@ -113,33 +127,52 @@ public interface RelinkableCallSite {
public CallSiteDescriptor getDescriptor();
/**
* This method will be called by the dynamic linker every time the call site is normally relinked. It will be passed
* a {@code GuardedInvocation} that the call site should incorporate into its target method handle. When this method
* is called, the call site is allowed to keep other non-invalidated invocations around for implementation of
* polymorphic inline caches and compose them with this invocation to form its final target.
* This method will be called by the dynamic linker every time the call site
* is relinked (but see
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)} for an
* exception). It will be passed a {@code GuardedInvocation} that the call
* site should incorporate into its target method handle. When this method
* is called, the call site is allowed to keep other non-invalidated
* invocations around for implementation of polymorphic inline caches and
* compose them with this invocation to form its final target.
*
* @param guardedInvocation the guarded invocation that the call site should incorporate into its target method
* handle.
* @param fallback the fallback method. This is a method matching the method type of the call site that is supplied
* by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the
* passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target
* for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target.
* @param guardedInvocation the guarded invocation that the call site should
* incorporate into its target method handle.
* @param relinkAndInvoke a relink-and-invoke method handle. This is a
* method handle matching the method type of the call site that is supplied
* by the {@link DynamicLinker} as a callback. It should be used by this
* call site as the ultimate fallback when it can't invoke its target with
* the passed arguments. The fallback method is such that when it's invoked,
* it'll try to obtain an adequate target {@link GuardedInvocation} for the
* invocation, and subsequently invoke
* {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally
* invoke the target.
*/
public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback);
public void relink(GuardedInvocation guardedInvocation, MethodHandle relinkAndInvoke);
/**
* This method will be called by the dynamic linker every time the call site is relinked and the linker wishes the
* call site to throw away any prior linkage state. It will be passed a {@code GuardedInvocation} that the call site
* should use to build its target method handle. When this method is called, the call site is discouraged from
* keeping previous state around, and is supposed to only link the current invocation.
* This method will be called by the dynamic linker every time the call site
* is relinked <b>and</b> the linker wishes the call site to throw away any
* prior linkage state (that is how it differs from
* {@link #relink(GuardedInvocation, MethodHandle)}). It will be passed a
* {@code GuardedInvocation} that the call site should use to build its new
* target method handle. When this method is called, the call site is
* discouraged from keeping any previous state, and is supposed to only
* link the current invocation.
*
* @param guardedInvocation the guarded invocation that the call site should use to build its target method handle.
* @param fallback the fallback method. This is a method matching the method type of the call site that is supplied
* by the {@link DynamicLinker} to be used by this call site as a fallback when it can't invoke its target with the
* passed arguments. The fallback method is such that when it's invoked, it'll try to discover the adequate target
* for the invocation, subsequently invoke {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally invoke the target.
* @param guardedInvocation the guarded invocation that the call site should
* use to build its target method handle.
* @param relinkAndInvoke a relink-and-invoke method handle. This is a
* method handle matching the method type of the call site that is supplied
* by the {@link DynamicLinker} as a callback. It should be used by this
* call site as the ultimate fallback when it can't invoke its target with
* the passed arguments. The fallback method is such that when it's invoked,
* it'll try to obtain an adequate target {@link GuardedInvocation} for the
* invocation, and subsequently invoke
* {@link #relink(GuardedInvocation, MethodHandle)} or
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}, and finally
* invoke the target.
*/
public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback);
public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle relinkAndInvoke);
}

View File

@ -0,0 +1,176 @@
/*
* 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;
/**
* Defines the standard dynamic operations. Getter and setter operations defined
* in this enumeration can be composed into a {@link CompositeOperation}, and
* {@link NamedOperation} can be used to bind the name parameter of operations
* that take one, in which case it disappears from the type signature.
*/
public enum StandardOperation implements Operation {
/**
* Get the value of a property defined on an object. Call sites with this
* operation should have a signature of
* <tt>(receiver,&nbsp;propertyName)&rarr;value</tt> or
* <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}, with
* all parameters and return type being of any type (either primitive or
* reference).
*/
GET_PROPERTY,
/**
* Set the value of a property defined on an object. Call sites with this
* operation should have a signature of
* <tt>(receiver,&nbsp;propertyName,&nbsp;value)&rarr;void</tt> or
* <tt>(receiver,&nbsp;value)&rarr;void</tt> when used with {@link NamedOperation},
* with all parameters and return type being of any type (either primitive
* or reference).
*/
SET_PROPERTY,
/**
* Get the value of an element of a collection. Call sites with this
* operation should have a signature of
* <tt>(receiver,&nbsp;index)&rarr;value</tt> or
* <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}, with
* all parameters and return type being of any type (either primitive or
* reference).
*/
GET_ELEMENT,
/**
* Set the value of an element of a collection. Call sites with this
* operation should have a signature of
* <tt>(receiver,&nbsp;index,&nbsp;value)&rarr;void</tt> or
* <tt>(receiver,&nbsp;value)&rarr;void</tt> when used with {@link NamedOperation},
* with all parameters and return type being of any type (either primitive
* or reference).
*/
SET_ELEMENT,
/**
* Get the length of an array of size of a collection. Call sites with
* this operation should have a signature of <tt>(receiver)&rarr;value</tt>,
* with all parameters and return type being of any type (either primitive
* or reference).
*/
GET_LENGTH,
/**
* Gets an object representing a method defined on an object. Call sites
* with this operation should have a signature of
* <tt>(receiver,&nbsp;methodName)&rarr;value</tt>, or
* <tt>(receiver)&rarr;value</tt> when used with {@link NamedOperation}
* with all parameters and return type being of any type (either primitive
* or reference).
*/
GET_METHOD,
/**
* Calls a method defined on an object. Call sites with this
* operation should have a signature of
* <tt>(receiver,&nbsp;methodName,&nbsp;arguments...)&rarr;value</tt> or
* <tt>(receiver,&nbsp;arguments...)&rarr;value</tt> when used with {@link NamedOperation},
* with all parameters and return type being of any type (either primitive
* or reference).
*/
CALL_METHOD,
/**
* Calls a callable object. Call sites with this operation should have a
* signature of <tt>(receiver,&nbsp;arguments...)&rarr;value</tt>, with all
* parameters and return type being of any type (either primitive or
* reference). Typically, if the callable is a method of an object, the
* first argument will act as the "this" value passed to the called method.
* The <tt>CALL</tt> operation is allowed to be used with a
* {@link NamedOperation} even though it does not take a name. Using it with
* a named operation won't affect its signature; the name is solely meant to
* be used as a diagnostic description for error messages.
*/
CALL,
/**
* Calls a constructor object. Call sites with this operation should have a
* signature of <tt>(receiver,&nbsp;arguments...)&rarr;value</tt>, with all
* parameters and return type being of any type (either primitive or
* reference). The <tt>NEW</tt> operation is allowed to be used with a
* {@link NamedOperation} even though it does not take a name. Using it with
* a named operation won't affect its signature; the name is solely meant to
* be used as a diagnostic description for error messages.
*/
NEW
}

View File

@ -81,30 +81,36 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.linker.ConversionComparator;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardedTypeConversion;
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* A factory for type converters. This class is the main implementation behind the
* {@link LinkerServices#asType(MethodHandle, MethodType)}. It manages the known {@link GuardingTypeConverterFactory}
* instances and creates appropriate converters for method handles.
*/
public class TypeConverterFactory {
final class TypeConverterFactory {
private static final AccessControlContext GET_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext("getClassLoader");
private final GuardingTypeConverterFactory[] factories;
private final ConversionComparator[] comparators;
@ -170,7 +176,7 @@ public class TypeConverterFactory {
public ClassLoader run() {
return clazz.getClassLoader();
}
}, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT);
}, GET_CLASS_LOADER_CONTEXT);
}
/**
@ -193,7 +199,7 @@ public class TypeConverterFactory {
* only be ones that can be subjected to method invocation conversions. Can be null, in which case no
* custom strategy is employed.
*/
public TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories,
TypeConverterFactory(final Iterable<? extends GuardingTypeConverterFactory> factories,
final MethodTypeConversionStrategy autoConversionStrategy) {
final List<GuardingTypeConverterFactory> l = new LinkedList<>();
final List<ConversionComparator> c = new LinkedList<>();
@ -226,7 +232,7 @@ public class TypeConverterFactory {
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory} produced type converters as filters.
*/
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
MethodHandle newHandle = handle;
final MethodType toType = newHandle.type();
final int l = toType.parameterCount();
@ -295,7 +301,7 @@ public class TypeConverterFactory {
* @param to the target type for the conversion
* @return true if there can be a conversion, false if there can not.
*/
public boolean canConvert(final Class<?> from, final Class<?> to) {
boolean canConvert(final Class<?> from, final Class<?> to) {
return canAutoConvert(from, to) || canConvert.get(from).get(to);
}
@ -309,7 +315,7 @@ public class TypeConverterFactory {
* @return one of Comparison constants that establish which - if any - of the target types is preferable for the
* conversion.
*/
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
for(final ConversionComparator comparator: comparators) {
final Comparison result = comparator.compareConversion(sourceType, targetType1, targetType2);
if(result != Comparison.INDETERMINATE) {
@ -363,7 +369,7 @@ public class TypeConverterFactory {
* @param targetType the type to convert to
* @return a method handle performing the conversion.
*/
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
try {
return converterIdentityMap.get(sourceType).get(targetType);
} catch(final NotCacheableConverter e) {
@ -371,26 +377,49 @@ public class TypeConverterFactory {
}
}
private static class LookupSupplier implements Supplier<MethodHandles.Lookup> {
volatile boolean returnedLookup;
volatile boolean closed;
@Override
public Lookup get() {
if (closed) {
// Something held on to this supplier and tried to invoke it
// after we're done with it.
throw new IllegalStateException();
}
final Lookup lookup = LinkerServicesImpl.getCurrentLookup();
returnedLookup = true;
return lookup;
}
}
/*private*/ MethodHandle createConverter(final Class<?> sourceType, final Class<?> targetType) throws Exception {
final MethodType type = MethodType.methodType(targetType, sourceType);
final MethodHandle identity = IDENTITY_CONVERSION.asType(type);
MethodHandle last = identity;
boolean cacheable = true;
for(int i = factories.length; i-- > 0;) {
final GuardedTypeConversion next = factories[i].convertToType(sourceType, targetType);
if(next != null) {
cacheable = cacheable && next.isCacheable();
final GuardedInvocation conversionInvocation = next.getConversionInvocation();
conversionInvocation.assertType(type);
last = conversionInvocation.compose(last);
final LookupSupplier lookupSupplier = new LookupSupplier();
try {
for(int i = factories.length; i-- > 0;) {
final GuardedInvocation next = factories[i].convertToType(sourceType, targetType, lookupSupplier);
if(next != null) {
last = next.compose(last);
}
}
} finally {
lookupSupplier.closed = true;
}
if(last == identity) {
return IDENTITY_CONVERSION;
}
if(cacheable) {
if(!lookupSupplier.returnedLookup) {
return last;
}
// At least one of the consulted converter factories obtained the
// lookup, so we must presume the created converter is sensitive to the
// lookup class and thus we will not cache it.
throw new NotCacheableConverter(last);
}

View File

@ -92,21 +92,26 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.CompositeOperation;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.Operation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.internal.dynalink.linker.support.Lookup;
import sun.reflect.CallerSensitive;
/**
* A base class for both {@link StaticClassLinker} and {@link BeanLinker}. Deals with common aspects of property
@ -284,7 +289,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
* @return the single dynamic method representing the reflective member
*/
private static SingleDynamicMethod createDynamicMethod(final AccessibleObject m) {
if(CallerSensitiveDetector.isCallerSensitive(m)) {
if (m.isAnnotationPresent(CallerSensitive.class)) {
// Method has @CallerSensitive annotation
return new CallerSensitiveDynamicMethod(m);
}
@ -342,18 +347,27 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
throws Exception {
final LinkRequest ncrequest = request.withoutRuntimeContext();
// BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn".
final CallSiteDescriptor callSiteDescriptor = ncrequest.getCallSiteDescriptor();
final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR);
// Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]).
if("callMethod" == op) {
return getCallPropWithThis(callSiteDescriptor, linkerServices);
final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
// Handle NamedOperation(CALL_METHOD, name) separately
final Operation operation = callSiteDescriptor.getOperation();
if (operation instanceof NamedOperation) {
final NamedOperation namedOperation = (NamedOperation)operation;
if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) {
return createGuardedDynamicMethodInvocation(callSiteDescriptor,
linkerServices, namedOperation.getName().toString(), methods);
}
}
List<String> operations = CallSiteDescriptorFactory.tokenizeOperators(callSiteDescriptor);
List<Operation> operations = Arrays.asList(
CompositeOperation.getOperations(
NamedOperation.getBaseOperation(operation)));
final Object name = NamedOperation.getName(operation);
while(!operations.isEmpty()) {
final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices,
operations);
final GuardedInvocationComponent gic =
getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, name);
if(gic != null) {
return gic.getGuardedInvocation();
}
@ -362,23 +376,26 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return null;
}
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
protected GuardedInvocationComponent getGuardedInvocationComponent(
final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices,
final List<Operation> operations, final Object name)
throws Exception {
if(operations.isEmpty()) {
return null;
}
final String op = operations.get(0);
// Either dyn:getProp:name(this) or dyn:getProp(this, name)
if("getProp".equals(op)) {
return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations));
final Operation op = operations.get(0);
// Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name)
if(op == StandardOperation.GET_PROPERTY) {
return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
// Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value)
if("setProp".equals(op)) {
return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations));
// Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value)
if(op == StandardOperation.SET_PROPERTY) {
return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
// Either dyn:getMethod:name(this), or dyn:getMethod(this, name)
if("getMethod".equals(op)) {
return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations));
// Either GET_METHOD:name(this), or GET_METHOD(this, name)
if(op == StandardOperation.GET_METHOD) {
return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
return null;
}
@ -407,18 +424,6 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return Guards.asType(assignableGuard, type);
}
private GuardedInvocation getCallPropWithThis(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
switch(callSiteDescriptor.getNameTokenCount()) {
case 3: {
return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
}
default: {
return null;
}
}
}
private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final String methodName, final Map<String, DynamicMethod> methodMap){
final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
@ -481,84 +486,86 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
}
default: {
// More than two name components; don't know what to do with it.
return null;
}
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
if (name == null) {
return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations);
}
return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name);
}
private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations) throws Exception {
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
// valid for us to convert return values proactively. Also, since we don't know what setters will be
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
// get_setter_handle(type, linkerServices))
// only with a bunch of method signature adjustments. Basically, retrieve method setter
// MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
// component's invocation.
// Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
// abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
// Object return type).
final MethodType setterType = type.dropParameterTypes(1, 2);
// Bind property setter handle to the expected setter type and linker services. Type is
// MethodHandle(Object, String, Object)
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
callSiteDescriptor.changeMethodType(setterType), linkerServices);
// Cast getter to MethodHandle(O, N, V)
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
MethodHandle.class));
// Handle to invoke the setter R(MethodHandle, O, V)
final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, null);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
} else {
// Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
// extra argument resulting from fold
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
0, MethodHandle.class);
}
// fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeSetter, type);
}
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
name.toString(), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name);
}
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
@ -568,91 +575,93 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
"getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class, LinkerServices.class));
"getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class));
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> ops) throws Exception {
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Since we can't know what kind of a getter we'll get back on different invocations, we'll just
// conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
// runtime might not allow coercing at that call site.
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
// only with a bunch of method signature adjustments. Basically, retrieve method getter
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
// or delegate to next component's invocation.
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
AnnotatedDynamicMethod.class));
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup(), linkerServices);
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
callSiteBoundMethodGetter);
// Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
// Since it's in the target of a fold, drop the unnecessary second argument
// Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
type.parameterType(1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
} else {
// Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
// drop the extra argument resulting from fold and to change its return type to Object.
final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
final MethodType nextType = nextInvocation.type();
fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
}
// fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeGetter, type);
}
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
// Fixed name
final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
CallSiteDescriptor.NAME_OPERAND));
if(annGetter == null) {
// We have no such property, always delegate to the next component operation
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
}
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
// we're linking against a field getter, don't make the assumption.
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
// value is null.
final ValidationType validationType = annGetter.validationType;
// TODO: we aren't using the type that declares the most generic getter here!
return new GuardedInvocationComponent(getter, getGuard(validationType,
callSiteDescriptor.getMethodType()), clazz, validationType);
}
default: {
// Can't do anything with more than 3 name components
return null;
}
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
if (name == null) {
return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops);
}
return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name);
}
private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops) throws Exception {
// Since we can't know what kind of a getter we'll get back on different invocations, we'll just
// conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
// runtime might not allow coercing at that call site.
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
// only with a bunch of method signature adjustments. Basically, retrieve method getter
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
// or delegate to next component's invocation.
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
AnnotatedDynamicMethod.class));
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices);
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
callSiteBoundMethodGetter);
// Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
// Since it's in the target of a fold, drop the unnecessary second argument
// Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
type.parameterType(1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops, null);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
// Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
} else {
// Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
// drop the extra argument resulting from fold and to change its return type to Object.
final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
final MethodType nextType = nextInvocation.type();
fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
}
// fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
if(nextComponent == null) {
return getClassGuardedInvocationComponent(compositeGetter, type);
}
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
// Fixed name
final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString());
if(annGetter == null) {
// We have no such property, always delegate to the next component operation
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
}
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
// we're linking against a field getter, don't make the assumption.
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
// value is null.
final ValidationType validationType = annGetter.validationType;
// TODO: we aren't using the type that declares the most generic getter here!
return new GuardedInvocationComponent(getter, getGuard(validationType,
callSiteDescriptor.getMethodType()), clazz, validationType);
}
private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) {
@ -680,64 +689,67 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> ops) throws Exception {
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
// be visible outside of this linker, declare it to return Object.
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
switch(callSiteDescriptor.getNameTokenCount()) {
case 2: {
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops);
if(nextComponent == null || !TypeUtilities.areAssignable(DynamicMethod.class,
nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
// No next component operation, or it can never produce a dynamic method; just return a component
// for this operation.
return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
}
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
// bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
// DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
// Since it is part of the foldArgument() target, it will have extra args that we need to drop.
final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
// The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
// return type.
assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
// Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
Object.class);
// Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
case 3: {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken(
CallSiteDescriptor.NAME_OPERAND));
if(method == null) {
// We have no such method, always delegate to the next component
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
}
// No delegation to the next component of the composite operation; if we have a method with that name,
// we'll always return it at this point.
return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
}
default: {
// Can't do anything with more than 3 name components
return null;
}
if (name == null) {
return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type);
}
return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type);
}
private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final MethodType type) throws Exception {
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops, null);
if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
// No next component operation, or it can never produce a dynamic method; just return a component
// for this operation.
return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
}
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
// bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
// DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
// Since it is part of the foldArgument() target, it will have extra args that we need to drop.
final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
// The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
// return type.
assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
// Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
Object.class);
// Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name, final MethodType type)
throws Exception {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
final DynamicMethod method = getDynamicMethod(name.toString());
if(method == null) {
// We have no such method, always delegate to the next component
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
}
// No delegation to the next component of the composite operation; if we have a method with that name,
// we'll always return it at this point.
return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
}
static class MethodPair {
@ -757,7 +769,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
static MethodPair matchReturnTypes(final MethodHandle m1, final MethodHandle m2) {
final MethodType type1 = m1.type();
final MethodType type2 = m2.type();
final Class<?> commonRetType = TypeUtilities.getCommonLosslessConversionType(type1.returnType(),
final Class<?> commonRetType = InternalTypeUtilities.getCommonLosslessConversionType(type1.returnType(),
type2.returnType());
return new MethodPair(
m1.asType(type1.changeReturnType(commonRetType)),
@ -766,7 +778,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
if(descriptor.getMethodType().parameterCount() != paramCount) {
throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
}
}
@ -805,7 +817,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
@SuppressWarnings("unused")
// This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
// want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
// "dyn:getMethod" linking).
// GET_METHOD linking).
private Object getDynamicMethod(final Object name) {
return getDynamicMethod(String.valueOf(name), methods);
}
@ -871,8 +883,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
@SuppressWarnings("unused")
MethodHandle getTarget(final MethodHandles.Lookup lookup, final LinkerServices linkerServices) {
final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(lookup));
MethodHandle getTarget(final CallSiteDescriptor desc, final LinkerServices linkerServices) {
final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(desc));
assert inv != null;
return inv;
}

View File

@ -86,7 +86,7 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodType;
import java.util.LinkedList;
import java.util.List;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Represents overloaded methods applicable to a specific call site signature.

View File

@ -91,13 +91,15 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.Operation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.internal.dynalink.linker.support.Lookup;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* A class that provides linking capabilities for a single POJO class. Normally not used directly, but managed by
@ -109,7 +111,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
// REVISIT: is it maybe a code smell that "dyn:getLength" is not needed?
// REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed?
setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY);
} else if(List.class.isAssignableFrom(clazz)) {
setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
@ -128,27 +130,23 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
@Override
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
linkerServices, operations, name);
if(superGic != null) {
return superGic;
}
if(operations.isEmpty()) {
return null;
}
final String op = operations.get(0);
// dyn:getElem(this, id)
// id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide
// conversion from call site argument type though.
if("getElem".equals(op)) {
return getElementGetter(callSiteDescriptor, linkerServices, pop(operations));
final Operation op = operations.get(0);
if(op == StandardOperation.GET_ELEMENT) {
return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
if("setElem".equals(op)) {
return getElementSetter(callSiteDescriptor, linkerServices, pop(operations));
if(op == StandardOperation.SET_ELEMENT) {
return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
// dyn:getLength(this) (works on Java arrays, collections, and maps)
if("getLength".equals(op)) {
if(op == StandardOperation.GET_LENGTH) {
return getLengthGetter(callSiteDescriptor);
}
return null;
@ -168,11 +166,11 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
};
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations);
linkerServices, operations, name);
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
@ -206,22 +204,20 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
return nextComponent;
}
// We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo"
final String fixedKey = getFixedKey(callSiteDescriptor);
// Convert the key to a number if we're working with a list or array
final Object typedFixedKey;
if(collectionType != CollectionType.MAP && fixedKey != null) {
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
if(typedFixedKey == null) {
final Object typedName;
if(collectionType != CollectionType.MAP && name != null) {
typedName = convertKeyToInteger(name, linkerServices);
if(typedName == null) {
// key is not numeric, it can never succeed
return nextComponent;
}
} else {
typedFixedKey = fixedKey;
typedName = name;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
if(nextComponent == null) {
@ -263,40 +259,50 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
validatorClass, validationType);
}
private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) {
return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken(
CallSiteDescriptor.NAME_OPERAND);
}
private static Integer convertKeyToInteger(final Object fixedKey, final LinkerServices linkerServices) throws Exception {
if (fixedKey instanceof Integer) {
return (Integer)fixedKey;
}
private static Object convertKeyToInteger(final String fixedKey, final LinkerServices linkerServices) throws Exception {
try {
if(linkerServices.canConvert(String.class, Number.class)) {
final Number n;
if (fixedKey instanceof Number) {
n = (Number)fixedKey;
} else {
final Class<?> keyClass = fixedKey.getClass();
if(linkerServices.canConvert(keyClass, Number.class)) {
final Object val;
try {
final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey);
if(!(val instanceof Number)) {
return null; // not a number
}
final Number n = (Number)val;
if(n instanceof Integer) {
return n;
}
final int intIndex = n.intValue();
final double doubleValue = n.doubleValue();
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
return null; // not an exact integer
}
return intIndex;
val = linkerServices.getTypeConverter(keyClass, Number.class).invoke(fixedKey);
} catch(Exception|Error e) {
throw e;
} catch(final Throwable t) {
throw new RuntimeException(t);
}
if(!(val instanceof Number)) {
return null; // not a number
}
n = (Number)val;
} else if (fixedKey instanceof String){
try {
return Integer.valueOf((String)fixedKey);
} catch(final NumberFormatException e) {
// key is not a number
return null;
}
} else {
return null;
}
return Integer.valueOf(fixedKey);
} catch(final NumberFormatException e) {
// key is not a number
return null;
}
if(n instanceof Integer) {
return (Integer)n;
}
final int intIndex = n.intValue();
final double doubleValue = n.doubleValue();
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
return null; // not an exact integer
}
return intIndex;
}
private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) {
@ -389,7 +395,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
MethodType.methodType(Object.class, Object.class, Object.class));
private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<String> operations) throws Exception {
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
@ -431,27 +437,25 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
// as maps will always succeed in setting the element and will never need to fall back to the next component
// operation.
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
callSiteDescriptor, linkerServices, operations);
callSiteDescriptor, linkerServices, operations, name);
if(gic == null) {
return nextComponent;
}
// We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo"
final String fixedKey = getFixedKey(callSiteDescriptor);
// Convert the key to a number if we're working with a list or array
final Object typedFixedKey;
if(collectionType != CollectionType.MAP && fixedKey != null) {
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
if(typedFixedKey == null) {
final Object typedName;
if(collectionType != CollectionType.MAP && name != null) {
typedName = convertKeyToInteger(name, linkerServices);
if(typedName == null) {
// key is not numeric, it can never succeed
return nextComponent;
}
} else {
typedFixedKey = fixedKey;
typedName = name;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
if(nextComponent == null) {
@ -510,7 +514,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
if(descriptor.getMethodType().parameterCount() != paramCount) {
throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
}
}
}

View File

@ -83,11 +83,11 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.Collection;
import java.util.Collections;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
@ -95,36 +95,61 @@ import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
/**
* A linker for POJOs. Normally used as the ultimate fallback linker by the {@link DynamicLinkerFactory} so it is given
* the chance to link calls to all objects that no other language runtime recognizes. Specifically, this linker will:
* A linker for ordinary Java objects. Normally used as the ultimate fallback
* linker by the {@link DynamicLinkerFactory} so it is given the chance to link
* calls to all objects that no other linker recognized. Specifically, this
* linker will:
* <ul>
* <li>expose all public methods of form {@code setXxx()}, {@code getXxx()}, and {@code isXxx()} as property setters and
* getters for {@code dyn:setProp} and {@code dyn:getProp} operations;</li>
* <li>expose all public methods for invocation through {@code dyn:callMethod} operation;</li>
* <li>expose all public methods for retrieval for {@code dyn:getMethod} operation; the methods thus retrieved can then
* be invoked using {@code dyn:call};</li>
* <li>expose all public fields as properties, unless there are getters or setters for the properties of the same name;</li>
* <li>expose {@code dyn:getLength}, {@code dyn:getElem} and {@code dyn:setElem} on native Java arrays, as well as
* {@link java.util.List} and {@link java.util.Map} objects; ({@code dyn:getLength} works on any
* {@link java.util.Collection});</li>
* <li>expose all public methods of form {@code setXxx()}, {@code getXxx()},
* and {@code isXxx()} as property setters and getters for
* {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY}
* operations;</li>
* <li>expose all public methods for invocation through
* {@link StandardOperation#CALL_METHOD} operation;</li>
* <li>expose all public methods for retrieval for
* {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved
* can then be invoked using {@link StandardOperation#CALL}.</li>
* <li>expose all public fields as properties, unless there are getters or
* setters for the properties of the same name;</li>
* <li>expose {@link StandardOperation#GET_LENGTH},
* {@link StandardOperation#GET_ELEMENT} and {@link StandardOperation#SET_ELEMENT}
* on native Java arrays, as well as {@link java.util.List} and
* {@link java.util.Map} objects; ({@link StandardOperation#GET_LENGTH} works on
* any {@link java.util.Collection});</li>
* <li>expose a virtual property named {@code length} on Java arrays;</li>
* <li>expose {@code dyn:new} on instances of {@link StaticClass} as calls to constructors, including those static class
* objects that represent Java arrays (their constructors take a single {@code int} parameter representing the length of
* the array to create);</li>
* <li>expose static methods, fields, and properties of classes in a similar manner to how instance method, fields, and
* properties are exposed, on {@link StaticClass} objects.</li>
* <li>expose a virtual property named {@code static} on instances of {@link java.lang.Class} to access their
* {@link StaticClass}.</li>
* <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
* as calls to constructors, including those static class objects that represent
* Java arrays (their constructors take a single {@code int} parameter
* representing the length of the array to create);</li>
* <li>expose static methods, fields, and properties of classes in a similar
* manner to how instance method, fields, and properties are exposed, on
* {@link StaticClass} objects.</li>
* <li>expose a virtual property named {@code static} on instances of
* {@link java.lang.Class} to access their {@link StaticClass}.</li>
* </ul>
* <p><strong>Overloaded method resolution</strong> is performed automatically for property setters, methods, and
* constructors. Additionally, manual overloaded method selection is supported by having a call site specify a name for
* a method that contains an explicit signature, i.e. {@code dyn:getMethod:parseInt(String,int)}. You can use
* non-qualified class names in such signatures regardless of those classes' packages, they will match any class with
* the same non-qualified name. You only have to use a fully qualified class name in case non-qualified class names
* would cause selection ambiguity (that is extremely rare).</p>
* <p><strong>Variable argument invocation</strong> is handled for both methods and constructors.</p>
* <p>Currently, only public fields and methods are supported. Any Lookup objects passed in the
* {@link LinkRequest}s are ignored and {@link MethodHandles#publicLookup()} is used instead.</p>
* <p><strong>Overloaded method resolution</strong> is performed automatically
* for property setters, methods, and constructors. Additionally, manual
* overloaded method selection is supported by having a call site specify a name
* for a method that contains an explicit signature, i.e.
* {@code NamedMethod(GET_METHOD, "parseInt(String,int)")}. You can use
* non-qualified class names in such signatures regardless of those classes'
* packages, they will match any class with the same non-qualified name. You
* only have to use a fully qualified class name in case non-qualified class
* names would cause selection ambiguity (that is extremely rare). Overloaded
* resolution for constructors is not automatic as there is no logical place to
* attach that functionality to but if a language wishes to provide this
* functionality, it can use {@link #getConstructorMethod(Class, String)} as a
* useful building block for it.</p>
* <p><strong>Variable argument invocation</strong> is handled for both methods
* and constructors.</p>
* <p><strong>Caller sensitive methods</strong> can be linked as long as they
* are otherwise public and link requests have call site descriptors carrying
* full-strength {@link Lookup} objects and not weakened lookups or the public
* lookup.</p>
* <p>The class also exposes various static methods for discovery of available
* property and method names on classes and class instances, as well as access
* to per-class linkers using the {@link #getLinkerForClass(Class)}
* method.</p>
*/
public class BeansLinker implements GuardingDynamicLinker {
private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<TypeBasedGuardingDynamicLinker>() {
@ -140,15 +165,16 @@ public class BeansLinker implements GuardingDynamicLinker {
};
/**
* Creates a new POJO linker.
* Creates a new beans linker.
*/
public BeansLinker() {
}
/**
* Returns a bean linker for a particular single class. Useful when you need to override or extend the behavior of
* linking for some classes in your language runtime's linker, but still want to delegate to the default behavior in
* some cases.
* Returns a bean linker for a particular single class. Useful when you need
* to override or extend the behavior of linking for some classes in your
* language runtime's linker, but still want to delegate to the default
* behavior in some cases.
* @param clazz the class
* @return a bean linker for that class
*/
@ -157,9 +183,12 @@ public class BeansLinker implements GuardingDynamicLinker {
}
/**
* Returns true if the object is a Dynalink Java dynamic method.
* Returns true if the object is a Java dynamic method (e.g., one
* obtained through a {@code GET_METHOD} operation on a Java object or
* {@link StaticClass} or through
* {@link #getConstructorMethod(Class, String)}.
*
* @param obj the object we want to test for being a dynamic method
* @param obj the object we want to test for being a Java dynamic method.
* @return true if it is a dynamic method, false otherwise.
*/
public static boolean isDynamicMethod(final Object obj) {
@ -167,9 +196,10 @@ public class BeansLinker implements GuardingDynamicLinker {
}
/**
* Returns true if the object is a Dynalink Java constructor.
* Returns true if the object is a Java constructor (obtained through
* {@link #getConstructorMethod(Class, String)}}.
*
* @param obj the object we want to test for being a constructor
* @param obj the object we want to test for being a Java constructor.
* @return true if it is a constructor, false otherwise.
*/
public static boolean isDynamicConstructor(final Object obj) {
@ -177,10 +207,22 @@ public class BeansLinker implements GuardingDynamicLinker {
}
/**
* Return the dynamic method of constructor of the given class and the given signature.
* Return the dynamic method of constructor of the given class and the given
* signature. This method is useful for exposing a functionality for
* selecting an overloaded constructor based on an explicit signature, as
* this functionality is not otherwise exposed by Dynalink as
* {@link StaticClass} objects act as overloaded constructors without
* explicit signature selection. Example usage would be:
* {@code getConstructorMethod(java.awt.Color.class, "int, int, int")}.
* @param clazz the class
* @param signature full signature of the constructor
* @return DynamicMethod for the constructor
* @param signature full signature of the constructor. Note how you can use
* names of primitive types, array names with normal Java notation (e.g.
* {@code "int[]"}), and normally you can even use unqualified class names
* (e.g. {@code "String, List"} instead of
* {@code "java.lang.String, java.util.List"} as long as they don't cause
* ambiguity in the specific parameter position.
* @return dynamic method for the constructor or null if no constructor with
* the specified signature exists.
*/
public static Object getConstructorMethod(final Class<?> clazz, final String signature) {
return StaticClassLinker.getConstructorMethod(clazz, signature);
@ -255,13 +297,6 @@ public class BeansLinker implements GuardingDynamicLinker {
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
throws Exception {
final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
final int l = callSiteDescriptor.getNameTokenCount();
// All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn"
if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) {
return null;
}
final Object receiver = request.getReceiver();
if(receiver == null) {
// Can't operate on null

View File

@ -1,148 +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.beans;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import sun.reflect.CallerSensitive;
/**
* Utility class that determines if a method or constructor is caller sensitive. It actually encapsulates two different
* strategies for determining caller sensitivity; a more robust one that works if Dynalink runs as code with access
* to {@code sun.reflect} package, and an unprivileged one that is used when Dynalink doesn't have access to that
* package. Note that even the unprivileged strategy is ordinarily robust, but it relies on the {@code toString} method
* of the annotation. If an attacker were to use a different annotation to spoof the string representation of the
* {@code CallerSensitive} annotation, they could designate their own methods as caller sensitive. This however does not
* escalate privileges, only causes Dynalink to never cache method handles for such methods, so all it would do would
* decrease the performance in linking such methods. In the opposite case when an attacker could trick Dynalink into not
* recognizing genuine {@code CallerSensitive} annotations, Dynalink would treat caller sensitive methods as ordinary
* methods, and would cache them bound to a zero-privilege delegate as the caller (just what Dynalink did before it
* could handle caller-sensitive methods). That would practically render caller-sensitive methods exposed through
* Dynalink unusable, but again, can not lead to any privilege escalations. Therefore, even the less robust unprivileged
* strategy is safe; the worst thing a successful attack against it can achieve is slight reduction in Dynalink-exposed
* functionality or performance.
*/
public class CallerSensitiveDetector {
private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy();
static boolean isCallerSensitive(final AccessibleObject ao) {
return DETECTION_STRATEGY.isCallerSensitive(ao);
}
private static DetectionStrategy getDetectionStrategy() {
try {
return new PrivilegedDetectionStrategy();
} catch(final Throwable t) {
return new UnprivilegedDetectionStrategy();
}
}
private abstract static class DetectionStrategy {
abstract boolean isCallerSensitive(AccessibleObject ao);
}
private static class PrivilegedDetectionStrategy extends DetectionStrategy {
private static final Class<? extends Annotation> CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class;
@Override
boolean isCallerSensitive(final AccessibleObject ao) {
return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null;
}
}
private static class UnprivilegedDetectionStrategy extends DetectionStrategy {
private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()";
@Override
boolean isCallerSensitive(final AccessibleObject o) {
for(final Annotation a: o.getAnnotations()) {
if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) {
return true;
}
}
return false;
}
}
}

View File

@ -91,15 +91,24 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import jdk.internal.dynalink.support.Lookup;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is
* caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in
* {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on
* {@link #getTarget(CallSiteDescriptor)} to unreflect a method handle from the reflective member on
* every request.
*/
class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
private static final AccessControlContext GET_LOOKUP_CONTEXT =
AccessControlContextFactory.createAccessControlContext(
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
private final AccessibleObject target;
@ -143,7 +152,11 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
}
@Override
MethodHandle getTarget(final MethodHandles.Lookup lookup) {
MethodHandle getTarget(final CallSiteDescriptor desc) {
final MethodHandles.Lookup lookup = AccessController.doPrivileged(
(PrivilegedAction<MethodHandles.Lookup>)()->desc.getLookup(),
GET_LOOKUP_CONTEXT);
if(target instanceof Method) {
final MethodHandle mh = Lookup.unreflect(lookup, (Method)target);
if(Modifier.isStatic(((Member)target).getModifiers())) {

View File

@ -86,15 +86,15 @@ package jdk.internal.dynalink.beans;
import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
/**
* A utility class to check whether a given class is in a package with restricted access e.g. "sun.*" etc.
*/
class CheckRestrictedPackage {
private static final AccessControlContext NO_PERMISSIONS_CONTEXT = createNoPermissionsContext();
private static final AccessControlContext NO_PERMISSIONS_CONTEXT =
AccessControlContextFactory.createAccessControlContext();
/**
* Returns true if the class is either not public, or it resides in a package with restricted access.
@ -131,8 +131,4 @@ class CheckRestrictedPackage {
}
return false;
}
private static AccessControlContext createNoPermissionsContext() {
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
}
}

View File

@ -87,7 +87,7 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* A linker for java.lang.Class objects. Provides a synthetic property "static" that allows access to static fields and

View File

@ -85,11 +85,15 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Represents a sequence of {@link Class} objects, useful for representing method signatures. Provides value
@ -97,6 +101,9 @@ import jdk.internal.dynalink.support.TypeUtilities;
* JLS.
*/
final class ClassString {
private static final AccessControlContext GET_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext("getClassLoader");
/**
* An anonymous inner class used solely to represent the "type" of null values for method applicability checking.
*/
@ -143,12 +150,17 @@ final class ClassString {
}
boolean isVisibleFrom(final ClassLoader classLoader) {
for(int i = 0; i < classes.length; ++i) {
if(!Guards.canReferenceDirectly(classLoader, classes[i].getClassLoader())) {
return false;
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
for(final Class<?> clazz: classes) {
if(!InternalTypeUtilities.canReferenceDirectly(classLoader, clazz.getClassLoader())) {
return false;
}
}
return true;
}
}
return true;
}, GET_CLASS_LOADER_CONTEXT);
}
List<MethodHandle> getMaximallySpecifics(final List<MethodHandle> methods, final LinkerServices linkerServices, final boolean varArg) {

View File

@ -86,16 +86,19 @@ package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.Operation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.linker.support.Guards;
/**
* Simple linker that implements the "dyn:call" operation for {@link DynamicMethod} objects - the objects returned by
* "dyn:getMethod" from {@link AbstractJavaLinker}.
* Simple linker that implements the {@link StandardOperation#CALL} operation
* for {@link DynamicMethod} objects - the objects returned by
* {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}.
*/
class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
@Override
@ -109,19 +112,16 @@ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
if(!(receiver instanceof DynamicMethod)) {
return null;
}
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
return null;
}
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
if (operator == "call" && !constructor) {
invocation = dynMethod.getInvocation(
CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
} else if (operator == "new" && constructor) {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
final Operation op = NamedOperation.getBaseOperation(desc.getOperation());
if (op == StandardOperation.CALL && !constructor) {
invocation = dynMethod.getInvocation(desc.changeMethodType(
desc.getMethodType().dropParameterTypes(0, 1)), linkerServices);
} else if (op == StandardOperation.NEW && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;

View File

@ -92,7 +92,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* Base for classes that expose class field and method information to an {@link AbstractJavaLinker}. There are

View File

@ -90,7 +90,7 @@ import java.util.LinkedList;
import java.util.List;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Utility class that encapsulates the algorithm for choosing the maximally specific methods.

View File

@ -84,18 +84,24 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
import jdk.internal.dynalink.internal.AccessControlContextFactory;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.TypeUtilities;
/**
* Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all
@ -216,14 +222,25 @@ class OverloadedDynamicMethod extends DynamicMethod {
// methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
// has an already determined Lookup.
final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size());
final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
for(final SingleDynamicMethod method: invokables) {
methodHandles.add(method.getTarget(lookup));
methodHandles.add(method.getTarget(callSiteDescriptor));
}
return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices).getInvoker();
}
}
}
private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext(
"getClassLoader", CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return callSiteDescriptor.getLookup().lookupClass().getClassLoader();
}
}, GET_CALL_SITE_CLASS_LOADER_CONTEXT);
}
@Override
@ -324,7 +341,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
private static boolean isApplicableDynamically(final LinkerServices linkerServices, final Class<?> callSiteType,
final Class<?> methodType) {
return TypeUtilities.isPotentiallyConvertible(callSiteType, methodType)
return isPotentiallyConvertible(callSiteType, methodType)
|| linkerServices.canConvert(callSiteType, methodType);
}
@ -345,4 +362,72 @@ class OverloadedDynamicMethod extends DynamicMethod {
private boolean constructorFlagConsistent(final SingleDynamicMethod method) {
return methods.isEmpty()? true : (methods.getFirst().isConstructor() == method.isConstructor());
}
/**
* Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between
* any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as
* well as between any primitive type and any reference type that can hold a boxed primitive.
*
* @param callSiteType the parameter type at the call site
* @param methodType the parameter type in the method declaration
* @return true if callSiteType is potentially convertible to the methodType.
*/
private static boolean isPotentiallyConvertible(final Class<?> callSiteType, final Class<?> methodType) {
// Widening or narrowing reference conversion
if(InternalTypeUtilities.areAssignable(callSiteType, methodType)) {
return true;
}
if(callSiteType.isPrimitive()) {
// Allow any conversion among primitives, as well as from any
// primitive to any type that can receive a boxed primitive.
// TODO: narrow this a bit, i.e. allow, say, boolean to Character?
// MethodHandles.convertArguments() allows it, so we might need to
// too.
return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType);
}
if(methodType.isPrimitive()) {
// Allow conversion from any reference type that can contain a
// boxed primitive to any primitive.
// TODO: narrow this a bit too?
return isAssignableFromBoxedPrimitive(callSiteType);
}
return false;
}
private static final Set<Class<?>> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes();
private static Set<Class<?>> createPrimitiveWrapperTypes() {
final Map<Class<?>, Class<?>> classes = new IdentityHashMap<>();
addClassHierarchy(classes, Boolean.class);
addClassHierarchy(classes, Byte.class);
addClassHierarchy(classes, Character.class);
addClassHierarchy(classes, Short.class);
addClassHierarchy(classes, Integer.class);
addClassHierarchy(classes, Long.class);
addClassHierarchy(classes, Float.class);
addClassHierarchy(classes, Double.class);
return classes.keySet();
}
private static void addClassHierarchy(final Map<Class<?>, Class<?>> map, final Class<?> clazz) {
if(clazz == null) {
return;
}
map.put(clazz, clazz);
addClassHierarchy(map, clazz.getSuperclass());
for(final Class<?> itf: clazz.getInterfaces()) {
addClassHierarchy(map, itf);
}
}
/**
* Returns true if the class can be assigned from any boxed primitive.
*
* @param clazz the class
* @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any
* primitive wrapper class, or a superclass or superinterface of any primitive wrapper class.
*/
private static boolean isAssignableFromBoxedPrimitive(final Class<?> clazz) {
return PRIMITIVE_WRAPPER_TYPES.contains(clazz);
}
}

View File

@ -91,9 +91,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or
@ -104,15 +104,20 @@ import jdk.internal.dynalink.support.TypeUtilities;
class OverloadedMethod {
private final Map<ClassString, MethodHandle> argTypesToMethods = new ConcurrentHashMap<>();
private final OverloadedDynamicMethod parent;
private final ClassLoader callSiteClassLoader;
private final MethodType callSiteType;
private final MethodHandle invoker;
private final LinkerServices linkerServices;
private final ArrayList<MethodHandle> fixArgMethods;
private final ArrayList<MethodHandle> varArgMethods;
OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,
OverloadedMethod(final List<MethodHandle> methodHandles,
final OverloadedDynamicMethod parent,
final ClassLoader callSiteClassLoader,
final MethodType callSiteType,
final LinkerServices linkerServices) {
this.parent = parent;
this.callSiteClassLoader = callSiteClassLoader;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
@ -177,9 +182,9 @@ class OverloadedMethod {
break;
}
}
// Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader
// memory leaks.
if(classString.isVisibleFrom(parent.getClassLoader())) {
// Avoid keeping references to unrelated classes; this ruins the
// performance a bit, but avoids class loader memory leaks.
if(classString.isVisibleFrom(callSiteClassLoader)) {
argTypesToMethods.put(classString, method);
}
}
@ -268,7 +273,7 @@ class OverloadedMethod {
final Iterator<MethodHandle> it = methodHandles.iterator();
Class<?> retType = it.next().type().returnType();
while(it.hasNext()) {
retType = TypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType());
retType = InternalTypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType());
}
return retType;
}

View File

@ -84,13 +84,13 @@
package jdk.internal.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
/**
* A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
* not caller sensitive, this class pre-caches its method handle and always returns it from the call to
* {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
* {@link #getTarget(CallSiteDescriptor)}. Can be used in general to represents dynamic methods bound to a single method handle,
* even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
* getters/setters, etc.
*/
@ -140,7 +140,7 @@ class SimpleDynamicMethod extends SingleDynamicMethod {
}
@Override
MethodHandle getTarget(final Lookup lookup) {
MethodHandle getTarget(final CallSiteDescriptor desc) {
return target;
}

View File

@ -90,8 +90,8 @@ import java.lang.reflect.Array;
import java.util.StringTokenizer;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
@ -119,15 +119,17 @@ abstract class SingleDynamicMethod extends DynamicMethod {
abstract MethodType getMethodType();
/**
* Given a specified lookup, returns a method handle to this method's target.
* @param lookup the lookup to use.
* Given a specified call site descriptor, returns a method handle to this method's target. The target
* should only depend on the descriptor's lookup, and it should only retrieve it (as a privileged
* operation) when it is absolutely needed.
* @param desc the call site descriptor to use.
* @return the handle to this method's target method.
*/
abstract MethodHandle getTarget(MethodHandles.Lookup lookup);
abstract MethodHandle getTarget(CallSiteDescriptor desc);
@Override
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(),
return getInvocation(getTarget(callSiteDescriptor), callSiteDescriptor.getMethodType(),
linkerServices);
}

View File

@ -85,16 +85,48 @@ package jdk.internal.dynalink.beans;
import java.io.Serializable;
import java.util.Objects;
import jdk.internal.dynalink.StandardOperation;
/**
* Object that represents the static facet of a class (its static methods, properties, and fields, as well as
* construction of instances using "dyn:new"). Objects of this class are recognized by the {@link BeansLinker} as being
* special, and operations on them will be linked against the represented class' static facet. The "class" synthetic
* property is additionally recognized and returns the Java {@link Class} object, as per {@link #getRepresentedClass()}
* method. Conversely, {@link Class} objects exposed through {@link BeansLinker} expose the "static" synthetic property
* which returns an instance of this class.
* Object that allows access to the static members of a class (its static
* methods, properties, and fields), as well as construction of instances using
* {@link StandardOperation#NEW} operation. In Dynalink, {@link Class} objects
* are not treated specially and act as ordinary Java objects; you can use e.g.
* {@code NamedOperation(GET_PROPERTY, "superclass")} as a property getter to
* invoke {@code clazz.getSuperclass()}. On the other hand, you can not use
* {@code Class} objects to access static members of a class, nor to create new
* instances of the class using {@code NEW}. This is consistent with how
* {@code Class} objects behave in Java: in Java, you write e.g.
* {@code new BitSet()} instead of {@code new BitSet.class()}. Similarly, you
* write {@code System.out} and not {@code System.class.out}. It is this aspect
* of using a class name as the constructor and a namespace for static members
* that {@code StaticClass} embodies.
* <p>
* Objects of this class are recognized by the {@link BeansLinker} as being
* special, and operations on them will be linked against the represented class'
* static members. The {@code "class"} synthetic property is additionally
* recognized and returns the Java {@link Class} object, just as in Java
* {@code System.class} evaluates to the {@code Class} object for the
* {@code} System class. Conversely, {@link Class} objects exposed through
* {@link BeansLinker} expose the {@code "static"} synthetic property which
* returns their {@code StaticClass} object (there is no equivalent to this in
* Java).
* <p>
* In summary, instances of this class act as namespaces for static members and
* as constructors for classes, much the same way as specifying a class name in
* Java language does, except that in Java this is just a syntactic element,
* while in Dynalink they are expressed as actual objects.
* <p>{@code StaticClass} objects representing Java array types will act as
* constructors taking a single int argument and create an array of the
* specified size.
* <p>
* If the class has several constructors, {@link StandardOperation#NEW} on
* {@code StaticClass} will try to select the most specific applicable
* constructor. You might want to expose a mechanism in your language for
* selecting a constructor with an explicit signature through
* {@link BeansLinker#getConstructorMethod(Class, String)}.
*/
public class StaticClass implements Serializable {
public final class StaticClass implements Serializable {
private static final ClassValue<StaticClass> staticClasses = new ClassValue<StaticClass>() {
@Override
protected StaticClass computeValue(final Class<?> type) {
@ -129,7 +161,7 @@ public class StaticClass implements Serializable {
@Override
public String toString() {
return "JavaClassStatics[" + clazz.getName() + "]";
return "StaticClass[" + clazz.getName() + "]";
}
private Object readResolve() {

View File

@ -90,12 +90,14 @@ import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* Provides a linker for the {@link StaticClass} objects.
@ -150,8 +152,7 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
return gi;
}
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR);
if("new" == op && constructor != null) {
if(NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.NEW && constructor != null) {
final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices);
if(ctorInvocation != null) {
return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType()));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -81,38 +81,9 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.linker;
/**
* Guarded type conversion
* Contains the linker for ordinary Java objects.
* @since 1.9
*/
public class GuardedTypeConversion {
private final GuardedInvocation conversionInvocation;
private final boolean cacheable;
/**
* Constructor
* @param conversionInvocation guarded invocation for this type conversion
* @param cacheable is this invocation cacheable
*/
public GuardedTypeConversion(final GuardedInvocation conversionInvocation, final boolean cacheable) {
this.conversionInvocation = conversionInvocation;
this.cacheable = cacheable;
}
/**
* Get the invocation
* @return invocation
*/
public GuardedInvocation getConversionInvocation() {
return conversionInvocation;
}
/**
* Check if invocation is cacheable
* @return true if cacheable, false otherwise
*/
public boolean isCacheable() {
return cacheable;
}
}
@jdk.Exported
package jdk.internal.dynalink.beans;

View File

@ -1,86 +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.
-->
<body>
<p>
Contains the linker for POJOs.
</p>
</body>

View File

@ -0,0 +1,77 @@
/*
* 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.
*/
package jdk.internal.dynalink.internal;
import java.security.AccessControlContext;
import java.security.Permission;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.stream.Stream;
/**
* Utility class for creating permission-restricting {@link AccessControlContext}s.
*/
public final class AccessControlContextFactory {
private AccessControlContextFactory () {
}
/**
* Creates an access control context with no permissions.
* @return an access control context with no permissions.
*/
public static AccessControlContext createAccessControlContext() {
return createAccessControlContext(new Permission[0]);
}
/**
* Creates an access control context limited to only the specified permissions.
* @param permissions the permissions for the newly created access control context.
* @return a new access control context limited to only the specified permissions.
*/
public static AccessControlContext createAccessControlContext(final Permission... permissions) {
final Permissions perms = new Permissions();
for(final Permission permission: permissions) {
perms.add(permission);
}
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
}
/**
* Creates an access control context limited to only the {@link RuntimePermission}s
* of the given names.
* @param runtimePermissionNames the names of runtime permissions for the
* newly created access control context.
* @return a new access control context limited to only the runtime
* permissions with the specified names.
*/
public static AccessControlContext createAccessControlContext(final String... runtimePermissionNames) {
return createAccessControlContext(makeRuntimePermissions(runtimePermissionNames));
}
private static Permission[] makeRuntimePermissions(final String... runtimePermissionNames) {
return Stream.of(runtimePermissionNames).map(RuntimePermission::new).toArray(Permission[]::new);
}
}

View File

@ -0,0 +1,187 @@
/*
* 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.
*/
package jdk.internal.dynalink.internal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Various static utility methods for testing type relationships; internal to Dynalink.
*/
public class InternalTypeUtilities {
private InternalTypeUtilities() {
}
/**
* Returns true if either of the types is assignable from the other.
* @param c1 one type
* @param c2 another type
* @return true if either c1 is assignable from c2 or c2 is assignable from c1.
*/
public static boolean areAssignable(final Class<?> c1, final Class<?> c2) {
return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
}
/**
* Return true if it is safe to strongly reference a class from the referred
* class loader from a class associated with the referring class loader
* without risking a class loader memory leak. Generally, it is only safe
* to reference classes from the same or ancestor class loader. {@code null}
* indicates the system class loader; classes from it can always be
* directly referenced, and it can only directly reference classes from
* itself. This method can be used by language runtimes to ensure they are
* using weak references in their linkages when they need to link to methods
* in unrelated class loaders.
*
* @param referrerLoader the referrer class loader.
* @param referredLoader the referred class loader
* @return true if it is safe to strongly reference the class from referred
* in referred.
* @throws SecurityException if the caller does not have the
* {@code RuntimePermission("getClassLoader")} permission and the method
* needs to traverse the parent class loader chain.
*/
public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) {
if(referredLoader == null) {
// Can always refer directly to a system class
return true;
}
if(referrerLoader == null) {
// System classes can't refer directly to any non-system class
return false;
}
// Otherwise, can only refer directly to classes residing in same or
// parent class loader.
ClassLoader referrer = referrerLoader;
do {
if(referrer == referredLoader) {
return true;
}
referrer = referrer.getParent();
} while(referrer != null);
return false;
}
/**
* Given two types represented by c1 and c2, returns a type that is their
* most specific common supertype for purposes of lossless conversions.
*
* @param c1 one type
* @param c2 another type
* @return their most common superclass or superinterface for purposes of
* lossless conversions. If they have several unrelated superinterfaces as
* their most specific common type, or the types themselves are completely
* unrelated interfaces, {@link java.lang.Object} is returned.
*/
public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
if(c1 == c2) {
return c1;
} else if (c1 == void.class || c2 == void.class) {
return Object.class;
} else if(TypeUtilities.isConvertibleWithoutLoss(c2, c1)) {
return c1;
} else if(TypeUtilities.isConvertibleWithoutLoss(c1, c2)) {
return c2;
} else if(c1.isPrimitive() && c2.isPrimitive()) {
if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
// byte + char = int
return int.class;
} else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) {
// short + char = int
return int.class;
} else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) {
// int + float = double
return double.class;
}
}
// For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too.
return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2);
}
private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) {
final Class<?> npc1 = c1.isPrimitive() ? TypeUtilities.getWrapperType(c1) : c1;
final Class<?> npc2 = c2.isPrimitive() ? TypeUtilities.getWrapperType(c2) : c2;
final Set<Class<?>> a1 = getAssignables(npc1, npc2);
final Set<Class<?>> a2 = getAssignables(npc2, npc1);
a1.retainAll(a2);
if(a1.isEmpty()) {
// Can happen when at least one of the arguments is an interface,
// as they don't have Object at the root of their hierarchy.
return Object.class;
}
// Gather maximally specific elements. Yes, there can be more than one
// thank to interfaces. I.e., if you call this method for String.class
// and Number.class, you'll have Comparable, Serializable, and Object
// as maximal elements.
final List<Class<?>> max = new ArrayList<>();
outer: for(final Class<?> clazz: a1) {
for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
final Class<?> maxClazz = maxiter.next();
if(TypeUtilities.isSubtype(maxClazz, clazz)) {
// It can't be maximal, if there's already a more specific
// maximal than it.
continue outer;
}
if(TypeUtilities.isSubtype(clazz, maxClazz)) {
// If it's more specific than a currently maximal element,
// that currently maximal is no longer a maximal.
maxiter.remove();
}
}
// If we get here, no current maximal is more specific than the
// current class, so it is considered maximal as well
max.add(clazz);
}
if(max.size() > 1) {
return Object.class;
}
return max.get(0);
}
private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) {
final Set<Class<?>> s = new HashSet<>();
collectAssignables(c1, c2, s);
return s;
}
private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) {
if(c1.isAssignableFrom(c2)) {
s.add(c1);
}
final Class<?> sc = c1.getSuperclass();
if(sc != null) {
collectAssignables(sc, c2, s);
}
final Class<?>[] itf = c1.getInterfaces();
for(int i = 0; i < itf.length; ++i) {
collectAssignables(itf[i], c2, s);
}
}
}

View File

@ -85,11 +85,14 @@ package jdk.internal.dynalink.linker;
/**
* Optional interface to be implemented by {@link GuardingTypeConverterFactory} implementers. Language-specific
* conversions can cause increased overloaded method resolution ambiguity, as many methods can become applicable because
* of additional conversions. The static way of selecting the "most specific" method will fail more often, because there
* will be multiple maximally specific method with unrelated signatures. In these cases, language runtimes can be asked
* to resolve the ambiguity by expressing preferences for one conversion over the other.
* Optional interface to be implemented by {@link GuardingTypeConverterFactory}
* implementers. Language-specific conversions can cause increased overloaded
* method resolution ambiguity, as many methods can become applicable because of
* additional conversions. The static way of selecting the "most specific"
* method will fail more often, because there will be multiple maximally
* specific method with unrelated signatures. In these cases, language runtimes
* can be asked to resolve the ambiguity by expressing preferences for one
* conversion over the other.
*/
public interface ConversionComparator {
/**
@ -105,12 +108,13 @@ public interface ConversionComparator {
}
/**
* Determines which of the two target types is the preferred conversion target from a source type.
* Determines which of the two target types is the preferred conversion
* target from a source type.
* @param sourceType the source type.
* @param targetType1 one potential target type
* @param targetType2 another potential target type.
* @return one of Comparison constants that establish which - if any - of the target types is preferred for the
* conversion.
* @return one of Comparison constants that establish which - if any - of
* the target types is preferred for the conversion.
*/
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);
}

View File

@ -83,24 +83,32 @@
package jdk.internal.dynalink.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.invoke.WrongMethodTypeException;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.linker.support.Guards;
/**
* Represents a conditionally valid method handle. It is an immutable triple of an invocation method handle, a guard
* method handle that defines the applicability of the invocation handle, and a switch point that can be used for
* external invalidation of the invocation handle. The invocation handle is suitable for invocation if the guard
* handle returns true for its arguments, and as long as the switch point is not invalidated. Both the guard and the
* switch point are optional; neither, one, or both can be present.
* Represents a conditionally valid method handle. Usually produced as a return
* value of
* {@link GuardingDynamicLinker#getGuardedInvocation(LinkRequest, LinkerServices)}
* and
* {@link GuardingTypeConverterFactory#convertToType(Class, Class, Supplier)}.
* It is an immutable tuple of an invocation method handle, a guard method
* handle that defines the applicability of the invocation handle, zero or more
* switch points that can be used for external invalidation of the invocation
* handle, and an exception type that if thrown during an invocation of the
* method handle also invalidates it. The invocation handle is suitable for
* invocation if the guard handle returns true for its arguments, and as long
* as any of the switch points are not invalidated, and as long as it does not
* throw an exception of the designated type. The guard, the switch points, and
* the exception type are all optional (a guarded invocation having none of them
* is unconditionally valid).
*/
public class GuardedInvocation {
private final MethodHandle invocation;
@ -109,9 +117,11 @@ public class GuardedInvocation {
private final SwitchPoint[] switchPoints;
/**
* Creates a new guarded invocation. This invocation is unconditional as it has no invalidations.
* Creates a new unconditional guarded invocation. It is unconditional as it
* has no invalidations.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param invocation the method handle representing the invocation. Must not
* be null.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation) {
@ -119,12 +129,15 @@ public class GuardedInvocation {
}
/**
* Creates a new guarded invocation.
* Creates a new guarded invocation, with a guard method handle.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param guard the method handle representing the guard. Must have the same method type as the invocation, except
* it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null to represent
* an unconditional invocation, although that is unusual.
* @param invocation the method handle representing the invocation. Must not
* be null.
* @param guard the method handle representing the guard. Must have be
* compatible with the {@code invocation} handle as per
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}.
* For some useful guards, check out the {@link Guards} class. It can be
* null to represent an unconditional invocation.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard) {
@ -132,10 +145,14 @@ public class GuardedInvocation {
}
/**
* Creates a new guarded invocation.
* Creates a new guarded invocation that can be invalidated by a switch
* point.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param switchPoint the optional switch point that can be used to invalidate this linkage.
* @param invocation the method handle representing the invocation. Must
* not be null.
* @param switchPoint the optional switch point that can be used to
* invalidate this linkage. It can be null. If it is null, this represents
* an unconditional invocation.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation, final SwitchPoint switchPoint) {
@ -143,13 +160,19 @@ public class GuardedInvocation {
}
/**
* Creates a new guarded invocation.
* Creates a new guarded invocation, with both a guard method handle and a
* switch point that can be used to invalidate it.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param guard the method handle representing the guard. Must have the same method type as the invocation, except
* it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it
* and the switch point are null, this represents an unconditional invocation, which is legal but unusual.
* @param switchPoint the optional switch point that can be used to invalidate this linkage.
* @param invocation the method handle representing the invocation. Must
* not be null.
* @param guard the method handle representing the guard. Must have be
* compatible with the {@code invocation} handle as per
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}.
* For some useful guards, check out the {@link Guards} class. It can be
* null. If both it and the switch point are null, this represents an
* unconditional invocation.
* @param switchPoint the optional switch point that can be used to
* invalidate this linkage.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint) {
@ -157,15 +180,22 @@ public class GuardedInvocation {
}
/**
* Creates a new guarded invocation.
* Creates a new guarded invocation, with a guard method handle, a
* switch point that can be used to invalidate it, and an exception that if
* thrown when invoked also invalidates it.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param guard the method handle representing the guard. Must have the same method type as the invocation, except
* it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it
* and the switch point are null, this represents an unconditional invocation, which is legal but unusual.
* @param switchPoint the optional switch point that can be used to invalidate this linkage.
* @param exception the optional exception type that is expected to be thrown by the invocation and that also
* invalidates the linkage.
* @param invocation the method handle representing the invocation. Must not
* be null.
* @param guard the method handle representing the guard. Must have be
* compatible with the {@code invocation} handle as per
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}.
* For some useful guards, check out the {@link Guards} class. It can be
* null. If it and the switch point and the exception are all null, this
* represents an unconditional invocation.
* @param switchPoint the optional switch point that can be used to
* invalidate this linkage.
* @param exception the optional exception type that is when thrown by the
* invocation also invalidates it.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint switchPoint, final Class<? extends Throwable> exception) {
@ -176,15 +206,22 @@ public class GuardedInvocation {
}
/**
* Creates a new guarded invocation
* Creates a new guarded invocation, with a guard method handle, any number
* of switch points that can be used to invalidate it, and an exception that
* if thrown when invoked also invalidates it.
*
* @param invocation the method handle representing the invocation. Must not be null.
* @param guard the method handle representing the guard. Must have the same method type as the invocation, except
* it must return boolean. For some useful guards, check out the {@link Guards} class. It can be null. If both it
* and the switch point are null, this represents an unconditional invocation, which is legal but unusual.
* @param switchPoints the optional switch points that can be used to invalidate this linkage.
* @param exception the optional exception type that is expected to be thrown by the invocation and that also
* invalidates the linkage.
* @param invocation the method handle representing the invocation. Must not
* be null.
* @param guard the method handle representing the guard. Must have be
* compatible with the {@code invocation} handle as per
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}.
* For some useful guards, check out the {@link Guards} class. It can be
* null. If it and the exception are both null, and no switch points were
* specified, this represents an unconditional invocation.
* @param switchPoints optional switch points that can be used to
* invalidate this linkage.
* @param exception the optional exception type that is when thrown by the
* invocation also invalidates it.
* @throws NullPointerException if invocation is null.
*/
public GuardedInvocation(final MethodHandle invocation, final MethodHandle guard, final SwitchPoint[] switchPoints, final Class<? extends Throwable> exception) {
@ -213,26 +250,32 @@ public class GuardedInvocation {
}
/**
* Returns the switch point that can be used to invalidate the invocation handle.
* Returns the switch points that can be used to invalidate the linkage of
* this invocation handle.
*
* @return the switch point that can be used to invalidate the invocation handle. Can be null.
* @return the switch points that can be used to invalidate the linkage of
* this invocation handle. Can be null.
*/
public SwitchPoint[] getSwitchPoints() {
return switchPoints == null ? null : switchPoints.clone();
}
/**
* Returns the exception type that if thrown should be used to invalidate the linkage.
* Returns the exception type that if thrown by the invocation should
* invalidate the linkage of this guarded invocation.
*
* @return the exception type that if thrown should be used to invalidate the linkage. Can be null.
* @return the exception type that if thrown should be used to invalidate
* the linkage. Can be null.
*/
public Class<? extends Throwable> getException() {
return exception;
}
/**
* Returns true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated.
* @return true if and only if this guarded invocation has a switchpoint, and that switchpoint has been invalidated.
* Returns true if and only if this guarded invocation has at least one
* invalidated switch point.
* @return true if and only if this guarded invocation has at least one
* invalidated switch point.
*/
public boolean hasBeenInvalidated() {
if (switchPoints == null) {
@ -246,20 +289,6 @@ public class GuardedInvocation {
return false;
}
/**
* Asserts that the invocation is of the specified type, and the guard (if present) is of the specified type with a
* boolean return type.
*
* @param type the asserted type
* @throws WrongMethodTypeException if the invocation and the guard are not of the expected method type.
*/
public void assertType(final MethodType type) {
assertType(invocation, type);
if (guard != null) {
assertType(guard, type.changeReturnType(Boolean.TYPE));
}
}
/**
* Creates a new guarded invocation with different methods, preserving the switch point.
*
@ -272,9 +301,10 @@ public class GuardedInvocation {
}
/**
* Add a switchpoint to this guarded invocation
* @param newSwitchPoint new switchpoint, or null for nop
* @return new guarded invocation with the extra switchpoint
* Create a new guarded invocation with an added switch point.
* @param newSwitchPoint new switch point. Can be null in which case this
* method return the current guarded invocation with no changes.
* @return a guarded invocation with the added switch point.
*/
public GuardedInvocation addSwitchPoint(final SwitchPoint newSwitchPoint) {
if (newSwitchPoint == null) {
@ -301,9 +331,11 @@ public class GuardedInvocation {
}
/**
* Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation
* and its guard, if it has one (with return type changed to boolean, and parameter count potentially truncated for
* the guard). If the invocation already is of the required type, returns this object.
* Changes the type of the invocation, as if
* {@link MethodHandle#asType(MethodType)} was applied to its invocation
* and its guard, if it has one (with return type changed to boolean, and
* parameter count potentially truncated for the guard). If the invocation
* already is of the required type, returns this object.
* @param newType the new type of the invocation.
* @return a guarded invocation with the new type applied to it.
*/
@ -312,9 +344,11 @@ public class GuardedInvocation {
}
/**
* Changes the type of the invocation, as if {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to
* its invocation and its guard, if it has one (with return type changed to boolean, and parameter count potentially
* truncated for the guard). If the invocation already is of the required type, returns this object.
* Changes the type of the invocation, as if
* {@link LinkerServices#asType(MethodHandle, MethodType)} was applied to
* its invocation and its guard, if it has one (with return type changed to
* boolean, and parameter count potentially truncated for the guard). If the
* invocation already is of the required type, returns this object.
* @param linkerServices the linker services to use for the conversion
* @param newType the new type of the invocation.
* @return a guarded invocation with the new type applied to it.
@ -325,10 +359,13 @@ public class GuardedInvocation {
}
/**
* Changes the type of the invocation, as if {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was
* applied to its invocation and {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its guard, if it
* has one (with return type changed to boolean, and parameter count potentially truncated for the guard). If the
* invocation doesn't change its type, returns this object.
* Changes the type of the invocation, as if
* {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} was
* applied to its invocation and
* {@link LinkerServices#asType(MethodHandle, MethodType)} applied to its
* guard, if it has one (with return type changed to boolean, and parameter
* count potentially truncated for the guard). If the invocation doesn't
* change its type, returns this object.
* @param linkerServices the linker services to use for the conversion
* @param newType the new type of the invocation.
* @return a guarded invocation with the new type applied to it.
@ -339,9 +376,11 @@ public class GuardedInvocation {
}
/**
* Changes the type of the invocation, as if {@link MethodHandle#asType(MethodType)} was applied to its invocation
* and its guard, if it has one (with return type changed to boolean for guard). If the invocation already is of the
* required type, returns this object.
* Changes the type of the invocation, as if
* {@link MethodHandle#asType(MethodType)} was applied to its invocation
* and its guard, if it has one (with return type changed to boolean for
* guard). If the invocation already is of the required type, returns this
* object.
* @param desc a call descriptor whose method type is adapted.
* @return a guarded invocation with the new type applied to it.
*/
@ -350,7 +389,8 @@ public class GuardedInvocation {
}
/**
* Applies argument filters to both the invocation and the guard (if there is one).
* Applies argument filters to both the invocation and the guard (if there
* is one) with {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}.
* @param pos the position of the first argument being filtered
* @param filters the argument filters
* @return a filtered invocation
@ -361,7 +401,8 @@ public class GuardedInvocation {
}
/**
* Makes an invocation that drops arguments in both the invocation and the guard (if there is one).
* Makes an invocation that drops arguments in both the invocation and the
* guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, List)}.
* @param pos the position of the first argument being dropped
* @param valueTypes the types of the values being dropped
* @return an invocation that drops arguments
@ -372,7 +413,8 @@ public class GuardedInvocation {
}
/**
* Makes an invocation that drops arguments in both the invocation and the guard (if there is one).
* Makes an invocation that drops arguments in both the invocation and the
* guard (if there is one) with {@link MethodHandles#dropArguments(MethodHandle, int, Class...)}.
* @param pos the position of the first argument being dropped
* @param valueTypes the types of the values being dropped
* @return an invocation that drops arguments
@ -384,8 +426,11 @@ public class GuardedInvocation {
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param fallback the fallback method handle in case switchpoint is invalidated or guard returns false.
* Composes the invocation, guard, switch points, and the exception into a
* composite method handle that knows how to fall back when the guard fails
* or the invocation is invalidated.
* @param fallback the fallback method handle for when a switch point is
* invalidated, a guard returns false, or invalidating exception is thrown.
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle fallback) {
@ -393,10 +438,15 @@ public class GuardedInvocation {
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
* @param catchFallback the fallback method in case the exception handler triggers
* Composes the invocation, guard, switch points, and the exception into a
* composite method handle that knows how to fall back when the guard fails
* or the invocation is invalidated.
* @param switchpointFallback the fallback method handle in case a switch
* point is invalidated.
* @param guardFallback the fallback method handle in case guard returns
* false.
* @param catchFallback the fallback method in case the exception handler
* triggers.
* @return a composite method handle.
*/
public MethodHandle compose(final MethodHandle guardFallback, final MethodHandle switchpointFallback, final MethodHandle catchFallback) {
@ -411,7 +461,7 @@ public class GuardedInvocation {
final MethodHandle catchGuarded =
exception == null ?
guarded :
MH.catchException(
MethodHandles.catchException(
guarded,
exception,
MethodHandles.dropArguments(
@ -430,10 +480,4 @@ public class GuardedInvocation {
return spGuarded;
}
private static void assertType(final MethodHandle mh, final MethodType type) {
if(!mh.type().equals(type)) {
throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type());
}
}
}

View File

@ -81,25 +81,33 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink;
package jdk.internal.dynalink.linker;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* Interface for objects that are used to transform one guarded invocation into another one. Typical usage is for
* implementing {@link DynamicLinkerFactory#setPrelinkFilter(GuardedInvocationFilter) pre-link filters}.
* Interface for objects that are used to transform one guarded invocation into
* another one. Typical usage is for implementing
* {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer)
* pre-link transformers}.
*/
public interface GuardedInvocationFilter {
@FunctionalInterface
public interface GuardedInvocationTransformer {
/**
* Given a guarded invocation, return a potentially different guarded invocation.
* @param inv the original guarded invocation. Null is never passed.
* @param linkRequest the link request for which the invocation was generated (usually by some linker).
* @param linkerServices the linker services that can be used during creation of a new invocation.
* @return either the passed guarded invocation or a different one, with the difference usually determined based on
* information in the link request and the differing invocation created with the assistance of the linker services.
* Whether or not {@code null} is an accepted return value is dependent on the user of the filter.
* Given a guarded invocation, return either the same or potentially
* different guarded invocation.
* @param inv the original guarded invocation.
* @param linkRequest the link request for which the invocation was
* generated (usually by some linker).
* @param linkerServices the linker services that can be used during
* creation of a new invocation.
* @return either the passed guarded invocation or a different one, with
* the difference usually determined based on information in the link
* request and the differing invocation created with the assistance of the
* linker services. Whether or not {@code null} is an accepted return value
* is dependent on the user of the filter.
* @throws NullPointerException is allowed to be thrown by implementations
* if any of the passed arguments is null.
*/
public GuardedInvocation filter(GuardedInvocation inv, LinkRequest linkRequest, LinkerServices linkerServices);
}

View File

@ -83,32 +83,58 @@
package jdk.internal.dynalink.linker;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.List;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* The base interface for language-specific dynamic linkers. Such linkers always have to produce method handles with
* guards, as the validity of the method handle for calls at a call site inevitably depends on some condition (at the
* very least, it depends on the receiver belonging to the language runtime of the linker). Language runtime
* implementors will normally implement one for their own language, and declare it in the
* <tt>META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker</tt> file within their JAR file.
* The base interface for language-specific dynamic linkers. Such linkers
* always have to produce method handles with guards, as the validity of the
* method handle for calls at a call site inevitably depends on some condition
* (at the very least, it depends on the receiver belonging to the language
* runtime of the linker). Language runtime implementors will normally implement
* the linking logic for their own language as one or more
* {@link GuardingDynamicLinker} classes. They will typically set them as
* {@link DynamicLinkerFactory#setPrioritizedLinkers(List) prioritized linkers}
* in the {@code DynamicLinkerFactory} they configure for themselves, and maybe also
* set some as {@link DynamicLinkerFactory#setFallbackLinkers(List) fallback
* linkers} to handle language-specific "property not found" etc. conditions.
* <p>
* Consider implementing {@link TypeBasedGuardingDynamicLinker} interface
* instead of this interface for those linkers that are based on the Java class
* of the objects. If you need to implement language-specific type conversions,
* have your {@code GuardingDynamicLinker} also implement the
* {@link GuardingTypeConverterFactory} interface.
* <p>
* Languages can export linkers to other language runtimes for
* {@link DynamicLinkerFactory#setClassLoader(ClassLoader) automatic discovery}
* using a {@link GuardingDynamicLinkerExporter}.
*/
public interface GuardingDynamicLinker {
/**
* Creates a guarded invocation appropriate for a particular invocation with the specified arguments at a call site.
* Creates a guarded invocation appropriate for a particular invocation with
* the specified arguments at a call site.
*
* @param linkRequest the object describing the request for linking a particular invocation
* @param linkRequest the object describing the request for linking a
* particular invocation
* @param linkerServices linker services
* @return a guarded invocation with a method handle suitable for the arguments, as well as a guard condition that
* if fails should trigger relinking. Must return null if it can't resolve the invocation. If the returned
* invocation is unconditional (which is actually quite rare), the guard in the return value can be null. The
* invocation can also have a switch point for asynchronous invalidation of the linkage, as well as a
* {@link Throwable} subclass that describes an expected exception condition that also triggers relinking (often it
* is faster to rely on an infrequent but expected {@link ClassCastException} than on an always evaluated
* {@code instanceof} guard). If the linker does not recognize any native language runtime contexts in arguments, or
* does recognize its own, but receives a call site descriptor without its recognized context in the arguments, it
* should invoke {@link LinkRequest#withoutRuntimeContext()} and link for that. While the linker must produce an
* invocation with parameter types matching those in the call site descriptor of the link request, it should not try
* to match the return type expected at the call site except when it can do it with only the conversions that lose
* neither precision nor magnitude, see {@link LinkerServices#asTypeLosslessReturn(java.lang.invoke.MethodHandle,
* java.lang.invoke.MethodType)}.
* @return a guarded invocation with a method handle suitable for the
* arguments, as well as a guard condition that if fails should trigger
* relinking. Must return null if it can't resolve the invocation. If the
* returned invocation is unconditional (which is actually quite rare), the
* guard in the return value can be null. The invocation can also have any
* number of switch points for asynchronous invalidation of the linkage, as
* well as a {@link Throwable} subclass that describes an expected exception
* condition that also triggers relinking (often it is faster to rely on an
* infrequent but expected {@link ClassCastException} than on an always
* evaluated {@code instanceof} guard). While the linker must produce an
* invocation with parameter types matching those in the call site
* descriptor of the link request, it should not try to match the return
* type expected at the call site except when it can do it with only the
* conversions that lose neither precision nor magnitude, see
* {@link LinkerServices#asTypeLosslessReturn(MethodHandle, MethodType)} for
* further explanation.
* @throws Exception if the operation fails for whatever reason
*/
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest, LinkerServices linkerServices)

View File

@ -0,0 +1,74 @@
/*
* 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.
*/
package jdk.internal.dynalink.linker;
import java.security.Permission;
import java.util.List;
import java.util.ServiceLoader;
import java.util.function.Supplier;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* A class acting as a supplier of guarding dynamic linkers that can be
* automatically loaded by other language runtimes. Language runtimes wishing
* to export their own linkers should subclass this class and implement the
* {@link #get()} method to return a list of exported linkers and declare the
* subclass in
* {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter}
* resource of their distribution (typically, JAR file) so that dynamic linker
* factories can discover them using the {@link ServiceLoader} mechanism. Note
* that instantiating this class is tied to a security check for the
* {@code RuntimePermission("dynalink.exportLinkersAutomatically")} when a
* security manager is present, to ensure that only trusted runtimes can
* automatically export their linkers into other runtimes.
* @see DynamicLinkerFactory#setClassLoader(ClassLoader)
*/
public abstract class GuardingDynamicLinkerExporter implements Supplier<List<GuardingDynamicLinker>> {
/**
* The name of the runtime permission for creating instances of this class.
* Granting this permission to a language runtime allows it to export its
* linkers for automatic loading into other language runtimes.
*/
public static final String AUTOLOAD_PERMISSION_NAME = "dynalink.exportLinkersAutomatically";
private static final Permission AUTOLOAD_PERMISSION = new RuntimePermission(AUTOLOAD_PERMISSION_NAME);
/**
* Creates a new linker exporter. If there is a security manager installed
* checks for the
* {@code RuntimePermission("dynalink.exportLinkersAutomatically")} runtime
* permission. This ensures only language runtimes granted this permission
* will be allowed to export their linkers for automatic loading.
* @throws SecurityException if the necessary runtime permission is not
* granted.
*/
protected GuardingDynamicLinkerExporter() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(AUTOLOAD_PERMISSION);
}
}
}

View File

@ -83,30 +83,65 @@
package jdk.internal.dynalink.linker;
import jdk.internal.dynalink.support.TypeUtilities;
import java.lang.invoke.MethodHandles;
import java.util.function.Supplier;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Optional interface that can be implemented by {@link GuardingDynamicLinker} implementations to provide
* language-runtime specific implicit type conversion capabilities. Note that if you implement this interface, you will
* very likely want to implement {@link ConversionComparator} interface too, as your additional language-specific
* conversions, in absence of a strategy for prioritizing these conversions, will cause more ambiguity in selecting the
* correct overload when trying to link to an overloaded POJO method.
* Optional interface that can be implemented by {@link GuardingDynamicLinker}
* implementations to provide language-specific type conversion capabilities.
* Note that if you implement this interface, you will very likely want to
* implement {@link ConversionComparator} interface too, as your additional
* language-specific conversions, in absence of a strategy for prioritizing
* these conversions, will cause more ambiguity for {@link BeansLinker} in
* selecting the correct overload when trying to link to an overloaded Java
* method.
*/
public interface GuardingTypeConverterFactory {
/**
* Returns a guarded type conversion that receives an Object of the specified source type and returns an Object
* converted to the specified target type. The type of the invocation is targetType(sourceType), while the type of
* the guard is boolean(sourceType). Note that this will never be invoked for type conversions allowed by the JLS
* 5.3 "Method Invocation Conversion", see {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for
* details. An implementation can assume it is never requested to produce a converter for these conversions.
* Returns a guarded type conversion that receives a value of the specified
* source type and returns a value converted to the specified target type.
* Value types can be either primitives or reference types, including
* interfaces, so you can even provide converters for converting your
* language's objects to Java interfaces and classes by generating adapters
* for them.
* <p>
* The type of the invocation is {@code targetType(sourceType)}, while the
* type of the guard is {@code boolean(sourceType)}. You are allowed to
* return unconditional invocations (with no guard) if the source type is
* specific to your runtime and your runtime only.
* <p>Note that this method will never be invoked for type conversions
* allowed by the JLS 5.3 "Method Invocation Conversion", see
* {@link TypeUtilities#isMethodInvocationConvertible(Class, Class)} for
* details. An implementation can assume it is never requested to produce a
* converter for these conversions.
* <p>Dynalink is at liberty to either cache some of the returned converters
* or to repeatedly request the converter factory to create the same
* conversion.
*
* @param sourceType source type
* @param targetType the target type.
* @return a guarded type conversion that contains a guarded invocation that can take an object (if it passes guard)
* and return another object that is its representation coerced into the target type. In case the factory is certain
* it is unable to handle a conversion, it can return null. In case the factory is certain that it can always handle
* the conversion, it can return an unconditional invocation (one whose guard is null).
* @param lookupSupplier a supplier for retrieving the lookup of the class
* on whose behalf a type converter is requested. When a converter is
* requested as part of linking an {@code invokedynamic} instruction the
* supplier will return the lookup passed to the bootstrap method, otherwise
* it will return the public lookup. A typical case where the lookup might
* be needed is when the converter creates a Java adapter class on the fly
* (e.g. to convert some object from the dynamic language into a Java
* interface for interoperability). Invoking the {@link Supplier#get()}
* method on the passed supplier will be subject to the same security checks
* as {@link CallSiteDescriptor#getLookup()}. An implementation should avoid
* retrieving the lookup if it is not needed so as to avoid the expense of
* {@code AccessController.doPrivileged} call.
* @return a guarded invocation that can take an object (if it passes guard)
* and return another object that is its representation coerced into the
* target type. In case the factory is certain it is unable to handle a
* conversion, it can return null. In case the factory is certain that it
* can always handle the conversion, it can return an unconditional
* invocation (one whose guard is null).
* @throws Exception if there was an error during creation of the converter
*/
public GuardedTypeConversion convertToType(Class<?> sourceType, Class<?> targetType) throws Exception;
public GuardedInvocation convertToType(Class<?> sourceType, Class<?> targetType, Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception;
}

View File

@ -84,11 +84,14 @@
package jdk.internal.dynalink.linker;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* Represents a request to link a particular invocation at a particular call site. Instances of these requests are being
* passed to {@link GuardingDynamicLinker}.
* Represents a request to link a particular invocation at a particular call
* site. Instances of these requests will be constructed and passed to all
* {@link GuardingDynamicLinker} objects managed by the {@link DynamicLinker}
* that is trying to link the call site.
*/
public interface LinkRequest {
/**
@ -99,64 +102,34 @@ public interface LinkRequest {
public CallSiteDescriptor getCallSiteDescriptor();
/**
* Returns the call site token for the call site being linked. This token is an opaque object that is guaranteed to
* have different identity for different call sites, and is also guaranteed to not become weakly reachable before
* the call site does and to become weakly reachable some time after the call site does. This makes it ideal as a
* candidate for a key in a weak hash map in which a linker might want to keep per-call site linking state (usually
* profiling information).
*
* @return the call site token for the call site being linked.
*/
public Object getCallSiteToken();
/**
* Returns the arguments for the invocation being linked. The returned array is a clone; modifications to it won't
* affect the arguments in this request.
* Returns the arguments for the invocation being linked. The returned array
* must be a clone; modifications to it must not affect the arguments in
* this request.
*
* @return the arguments for the invocation being linked.
*/
public Object[] getArguments();
/**
* Returns the 0th argument for the invocation being linked; this is typically the receiver object.
* Returns the first argument for the invocation being linked; this is
* typically the receiver object. This is a shorthand for
* {@code getArguments()[0]} that also avoids the cloning of the arguments
* array.
*
* @return the receiver object.
*/
public Object getReceiver();
/**
* Returns the number of times this callsite has been linked/relinked. This can be useful if you want to
* change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep,
* for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in
* a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be
* much more performant to use exact type guards instead.
*
* @return link count for call site
*/
public int getLinkCount();
/**
* Returns true if the call site is considered unstable, that is, it has been relinked more times than was
* specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a
* hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption
* causes a less effective version of an operation to be linked. This is just a hint, of course, and linkers are
* free to ignore this property.
* causes a less effective version of an operation to be linked. This is just a hint, though, and linkers are
* allowed to ignore this property.
* @return true if the call site is considered unstable.
*/
public boolean isCallSiteUnstable();
/**
* Returns a request stripped from runtime context arguments. Some language runtimes will include runtime-specific
* context parameters in their call sites as few arguments between 0th argument "this" and the normal arguments. If
* a linker does not recognize such contexts at all, or does not recognize the call site as one with its own
* context, it can ask for the alternative link request with context parameters and arguments removed, and link
* against it instead.
*
* @return the context-stripped request. If the link request does not have any language runtime specific context
* parameters, the same link request is returned.
*/
public LinkRequest withoutRuntimeContext();
/**
* Returns a request identical to this one with call site descriptor and arguments replaced with the ones specified.
*
@ -165,5 +138,5 @@ public interface LinkRequest {
* @return a new request identical to this one, except with the call site descriptor and arguments replaced with the
* specified ones.
*/
public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments);
public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object... arguments);
}

View File

@ -89,44 +89,54 @@ import java.lang.invoke.MethodType;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Interface for services provided to {@link GuardingDynamicLinker} instances by the {@link DynamicLinker} that owns
* them. You can think of it as the interface of the {@link DynamicLinker} that faces the {@link GuardingDynamicLinker}
* s.
* Interface for services provided to {@link GuardingDynamicLinker} instances by
* the {@link DynamicLinker} that owns them.
*/
public interface LinkerServices {
/**
* Similar to {@link MethodHandle#asType(MethodType)} except it also hooks in method handles produced by
* {@link GuardingTypeConverterFactory} implementations, providing for language-specific type coercing of
* parameters. It will apply {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
* wrapper-to-primitive, primitive-to-wrapper conversions as well as for all upcasts. For all other conversions,
* it'll insert {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with composite filters
* provided by {@link GuardingTypeConverterFactory} implementations.
* Similar to {@link MethodHandle#asType(MethodType)} except it also hooks
* in method handles produced by all available
* {@link GuardingTypeConverterFactory} implementations, providing for
* language-specific type coercing of parameters. It will apply
* {@link MethodHandle#asType(MethodType)} for all primitive-to-primitive,
* wrapper-to-primitive, primitive-to-wrapper conversions as well as for all
* upcasts. For all other conversions, it'll insert
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}
* with composite filters provided by {@link GuardingTypeConverterFactory}
* implementations.
*
* @param handle target method handle
* @param fromType the types of source arguments
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)},
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}, and
* {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)} with
* {@link GuardingTypeConverterFactory}-produced type converters as filters.
* @return a method handle that is a suitable combination of
* {@link MethodHandle#asType(MethodType)},
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)},
* and {@link MethodHandles#filterReturnValue(MethodHandle, MethodHandle)}
* with {@link GuardingTypeConverterFactory}-produced type converters as
* filters.
*/
public MethodHandle asType(MethodHandle handle, MethodType fromType);
/**
* Similar to {@link #asType(MethodHandle, MethodType)} except it only converts the return type of the method handle
* when it can be done using a conversion that loses neither precision nor magnitude, otherwise it leaves it
* unchanged. The idea is that other conversions should not be performed by individual linkers, but instead the
* {@link DynamicLinkerFactory#setPrelinkFilter(jdk.internal.dynalink.GuardedInvocationFilter) pre-link filter of
* the dynamic linker} should implement the strategy of dealing with potentially lossy return type conversions in a
* manner specific to the language runtime.
* Similar to {@link #asType(MethodHandle, MethodType)} except it treats
* return value type conversion specially. It only converts the return type
* of the method handle when it can be done using a conversion that loses
* neither precision nor magnitude, otherwise it leaves it unchanged. These
* are the only return value conversions that should be performed by
* individual language-specific linkers, and
* {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer)
* pre-link transformer of the dynamic linker} should implement the strategy
* for dealing with potentially lossy return type conversions in a manner
* specific to the language runtime where the call site is located.
*
* @param handle target method handle
* @param fromType the types of source arguments
* @return a method handle that is a suitable combination of {@link MethodHandle#asType(MethodType)}, and
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)} with
* {@link GuardingTypeConverterFactory}-produced type converters as filters.
* @return a method handle that is a suitable combination of
* {@link MethodHandle#asType(MethodType)}, and
* {@link MethodHandles#filterArguments(MethodHandle, int, MethodHandle...)}
* with {@link GuardingTypeConverterFactory}-produced type converters as filters.
*/
public default MethodHandle asTypeLosslessReturn(final MethodHandle handle, final MethodType fromType) {
final Class<?> handleReturnType = handle.type().returnType();
@ -135,11 +145,13 @@ public interface LinkerServices {
}
/**
* Given a source and target type, returns a method handle that converts between them. Never returns null; in worst
* case it will return an identity conversion (that might fail for some values at runtime). You rarely need to use
* this method directly; you should mostly rely on {@link #asType(MethodHandle, MethodType)} instead. You really
* only need this method if you have a piece of your program that is written in Java, and you need to reuse existing
* type conversion machinery in a non-invokedynamic context.
* Given a source and target type, returns a method handle that converts
* between them. Never returns null; in worst case it will return an
* identity conversion (that might fail for some values at runtime). You
* rarely need to use this method directly and should mostly rely on
* {@link #asType(MethodHandle, MethodType)} instead. This method is needed
* when you need to reuse existing type conversion machinery outside the
* context of processing a link request.
* @param sourceType the type to convert from
* @param targetType the type to convert to
* @return a method handle performing the conversion.
@ -147,11 +159,13 @@ public interface LinkerServices {
public MethodHandle getTypeConverter(Class<?> sourceType, Class<?> targetType);
/**
* Returns true if there might exist a conversion between the requested types (either an automatic JVM conversion,
* or one provided by any available {@link GuardingTypeConverterFactory}), or false if there definitely does not
* exist a conversion between the requested types. Note that returning true does not guarantee that the conversion
* will succeed at runtime (notably, if the "from" or "to" types are sufficiently generic), but returning false
* guarantees that it would fail.
* Returns true if there might exist a conversion between the requested
* types (either an automatic JVM conversion, or one provided by any
* available {@link GuardingTypeConverterFactory}), or false if there
* definitely does not exist a conversion between the requested types. Note
* that returning true does not guarantee that the conversion will succeed
* at runtime for all values (especially if the "from" or "to" types are
* sufficiently generic), but returning false guarantees that it would fail.
*
* @param from the source type for the conversion
* @param to the target type for the conversion
@ -160,34 +174,47 @@ public interface LinkerServices {
public boolean canConvert(Class<?> from, Class<?> to);
/**
* Creates a guarded invocation using the {@link DynamicLinker} that exposes this linker services interface. Linkers
* can typically use them to delegate linking of wrapped objects.
* Creates a guarded invocation delegating back to the {@link DynamicLinker}
* that exposes this linker services object. The dynamic linker will then
* itself delegate the linking to all of its managed
* {@link GuardingDynamicLinker}s including potentially this one if no
* linker responds earlier, so beware of infinite recursion. You'll
* typically craft the link request so that it will be different than the
* one you are currently trying to link.
*
* @param linkRequest a request for linking the invocation
* @return a guarded invocation linked by the top-level linker (or any of its delegates). Can be null if no
* available linker is able to link the invocation.
* @return a guarded invocation linked by some of the guarding dynamic
* linkers managed by the top-level dynamic linker. Can be null if no
* available linker is able to link the invocation. You will typically use
* the elements of the returned invocation to compose your own invocation.
* @throws Exception in case the top-level linker throws an exception
*/
public GuardedInvocation getGuardedInvocation(LinkRequest linkRequest) throws Exception;
/**
* Determines which of the two type conversions from a source type to the two target types is preferred. This is
* used for dynamic overloaded method resolution. If the source type is convertible to exactly one target type with
* a method invocation conversion, it is chosen, otherwise available {@link ConversionComparator}s are consulted.
* Determines which of the two type conversions from a source type to the
* two target types is preferred. This is used for dynamic overloaded method
* resolution. If the source type is convertible to exactly one target type
* with a method invocation conversion, it is chosen, otherwise available
* {@link ConversionComparator}s are consulted.
* @param sourceType the source type.
* @param targetType1 one potential target type
* @param targetType2 another potential target type.
* @return one of Comparison constants that establish which - if any - of the target types is preferable for the
* conversion.
* @return one of Comparison constants that establish which &ndash; if any
* &ndash; of the target types is preferable for the conversion.
*/
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);
/**
* Modifies the method handle so that any parameters that can receive potentially internal language runtime objects
* will have a filter added on them to prevent them from escaping, potentially by wrapping them.
* It can also potentially add an unwrapping filter to the return value.
* Modifies the method handle so that any parameters that can receive
* potentially internal language runtime objects will have a filter added on
* them to prevent them from escaping, potentially by wrapping them. It can
* also potentially add an unwrapping filter to the return value. Basically
* transforms the method handle using the transformer configured by
* {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}.
* @param target the target method handle
* @return a method handle with parameters and/or return type potentially filtered for wrapping and unwrapping.
* @return a method handle with parameters and/or return type potentially
* filtered for wrapping and unwrapping.
*/
public MethodHandle filterInternalObjects(final MethodHandle target);
}

View File

@ -84,10 +84,15 @@
package jdk.internal.dynalink.linker;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* A generic interface describing operations that transform method handles.
* Typical usage is for implementing
* {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)
* internal objects filters}.
*/
@FunctionalInterface
public interface MethodHandleTransformer {
/**
* Transforms a method handle.

View File

@ -85,10 +85,16 @@ package jdk.internal.dynalink.linker;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.DynamicLinkerFactory;
/**
* Interface for objects representing a strategy for converting a method handle to a new type.
* Interface for objects representing a strategy for converting a method handle
* to a new type. Typical usage is for customizing a language runtime's handling
* of
* {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)
* method invocation conversions}.
*/
@FunctionalInterface
public interface MethodTypeConversionStrategy {
/**
* Converts a method handle to a new type.

View File

@ -83,11 +83,14 @@
package jdk.internal.dynalink.linker;
import jdk.internal.dynalink.linker.support.CompositeTypeBasedGuardingDynamicLinker;
/**
* A guarding dynamic linker that can determine whether it can link the call site solely based on the type of the first
* argument at linking invocation time. (The first argument is usually the receiver class). Most language-specific
* argument at linking invocation time. (The first argument is usually the receiver). Most language-specific
* linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing
* a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers.
* a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers,
* see {@link CompositeTypeBasedGuardingDynamicLinker}.
*/
public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker {
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -81,53 +81,37 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
import java.util.LinkedList;
import java.util.List;
import java.util.ServiceLoader;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
/**
* Provides methods for automatic discovery of all guarding dynamic linkers listed in the
* <tt>/META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker</tt> resources of all JAR files for a
* particular class loader. Ordinarily, you will not use this class directly, but you will use a
* {@link DynamicLinkerFactory} instead.
* <p>
* Contains interfaces and classes needed by language runtimes to implement
* their own language-specific object models and type conversions. The main
* entry point is the
* {@link jdk.internal.dynalink.linker.GuardingDynamicLinker} interface. It needs to be
* implemented in order to provide linking for the runtime's own object model.
* A language runtime can have more than one guarding dynamic linker
* implementation. When a runtime is configuring Dynalink for itself, it will
* normally set these guarding linkers as the prioritized linkers in its
* {@link jdk.internal.dynalink.DynamicLinkerFactory} (and maybe some of them as fallback
* linkers, for e.g. handling "method not found" and similar errors in a
* language-specific manner if no other linker managed to handle the operation.)
* </p><p>
* A language runtime that wishes to make at least some of its linkers available
* to other language runtimes for interoperability will need to declare the
* class names of those linkers in
* {@code /META-INF/services/jdk.internal.dynalink.linker.GuardingDynamicLinker} file in
* its distribution (typically, JAR file).
* </p><p>
* Most language runtimes will be able to implement their own linking logic by
* implementing {@link jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker}
* instead of {@link jdk.internal.dynalink.linker.GuardingDynamicLinker}; it allows for
* faster type-based linking dispatch.
* </p><p>
* Language runtimes that allow type conversions other than those provided by
* Java will need to have their guarding dynamic linker (or linkers) also
* implement the {@link jdk.internal.dynalink.linker.GuardingTypeConverterFactory}
* interface to provide the logic for these conversions.
* </p>
* @since 1.9
*/
public class AutoDiscovery {
private AutoDiscovery() {
}
/**
* Discovers all guarding dynamic linkers listed in JAR files of the context class loader of the current thread.
*
* @return a list of available linkers. Can be zero-length list but not null.
*/
public static List<GuardingDynamicLinker> loadLinkers() {
return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class));
}
/**
* Discovers all guarding dynamic linkers listed in JAR files of the specified class loader.
*
* @param cl the class loader to use
* @return a list of guarding dynamic linkers available through the specified class loader. Can be zero-length list
* but not null.
*/
public static List<GuardingDynamicLinker> loadLinkers(final ClassLoader cl) {
return getLinkers(ServiceLoader.load(GuardingDynamicLinker.class, cl));
}
/**
* I can't believe there's no Collections API for making a List given an Iterator...
*/
private static <T> List<T> getLinkers(final ServiceLoader<T> loader) {
final List<T> list = new LinkedList<>();
for(final T linker: loader) {
list.add(linker);
}
return list;
}
}
@jdk.Exported
package jdk.internal.dynalink.linker;

View File

@ -1,87 +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.
-->
<body>
<p>
Contains interfaces and classes needed by language runtimes to implement
their own language-specific linkers.
</p>
</body>

View File

@ -81,20 +81,21 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
/**
* A {@link GuardingDynamicLinker} that delegates sequentially to a list of other guarding dynamic linkers. The first
* value returned from a component linker other than null is returned. If no component linker returns an invocation,
* null is returned.
* A {@link GuardingDynamicLinker} that delegates sequentially to a list of
* other guarding dynamic linkers in its
* {@link #getGuardedInvocation(LinkRequest, LinkerServices)}.
*/
public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Serializable {
@ -106,15 +107,27 @@ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker, Se
* Creates a new composite linker.
*
* @param linkers a list of component linkers.
* @throws NullPointerException if {@code linkers} or any of its elements
* are null.
*/
public CompositeGuardingDynamicLinker(final Iterable<? extends GuardingDynamicLinker> linkers) {
final List<GuardingDynamicLinker> l = new LinkedList<>();
for(final GuardingDynamicLinker linker: linkers) {
l.add(linker);
l.add(Objects.requireNonNull(linker));
}
this.linkers = l.toArray(new GuardingDynamicLinker[l.size()]);
}
/**
* Delegates the call to its component linkers. The first non-null value
* returned from a component linker is returned. If no component linker
* returns a non-null invocation, null is returned.
* @param linkRequest the object describing the request for linking a
* particular invocation
* @param linkerServices linker services
* @return the first non-null return value from a component linker, or null
* if none of the components returned a non-null.
*/
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
throws Exception {

View File

@ -81,12 +81,13 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
@ -94,10 +95,12 @@ import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
/**
* A composite type-based guarding dynamic linker. When a receiver of a not yet seen class is encountered, all linkers
* are queried sequentially on their {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers
* returning true are then bound to the class, and next time a receiver of same type is encountered, the linking is
* delegated to those linkers only, speeding up dispatch.
* A composite type-based guarding dynamic linker. When a receiver of a not yet
* seen class is encountered, all linkers are queried sequentially on their
* {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} method. The linkers
* returning true are then bound to the class, and next time a receiver of same
* type is encountered, the linking is delegated to those linkers only, speeding
* up dispatch.
*/
public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker, Serializable {
private static final long serialVersionUID = 1L;
@ -149,15 +152,25 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
* Creates a new composite type-based linker.
*
* @param linkers the component linkers
* @throws NullPointerException if {@code linkers} or any of its elements
* are null.
*/
public CompositeTypeBasedGuardingDynamicLinker(final Iterable<? extends TypeBasedGuardingDynamicLinker> linkers) {
final List<TypeBasedGuardingDynamicLinker> l = new LinkedList<>();
for(final TypeBasedGuardingDynamicLinker linker: linkers) {
l.add(linker);
l.add(Objects.requireNonNull(linker));
}
this.classToLinker = new ClassToLinker(l.toArray(new TypeBasedGuardingDynamicLinker[l.size()]));
}
/**
* Returns true if at least one of the composite linkers returns true from
* {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)} for the type.
* @param type the type to link
* @return true true if at least one of the composite linkers returns true
* from {@link TypeBasedGuardingDynamicLinker#canLinkType(Class)}, false
* otherwise.
*/
@Override
public boolean canLinkType(final Class<?> type) {
return !classToLinker.get(type).isEmpty();
@ -180,17 +193,21 @@ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardin
}
/**
* Optimizes a list of type-based linkers. If a group of adjacent linkers in the list all implement
* {@link TypeBasedGuardingDynamicLinker}, they will be replaced with a single instance of
* Optimizes a list of type-based linkers. If a group of adjacent linkers in
* the list all implement {@link TypeBasedGuardingDynamicLinker}, they will
* be replaced with a single instance of
* {@link CompositeTypeBasedGuardingDynamicLinker} that contains them.
*
* @param linkers the list of linkers to optimize
* @return the optimized list
* @throws NullPointerException if {@code linkers} or any of its elements
* are null.
*/
public static List<GuardingDynamicLinker> optimize(final Iterable<? extends GuardingDynamicLinker> linkers) {
final List<GuardingDynamicLinker> llinkers = new LinkedList<>();
final List<TypeBasedGuardingDynamicLinker> tblinkers = new LinkedList<>();
for(final GuardingDynamicLinker linker: linkers) {
Objects.requireNonNull(linker);
if(linker instanceof TypeBasedGuardingDynamicLinker) {
tblinkers.add((TypeBasedGuardingDynamicLinker)linker);
} else {

View File

@ -81,7 +81,7 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -90,10 +90,19 @@ import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.MethodHandleTransformer;
/**
* Default implementation for a {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}.
* Given a method handle of {@code Object(Object)} type for filtering parameter and another one of the same type for
* filtering return values, applies them to passed method handles where their parameter types and/or return value types
* are declared to be {@link Object}.
* Default implementation for a
* {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}
* that delegates to a pair of filtering method handles. It takes a method
* handle of {@code Object(Object)} type for filtering parameter values and
* another one of the same type for filtering return values. It applies them as
* parameter and return value filters on method handles passed to its
* {@link #transform(MethodHandle)} method, on those parameters and return values
* that are declared to have type {@link Object}. Also handles
* {@link MethodHandle#isVarargsCollector() method handles that support variable
* arity calls} with a last {@code Object[]} parameter. You can broadly think of
* the parameter filter as being a wrapping method for exposing internal runtime
* objects wrapped into an adapter with some public interface, and the return
* value filter as being its inverse unwrapping method.
*/
public class DefaultInternalObjectFilter implements MethodHandleTransformer {
private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic(
@ -105,9 +114,12 @@ public class DefaultInternalObjectFilter implements MethodHandleTransformer {
/**
* Creates a new filter.
* @param parameterFilter the filter for method parameters. Must be of type {@code Object(Object)}, or null.
* @param returnFilter the filter for return values. Must be of type {@code Object(Object)}, or null.
* @throws IllegalArgumentException if one or both filters are not of the expected type.
* @param parameterFilter the filter for method parameters. Must be of type
* {@code Object(Object)}, or {@code null}.
* @param returnFilter the filter for return values. Must be of type
* {@code Object(Object)}, or {@code null}.
* @throws IllegalArgumentException if one or both filters are not of the
* expected type.
*/
public DefaultInternalObjectFilter(final MethodHandle parameterFilter, final MethodHandle returnFilter) {
this.parameterFilter = checkHandle(parameterFilter, "parameterFilter");

View File

@ -81,7 +81,7 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -92,10 +92,11 @@ import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.linker.LinkerServices;
/**
* Utility methods for creating typical guards. TODO: introduce reasonable caching of created guards.
*
* Utility methods for creating typical guards for
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}
* and for adjusting their method types.
*/
public class Guards {
public final class Guards {
private static final Logger LOG = Logger
.getLogger(Guards.class.getName(), "jdk.internal.dynalink.support.messages");
@ -184,44 +185,17 @@ public class Guards {
return asType(IS_ARRAY, pos, type);
}
/**
* Return true if it is safe to strongly reference a class from the referred class loader from a class associated
* with the referring class loader without risking a class loader memory leak.
*
* @param referrerLoader the referrer class loader
* @param referredLoader the referred class loader
* @return true if it is safe to strongly reference the class
*/
public static boolean canReferenceDirectly(final ClassLoader referrerLoader, final ClassLoader referredLoader) {
if(referredLoader == null) {
// Can always refer directly to a system class
return true;
}
if(referrerLoader == null) {
// System classes can't refer directly to any non-system class
return false;
}
// Otherwise, can only refer directly to classes residing in same or
// parent class loader.
ClassLoader referrer = referrerLoader;
do {
if(referrer == referredLoader) {
return true;
}
referrer = referrer.getParent();
} while(referrer != null);
return false;
}
private static MethodHandle getClassBoundArgumentTest(final MethodHandle test, final Class<?> clazz, final int pos, final MethodType type) {
// Bind the class to the first argument of the test
return asType(test.bindTo(clazz), pos, type);
}
/**
* Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Only applies
* conversions as per {@link MethodHandle#asType(MethodType)}.
* Takes a method handle intended to be used as a guard, and adapts it to
* the requested type, but returning a boolean. Applies
* {@link MethodHandle#asType(MethodType)} to convert types and uses
* {@link MethodHandles#dropArguments(MethodHandle, int, Class...)} to match
* the requested type arity.
* @param test the test method handle
* @param type the type to adapt the method handle to
* @return the adapted method handle
@ -231,8 +205,12 @@ public class Guards {
}
/**
* Takes a guard-test method handle, and adapts it to the requested type, returning a boolean. Applies the passed
* {@link LinkerServices} object's {@link LinkerServices#asType(MethodHandle, MethodType)}.
* Takes a method handle intended to be used as a guard, and adapts it to
* the requested type, but returning a boolean. Applies
* {@link LinkerServices#asType(MethodHandle, MethodType)} to convert types
* and uses
* {@link MethodHandles#dropArguments(MethodHandle, int, Class...)} to match
* the requested type arity.
* @param linkerServices the linker services to use for type conversions
* @param test the test method handle
* @param type the type to adapt the method handle to

View File

@ -81,7 +81,7 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -91,14 +91,17 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods
* within your own codebase (therefore it is an error if they are not present).
* A wrapper around {@link java.lang.invoke.MethodHandles.Lookup} that masks
* checked exceptions. It is useful in those cases when you're looking up
* methods within your own codebase (therefore it is an error if they are not
* present).
*/
public class Lookup {
public final class Lookup {
private final MethodHandles.Lookup lookup;
/**
* Creates a new instance, bound to an instance of {@link java.lang.invoke.MethodHandles.Lookup}.
* Creates a new instance, bound to an instance of
* {@link java.lang.invoke.MethodHandles.Lookup}.
*
* @param lookup the {@link java.lang.invoke.MethodHandles.Lookup} it delegates to.
*/
@ -112,23 +115,27 @@ public class Lookup {
public static final Lookup PUBLIC = new Lookup(MethodHandles.publicLookup());
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError}.
*
* @param m the method to unreflect
* @return the unreflected method handle.
* @throws IllegalAccessError if the method is inaccessible.
*/
public MethodHandle unreflect(final Method m) {
return unreflect(lookup, m);
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError}.
*
* @param lookup the lookup used to unreflect
* @param m the method to unreflect
* @return the unreflected method handle.
* @throws IllegalAccessError if the method is inaccessible.
*/
public static MethodHandle unreflect(final MethodHandles.Lookup lookup, final Method m) {
try {
@ -141,11 +148,12 @@ public class Lookup {
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)},
* converting any encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
*
* @param f the field for which a getter is unreflected
* @return the unreflected field getter handle.
* @throws IllegalAccessError if the getter is inaccessible.
*/
public MethodHandle unreflectGetter(final Field f) {
try {
@ -158,9 +166,10 @@ public class Lookup {
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)}, converting any
* encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and {@link NoSuchFieldException}
* into a {@link NoSuchFieldError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#findGetter(Class, String, Class)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError} and {@link NoSuchFieldException} into a
* {@link NoSuchFieldError}.
*
* @param refc the class declaring the field
* @param name the name of the field
@ -186,11 +195,14 @@ public class Lookup {
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)}, converting any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter(Field)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError}.
*
* @param f the field for which a setter is unreflected
* @return the unreflected field setter handle.
* @throws IllegalAccessError if the field is inaccessible.
* @throws NoSuchFieldError if the field does not exist.
*/
public MethodHandle unreflectSetter(final Field f) {
try {
@ -203,23 +215,27 @@ public class Lookup {
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any
* encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError}.
*
* @param c the constructor to unreflect
* @return the unreflected constructor handle.
* @throws IllegalAccessError if the constructor is inaccessible.
*/
public MethodHandle unreflectConstructor(final Constructor<?> c) {
return unreflectConstructor(lookup, c);
}
/**
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any
* encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)},
* converting any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError}.
*
* @param lookup the lookup used to unreflect
* @param c the constructor to unreflect
* @return the unreflected constructor handle.
* @throws IllegalAccessError if the constructor is inaccessible.
*/
public static MethodHandle unreflectConstructor(final MethodHandles.Lookup lookup, final Constructor<?> c) {
try {
@ -232,8 +248,10 @@ public class Lookup {
}
/**
* Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#findSpecial(Class, String, MethodType, Class)}
* on the underlying lookup. Converts any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError} and
* {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
*
* @param declaringClass class declaring the method
* @param name the name of the method
@ -263,8 +281,10 @@ public class Lookup {
}
/**
* Performs a findStatic on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#findStatic(Class, String, MethodType)}
* on the underlying lookup. Converts any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError} and
* {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
*
* @param declaringClass class declaring the method
* @param name the name of the method
@ -290,8 +310,10 @@ public class Lookup {
}
/**
* Performs a findVirtual on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an
* {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#findVirtual(Class, String, MethodType)}
* on the underlying lookup. Converts any encountered
* {@link IllegalAccessException} into an {@link IllegalAccessError} and
* {@link NoSuchMethodException} into a {@link NoSuchMethodError}.
*
* @param declaringClass class declaring the method
* @param name the name of the method
@ -317,8 +339,9 @@ public class Lookup {
}
/**
* Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class.
* Useful in classes' code for convenient linking to their own privates.
* Given a lookup, finds using {@link #findSpecial(Class, String, MethodType)}
* a method on that lookup's class. Useful in classes' code for convenient
* linking to their own privates.
* @param lookup the lookup for the class
* @param name the name of the method
* @param rtype the return type of the method
@ -331,9 +354,11 @@ public class Lookup {
/**
* Finds using {@link #findSpecial(Class, String, MethodType)} a method on that lookup's class. Useful in classes'
* code for convenient linking to their own privates. It's easier to use than {@code findSpecial} in that you can
* just list the parameter types, and don't have to specify lookup class.
* Finds using {@link #findSpecial(Class, String, MethodType)} a method on
* that lookup's class. Useful in classes' code for convenient linking to
* their own privates. It's also more convenient than {@code findSpecial}
* in that you can just list the parameter types, and don't have to specify
* lookup class.
* @param name the name of the method
* @param rtype the return type of the method
* @param ptypes the parameter types of the method
@ -344,9 +369,11 @@ public class Lookup {
}
/**
* Given a lookup, finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class.
* Useful in classes' code for convenient linking to their own privates. It's easier to use than {@code findStatic}
* in that you can just list the parameter types, and don't have to specify lookup class.
* Given a lookup, finds using {@link #findStatic(Class, String, MethodType)}
* a method on that lookup's class. Useful in classes' code for convenient
* linking to their own privates. It's easier to use than {@code findStatic}
* in that you can just list the parameter types, and don't have to specify
* lookup class.
* @param lookup the lookup for the class
* @param name the name of the method
* @param rtype the return type of the method
@ -358,9 +385,11 @@ public class Lookup {
}
/**
* Finds using {@link #findStatic(Class, String, MethodType)} a method on that lookup's class. Useful in classes'
* code for convenient linking to their own privates. It's easier to use than {@code findStatic} in that you can
* just list the parameter types, and don't have to specify lookup class.
* Finds using {@link #findStatic(Class, String, MethodType)} a method on
* that lookup's class. Useful in classes' code for convenient linking to
* their own privates. It's easier to use than {@code findStatic}
* in that you can just list the parameter types, and don't have to specify
* lookup class.
* @param name the name of the method
* @param rtype the return type of the method
* @param ptypes the parameter types of the method

View File

@ -81,48 +81,46 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.util.Objects;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest;
/**
* Default implementation of the {@link LinkRequest}, representing a link request to a call site that passes no language
* runtime specific native context arguments on the stack.
* Default simple implementation of {@link LinkRequest}.
*/
public class LinkRequestImpl implements LinkRequest {
public class SimpleLinkRequest implements LinkRequest {
private final CallSiteDescriptor callSiteDescriptor;
private final Object callSiteToken;
private final Object[] arguments;
private final boolean callSiteUnstable;
private final int linkCount;
/**
* Creates a new link request.
*
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
* @param linkCount how many times this callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param arguments the arguments for the invocation
* @param callSiteDescriptor the descriptor for the call site being linked.
* Must not be null.
* @param callSiteUnstable true if the call site being linked is considered
* unstable.
* @param arguments the arguments for the invocation. Must not be null.
* @throws NullPointerException if either {@code callSiteDescriptor} or
* {@code arguments} is null.
*/
public LinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken, final int linkCount, final boolean callSiteUnstable, final Object... arguments) {
this.callSiteDescriptor = callSiteDescriptor;
this.callSiteToken = callSiteToken;
this.linkCount = linkCount;
public SimpleLinkRequest(final CallSiteDescriptor callSiteDescriptor, final boolean callSiteUnstable, final Object... arguments) {
this.callSiteDescriptor = Objects.requireNonNull(callSiteDescriptor);
this.callSiteUnstable = callSiteUnstable;
this.arguments = arguments;
this.arguments = arguments.clone();
}
@Override
public Object[] getArguments() {
return arguments != null ? arguments.clone() : null;
return arguments.clone();
}
@Override
public Object getReceiver() {
return arguments != null && arguments.length > 0 ? arguments[0] : null;
return arguments.length > 0 ? arguments[0] : null;
}
@Override
@ -130,28 +128,13 @@ public class LinkRequestImpl implements LinkRequest {
return callSiteDescriptor;
}
@Override
public Object getCallSiteToken() {
return callSiteToken;
}
@Override
public boolean isCallSiteUnstable() {
return callSiteUnstable;
}
@Override
public int getLinkCount() {
return linkCount;
}
@Override
public LinkRequest withoutRuntimeContext() {
return this;
}
@Override
public LinkRequest replaceArguments(final CallSiteDescriptor newCallSiteDescriptor, final Object[] newArguments) {
return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, newArguments);
public LinkRequest replaceArguments(final CallSiteDescriptor newCallSiteDescriptor, final Object... newArguments) {
return new SimpleLinkRequest(newCallSiteDescriptor, callSiteUnstable, newArguments);
}
}

View File

@ -81,21 +81,18 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
package jdk.internal.dynalink.linker.support;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
/**
* Various static utility methods for testing type relationships.
* Various static utility methods for working with Java types.
*/
public class TypeUtilities {
static final Class<Object> OBJECT_CLASS = Object.class;
@ -103,107 +100,13 @@ public class TypeUtilities {
private TypeUtilities() {
}
/**
* Given two types represented by c1 and c2, returns a type that is their most specific common supertype for
* purposes of lossless conversions.
*
* @param c1 one type
* @param c2 another type
* @return their most common superclass or superinterface for purposes of lossless conversions. If they have several
* unrelated superinterfaces as their most specific common type, or the types themselves are completely
* unrelated interfaces, {@link java.lang.Object} is returned.
*/
public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
if(c1 == c2) {
return c1;
} else if (c1 == void.class || c2 == void.class) {
return Object.class;
} else if(isConvertibleWithoutLoss(c2, c1)) {
return c1;
} else if(isConvertibleWithoutLoss(c1, c2)) {
return c2;
} else if(c1.isPrimitive() && c2.isPrimitive()) {
if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
// byte + char = int
return int.class;
} else if((c1 == short.class && c2 == char.class) || (c1 == char.class && c2 == short.class)) {
// short + char = int
return int.class;
} else if((c1 == int.class && c2 == float.class) || (c1 == float.class && c2 == int.class)) {
// int + float = double
return double.class;
}
}
// For all other cases. This will handle long + (float|double) = Number case as well as boolean + anything = Object case too.
return getMostSpecificCommonTypeUnequalNonprimitives(c1, c2);
}
private static Class<?> getMostSpecificCommonTypeUnequalNonprimitives(final Class<?> c1, final Class<?> c2) {
final Class<?> npc1 = c1.isPrimitive() ? getWrapperType(c1) : c1;
final Class<?> npc2 = c2.isPrimitive() ? getWrapperType(c2) : c2;
final Set<Class<?>> a1 = getAssignables(npc1, npc2);
final Set<Class<?>> a2 = getAssignables(npc2, npc1);
a1.retainAll(a2);
if(a1.isEmpty()) {
// Can happen when at least one of the arguments is an interface,
// as they don't have Object at the root of their hierarchy.
return Object.class;
}
// Gather maximally specific elements. Yes, there can be more than one
// thank to interfaces. I.e., if you call this method for String.class
// and Number.class, you'll have Comparable, Serializable, and Object
// as maximal elements.
final List<Class<?>> max = new ArrayList<>();
outer: for(final Class<?> clazz: a1) {
for(final Iterator<Class<?>> maxiter = max.iterator(); maxiter.hasNext();) {
final Class<?> maxClazz = maxiter.next();
if(isSubtype(maxClazz, clazz)) {
// It can't be maximal, if there's already a more specific
// maximal than it.
continue outer;
}
if(isSubtype(clazz, maxClazz)) {
// If it's more specific than a currently maximal element,
// that currently maximal is no longer a maximal.
maxiter.remove();
}
}
// If we get here, no current maximal is more specific than the
// current class, so it is considered maximal as well
max.add(clazz);
}
if(max.size() > 1) {
return Object.class;
}
return max.get(0);
}
private static Set<Class<?>> getAssignables(final Class<?> c1, final Class<?> c2) {
final Set<Class<?>> s = new HashSet<>();
collectAssignables(c1, c2, s);
return s;
}
private static void collectAssignables(final Class<?> c1, final Class<?> c2, final Set<Class<?>> s) {
if(c1.isAssignableFrom(c2)) {
s.add(c1);
}
final Class<?> sc = c1.getSuperclass();
if(sc != null) {
collectAssignables(sc, c2, s);
}
final Class<?>[] itf = c1.getInterfaces();
for(int i = 0; i < itf.length; ++i) {
collectAssignables(itf[i], c2, s);
}
}
private static final Map<Class<?>, Class<?>> WRAPPER_TYPES = createWrapperTypes();
private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPES = invertMap(WRAPPER_TYPES);
private static final Map<String, Class<?>> PRIMITIVE_TYPES_BY_NAME = createClassNameMapping(WRAPPER_TYPES.keySet());
private static Map<Class<?>, Class<?>> createWrapperTypes() {
final Map<Class<?>, Class<?>> wrapperTypes = new IdentityHashMap<>(8);
wrapperTypes.put(Void.TYPE, Void.class);
wrapperTypes.put(Boolean.TYPE, Boolean.class);
wrapperTypes.put(Byte.TYPE, Byte.class);
wrapperTypes.put(Character.TYPE, Character.class);
@ -249,23 +152,32 @@ public class TypeUtilities {
if(targetType.isPrimitive()) {
return isProperPrimitiveSubtype(sourceType, targetType);
}
// Boxing + widening reference conversion
assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
return isBoxingAndWideningReferenceConversion(sourceType, targetType);
}
if(targetType.isPrimitive()) {
final Class<?> unboxedCallSiteType = PRIMITIVE_TYPES.get(sourceType);
final Class<?> unboxedCallSiteType = getPrimitiveType(sourceType);
return unboxedCallSiteType != null
&& (unboxedCallSiteType == targetType || isProperPrimitiveSubtype(unboxedCallSiteType, targetType));
}
return false;
}
private static boolean isBoxingAndWideningReferenceConversion(final Class<?> sourceType, final Class<?> targetType) {
final Class<?> wrapperType = getWrapperType(sourceType);
assert wrapperType != null : sourceType.getName();
return targetType.isAssignableFrom(wrapperType);
}
/**
* Determines whether a type can be converted to another without losing any precision. As a special case,
* void is considered convertible only to Object and void, while anything can be converted to void. This
* is because a target type of void means we don't care about the value, so the conversion is always
* permissible.
* Determines whether a type can be converted to another without losing any
* precision. As a special case, void is considered convertible only to void
* and {@link Object} (either as {@code null} or as a custom value set in
* {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy)}).
* Somewhat unintuitively, we consider anything to be convertible to void
* even though converting to void causes the ultimate loss of data. On the
* other hand, conversion to void essentially means that the value is of no
* interest and should be discarded, thus there's no expectation of
* preserving any precision.
*
* @param sourceType the source type
* @param targetType the target type
@ -284,9 +196,7 @@ public class TypeUtilities {
if(targetType.isPrimitive()) {
return isProperPrimitiveLosslessSubtype(sourceType, targetType);
}
// Boxing + widening reference conversion
assert WRAPPER_TYPES.get(sourceType) != null : sourceType.getName();
return targetType.isAssignableFrom(WRAPPER_TYPES.get(sourceType));
return isBoxingAndWideningReferenceConversion(sourceType, targetType);
}
// Can't convert from any non-primitive type to any primitive type without data loss because of null.
// Also, can't convert non-assignable reference types.
@ -294,51 +204,11 @@ public class TypeUtilities {
}
/**
* Determines whether one type can be potentially converted to another type at runtime. Allows a conversion between
* any subtype and supertype in either direction, and also allows a conversion between any two primitive types, as
* well as between any primitive type and any reference type that can hold a boxed primitive.
*
* @param callSiteType the parameter type at the call site
* @param methodType the parameter type in the method declaration
* @return true if callSiteType is potentially convertible to the methodType.
*/
public static boolean isPotentiallyConvertible(final Class<?> callSiteType, final Class<?> methodType) {
// Widening or narrowing reference conversion
if(areAssignable(callSiteType, methodType)) {
return true;
}
if(callSiteType.isPrimitive()) {
// Allow any conversion among primitives, as well as from any
// primitive to any type that can receive a boxed primitive.
// TODO: narrow this a bit, i.e. allow, say, boolean to Character?
// MethodHandles.convertArguments() allows it, so we might need to
// too.
return methodType.isPrimitive() || isAssignableFromBoxedPrimitive(methodType);
}
if(methodType.isPrimitive()) {
// Allow conversion from any reference type that can contain a
// boxed primitive to any primitive.
// TODO: narrow this a bit too?
return isAssignableFromBoxedPrimitive(callSiteType);
}
return false;
}
/**
* Returns true if either of the types is assignable from the other.
* @param c1 one of the types
* @param c2 another one of the types
* @return true if either c1 is assignable from c2 or c2 is assignable from c1.
*/
public static boolean areAssignable(final Class<?> c1, final Class<?> c2) {
return c1.isAssignableFrom(c2) || c2.isAssignableFrom(c1);
}
/**
* Determines whether one type is a subtype of another type, as per JLS 4.10 "Subtyping". Note: this is not strict
* or proper subtype, therefore true is also returned for identical types; to be completely precise, it allows
* identity conversion (JLS 5.1.1), widening primitive conversion (JLS 5.1.2) and widening reference conversion (JLS
* 5.1.5).
* Determines whether one type is a subtype of another type, as per JLS
* 4.10 "Subtyping". Note: this is not strict or proper subtype, therefore
* true is also returned for identical types; to be completely precise, it
* allows identity conversion (JLS 5.1.1), widening primitive conversion
* (JLS 5.1.2) and widening reference conversion (JLS 5.1.5).
*
* @param subType the supposed subtype
* @param superType the supposed supertype of the subtype
@ -432,82 +302,31 @@ public class TypeUtilities {
return false;
}
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPES = createWrapperToPrimitiveTypes();
private static Map<Class<?>, Class<?>> createWrapperToPrimitiveTypes() {
final Map<Class<?>, Class<?>> classes = new IdentityHashMap<>();
classes.put(Void.class, Void.TYPE);
classes.put(Boolean.class, Boolean.TYPE);
classes.put(Byte.class, Byte.TYPE);
classes.put(Character.class, Character.TYPE);
classes.put(Short.class, Short.TYPE);
classes.put(Integer.class, Integer.TYPE);
classes.put(Long.class, Long.TYPE);
classes.put(Float.class, Float.TYPE);
classes.put(Double.class, Double.TYPE);
return classes;
}
private static final Set<Class<?>> PRIMITIVE_WRAPPER_TYPES = createPrimitiveWrapperTypes();
private static Set<Class<?>> createPrimitiveWrapperTypes() {
final Map<Class<?>, Class<?>> classes = new IdentityHashMap<>();
addClassHierarchy(classes, Boolean.class);
addClassHierarchy(classes, Byte.class);
addClassHierarchy(classes, Character.class);
addClassHierarchy(classes, Short.class);
addClassHierarchy(classes, Integer.class);
addClassHierarchy(classes, Long.class);
addClassHierarchy(classes, Float.class);
addClassHierarchy(classes, Double.class);
return classes.keySet();
}
private static void addClassHierarchy(final Map<Class<?>, Class<?>> map, final Class<?> clazz) {
if(clazz == null) {
return;
}
map.put(clazz, clazz);
addClassHierarchy(map, clazz.getSuperclass());
for(final Class<?> itf: clazz.getInterfaces()) {
addClassHierarchy(map, itf);
}
}
/**
* Returns true if the class can be assigned from any boxed primitive.
*
* @param clazz the class
* @return true if the class can be assigned from any boxed primitive. Basically, it is true if the class is any
* primitive wrapper class, or a superclass or superinterface of any primitive wrapper class.
*/
private static boolean isAssignableFromBoxedPrimitive(final Class<?> clazz) {
return PRIMITIVE_WRAPPER_TYPES.contains(clazz);
}
/**
* Given a name of a primitive type (except "void"), returns the class representing it. I.e. when invoked with
* "int", returns {@link Integer#TYPE}.
* Given a name of a primitive type returns the class representing it. I.e.
* when invoked with "int", returns {@link Integer#TYPE}.
* @param name the name of the primitive type
* @return the class representing the primitive type, or null if the name does not correspond to a primitive type
* or is "void".
* @return the class representing the primitive type, or null if the name
* does not correspond to a primitive type.
*/
public static Class<?> getPrimitiveTypeByName(final String name) {
return PRIMITIVE_TYPES_BY_NAME.get(name);
}
/**
* When passed a class representing a wrapper for a primitive type, returns the class representing the corresponding
* primitive type. I.e. calling it with {@code Integer.class} will return {@code Integer.TYPE}. If passed a class
* that is not a wrapper for primitive type, returns null.
* @param wrapperType the class object representing a wrapper for a primitive type
* @return the class object representing the primitive type, or null if the passed class is not a primitive wrapper.
* When passed a class representing a wrapper for a primitive type, returns
* the class representing the corresponding primitive type. I.e. calling it
* with {@code Integer.class} will return {@code Integer.TYPE}. If passed a
* class that is not a wrapper for primitive type, returns null.
* @param wrapperType the class object representing a wrapper for a
* primitive type.
* @return the class object representing the primitive type, or null if the
* passed class is not a primitive wrapper.
*/
public static Class<?> getPrimitiveType(final Class<?> wrapperType) {
return WRAPPER_TO_PRIMITIVE_TYPES.get(wrapperType);
return PRIMITIVE_TYPES.get(wrapperType);
}
/**
* When passed a class representing a primitive type, returns the class representing the corresponding
* wrapper type. I.e. calling it with {@code int.class} will return {@code Integer.class}. If passed a class

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -31,7 +31,7 @@
* license:
*/
/*
Copyright 2009-2013 Attila Szegedi
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
@ -81,37 +81,13 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
class NamedDynCallSiteDescriptor extends UnnamedDynCallSiteDescriptor {
private final String name;
NamedDynCallSiteDescriptor(final String op, final String name, final MethodType methodType) {
super(op, methodType);
this.name = name;
}
@Override
public int getNameTokenCount() {
return 3;
}
@Override
public String getNameToken(final int i) {
switch(i) {
case 0: return "dyn";
case 1: return getOp();
case 2: return name;
default: throw new IndexOutOfBoundsException(String.valueOf(i));
}
}
@Override
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new NamedDynCallSiteDescriptor(getOp(), name,
newMethodType));
}
}
/**
* <p>Contains classes that make it more convenient for language runtimes to
* implement their own language-specific object models and type conversions
* by providing basic implementations of some classes as well as various
* utilities.
* </p>
* @since 1.9
*/
@jdk.Exported
package jdk.internal.dynalink.linker.support;

View File

@ -0,0 +1,277 @@
/*
* 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 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.
*/
/**
* <p>
* Dynalink is a library for dynamic linking high-level operations on objects.
* These operations include "read a property",
* "write a property", "invoke a function" and so on. Dynalink is primarily
* useful for implementing programming languages where at least some expressions
* have dynamic types (that is, types that can not be decided statically), and
* the operations on dynamic types are expressed as
* {@link java.lang.invoke.CallSite call sites}. These call sites will be
* linked to appropriate target {@link java.lang.invoke.MethodHandle method handles}
* at run time based on actual types of the values the expressions evaluated to.
* These can change between invocations, necessitating relinking the call site
* multiple times to accommodate new types; Dynalink handles all that and more.
* <p>
* Dynalink supports implementation of programming languages with object models
* that differ (even radically) from the JVM's class-based model and have their
* custom type conversions.
* <p>
* Dynalink is closely related to, and relies on, the {@link java.lang.invoke}
* package.
* <p>
*
* While {@link java.lang.invoke} provides a low level API for dynamic linking
* of {@code invokedynamic} call sites, it does not provide a way to express
* higher level operations on objects, nor methods that implement them. These
* operations are the usual ones in object-oriented environments: property
* access, access of elements of collections, invocation of methods and
* constructors (potentially with multiple dispatch, e.g. link- and run-time
* equivalents of Java overloaded method resolution). These are all functions
* that are normally desired in a language on the JVM. If a language is
* statically typed and its type system matches that of the JVM, it can
* accomplish this with use of the usual invocation, field access, etc.
* instructions (e.g. {@code invokevirtual}, {@code getfield}). However, if the
* language is dynamic (hence, types of some expressions are not known until
* evaluated at run time), or its object model or type system don't match
* closely that of the JVM, then it should use {@code invokedynamic} call sites
* instead and let Dynalink manage them.
* <h2>Example</h2>
* Dynalink is probably best explained by an example showing its use. Let's
* suppose you have a program in a language where you don't have to declare the
* type of an object and you want to access a property on it:
* <pre>
* var color = obj.color;
* </pre>
* If you generated a Java class to represent the above one-line program, its
* bytecode would look something like this:
* <pre>
* aload 2 // load "obj" on stack
* invokedynamic "GET_PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
* astore 3 // store the return value into local variable "color"
* </pre>
* In order to link the {@code invokedynamic} instruction, we need a bootstrap
* method. A minimalist bootstrap method with Dynalink could look like this:
* <pre>
* import java.lang.invoke.*;
* import jdk.internal.dynalink.*;
* import jdk.internal.dynalink.support.*;
*
* class MyLanguageRuntime {
* private static final DynamicLinker dynamicLinker = new DynamicLinkerFactory().createLinker();
*
* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
* return dynamicLinker.link(
* new SimpleRelinkableCallSite(
* new CallSiteDescriptor(lookup, parseOperation(name), type)));
* }
*
* private static Operation parseOperation(String name) {
* ...
* }
* }
* </pre>
* There are several objects of significance in the above code snippet:
* <ul>
* <li>{@link jdk.internal.dynalink.DynamicLinker} is the main object in Dynalink, it
* coordinates the linking of call sites to method handles that implement the
* operations named in them. It is configured and created using a
* {@link jdk.internal.dynalink.DynamicLinkerFactory}.</li>
* <li>When the bootstrap method is invoked, it needs to create a
* {@link java.lang.invoke.CallSite} object. In Dynalink, these call sites need
* to additionally implement the {@link jdk.internal.dynalink.RelinkableCallSite}
* interface. "Relinkable" here alludes to the fact that if the call site
* encounters objects of different types at run time, its target will be changed
* to a method handle that can perform the operation on the newly encountered
* type. {@link jdk.internal.dynalink.support.SimpleRelinkableCallSite} and
* {@link jdk.internal.dynalink.support.ChainedCallSite} (not used in the above example)
* are two implementations already provided by the library.</li>
* <li>Dynalink uses {@link jdk.internal.dynalink.CallSiteDescriptor} objects to
* preserve the parameters to the bootstrap method: the lookup and the method type,
* as it will need them whenever it needs to relink a call site.</li>
* <li>Dynalink uses {@link jdk.internal.dynalink.Operation} objects to express
* dynamic operations. It does not prescribe how would you encode the operations
* in your call site, though. That is why in the above example the
* {@code parseOperation} function is left empty, and you would be expected to
* provide the code to parse the string {@code "GET_PROPERTY:color"}
* in the call site's name into a named property getter operation object as
* {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}.
* </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
* usual Java semantics. If you have these three simple classes:
* <pre>
* public class A {
* public String color;
* public A(String color) { this.color = color; }
* }
*
* public class B {
* private String color;
* public B(String color) { this.color = color; }
* public String getColor() { return color; }
* }
*
* public class C {
* private int color;
* public C(int color) { this.color = color; }
* public int getColor() { return color; }
* }
* </pre>
* and you somehow create their instances and pass them to your call site in your
* programming language:
* <pre>
* for each(var obj in [new A("red"), new B("green"), new C(0x0000ff)]) {
* print(obj.color);
* }
* </pre>
* then on first invocation, Dynalink will link the {@code .color} getter
* operation to a field getter for {@code A.color}, on second invocation it will
* relink it to {@code B.getColor()} returning a {@code String}, and finally on
* third invocation it will relink it to {@code C.getColor()} returning an {@code int}.
* The {@code SimpleRelinkableCallSite} we used above only remembers the linkage
* for the last encountered type (it implements what is known as a <i>monomorphic
* inline cache</i>). Another already provided implementation,
* {@link jdk.internal.dynalink.support.ChainedCallSite} will remember linkages for
* several different types (it is a <i>polymorphic inline cache</i>) and is
* probably a better choice in serious applications.
* <h2>Dynalink and bytecode creation</h2>
* {@code CallSite} objects are usually created as part of bootstrapping
* {@code invokedynamic} instructions in bytecode. Hence, Dynalink is typically
* used as part of language runtimes that compile programs into Java
* {@code .class} bytecode format. Dynalink does not address the aspects of
* either creating bytecode classes or loading them into the JVM. That said,
* Dynalink can also be used without bytecode compilation (e.g. in language
* interpreters) by creating {@code CallSite} objects explicitly and associating
* them with representations of dynamic operations in the interpreted program
* (e.g. a typical representation would be some node objects in a syntax tree).
* <h2>Available operations</h2>
* Dynalink defines several standard operations in its
* {@link jdk.internal.dynalink.StandardOperation} class. The linker for Java
* objects can link all of these operations, and you are encouraged to at
* minimum support and use these operations in your language too. To associate
* a fixed name with an operation, you can use
* {@link jdk.internal.dynalink.NamedOperation} as in the above example where
* {@code StandardOperation.GET_PROPERTY} was combined with the name
* {@code "color"} in a {@code NamedOperation} to form a property getter for the
* property named "color".
* <h2>Composite operations</h2>
* Some languages might not have separate namespaces on objects for
* properties, elements, and methods, and a source language construct might
* address two or three of them. Dynalink supports specifying composite
* operations for this purpose using the
* {@link jdk.internal.dynalink.CompositeOperation} class.
* <h2>Language-specific linkers</h2>
* Languages that define their own object model different than the JVM
* class-based model and/or use their own type conversions will need to create
* their own language-specific linkers. See the {@link jdk.internal.dynalink.linker}
* package and specifically the {@link jdk.internal.dynalink.linker.GuardingDynamicLinker}
* interface to get started.
* <h2>Dynalink and Java objects</h2>
* The {@code DynamicLinker} objects created by {@code DynamicLinkerFactory} by
* default contain an internal instance of
* {@code BeansLinker}, which is a language-specific linker
* that implements the usual Java semantics for all of the above operations and
* can link any Java object that no other language-specific linker has managed
* to link. This way, all language runtimes have built-in interoperability with
* ordinary Java objects. See {@link jdk.internal.dynalink.beans.BeansLinker} for details
* on how it links the various operations.
* <h2>Cross-language interoperability</h2>
* A {@code DynamicLinkerFactory} can be configured with a
* {@link jdk.internal.dynalink.DynamicLinkerFactory#setClassLoader(ClassLoader) class
* loader}. It will try to instantiate all
* {@link jdk.internal.dynalink.linker.GuardingDynamicLinkerExporter} classes visible to
* that class loader and compose the linkers they provide into the
* {@code DynamicLinker} it creates. This allows for interoperability between
* languages: if you have two language runtimes A and B deployed in your JVM and
* they export their linkers through the above mechanism, language runtime A
* will have a language-specific linker instance from B and vice versa inside
* their {@code DynamicLinker} objects. This means that if an object from
* language runtime B gets passed to code from language runtime A, the linker
* from B will get a chance to link the call site in A when it encounters the
* object from B.
*/
@jdk.Exported
package jdk.internal.dynalink;

View File

@ -1,93 +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.
-->
<body>
<p>
Contains the main API for using the dynamic linking facilities. A
scripting framework or a language runtime that does not define its own
linker but only uses linkers available in the system will only need to
use classes and interfaces from this package.
</p>
<p>
Languages that wish to define and use their own linkers will also need to
use the {@link jdk.internal.dynalink.linker} package.
</p>
</body>

View File

@ -83,20 +83,31 @@
package jdk.internal.dynalink.support;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MutableCallSite;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.RelinkableCallSite;
import jdk.internal.dynalink.linker.GuardedInvocation;
/**
* A basic implementation of the {@link RelinkableCallSite} as a {@link MutableCallSite} subclass.
* A basic implementation of the {@link RelinkableCallSite} as a
* {@link MutableCallSite}. It carries a {@link CallSiteDescriptor} passed in
* the constructor and provides the correct implementation of the
* {@link #initialize(MethodHandle)} method. Subclasses must provide
* {@link #relink(GuardedInvocation, MethodHandle)} and
* {@link #resetAndRelink(GuardedInvocation, MethodHandle)}
* methods.
*/
public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite {
private final CallSiteDescriptor descriptor;
/**
* Creates a new relinkable call site.
* @param descriptor the descriptor for this call site
* Creates a new abstract relinkable call site.
* @param descriptor the descriptor for this call site that will be returned
* from {@link #getDescriptor()}. The call site's {@link CallSite#type()}
* will be equal to descriptor's {@link CallSiteDescriptor#getMethodType()}.
* @throws NullPointerException if {@code descriptor} is null.
*/
protected AbstractRelinkableCallSite(final CallSiteDescriptor descriptor) {
super(descriptor.getMethodType());

View File

@ -1,114 +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 jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
/**
* A linker that can't link any call site. Only used internally by {@link CompositeTypeBasedGuardingDynamicLinker}. Can
* be used by other language runtimes if they need it though.
*/
public class BottomGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker {
/**
* The sole instance of this stateless linker.
*/
public static final BottomGuardingDynamicLinker INSTANCE = new BottomGuardingDynamicLinker();
private BottomGuardingDynamicLinker() {
}
@Override
public boolean canLinkType(final Class<?> type) {
return false;
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) {
return null;
}
}

View File

@ -1,274 +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.lang.invoke.MethodType;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.StringTokenizer;
import java.util.WeakHashMap;
import jdk.internal.dynalink.CallSiteDescriptor;
/**
* Usable as a default factory for call site descriptor implementations. It is weakly canonicalizing, meaning
* it will return the same immutable call site descriptor for identical inputs, i.e. repeated requests for a
* descriptor signifying public lookup for {@code "dyn:getProp:color"} of type {@code Object(Object)} will
* return the same object as long as a previously created, at least softly reachable one exists. It also uses
* several different implementations of the {@link CallSiteDescriptor} internally, and chooses the most
* space-efficient one based on the input.
*/
public class CallSiteDescriptorFactory {
private static final WeakHashMap<CallSiteDescriptor, Reference<CallSiteDescriptor>> publicDescs =
new WeakHashMap<>();
private CallSiteDescriptorFactory() {
}
/**
* Creates a new call site descriptor instance. The actual underlying class of the instance is dependent on the
* passed arguments to be space efficient; i.e. if you only use the public lookup, you'll get back an
* implementation that doesn't waste space on storing the lookup object.
* @param lookup the lookup that determines access rights at the call site. If your language runtime doesn't have
* equivalents of Java access concepts, just use {@link MethodHandles#publicLookup()}. Must not be null.
* @param name the name of the method at the call site. Must not be null.
* @param methodType the type of the method at the call site. Must not be null.
* @return a call site descriptor representing the input. Note that although the method name is "create", it will
* in fact return a weakly-referenced canonical instance.
*/
public static CallSiteDescriptor create(final Lookup lookup, final String name, final MethodType methodType) {
Objects.requireNonNull(name);
Objects.requireNonNull(methodType);
Objects.requireNonNull(lookup);
final String[] tokenizedName = tokenizeName(name);
if(isPublicLookup(lookup)) {
return getCanonicalPublicDescriptor(createPublicCallSiteDescriptor(tokenizedName, methodType));
}
return new LookupCallSiteDescriptor(tokenizedName, methodType, lookup);
}
static CallSiteDescriptor getCanonicalPublicDescriptor(final CallSiteDescriptor desc) {
synchronized(publicDescs) {
final Reference<CallSiteDescriptor> ref = publicDescs.get(desc);
if(ref != null) {
final CallSiteDescriptor canonical = ref.get();
if(canonical != null) {
return canonical;
}
}
publicDescs.put(desc, createReference(desc));
}
return desc;
}
/**
* Override this to use a different kind of references for the cache
* @param desc desc
* @return reference
*/
protected static Reference<CallSiteDescriptor> createReference(final CallSiteDescriptor desc) {
return new WeakReference<>(desc);
}
private static CallSiteDescriptor createPublicCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) {
final int l = tokenizedName.length;
if(l > 0 && tokenizedName[0] == "dyn") {
if(l == 2) {
return new UnnamedDynCallSiteDescriptor(tokenizedName[1], methodType);
} if (l == 3) {
return new NamedDynCallSiteDescriptor(tokenizedName[1], tokenizedName[2], methodType);
}
}
return new DefaultCallSiteDescriptor(tokenizedName, methodType);
}
private static boolean isPublicLookup(final Lookup lookup) {
return lookup == MethodHandles.publicLookup();
}
/**
* Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns
* the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of
* the operation which can be expected to consist of just alphabetical characters.
* @param name the composite name consisting of colon-separated, possibly mangled tokens.
* @return an array of tokens
*/
public static String[] tokenizeName(final String name) {
final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
final String[] tokens = new String[tok.countTokens()];
for(int i = 0; i < tokens.length; ++i) {
String token = tok.nextToken();
if(i > 1) {
token = NameCodec.decode(token);
}
tokens[i] = token.intern();
}
return tokens;
}
/**
* Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod"
* operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned.
* @param desc the call site descriptor with the operation
* @return a list of tokens
*/
public static List<String> tokenizeOperators(final CallSiteDescriptor desc) {
final String ops = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
final int count = tok.countTokens();
if(count == 1) {
return Collections.singletonList(ops);
}
final String[] tokens = new String[count];
for(int i = 0; i < count; ++i) {
tokens[i] = tok.nextToken();
}
return Arrays.asList(tokens);
}
/**
* Returns a new call site descriptor that is identical to the passed one, except that it has some parameter types
* removed from its method type.
* @param desc the original call site descriptor
* @param start index of the first parameter to remove
* @param end index of the first parameter to not remove
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor dropParameterTypes(final CallSiteDescriptor desc, final int start, final int end) {
return desc.changeMethodType(desc.getMethodType().dropParameterTypes(start, end));
}
/**
* Returns a new call site descriptor that is identical to the passed one, except that it has a single parameter
* type changed in its method type.
* @param desc the original call site descriptor
* @param num index of the parameter to change
* @param nptype the new parameter type
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor changeParameterType(final CallSiteDescriptor desc, final int num, final Class<?> nptype) {
return desc.changeMethodType(desc.getMethodType().changeParameterType(num, nptype));
}
/**
* Returns a new call site descriptor that is identical to the passed one, except that it has the return type
* changed in its method type.
* @param desc the original call site descriptor
* @param nrtype the new return type
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor changeReturnType(final CallSiteDescriptor desc, final Class<?> nrtype) {
return desc.changeMethodType(desc.getMethodType().changeReturnType(nrtype));
}
/**
* Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter
* types inserted into its method type.
* @param desc the original call site descriptor
* @param num index at which the new parameters are inserted
* @param ptypesToInsert the new types to insert
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final Class<?>... ptypesToInsert) {
return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert));
}
/**
* Returns a new call site descriptor that is identical to the passed one, except that it has additional parameter
* types inserted into its method type.
* @param desc the original call site descriptor
* @param num index at which the new parameters are inserted
* @param ptypesToInsert the new types to insert
* @return a new call site descriptor with modified method type
*/
public static CallSiteDescriptor insertParameterTypes(final CallSiteDescriptor desc, final int num, final List<Class<?>> ptypesToInsert) {
return desc.changeMethodType(desc.getMethodType().insertParameterTypes(num, ptypesToInsert));
}
}

View File

@ -81,26 +81,33 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink;
package jdk.internal.dynalink.support;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Lookup;
/**
* A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method
* handles can be chained, cascading from one to the other through
* {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)}. When this call site has to link a new
* method handle and the length of the chain is already at the maximum, it will throw away the oldest method handle.
* Switchpoint-invalidated handles in the chain are removed eagerly (on each linking request, and whenever a
* switchpoint-invalidated method handle is traversed during invocation). There is currently no profiling
* attached to the handles in the chain, so they are never reordered based on usage; the most recently linked method
* handle is always at the start of the chain.
* A relinkable call site that implements a polymorphic inline caching strategy.
* It remembers up to 8 {@link GuardedInvocation}s it was linked with, and on
* each relink request builds a cascading chain of method handles of one
* invocation falling back to the next one. The number of remembered invocations
* can be customized by overriding {@link #getMaxChainLength()} in a subclass.
* When this call site is relinked with a new invocation and the length of the
* chain is already at the maximum, it will throw away the oldest invocation.
* Invocations with invalidated switch points and ones for which their
* invalidating exception triggered are removed eagerly from the chain. The
* invocations are never reordered; the most recently linked method handle is
* always at the start of the chain and the least recently linked at its end.
* The call site can be safely relinked on more than one thread concurrently.
* Race conditions in linking are resolved by throwing away the
* {@link GuardedInvocation} produced on the losing thread without incorporating
* it into the chain, so it can lead to repeated linking for the same arguments.
*/
public class ChainedCallSite extends AbstractRelinkableCallSite {
private static final MethodHandle PRUNE_CATCHES;
@ -130,22 +137,24 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
}
/**
* The maximum number of method handles in the chain. Defaults to 8. You can override it in a subclass if you need
* to change the value. If your override returns a value less than 1, the code will break.
* @return the maximum number of method handles in the chain.
* The maximum number of method handles in the chain. Defaults to 8. You can
* override it in a subclass if you need to change the value.
* @return the maximum number of method handles in the chain. The return
* value is checked, and if your override returns a value less than 1, a
* {@link RuntimeException} will be thrown.
*/
protected int getMaxChainLength() {
return 8;
}
@Override
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
relinkInternal(guardedInvocation, fallback, false, false);
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
relinkInternal(guardedInvocation, relinkAndInvoke, false, false);
}
@Override
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle fallback) {
relinkInternal(guardedInvocation, fallback, true, false);
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
relinkInternal(guardedInvocation, relinkAndInvoke, true, false);
}
private MethodHandle relinkInternal(final GuardedInvocation invocation, final MethodHandle relink, final boolean reset, final boolean removeCatches) {
@ -175,7 +184,7 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
// adding any new invocations to it.
if(invocation != null) {
// Remove oldest entry if we're at max length
if(newInvocations.size() == getMaxChainLength()) {
if(newInvocations.size() == checkMaxChainLength(getMaxChainLength())) {
newInvocations.removeFirst();
}
newInvocations.addLast(invocation);
@ -206,15 +215,22 @@ public class ChainedCallSite extends AbstractRelinkableCallSite {
return target;
}
private static int checkMaxChainLength(final int maxChainLength) {
if (maxChainLength > 0) {
return maxChainLength;
}
throw new RuntimeException("getMaxChainLength() returned a non-positive value");
}
/**
* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
* chain.
* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
* @param relinkAndInvoke the ultimate fallback for the chain passed from the dynamic linker.
* @return a method handle for prune-and-invoke
*/
private MethodHandle makePruneAndInvokeMethod(final MethodHandle relink, final MethodHandle prune) {
private MethodHandle makePruneAndInvokeMethod(final MethodHandle relinkAndInvoke, final MethodHandle prune) {
// Bind prune to (this, relink)
final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relinkAndInvoke);
// Make it ignore all incoming arguments
final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
// Invoke prune, then invoke the call site target with original arguments

View File

@ -1,133 +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.Lookup;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
/**
* A default, fairly light implementation of a call site descriptor used for describing non-standard operations. It does
* not store {@link Lookup} objects but always returns the public lookup from its {@link #getLookup()} method. If you
* need to support non-public lookup, you can use {@link LookupCallSiteDescriptor}.
*/
class DefaultCallSiteDescriptor extends AbstractCallSiteDescriptor {
private final String[] tokenizedName;
private final MethodType methodType;
DefaultCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType) {
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());
}
}
String[] getTokenizedName() {
return tokenizedName;
}
@Override
public MethodType getMethodType() {
return methodType;
}
@Override
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new DefaultCallSiteDescriptor(tokenizedName,
newMethodType));
}
}

View File

@ -1,116 +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.Lookup;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
/**
* A call site descriptor that stores a specific {@link Lookup}. It does not, however, store static bootstrap arguments.
*/
class LookupCallSiteDescriptor extends DefaultCallSiteDescriptor {
private final Lookup lookup;
/**
* Create a new call site descriptor from explicit information.
* @param tokenizedName the name of the method
* @param methodType the method type
* @param lookup the lookup
*/
LookupCallSiteDescriptor(final String[] tokenizedName, final MethodType methodType, final Lookup lookup) {
super(tokenizedName, methodType);
this.lookup = lookup;
}
@Override
public Lookup getLookup() {
return lookup;
}
@Override
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return new LookupCallSiteDescriptor(getTokenizedName(), newMethodType, lookup);
}
}

View File

@ -83,24 +83,15 @@
package jdk.internal.dynalink.support;
import jdk.internal.dynalink.CallSiteDescriptor;
/**
* Implements the name mangling and demangling as specified by John Rose's
* <a href="https://blogs.oracle.com/jrose/entry/symbolic_freedom_in_the_vm" target="_blank">"Symbolic Freedom in the
* VM"</a> article. It is recommended that implementers of languages on the JVM uniformly adopt this for symbolic
* interoperability between languages. Normally, you would mangle the names as you're generating bytecode, and then
* demangle them when you're creating {@link CallSiteDescriptor} objects. Note that you are expected to mangle
* individual tokens, and not the whole name at the call site, i.e. the colon character normally separating the tokens
* is never mangled. I.e. you wouldn't mangle {@code dyn:getProp:color} into {@code dyn\!getProp\!color}, but you would
* mangle {@code dyn:getProp:color$} into {@code dyn:getProp:\=color\%} (only mangling the individual token containing
* the symbol {@code color$}). {@link CallSiteDescriptorFactory#tokenizeName(String)} (and by implication, all call site
* descriptors it creates) will automatically perform demangling on the passed names. If you use this factory, or you
* have your own way of creating call site descriptors, but you still delegate to this method of the default factory
* (it is recommended that you do), then you have demangling handled for you already, and only need to ensure that you
* mangle the names when you're emitting them in the bytecode.
* <a href="https://blogs.oracle.com/jrose/entry/symbolic_freedom_in_the_vm"
* target="_blank">"Symbolic Freedom in the VM"</a> article. Normally, you would
* mangle the names in the call sites as you're generating bytecode, and then
* demangle them when you receive them in bootstrap methods.
*/
public class NameCodec {
public final class NameCodec {
private static final char ESCAPE_CHAR = '\\';
private static final char EMPTY_ESCAPE = '=';
private static final String EMPTY_NAME = new String(new char[] { ESCAPE_CHAR, EMPTY_ESCAPE });
@ -175,7 +166,7 @@ public class NameCodec {
* @return the demangled form of the symbolic name.
*/
public static String decode(final String name) {
if(name.charAt(0) != ESCAPE_CHAR) {
if(name.isEmpty() || name.charAt(0) != ESCAPE_CHAR) {
return name;
}
final int l = name.length();

View File

@ -1,142 +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 jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest;
/**
* A link request implementation for call sites that pass language runtime specific context arguments on the stack. The
* context specific arguments should be the first "n" arguments.
*/
public class RuntimeContextLinkRequestImpl extends LinkRequestImpl {
private final int runtimeContextArgCount;
private LinkRequestImpl contextStrippedRequest;
/**
* Creates a new link request.
*
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
* @param arguments the arguments for the invocation
* @param linkCount number of times callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language
* runtime specific context arguments.
* @throws IllegalArgumentException if runtimeContextArgCount is less than 1.
*/
public RuntimeContextLinkRequestImpl(final CallSiteDescriptor callSiteDescriptor, final Object callSiteToken,
final int linkCount, final boolean callSiteUnstable, final Object[] arguments, final int runtimeContextArgCount) {
super(callSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, arguments);
if(runtimeContextArgCount < 1) {
throw new IllegalArgumentException("runtimeContextArgCount < 1");
}
this.runtimeContextArgCount = runtimeContextArgCount;
}
@Override
public LinkRequest withoutRuntimeContext() {
if(contextStrippedRequest == null) {
contextStrippedRequest =
new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1,
runtimeContextArgCount + 1), getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), getTruncatedArguments());
}
return contextStrippedRequest;
}
@Override
public LinkRequest replaceArguments(final CallSiteDescriptor callSiteDescriptor, final Object[] arguments) {
return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), arguments,
runtimeContextArgCount);
}
private Object[] getTruncatedArguments() {
final Object[] args = getArguments();
final Object[] newargs = new Object[args.length - runtimeContextArgCount];
newargs[0] = args[0]; // "this" remains at the 0th position
System.arraycopy(args, runtimeContextArgCount + 1, newargs, 1, newargs.length - 1);
return newargs;
}
}

View File

@ -81,33 +81,35 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink;
package jdk.internal.dynalink.support;
import java.lang.invoke.MethodHandle;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
/**
* A relinkable call site that implements monomorphic inline caching strategy. After it linked a method, it will keep it
* until either its guard evaluates to false, or its switchpoint is invalidated, at which time it will throw away the
* previous linkage, and trigger relinking with its associated {@link DynamicLinker}.
* A relinkable call site that implements monomorphic inline caching strategy,
* only being linked to a single {@link GuardedInvocation}. If that invocation
* is invalidated, it will throw it away and ask its associated
* {@link DynamicLinker} to relink it.
*/
public class MonomorphicCallSite extends AbstractRelinkableCallSite {
public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite {
/**
* Creates a new call site with monomorphic inline caching strategy.
* @param descriptor the descriptor for this call site
*/
public MonomorphicCallSite(final CallSiteDescriptor descriptor) {
public SimpleRelinkableCallSite(final CallSiteDescriptor descriptor) {
super(descriptor);
}
@Override
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relink) {
setTarget(guardedInvocation.compose(relink));
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
setTarget(guardedInvocation.compose(relinkAndInvoke));
}
@Override
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relink) {
relink(guardedInvocation, relink);
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
relink(guardedInvocation, relinkAndInvoke);
}
}

View File

@ -1,126 +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.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
class UnnamedDynCallSiteDescriptor extends AbstractCallSiteDescriptor {
private final MethodType methodType;
private final String op;
UnnamedDynCallSiteDescriptor(final String op, final MethodType methodType) {
this.op = op;
this.methodType = methodType;
}
@Override
public int getNameTokenCount() {
return 2;
}
String getOp() {
return op;
}
@Override
public String getNameToken(final int i) {
switch(i) {
case 0: return "dyn";
case 1: return op;
default: throw new IndexOutOfBoundsException(String.valueOf(i));
}
}
@Override
public MethodType getMethodType() {
return methodType;
}
@Override
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
return CallSiteDescriptorFactory.getCanonicalPublicDescriptor(new UnnamedDynCallSiteDescriptor(op,
newMethodType));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* 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
@ -81,19 +81,11 @@
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.dynalink.support;
import jdk.internal.dynalink.GuardedInvocationFilter;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
/**
* Default filter for guarded invocation pre link filtering
* <p>Contains classes that make using Dynalink more convenient by providing
* basic implementations of some classes as well as various utilities.
* </p>
* @since 1.9
*/
public class DefaultPrelinkFilter implements GuardedInvocationFilter {
@Override
public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
return inv.asType(linkerServices, request.getCallSiteDescriptor().getMethodType());
}
}
@jdk.Exported
package jdk.internal.dynalink.support;

View File

@ -1,89 +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.
-->
<body>
<p>
Contains supporting classes for other packages. There is no guarantee that
any of these classes or interfaces will not change in a manner that breaks
backwards compatibility; they are not considered to be part of the public
API.
</p>
</body>

View File

@ -683,9 +683,9 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
// (in)equality operators need the specialized JSType.toNumberFor[Strict]Equals. E.g. in the code snippet
// "i < obj.size" (where i is primitive and obj.size is statically an object), ".size" will thus be allowed
// to compile as:
// invokedynamic dyn:getProp|getElem|getMethod:size(Object;)D
// invokedynamic GET_PROPERTY:size(Object;)D
// instead of the more costly:
// invokedynamic dyn:getProp|getElem|getMethod:size(Object;)Object
// invokedynamic GET_PROPERTY:size(Object;)Object
// invokestatic JSType.toNumber(Object)D
// Note also that even if this is allowed, we're only using it on operands that are non-optimistic, as
// otherwise the logic for determining effective optimistic-ness would turn an optimistic double return
@ -1494,11 +1494,11 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
void loadStack() {
/*
* We want to load 'eval' to check if it is indeed global builtin eval.
* If this eval call is inside a 'with' statement, dyn:getMethod|getProp|getElem
* If this eval call is inside a 'with' statement, GET_METHOD_PROPERTY
* would be generated if ident is a "isFunction". But, that would result in a
* bound function from WithObject. We don't want that as bound function as that
* won't be detected as builtin eval. So, we make ident as "not a function" which
* results in "dyn:getProp|getElem|getMethod" being generated and so WithObject
* results in GET_PROPERTY being generated and so WithObject
* would return unbounded eval function.
*
* Example:
@ -1525,7 +1525,7 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
method._goto(invoke_direct_eval);
method.label(is_not_eval);
// load this time but with dyn:getMethod|getProp|getElem
// load this time but with GET_METHOD_PROPERTY
loadExpressionAsObject(ident); // Type.OBJECT as foo() makes no sense if foo == 3
// This is some scope 'eval' or global eval replaced by user
// but not the built-in ECMAScript 'eval' function call

View File

@ -107,6 +107,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.options.Options;
@ -124,6 +125,8 @@ import jdk.nashorn.internal.runtime.options.Options;
* including bytecode stack contents
*/
public class MethodEmitter {
private static final String EMPTY_NAME = NameCodec.encode("");
/** The ASM MethodVisitor we are plugged into */
private final MethodVisitor method;
@ -2148,8 +2151,8 @@ public class MethodEmitter {
debug("dynamic_new", "argcount=", argCount);
final String signature = getDynamicSignature(Type.OBJECT, argCount);
method.visitInvokeDynamicInsn(
msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:new:" + NameCodec.encode(msg) : "dyn:new",
signature, LINKERBOOTSTRAP, flags);
msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.NEW);
pushType(Type.OBJECT); //TODO fix result type
return this;
}
@ -2182,8 +2185,8 @@ public class MethodEmitter {
final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
debug(" signature", signature);
method.visitInvokeDynamicInsn(
msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:call:" + NameCodec.encode(msg) : "dyn:call",
signature, LINKERBOOTSTRAP, flags);
msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.CALL);
pushType(returnType);
return this;
@ -2220,8 +2223,8 @@ public class MethodEmitter {
}
popType(Type.SCOPE);
method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
method.visitInvokeDynamicInsn(NameCodec.encode(name),
Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, isIndex));
pushType(type);
convert(valueType); //most probably a nop
@ -2253,8 +2256,8 @@ public class MethodEmitter {
popType(type);
popType(Type.SCOPE);
method.visitInvokeDynamicInsn(dynSetOperation(isIndex) + ':' + NameCodec.encode(name),
methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
method.visitInvokeDynamicInsn(NameCodec.encode(name),
methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags | dynSetOperation(isIndex));
}
/**
@ -2287,7 +2290,7 @@ public class MethodEmitter {
final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags);
method.visitInvokeDynamicInsn(EMPTY_NAME, signature, LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, true));
pushType(resultType);
if (result.isBoolean()) {
@ -2331,7 +2334,9 @@ public class MethodEmitter {
final Type receiver = popType(Type.OBJECT);
assert receiver.isObject();
method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags);
method.visitInvokeDynamicInsn(EMPTY_NAME,
methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()),
LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.SET_ELEMENT);
}
/**
@ -2501,16 +2506,16 @@ public class MethodEmitter {
}
}
private static String dynGetOperation(final boolean isMethod, final boolean isIndex) {
private static int dynGetOperation(final boolean isMethod, final boolean isIndex) {
if (isMethod) {
return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem";
return isIndex ? NashornCallSiteDescriptor.GET_METHOD_ELEMENT : NashornCallSiteDescriptor.GET_METHOD_PROPERTY;
} else {
return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod";
return isIndex ? NashornCallSiteDescriptor.GET_ELEMENT : NashornCallSiteDescriptor.GET_PROPERTY;
}
}
private static String dynSetOperation(final boolean isIndex) {
return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem";
private static int dynSetOperation(final boolean isIndex) {
return isIndex ? NashornCallSiteDescriptor.SET_ELEMENT : NashornCallSiteDescriptor.SET_PROPERTY;
}
private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) {

View File

@ -25,14 +25,16 @@
package jdk.nashorn.internal.ir;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Interface used by AccessNodes, IndexNodes and IdentNodes to signal that when evaluated, their value will be treated
* as a function and immediately invoked, e.g. {@code foo()}, {@code foo.bar()} or {@code foo[bar]()}. Used to customize
* the priority of composite dynamic operations when emitting {@code INVOKEDYNAMIC} instructions that implement them,
* namely prioritize {@code getMethod} over {@code getElem} or {@code getProp}. An access or ident node with isFunction
* set to true will be emitted as {@code dyn:getMethod|getProp|getElem} while one with it set to false will be emitted
* as {@code dyn:getProp|getElem|getMethod}. Similarly, an index node with isFunction set to true will be emitted as
* {@code dyn:getMethod|getElem|getProp} while the one set to false will be emitted as {@code dyn:getElem|getProp|getMethod}.
* set to true will be emitted as {@link NashornCallSiteDescriptor#GET_METHOD_PROPERTY} while one with it set to false will be emitted
* as {@link NashornCallSiteDescriptor#GET_PROPERTY}. Similarly, an index node with isFunction set to true will be emitted as
* {@link NashornCallSiteDescriptor#GET_METHOD_ELEMENT} while the one set to false will be emitted as {@link NashornCallSiteDescriptor#GET_ELEMENT}.
*/
public interface FunctionCall {
/**

View File

@ -39,6 +39,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
@ -48,6 +49,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader;
import jdk.internal.org.objectweb.asm.util.Printer;
import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
@ -55,6 +57,7 @@ import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
* Also supports dot formats if --print-code has arguments
*/
public final class NashornTextifier extends Printer {
private static final String BOOTSTRAP_CLASS_NAME = Bootstrap.class.getName().replace('.', '/');
private String currentClassName;
private Iterator<Label> labelIter;
@ -498,7 +501,16 @@ public final class NashornTextifier extends Printer {
final StringBuilder sb = new StringBuilder();
appendOpcode(sb, Opcodes.INVOKEDYNAMIC).append(' ');
sb.append(name);
final boolean isNashornBootstrap = isNashornBootstrap(bsm);
if (isNashornBootstrap) {
sb.append(NashornCallSiteDescriptor.getOperationName((Integer)bsmArgs[0]));
final String decodedName = NameCodec.decode(name);
if (!decodedName.isEmpty()) {
sb.append(':').append(decodedName);
}
} else {
sb.append(name);
}
appendDescriptor(sb, METHOD_DESCRIPTOR, desc);
final int len = sb.length();
for (int i = 0; i < 80 - len ; i++) {
@ -516,7 +528,7 @@ public final class NashornTextifier extends Printer {
sb.append(((Type)cst).getDescriptor()).append(".class");
} else if (cst instanceof Handle) {
appendHandle(sb, (Handle)cst);
} else if (cst instanceof Integer) {
} else if (cst instanceof Integer && isNashornBootstrap) {
final int c = (Integer)cst;
final int pp = c >> CALLSITE_PROGRAM_POINT_SHIFT;
if (pp != 0) {
@ -535,6 +547,10 @@ public final class NashornTextifier extends Printer {
addText(sb);
}
private static boolean isNashornBootstrap(final Handle bsm) {
return "bootstrap".equals(bsm.getName()) && BOOTSTRAP_CLASS_NAME.equals(bsm.getOwner());
}
private static boolean noFallThru(final int opcode) {
switch (opcode) {
case Opcodes.GOTO:

View File

@ -48,6 +48,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.ClassFilter;
@ -2148,17 +2149,17 @@ public final class Global extends Scope {
}
@Override
public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
if (lexicalScope.hasOwnProperty(name)) {
return lexicalScope.findGetMethod(desc, request, operator);
return lexicalScope.findGetMethod(desc, request, operation);
}
}
final GuardedInvocation invocation = super.findGetMethod(desc, request, operator);
final GuardedInvocation invocation = super.findGetMethod(desc, request, operation);
// We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
// because those are invalidated per-key in the addBoundProperties method above.
@ -2188,7 +2189,7 @@ public final class Global extends Scope {
final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
if (lexicalScope != null && isScope) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (lexicalScope.hasOwnProperty(name)) {
return lexicalScope.findSetMethod(desc, request);
}
@ -2725,8 +2726,8 @@ public final class Global extends Scope {
}
@Override
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
return filterInvocation(super.findGetMethod(desc, request, operator));
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
return filterInvocation(super.findGetMethod(desc, request, operation));
}
@Override

View File

@ -144,15 +144,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
setIsArray();
}
@Override
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final GuardedInvocation inv = getArray().findFastGetMethod(getArray().getClass(), desc, request, operator);
if (inv != null) {
return inv;
}
return super.findGetMethod(desc, request, operator);
}
@Override
protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
@ -187,7 +178,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class,
return Bootstrap.createDynamicCallInvoker(rtype, Object.class, Object.class, Object.class,
long.class, Object.class);
}
});
@ -218,7 +209,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class,
return Bootstrap.createDynamicCallInvoker(Object.class, Object.class,
Undefined.class, Object.class, Object.class, long.class, Object.class);
}
});
@ -229,7 +220,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", double.class,
return Bootstrap.createDynamicCallInvoker(double.class,
ScriptFunction.class, Object.class, Object.class, Object.class);
}
});

View File

@ -33,7 +33,7 @@ import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.List;
import jdk.internal.dynalink.support.Lookup;
import jdk.internal.dynalink.linker.support.Lookup;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;

View File

@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.lookup.Lookup;
@ -49,6 +50,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.scripts.JO;
/**
@ -588,7 +590,7 @@ public final class NativeJSAdapter extends ScriptObject {
@Override
protected GuardedInvocation findCallMethodMethod(final CallSiteDescriptor desc, final LinkRequest request) {
if (overrides && super.hasOwnProperty(desc.getNameToken(2))) {
if (overrides && super.hasOwnProperty(NashornCallSiteDescriptor.getOperand(desc))) {
try {
final GuardedInvocation inv = super.findCallMethodMethod(desc, request);
if (inv != null) {
@ -603,8 +605,8 @@ public final class NativeJSAdapter extends ScriptObject {
}
@Override
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operation) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (overrides && super.hasOwnProperty(name)) {
try {
final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
@ -617,10 +619,10 @@ public final class NativeJSAdapter extends ScriptObject {
}
switch(operation) {
case "getProp":
case "getElem":
case GET_PROPERTY:
case GET_ELEMENT:
return findHook(desc, __get__);
case "getMethod":
case GET_METHOD:
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
final Object value = find.getObjectValue();
@ -634,7 +636,7 @@ public final class NativeJSAdapter extends ScriptObject {
adaptee.getProtoSwitchPoints(__call__, find.getOwner()), null);
}
}
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
throw typeError("no.such.function", name, ScriptRuntime.safeToString(this));
default:
break;
}
@ -644,7 +646,7 @@ public final class NativeJSAdapter extends ScriptObject {
@Override
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
if (overrides && super.hasOwnProperty(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
if (overrides && super.hasOwnProperty(NashornCallSiteDescriptor.getOperand(desc))) {
try {
final GuardedInvocation inv = super.findSetMethod(desc, request);
if (inv != null) {
@ -691,7 +693,7 @@ public final class NativeJSAdapter extends ScriptObject {
final FindProperty findData = adaptee.findProperty(hook, true);
final MethodType type = desc.getMethodType();
if (findData != null) {
final String name = desc.getNameTokenCount() > 2 ? desc.getNameToken(2) : null;
final String name = NashornCallSiteDescriptor.getOperand(desc);
final Object value = findData.getObjectValue();
if (value instanceof ScriptFunction) {
final ScriptFunction func = (ScriptFunction)value;
@ -709,7 +711,7 @@ public final class NativeJSAdapter extends ScriptObject {
switch (hook) {
case __call__:
throw typeError("no.such.function", desc.getNameToken(2), ScriptRuntime.safeToString(this));
throw typeError("no.such.function", NashornCallSiteDescriptor.getOperand(desc), ScriptRuntime.safeToString(this));
default:
final MethodHandle methodHandle = hook.equals(__put__) ?
MH.asType(Lookup.EMPTY_SETTER, type) :

View File

@ -76,7 +76,7 @@ public final class NativeJSON extends ScriptObject {
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
return Bootstrap.createDynamicCallInvoker(Object.class,
ScriptFunction.class, ScriptObject.class, Object.class, Object.class);
}
});

View File

@ -39,7 +39,7 @@ import java.util.Map;
import java.util.Queue;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.objects.annotations.Attribute;

View File

@ -43,6 +43,7 @@ import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* This is "JavaImporter" constructor. This constructor allows you to use Java types omitting explicit package names.
@ -143,7 +144,7 @@ public final class NativeJavaImporter extends ScriptObject {
}
private boolean createAndSetProperty(final CallSiteDescriptor desc) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
final Object value = createProperty(name);
if(value != null) {
set(name, value, 0);

View File

@ -39,13 +39,16 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.Operation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.LinkRequestImpl;
import jdk.internal.dynalink.linker.support.SimpleLinkRequest;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.annotations.Attribute;
@ -64,6 +67,7 @@ import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
import jdk.nashorn.internal.runtime.linker.NashornBeansLinker;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* ECMA 15.2 Object objects
@ -694,10 +698,7 @@ public final class NativeObject {
// make accessor properties using dynamic invoker getters and setters
final AccessorProperty[] props = new AccessorProperty[keys.length];
for (int idx = 0; idx < keys.length; idx++) {
final String name = keys[idx];
final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE);
final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE);
props[idx] = AccessorProperty.create(name, 0, getter, setter);
props[idx] = createAccessorProperty(keys[idx]);
}
targetObj.addBoundProperties(source, props);
@ -716,6 +717,12 @@ public final class NativeObject {
return target;
}
private static AccessorProperty createAccessorProperty(final String name) {
final MethodHandle getter = Bootstrap.createDynamicInvoker(name, NashornCallSiteDescriptor.GET_METHOD_PROPERTY, MIRROR_GETTER_TYPE);
final MethodHandle setter = Bootstrap.createDynamicInvoker(name, NashornCallSiteDescriptor.SET_PROPERTY, MIRROR_SETTER_TYPE);
return AccessorProperty.create(name, 0, getter, setter);
}
/**
* Binds the source mirror object's properties to the target object. Binding
* properties allows two-way read/write for the properties of the source object.
@ -732,9 +739,7 @@ public final class NativeObject {
final AccessorProperty[] props = new AccessorProperty[keys.size()];
int idx = 0;
for (final String name : keys) {
final MethodHandle getter = Bootstrap.createDynamicInvoker("dyn:getMethod|getProp|getElem:" + name, MIRROR_GETTER_TYPE);
final MethodHandle setter = Bootstrap.createDynamicInvoker("dyn:setProp|setElem:" + name, MIRROR_SETTER_TYPE);
props[idx] = AccessorProperty.create(name, 0, getter, setter);
props[idx] = createAccessorProperty(name);
idx++;
}
@ -759,7 +764,7 @@ public final class NativeObject {
for(final String methodName: methodNames) {
final MethodHandle method;
try {
method = getBeanOperation(linker, "dyn:getMethod:" + methodName, getterType, source);
method = getBeanOperation(linker, StandardOperation.GET_METHOD, methodName, getterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
continue;
@ -771,7 +776,7 @@ public final class NativeObject {
MethodHandle getter;
if(readablePropertyNames.contains(propertyName)) {
try {
getter = getBeanOperation(linker, "dyn:getProp:" + propertyName, getterType, source);
getter = getBeanOperation(linker, StandardOperation.GET_PROPERTY, propertyName, getterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
getter = Lookup.EMPTY_GETTER;
@ -783,7 +788,7 @@ public final class NativeObject {
MethodHandle setter;
if(isWritable) {
try {
setter = getBeanOperation(linker, "dyn:setProp:" + propertyName, setterType, source);
setter = getBeanOperation(linker, StandardOperation.SET_PROPERTY, propertyName, setterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
setter = Lookup.EMPTY_SETTER;
@ -801,7 +806,7 @@ public final class NativeObject {
private static MethodHandle getBoundBeanMethodGetter(final Object source, final MethodHandle methodGetter) {
try {
// NOTE: we're relying on the fact that "dyn:getMethod:..." return value is constant for any given method
// NOTE: we're relying on the fact that StandardOperation.GET_METHOD return value is constant for any given method
// name and object linked with BeansLinker. (Actually, an even stronger assumption is true: return value is
// constant for any given method name and object's class.)
return MethodHandles.dropArguments(MethodHandles.constant(Object.class,
@ -813,11 +818,11 @@ public final class NativeObject {
}
}
private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final String operation,
final MethodType methodType, final Object source) {
private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final StandardOperation operation,
final String name, final MethodType methodType, final Object source) {
final GuardedInvocation inv;
try {
inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation, methodType, source), Bootstrap.getLinkerServices());
inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(new NamedOperation(operation, name), methodType, source), Bootstrap.getLinkerServices());
assert passesGuard(source, inv.getGuard());
} catch(RuntimeException|Error e) {
throw e;
@ -833,9 +838,9 @@ public final class NativeObject {
return guard == null || (boolean)guard.invoke(obj);
}
private static LinkRequest createLinkRequest(final String operation, final MethodType methodType, final Object source) {
return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
methodType), null, 0, false, source);
private static LinkRequest createLinkRequest(final Operation operation, final MethodType methodType, final Object source) {
return new SimpleLinkRequest(new CallSiteDescriptor(MethodHandles.publicLookup(), operation,
methodType), false, source);
}
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {

View File

@ -33,7 +33,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@ -808,7 +807,7 @@ public final class NativeRegExp extends ScriptObject {
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", String.class, ScriptFunction.class, Object.class, Object[].class);
return Bootstrap.createDynamicCallInvoker(String.class, ScriptFunction.class, Object.class, Object[].class);
}
});
}

View File

@ -41,6 +41,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Set;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException;
@ -60,6 +61,7 @@ import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
@ -138,15 +140,15 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
// This is to support length as method call as well.
@Override
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final String name = desc.getNameToken(2);
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
// if str.length(), then let the bean linker handle it
if ("length".equals(name) && "getMethod".equals(operator)) {
if ("length".equals(name) && operation == StandardOperation.GET_METHOD) {
return null;
}
return super.findGetMethod(desc, request, operator);
return super.findGetMethod(desc, request, operation);
}
// This is to provide array-like access to string characters without creating a NativeString wrapper.

View File

@ -0,0 +1,77 @@
/*
* 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.
*/
package jdk.nashorn.internal.runtime;
import java.security.AccessControlContext;
import java.security.Permission;
import java.security.Permissions;
import java.security.ProtectionDomain;
import java.util.stream.Stream;
/**
* Utility class for creating permission-restricting {@link AccessControlContext}s.
*/
public final class AccessControlContextFactory {
private AccessControlContextFactory () {
}
/**
* Creates an access control context with no permissions.
* @return an access control context with no permissions.
*/
public static AccessControlContext createAccessControlContext() {
return createAccessControlContext(new Permission[0]);
}
/**
* Creates an access control context limited to only the specified permissions.
* @param permissions the permissions for the newly created access control context.
* @return a new access control context limited to only the specified permissions.
*/
public static AccessControlContext createAccessControlContext(final Permission... permissions) {
final Permissions perms = new Permissions();
for(final Permission permission: permissions) {
perms.add(permission);
}
return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) });
}
/**
* Creates an access control context limited to only the {@link RuntimePermission}s
* of the given names.
* @param runtimePermissionNames the names of runtime permissions for the
* newly created access control context.
* @return a new access control context limited to only the runtime
* permissions with the specified names.
*/
public static AccessControlContext createAccessControlContext(final String... runtimePermissionNames) {
return createAccessControlContext(makeRuntimePermissions(runtimePermissionNames));
}
private static Permission[] makeRuntimePermissions(final String... runtimePermissionNames) {
return Stream.of(runtimePermissionNames).map(RuntimePermission::new).toArray(Permission[]::new);
}
}

View File

@ -357,7 +357,7 @@ public final class GlobalConstants implements Loggable {
return null;
}
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
synchronized (this) {
final Access acc = getOrCreateSwitchPoint(name);
@ -432,7 +432,7 @@ public final class GlobalConstants implements Loggable {
final boolean isOptimistic = NashornCallSiteDescriptor.isOptimistic(desc);
final int programPoint = isOptimistic ? getProgramPoint(desc) : INVALID_PROGRAM_POINT;
final Class<?> retType = desc.getMethodType().returnType();
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
synchronized (this) {
final Access acc = getOrCreateSwitchPoint(name);

View File

@ -45,7 +45,7 @@ public final class JSONFunctions {
new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
return Bootstrap.createDynamicCallInvoker(Object.class,
ScriptFunction.class, ScriptObject.class, String.class, Object.class);
}
});

View File

@ -400,7 +400,7 @@ public class ListAdapter extends AbstractList<Object> implements RandomAccess, D
return new Callable<MethodHandle>() {
@Override
public MethodHandle call() {
return Bootstrap.createDynamicInvoker("dyn:call", rtype, ptypes);
return Bootstrap.createDynamicCallInvoker(rtype, ptypes);
}
};
}

View File

@ -36,11 +36,12 @@ import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* An object that exposes Java packages and classes as its properties. Packages are exposed as objects that have further
@ -200,7 +201,7 @@ public final class NativeJavaPackage extends ScriptObject {
*/
@Override
public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
final String propertyName = desc.getNameToken(2);
final String propertyName = NashornCallSiteDescriptor.getOperand(desc);
createProperty(propertyName);
return super.lookup(desc, request);
}

View File

@ -34,7 +34,7 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;

View File

@ -31,8 +31,12 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -43,7 +47,7 @@ import java.util.concurrent.atomic.LongAdder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@ -123,6 +127,9 @@ public class ScriptFunction extends ScriptObject {
// Marker object for lazily initialized prototype object
private static final Object LAZY_PROTOTYPE = new Object();
private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
private static PropertyMap createStrictModeMap(final PropertyMap map) {
final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
PropertyMap newMap = map;
@ -806,7 +813,7 @@ public class ScriptFunction extends ScriptObject {
}
/**
* dyn:call call site signature: (callee, thiz, [args...]) generated method
* StandardOperation.CALL call site signature: (callee, thiz, [args...]) generated method
* signature: (callee, thiz, [args...])
*
* cases:
@ -914,7 +921,7 @@ public class ScriptFunction extends ScriptObject {
} else if (data.isBuiltin() && "extend".equals(data.getName())) {
// NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
// current lookup as its "this" so it can do security-sensitive creation of adapter classes.
boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc.getLookup()), 0, type.parameterType(0), type.parameterType(1));
boundHandle = MH.dropArguments(MH.bindTo(callHandle, getLookupPrivileged(desc)), 0, type.parameterType(0), type.parameterType(1));
} else if (scopeCall && needsWrappedThis()) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (this, args...) => ([this], args...)
@ -955,6 +962,12 @@ public class ScriptFunction extends ScriptObject {
exceptionGuard);
}
private static Lookup getLookupPrivileged(final CallSiteDescriptor desc) {
// NOTE: we'd rather not make NashornCallSiteDescriptor.getLookupPrivileged public.
return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->desc.getLookup(),
GET_LOOKUP_PERMISSION_CONTEXT);
}
private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
final MethodType descType = desc.getMethodType();
final int paramCount = descType.parameterCount();

View File

@ -66,9 +66,10 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.LongAdder;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
@ -1836,32 +1837,35 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @return GuardedInvocation for the callsite
*/
public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
final int c = desc.getNameTokenCount();
// JavaScript is "immune" to all currently defined Dynalink composite operation - getProp is the same as getElem
// is the same as getMethod as JavaScript objects have a single namespace for all three. Therefore, we don't
// care about them, and just link to whatever is the first operation.
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
// NOTE: we support getElem and setItem as JavaScript doesn't distinguish items from properties. Nashorn itself
// emits "dyn:getProp:identifier" for "<expr>.<identifier>" and "dyn:getElem" for "<expr>[<expr>]", but we are
// NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
// emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
// more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
// operation has an associated name or not.
switch (operator) {
case "getProp":
case "getElem":
case "getMethod":
return c > 2 ? findGetMethod(desc, request, operator) : findGetIndexMethod(desc, request);
case "setProp":
case "setElem":
return c > 2 ? findSetMethod(desc, request) : findSetIndexMethod(desc, request);
case "call":
return findCallMethod(desc, request);
case "new":
return findNewMethod(desc, request);
case "callMethod":
return findCallMethodMethod(desc, request);
default:
final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
if (op == null) {
return null;
}
switch (op) {
case GET_PROPERTY:
case GET_ELEMENT:
case GET_METHOD:
return desc.getOperation() instanceof NamedOperation
? findGetMethod(desc, request, op)
: findGetIndexMethod(desc, request);
case SET_PROPERTY:
case SET_ELEMENT:
return desc.getOperation() instanceof NamedOperation
? findSetMethod(desc, request)
: findSetIndexMethod(desc, request);
case CALL:
return findCallMethod(desc, request);
case NEW:
return findNewMethod(desc, request);
case CALL_METHOD:
return findCallMethodMethod(desc, request);
default:
}
return null;
}
/**
@ -1894,10 +1898,10 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
/**
* Find an implementation for a "dyn:callMethod" operation. Note that Nashorn internally never uses
* "dyn:callMethod", but instead always emits two call sites in bytecode, one for "dyn:getMethod", and then another
* one for "dyn:call". Explicit support for "dyn:callMethod" is provided for the benefit of potential external
* callers. The implementation itself actually folds a "dyn:getMethod" method handle into a "dyn:call" method handle.
* Find an implementation for a CALL_METHOD operation. Note that Nashorn internally never uses
* CALL_METHOD, but instead always emits two call sites in bytecode, one for GET_METHOD, and then another
* one for CALL. Explicit support for CALL_METHOD is provided for the benefit of potential external
* callers. The implementation itself actually folds a GET_METHOD method handle into a CALL method handle.
*
* @param desc the call site descriptor.
* @param request the link request
@ -1909,12 +1913,12 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
final MethodType callType = desc.getMethodType();
// use type Object(P0) for the getter
final CallSiteDescriptor getterType = desc.changeMethodType(MethodType.methodType(Object.class, callType.parameterType(0)));
final GuardedInvocation getter = findGetMethod(getterType, request, "getMethod");
final GuardedInvocation getter = findGetMethod(getterType, request, StandardOperation.GET_METHOD);
// Object(P0) => Object(P0, P1, ...)
final MethodHandle argDroppingGetter = MH.dropArguments(getter.getInvocation(), 1, callType.parameterList().subList(1, callType.parameterCount()));
// R(Object, P0, P1, ...)
final MethodHandle invoker = Bootstrap.createDynamicInvoker("dyn:call", callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
final MethodHandle invoker = Bootstrap.createDynamicInvoker("", NashornCallSiteDescriptor.CALL, callType.insertParameterTypes(0, argDroppingGetter.type().returnType()));
// Fold Object(P0, P1, ...) into R(Object, P0, P1, ...) => R(P0, P1, ...)
return getter.replaceMethods(MH.foldArguments(invoker, argDroppingGetter), getter.getGuard());
}
@ -1955,15 +1959,14 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
*
* @param desc the call site descriptor
* @param request the link request
* @param operator operator for get: getProp, getMethod, getElem etc
* @param operation operation for get: getProp, getMethod, getElem etc
*
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
String name;
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
String name = NashornCallSiteDescriptor.getOperand(desc);
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
if (Global.isBuiltinFunctionPrototypeApply()) {
name = "call";
@ -1971,21 +1974,21 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
return findMegaMorphicGetMethod(desc, name, operation == StandardOperation.GET_METHOD);
}
final FindProperty find = findProperty(name, true);
MethodHandle mh;
if (find == null) {
switch (operator) {
case "getElem": // getElem only gets here if element name is constant, so treat it like a property access
case "getProp":
switch (operation) {
case GET_ELEMENT: // getElem only gets here if element name is constant, so treat it like a property access
case GET_PROPERTY:
return noSuchProperty(desc, request);
case "getMethod":
case GET_METHOD:
return noSuchMethod(desc, request);
default:
throw new AssertionError(operator); // never invoked with any other operation
throw new AssertionError(operation); // never invoked with any other operation
}
}
@ -2163,7 +2166,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicSetMethod(desc, name);
@ -2225,7 +2228,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (NashornCallSiteDescriptor.isStrict(desc)) {
throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString(this));
}
@ -2307,7 +2310,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @return GuardedInvocation to be invoked at call site.
*/
public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(2);
final String name = NashornCallSiteDescriptor.getOperand(desc);
final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true);
final boolean scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc);
@ -2345,7 +2348,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @return GuardedInvocation to be invoked at call site.
*/
public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
@ -2685,7 +2688,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @param newLength new length to set
*/
public final void setLength(final long newLength) {
ArrayData data = getArray();
final ArrayData data = getArray();
final long arrayLength = data.length();
if (newLength == arrayLength) {
return;

View File

@ -380,8 +380,8 @@ public final class ScriptRuntime {
/**
* Call a function given self and args. If the number of the arguments is known in advance, you can likely achieve
* better performance by {@link Bootstrap#createDynamicInvoker(String, Class, Class...) creating a dynamic invoker}
* for operation {@code "dyn:call"}, then using its {@link MethodHandle#invokeExact(Object...)} method instead.
* better performance by creating a dynamic invoker using {@link Bootstrap#createDynamicCallInvoker(Class, Class...)}
* then using its {@link MethodHandle#invokeExact(Object...)} method instead.
*
* @param target ScriptFunction object.
* @param self Receiver in call.

View File

@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
@ -69,7 +70,7 @@ final class SetMethodCreator {
}
private String getName() {
return desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
return NashornCallSiteDescriptor.getOperand(desc);
}
private PropertyMap getMap() {
@ -196,7 +197,7 @@ final class SetMethodCreator {
final PropertyMap oldMap = getMap();
final PropertyMap newMap = getNewMap(property);
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final String name = NashornCallSiteDescriptor.getOperand(desc);
//fast type specific setter
final MethodHandle fastSetter = property.getSetter(type, newMap); //0 sobj, 1 value, slot folded for spill property already

View File

@ -31,9 +31,10 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.internal.dynalink.linker.support.Guards;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
@ -92,44 +93,39 @@ public final class Undefined extends DefaultPropertyAccess {
* @return GuardedInvocation to be invoked at call site.
*/
public static GuardedInvocation lookup(final CallSiteDescriptor desc) {
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
switch (operator) {
case "new":
case "call": {
final String name = NashornCallSiteDescriptor.getFunctionDescription(desc);
final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
switch (op) {
case CALL:
case NEW:
final String name = NashornCallSiteDescriptor.getOperand(desc);
final String msg = name != null? "not.a.function" : "cant.call.undefined";
throw typeError(msg, name);
}
case "callMethod":
case CALL_METHOD:
throw lookupTypeError("cant.read.property.of.undefined", desc);
// NOTE: we support getElem and setItem as JavaScript doesn't distinguish items from properties. Nashorn itself
// emits "dyn:getProp:identifier" for "<expr>.<identifier>" and "dyn:getElem" for "<expr>[<expr>]", but we are
// more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
// operation has an associated name or not.
case "getProp":
case "getElem":
case "getMethod":
if (desc.getNameTokenCount() < 3) {
case GET_PROPERTY:
case GET_ELEMENT:
case GET_METHOD:
// NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
// emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
// more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
// operation has an associated name or not.
if (!(desc.getOperation() instanceof NamedOperation)) {
return findGetIndexMethod(desc);
}
return findGetMethod(desc);
case "setProp":
case "setElem":
if (desc.getNameTokenCount() < 3) {
case SET_PROPERTY:
case SET_ELEMENT:
if (!(desc.getOperation() instanceof NamedOperation)) {
return findSetIndexMethod(desc);
}
return findSetMethod(desc);
default:
break;
}
return null;
}
private static ECMAException lookupTypeError(final String msg, final CallSiteDescriptor desc) {
final String name = desc.getNameToken(2);
final String name = NashornCallSiteDescriptor.getOperand(desc);
return typeError(msg, name != null && !name.isEmpty()? name : null);
}
@ -137,7 +133,7 @@ public final class Undefined extends DefaultPropertyAccess {
private static final MethodHandle SET_METHOD = MH.insertArguments(findOwnMH("set", void.class, Object.class, Object.class, int.class), 3, NashornCallSiteDescriptor.CALLSITE_STRICT);
private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) {
return new GuardedInvocation(MH.insertArguments(GET_METHOD, 1, desc.getNameToken(2)), UNDEFINED_GUARD).asType(desc);
return new GuardedInvocation(MH.insertArguments(GET_METHOD, 1, NashornCallSiteDescriptor.getOperand(desc)), UNDEFINED_GUARD).asType(desc);
}
private static GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc) {
@ -145,7 +141,7 @@ public final class Undefined extends DefaultPropertyAccess {
}
private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc) {
return new GuardedInvocation(MH.insertArguments(SET_METHOD, 1, desc.getNameToken(2)), UNDEFINED_GUARD).asType(desc);
return new GuardedInvocation(MH.insertArguments(SET_METHOD, 1, NashornCallSiteDescriptor.getOperand(desc)), UNDEFINED_GUARD).asType(desc);
}
private static GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc) {

View File

@ -92,10 +92,10 @@ public final class UserAccessorProperty extends SpillProperty {
static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) {
if (UnwarrantedOptimismException.isValid(programPoint)) {
final int flags = NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT;
return Bootstrap.createDynamicInvoker("dyn:call", flags, returnType, Object.class, Object.class);
final int flags = NashornCallSiteDescriptor.CALL | NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT;
return Bootstrap.createDynamicInvoker("", flags, returnType, Object.class, Object.class);
} else {
return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class);
return Bootstrap.createDynamicCallInvoker(Object.class, Object.class, Object.class);
}
}
@ -110,7 +110,7 @@ public final class UserAccessorProperty extends SpillProperty {
}
static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) {
return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType);
return Bootstrap.createDynamicCallInvoker(void.class, Object.class, Object.class, valueType);
}
/**
@ -295,7 +295,7 @@ public final class UserAccessorProperty extends SpillProperty {
return super.getGetter(Object.class).asType(MethodType.methodType(Accessors.class, Object.class));
}
// User defined getter and setter are always called by "dyn:call". Note that the user
// User defined getter and setter are always called by StandardOperation.CALL. Note that the user
// getter/setter may be inherited. If so, proto is bound during lookup. In either
// inherited or self case, slot is also bound during lookup. Actual ScriptFunction
// to be called is retrieved everytime and applied.

View File

@ -33,9 +33,11 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.NamedOperation;
import jdk.internal.dynalink.Operation;
import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@ -103,9 +105,10 @@ public final class WithObject extends Scope {
final boolean isNamedOperation;
final String name;
if (desc.getNameTokenCount() > 2) {
final Operation op = desc.getOperation();
if (op instanceof NamedOperation) {
isNamedOperation = true;
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
name = ((NamedOperation)op).getName().toString();
} else {
isNamedOperation = false;
name = null;
@ -137,16 +140,13 @@ public final class WithObject extends Scope {
if (self != null) {
final String fallBack;
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
switch (operator) {
case "callMethod":
throw new AssertionError(); // Nashorn never emits callMethod
case "getMethod":
final StandardOperation firstOp = ndesc.getFirstOperation();
switch (firstOp) {
case GET_METHOD:
fallBack = NO_SUCH_METHOD_NAME;
break;
case "getProp":
case "getElem":
case GET_PROPERTY:
case GET_ELEMENT:
fallBack = NO_SUCH_PROPERTY_NAME;
break;
default:
@ -157,12 +157,12 @@ public final class WithObject extends Scope {
if (fallBack != null) {
find = self.findProperty(fallBack, true);
if (find != null) {
switch (operator) {
case "getMethod":
switch (firstOp) {
case GET_METHOD:
link = self.noSuchMethod(desc, request);
break;
case "getProp":
case "getElem":
case GET_PROPERTY:
case GET_ELEMENT:
link = self.noSuchProperty(desc, request);
break;
default:
@ -211,7 +211,7 @@ public final class WithObject extends Scope {
@Override
protected Object invokeNoSuchProperty(final String name, final boolean isScope, final int programPoint) {
FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
final FindProperty find = expression.findProperty(NO_SUCH_PROPERTY_NAME, true);
if (find != null) {
final Object func = find.getObjectValue();
if (func instanceof ScriptFunction) {
@ -263,7 +263,7 @@ public final class WithObject extends Scope {
private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
// If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
// expression.
if (!"getMethod".equals(desc.getFirstOperator())) {
if (desc.getFirstOperation() != StandardOperation.GET_METHOD) {
return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
}

View File

@ -910,19 +910,6 @@ public abstract class ArrayData {
return null;
}
/**
* Find a fast property getter if one exists
*
* @param clazz array data class
* @param desc callsite descriptor
* @param request link request
* @param operator operator
* @return fast property getter if one is found
*/
public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
return null;
}
/**
* Find a fast element getter if one exists
*

View File

@ -29,10 +29,10 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import jdk.internal.dynalink.support.TypeUtilities;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import jdk.internal.dynalink.linker.support.TypeUtilities;
/**
* Implementation of {@link ArrayData} as soon as a double has been

View File

@ -37,14 +37,15 @@ import java.lang.invoke.MethodType;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.GuardedInvocationFilter;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardedInvocationTransformer;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.internal.dynalink.linker.support.TypeUtilities;
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
@ -102,7 +103,7 @@ public final class Bootstrap {
new ReflectionCheckLinker());
factory.setFallbackLinkers(nashornBeansLinker, new NashornBottomLinker());
factory.setSyncOnRelink(true);
factory.setPrelinkFilter(new GuardedInvocationFilter() {
factory.setPrelinkTransformer(new GuardedInvocationTransformer() {
@Override
public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
@ -260,130 +261,156 @@ public final class Bootstrap {
}
/**
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. You can use this method to
* create a method handle that when invoked acts completely as if it were a Nashorn-linked call site. An overview of
* available dynamic operations can be found in the
* <a href="https://github.com/szegedi/dynalink/wiki/User-Guide-0.6">Dynalink User Guide</a>, but we'll show few
* examples here:
* Returns a dynamic invoker for a specified dynamic operation using the
* public lookup. You can use this method to create a method handle that
* when invoked acts completely as if it were a Nashorn-linked call site.
* Note that the available operations are encoded in the flags, see
* {@link NashornCallSiteDescriptor} operation constants. If the operation
* takes a name, it should be set otherwise empty name (not null) should be
* used. All names (including the empty one) should be encoded using
* {@link NameCodec#encode(String)}. Few examples:
* <ul>
* <li>Get a named property with fixed name:
* <pre>
* MethodHandle getColor = Boostrap.createDynamicInvoker("dyn:getProp:color", Object.class, Object.class);
* MethodHandle getColor = Boostrap.createDynamicInvoker(
* "color",
* NashornCallSiteDescriptor.GET_PROPERTY,
* Object.class, Object.class);
* Object obj = ...; // somehow obtain the object
* Object color = getColor.invokeExact(obj);
* </pre>
* </li>
* <li>Get a named property with variable name:
* <pre>
* MethodHandle getProperty = Boostrap.createDynamicInvoker("dyn:getElem", Object.class, Object.class, String.class);
* MethodHandle getProperty = Boostrap.createDynamicInvoker(
* NameCodec.encode(""),
* NashornCallSiteDescriptor.GET_PROPERTY,
* Object.class, Object.class, String.class);
* Object obj = ...; // somehow obtain the object
* Object color = getProperty.invokeExact(obj, "color");
* Object shape = getProperty.invokeExact(obj, "shape");
* MethodHandle getNumProperty = Boostrap.createDynamicInvoker("dyn:getElem", Object.class, Object.class, int.class);
*
* MethodHandle getNumProperty = Boostrap.createDynamicInvoker(
* NameCodec.encode(""),
* NashornCallSiteDescriptor.GET_ELEMENT,
* Object.class, Object.class, int.class);
* Object elem42 = getNumProperty.invokeExact(obj, 42);
* </pre>
* </li>
* <li>Set a named property with fixed name:
* <pre>
* MethodHandle setColor = Boostrap.createDynamicInvoker("dyn:setProp:color", void.class, Object.class, Object.class);
* MethodHandle setColor = Boostrap.createDynamicInvoker(
* "color",
* NashornCallSiteDescriptor.SET_PROPERTY,
* void.class, Object.class, Object.class);
* Object obj = ...; // somehow obtain the object
* setColor.invokeExact(obj, Color.BLUE);
* </pre>
* </li>
* <li>Set a property with variable name:
* <pre>
* MethodHandle setProperty = Boostrap.createDynamicInvoker("dyn:setElem", void.class, Object.class, String.class, Object.class);
* MethodHandle setProperty = Boostrap.createDynamicInvoker(
* NameCodec.encode(""),
* NashornCallSiteDescriptor.SET_PROPERTY,
* void.class, Object.class, String.class, Object.class);
* Object obj = ...; // somehow obtain the object
* setProperty.invokeExact(obj, "color", Color.BLUE);
* setProperty.invokeExact(obj, "shape", Shape.CIRCLE);
* </pre>
* </li>
* <li>Call a function on an object; two-step variant. This is the actual variant used by Nashorn-generated code:
* <li>Call a function on an object; note it's a two-step process: get the
* method, then invoke the method. This is the actual:
* <pre>
* MethodHandle findFooFunction = Boostrap.createDynamicInvoker("dyn:getMethod:foo", Object.class, Object.class);
* MethodHandle findFooFunction = Boostrap.createDynamicInvoker(
* "foo",
* NashornCallSiteDescriptor.GET_METHOD,
* Object.class, Object.class);
* Object obj = ...; // somehow obtain the object
* Object foo_fn = findFooFunction.invokeExact(obj);
* MethodHandle callFunctionWithTwoArgs = Boostrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class, Object.class, Object.class);
* MethodHandle callFunctionWithTwoArgs = Boostrap.createDynamicCallInvoker(
* Object.class, Object.class, Object.class, Object.class, Object.class);
* // Note: "call" operation takes a function, then a "this" value, then the arguments:
* Object foo_retval = callFunctionWithTwoArgs.invokeExact(foo_fn, obj, arg1, arg2);
* </pre>
* </li>
* <li>Call a function on an object; single-step variant. Although Nashorn doesn't use this variant and never
* emits any INVOKEDYNAMIC instructions with {@code dyn:getMethod}, it still supports this standard Dynalink
* operation:
* <pre>
* MethodHandle callFunctionFooWithTwoArgs = Boostrap.createDynamicInvoker("dyn:callMethod:foo", Object.class, Object.class, Object.class, Object.class);
* Object obj = ...; // somehow obtain the object
* Object foo_retval = callFunctionFooWithTwoArgs.invokeExact(obj, arg1, arg2);
* </pre>
* </li>
* </ul>
* Few additional remarks:
* <ul>
* <li>Just as Nashorn works with any Java object, the invokers returned from this method can also be applied to
* arbitrary Java objects in addition to Nashorn JavaScript objects.</li>
* <li>For invoking a named function on an object, you can also use the {@link InvokeByName} convenience class.</li>
* <li>For Nashorn objects {@code getElem}, {@code getProp}, and {@code getMethod} are handled almost identically,
* since JavaScript doesn't distinguish between different kinds of properties on an object. Either can be used with
* fixed property name or a variable property name. The only significant difference is handling of missing
* properties: {@code getMethod} for a missing member will link to a potential invocation of
* {@code __noSuchMethod__} on the object, {@code getProp} for a missing member will link to a potential invocation
* of {@code __noSuchProperty__}, while {@code getElem} for a missing member will link to an empty getter.</li>
* <li>In similar vein, {@code setElem} and {@code setProp} are handled identically on Nashorn objects.</li>
* <li>There's no rule that the variable property identifier has to be a {@code String} for {@code getProp/setProp}
* and {@code int} for {@code getElem/setElem}. You can declare their type to be {@code int}, {@code double},
* {@code Object}, and so on regardless of the kind of the operation.</li>
* <li>You can be as specific in parameter types as you want. E.g. if you know that the receiver of the operation
* will always be {@code ScriptObject}, you can pass {@code ScriptObject.class} as its parameter type. If you happen
* to link to a method that expects different types, (you can use these invokers on POJOs too, after all, and end up
* linking with their methods that have strongly-typed signatures), all necessary conversions allowed by either Java
* or JavaScript will be applied: if invoked methods specify either primitive or wrapped Java numeric types, or
* {@code String} or {@code boolean/Boolean}, then the parameters might be subjected to standard ECMAScript
* {@code ToNumber}, {@code ToString}, and {@code ToBoolean} conversion, respectively. Less obviously, if the
* expected parameter type is a SAM type, and you pass a JavaScript function, a proxy object implementing the SAM
* type and delegating to the function will be passed. Linkage can often be optimized when linkers have more
* specific type information than "everything can be an object".</li>
* <li>You can also be as specific in return types as you want. For return types any necessary type conversion
* available in either Java or JavaScript will be automatically applied, similar to the process described for
* parameters, only in reverse direction: if you specify any either primitive or wrapped Java numeric type, or
* {@code String} or {@code boolean/Boolean}, then the return values will be subjected to standard ECMAScript
* {@code ToNumber}, {@code ToString}, and {@code ToBoolean} conversion, respectively. Less obviously, if the return
* type is a SAM type, and the return value is a JavaScript function, a proxy object implementing the SAM type and
* delegating to the function will be returned.</li>
* <li>Just as Nashorn works with any Java object, the invokers returned
* from this method can also be applied to arbitrary Java objects in
* addition to Nashorn JavaScript objects.</li>
* <li>For invoking a named function on an object, you can also use the
* {@link InvokeByName} convenience class.</li>
* <li>There's no rule that the variable property identifier has to be a
* {@code String} for {@code GET_PROPERTY/SET_PROPERTY} and {@code int} for
* {@code GET_ELEMENT/SET_ELEMENT}. You can declare their type to be
* {@code int}, {@code double}, {@code Object}, and so on regardless of the
* kind of the operation.</li>
* <li>You can be as specific in parameter types as you want. E.g. if you
* know that the receiver of the operation will always be
* {@code ScriptObject}, you can pass {@code ScriptObject.class} as its
* parameter type. If you happen to link to a method that expects different
* types, (you can use these invokers on POJOs too, after all, and end up
* linking with their methods that have strongly-typed signatures), all
* necessary conversions allowed by either Java or JavaScript will be
* applied: if invoked methods specify either primitive or wrapped Java
* numeric types, or {@code String} or {@code boolean/Boolean}, then the
* parameters might be subjected to standard ECMAScript {@code ToNumber},
* {@code ToString}, and {@code ToBoolean} conversion, respectively. Less
* obviously, if the expected parameter type is a SAM type, and you pass a
* JavaScript function, a proxy object implementing the SAM type and
* delegating to the function will be passed. Linkage can often be optimized
* when linkers have more specific type information than "everything can be
* an object".</li>
* <li>You can also be as specific in return types as you want. For return
* types any necessary type conversion available in either Java or
* JavaScript will be automatically applied, similar to the process
* described for parameters, only in reverse direction: if you specify any
* either primitive or wrapped Java numeric type, or {@code String} or
* {@code boolean/Boolean}, then the return values will be subjected to
* standard ECMAScript {@code ToNumber}, {@code ToString}, and
* {@code ToBoolean} conversion, respectively. Less obviously, if the return
* type is a SAM type, and the return value is a JavaScript function, a
* proxy object implementing the SAM type and delegating to the function
* will be returned.</li>
* </ul>
* @param opDesc Dynalink dynamic operation descriptor.
* @param name name at the call site. Must not be null. Must be encoded
* using {@link NameCodec#encode(String)}. If the operation does not take a
* name, use empty string (also has to be encoded).
* @param flags the call site flags for the operation; see
* {@link NashornCallSiteDescriptor} for available flags. The most important
* part of the flags are the ones encoding the actual operation.
* @param rtype the return type for the operation
* @param ptypes the parameter types for the operation
* @return MethodHandle for invoking the operation.
*/
public static MethodHandle createDynamicInvoker(final String opDesc, final Class<?> rtype, final Class<?>... ptypes) {
return createDynamicInvoker(opDesc, MethodType.methodType(rtype, ptypes));
public static MethodHandle createDynamicInvoker(final String name, final int flags, final Class<?> rtype, final Class<?>... ptypes) {
return bootstrap(MethodHandles.publicLookup(), name, MethodType.methodType(rtype, ptypes), flags).dynamicInvoker();
}
/**
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
* {@link #createDynamicInvoker(String, Class, Class...)} but with an additional parameter to
* set the call site flags of the dynamic invoker.
* @param opDesc Dynalink dynamic operation descriptor.
* @param flags the call site flags for the operation
* Returns a dynamic invoker for the {@link NashornCallSiteDescriptor#CALL}
* operation using the public lookup.
* @param rtype the return type for the operation
* @param ptypes the parameter types for the operation
* @return MethodHandle for invoking the operation.
* @return a dynamic invoker for the {@code CALL} operation.
*/
public static MethodHandle createDynamicInvoker(final String opDesc, final int flags, final Class<?> rtype, final Class<?>... ptypes) {
return bootstrap(MethodHandles.publicLookup(), opDesc, MethodType.methodType(rtype, ptypes), flags).dynamicInvoker();
public static MethodHandle createDynamicCallInvoker(final Class<?> rtype, final Class<?>... ptypes) {
return createDynamicInvoker("", NashornCallSiteDescriptor.CALL, rtype, ptypes);
}
/**
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
* {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a
* method type in the signature. See the discussion of that method for details.
* @param opDesc Dynalink dynamic operation descriptor.
* Returns a dynamic invoker for a specified dynamic operation using the
* public lookup. Similar to
* {@link #createDynamicInvoker(String, int, Class, Class...)} but with
* already precomposed method type.
* @param name name at the call site.
* @param flags flags at the call site
* @param type the method type for the operation
* @return MethodHandle for invoking the operation.
*/
public static MethodHandle createDynamicInvoker(final String opDesc, final MethodType type) {
return bootstrap(MethodHandles.publicLookup(), opDesc, type, 0).dynamicInvoker();
public static MethodHandle createDynamicInvoker(final String name, final int flags, final MethodType type) {
return bootstrap(MethodHandles.publicLookup(), name, type, flags).dynamicInvoker();
}
/**

Some files were not shown because too many files have changed in this diff Show More