Merge
This commit is contained in:
commit
3e9bab356e
@ -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?
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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)));
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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, propertyName)→value</tt> or
|
||||
* <tt>(receiver)→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, propertyName, value)→void</tt> or
|
||||
* <tt>(receiver, value)→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, index)→value</tt> or
|
||||
* <tt>(receiver)→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, index, value)→void</tt> or
|
||||
* <tt>(receiver, value)→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)→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, methodName)→value</tt>, or
|
||||
* <tt>(receiver)→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, methodName, arguments...)→value</tt> or
|
||||
* <tt>(receiver, arguments...)→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, arguments...)→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, arguments...)→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
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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())) {
|
||||
|
@ -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()) });
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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()));
|
||||
|
@ -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;
|
@ -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>
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 – if any
|
||||
* – 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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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;
|
@ -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>
|
@ -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 {
|
@ -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 {
|
@ -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");
|
@ -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
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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;
|
@ -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;
|
@ -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>
|
@ -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());
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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;
|
@ -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>
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
/**
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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) :
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user