1.1 --- a/rt/emul/compact/src/main/java/java/lang/invoke/MethodHandleProxies.java Sun Aug 17 20:09:05 2014 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,321 +0,0 @@
1.4 -/*
1.5 - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 - *
1.8 - * This code is free software; you can redistribute it and/or modify it
1.9 - * under the terms of the GNU General Public License version 2 only, as
1.10 - * published by the Free Software Foundation. Oracle designates this
1.11 - * particular file as subject to the "Classpath" exception as provided
1.12 - * by Oracle in the LICENSE file that accompanied this code.
1.13 - *
1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 - * version 2 for more details (a copy is included in the LICENSE file that
1.18 - * accompanied this code).
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License version
1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 - *
1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 - * or visit www.oracle.com if you need additional information or have any
1.26 - * questions.
1.27 - */
1.28 -
1.29 -package java.lang.invoke;
1.30 -
1.31 -import java.lang.reflect.*;
1.32 -import java.security.AccessController;
1.33 -import java.security.PrivilegedAction;
1.34 -import sun.invoke.WrapperInstance;
1.35 -import java.util.ArrayList;
1.36 -//import sun.reflect.CallerSensitive;
1.37 -//import sun.reflect.Reflection;
1.38 -//import sun.reflect.misc.ReflectUtil;
1.39 -
1.40 -/**
1.41 - * This class consists exclusively of static methods that help adapt
1.42 - * method handles to other JVM types, such as interfaces.
1.43 - */
1.44 -public class MethodHandleProxies {
1.45 -
1.46 - private MethodHandleProxies() { } // do not instantiate
1.47 -
1.48 - /**
1.49 - * Produces an instance of the given single-method interface which redirects
1.50 - * its calls to the given method handle.
1.51 - * <p>
1.52 - * A single-method interface is an interface which declares a uniquely named method.
1.53 - * When determining the uniquely named method of a single-method interface,
1.54 - * the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
1.55 - * are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
1.56 - * even though it re-declares the {@code Object.equals} method.
1.57 - * <p>
1.58 - * The interface must be public. No additional access checks are performed.
1.59 - * <p>
1.60 - * The resulting instance of the required type will respond to
1.61 - * invocation of the type's uniquely named method by calling
1.62 - * the given target on the incoming arguments,
1.63 - * and returning or throwing whatever the target
1.64 - * returns or throws. The invocation will be as if by
1.65 - * {@code target.invoke}.
1.66 - * The target's type will be checked before the
1.67 - * instance is created, as if by a call to {@code asType},
1.68 - * which may result in a {@code WrongMethodTypeException}.
1.69 - * <p>
1.70 - * The uniquely named method is allowed to be multiply declared,
1.71 - * with distinct type descriptors. (E.g., it can be overloaded,
1.72 - * or can possess bridge methods.) All such declarations are
1.73 - * connected directly to the target method handle.
1.74 - * Argument and return types are adjusted by {@code asType}
1.75 - * for each individual declaration.
1.76 - * <p>
1.77 - * The wrapper instance will implement the requested interface
1.78 - * and its super-types, but no other single-method interfaces.
1.79 - * This means that the instance will not unexpectedly
1.80 - * pass an {@code instanceof} test for any unrequested type.
1.81 - * <p style="font-size:smaller;">
1.82 - * <em>Implementation Note:</em>
1.83 - * Therefore, each instance must implement a unique single-method interface.
1.84 - * Implementations may not bundle together
1.85 - * multiple single-method interfaces onto single implementation classes
1.86 - * in the style of {@link java.awt.AWTEventMulticaster}.
1.87 - * <p>
1.88 - * The method handle may throw an <em>undeclared exception</em>,
1.89 - * which means any checked exception (or other checked throwable)
1.90 - * not declared by the requested type's single abstract method.
1.91 - * If this happens, the throwable will be wrapped in an instance of
1.92 - * {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
1.93 - * and thrown in that wrapped form.
1.94 - * <p>
1.95 - * Like {@link java.lang.Integer#valueOf Integer.valueOf},
1.96 - * {@code asInterfaceInstance} is a factory method whose results are defined
1.97 - * by their behavior.
1.98 - * It is not guaranteed to return a new instance for every call.
1.99 - * <p>
1.100 - * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
1.101 - * and other corner cases, the interface may also have several abstract methods
1.102 - * with the same name but having distinct descriptors (types of returns and parameters).
1.103 - * In this case, all the methods are bound in common to the one given target.
1.104 - * The type check and effective {@code asType} conversion is applied to each
1.105 - * method type descriptor, and all abstract methods are bound to the target in common.
1.106 - * Beyond this type check, no further checks are made to determine that the
1.107 - * abstract methods are related in any way.
1.108 - * <p>
1.109 - * Future versions of this API may accept additional types,
1.110 - * such as abstract classes with single abstract methods.
1.111 - * Future versions of this API may also equip wrapper instances
1.112 - * with one or more additional public "marker" interfaces.
1.113 - * <p>
1.114 - * If a security manager is installed, this method is caller sensitive.
1.115 - * During any invocation of the target method handle via the returned wrapper,
1.116 - * the original creator of the wrapper (the caller) will be visible
1.117 - * to context checks requested by the security manager.
1.118 - *
1.119 - * @param <T> the desired type of the wrapper, a single-method interface
1.120 - * @param intfc a class object representing {@code T}
1.121 - * @param target the method handle to invoke from the wrapper
1.122 - * @return a correctly-typed wrapper for the given target
1.123 - * @throws NullPointerException if either argument is null
1.124 - * @throws IllegalArgumentException if the {@code intfc} is not a
1.125 - * valid argument to this method
1.126 - * @throws WrongMethodTypeException if the target cannot
1.127 - * be converted to the type required by the requested interface
1.128 - */
1.129 - // Other notes to implementors:
1.130 - // <p>
1.131 - // No stable mapping is promised between the single-method interface and
1.132 - // the implementation class C. Over time, several implementation
1.133 - // classes might be used for the same type.
1.134 - // <p>
1.135 - // If the implementation is able
1.136 - // to prove that a wrapper of the required type
1.137 - // has already been created for a given
1.138 - // method handle, or for another method handle with the
1.139 - // same behavior, the implementation may return that wrapper in place of
1.140 - // a new wrapper.
1.141 - // <p>
1.142 - // This method is designed to apply to common use cases
1.143 - // where a single method handle must interoperate with
1.144 - // an interface that implements a function-like
1.145 - // API. Additional variations, such as single-abstract-method classes with
1.146 - // private constructors, or interfaces with multiple but related
1.147 - // entry points, must be covered by hand-written or automatically
1.148 - // generated adapter classes.
1.149 - //
1.150 -// @CallerSensitive
1.151 - public static
1.152 - <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
1.153 - if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
1.154 - throw new IllegalArgumentException("not a public interface: "+intfc.getName());
1.155 - final MethodHandle mh;
1.156 - if (false) {//System.getSecurityManager() != null) {
1.157 -// final Class<?> caller = Reflection.getCallerClass();
1.158 -// final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
1.159 -// ReflectUtil.checkProxyPackageAccess(ccl, intfc);
1.160 -// mh = ccl != null ? bindCaller(target, caller) : target;
1.161 - } else {
1.162 - mh = target;
1.163 - }
1.164 - ClassLoader proxyLoader = intfc.getClassLoader();
1.165 - if (proxyLoader == null) {
1.166 - ClassLoader cl = Thread.currentThread().getContextClassLoader(); // avoid use of BCP
1.167 - proxyLoader = cl != null ? cl : ClassLoader.getSystemClassLoader();
1.168 - }
1.169 - final Method[] methods = getSingleNameMethods(intfc);
1.170 - if (methods == null)
1.171 - throw new IllegalArgumentException("not a single-method interface: "+intfc.getName());
1.172 - final MethodHandle[] vaTargets = new MethodHandle[methods.length];
1.173 - for (int i = 0; i < methods.length; i++) {
1.174 - Method sm = methods[i];
1.175 - MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
1.176 - MethodHandle checkTarget = mh.asType(smMT); // make throw WMT
1.177 - checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
1.178 - vaTargets[i] = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
1.179 - }
1.180 - final InvocationHandler ih = new InvocationHandler() {
1.181 - private Object getArg(String name) {
1.182 - if ((Object)name == "getWrapperInstanceTarget") return target;
1.183 - if ((Object)name == "getWrapperInstanceType") return intfc;
1.184 - throw new AssertionError();
1.185 - }
1.186 - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
1.187 - for (int i = 0; i < methods.length; i++) {
1.188 - if (method.equals(methods[i]))
1.189 - return vaTargets[i].invokeExact(args);
1.190 - }
1.191 - if (method.getDeclaringClass() == WrapperInstance.class)
1.192 - return getArg(method.getName());
1.193 - if (isObjectMethod(method))
1.194 - return callObjectMethod(proxy, method, args);
1.195 - throw new InternalError("bad proxy method: "+method);
1.196 - }
1.197 - };
1.198 -
1.199 - final Object proxy;
1.200 - if (false) { // System.getSecurityManager() != null) {
1.201 - // sun.invoke.WrapperInstance is a restricted interface not accessible
1.202 - // by any non-null class loader.
1.203 - final ClassLoader loader = proxyLoader;
1.204 - proxy = AccessController.doPrivileged(new PrivilegedAction<Object>() {
1.205 - public Object run() {
1.206 - return Proxy.newProxyInstance(
1.207 - loader,
1.208 - new Class<?>[]{ intfc, WrapperInstance.class },
1.209 - ih);
1.210 - }
1.211 - });
1.212 - } else {
1.213 - proxy = Proxy.newProxyInstance(proxyLoader,
1.214 - new Class<?>[]{ intfc, WrapperInstance.class },
1.215 - ih);
1.216 - }
1.217 - return intfc.cast(proxy);
1.218 - }
1.219 -
1.220 - private static MethodHandle bindCaller(MethodHandle target, Class<?> hostClass) {
1.221 - MethodHandle cbmh = MethodHandleImpl.bindCaller(target, hostClass);
1.222 - if (target.isVarargsCollector()) {
1.223 - MethodType type = cbmh.type();
1.224 - int arity = type.parameterCount();
1.225 - return cbmh.asVarargsCollector(type.parameterType(arity-1));
1.226 - }
1.227 - return cbmh;
1.228 - }
1.229 -
1.230 - /**
1.231 - * Determines if the given object was produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
1.232 - * @param x any reference
1.233 - * @return true if the reference is not null and points to an object produced by {@code asInterfaceInstance}
1.234 - */
1.235 - public static
1.236 - boolean isWrapperInstance(Object x) {
1.237 - return x instanceof WrapperInstance;
1.238 - }
1.239 -
1.240 - private static WrapperInstance asWrapperInstance(Object x) {
1.241 - try {
1.242 - if (x != null)
1.243 - return (WrapperInstance) x;
1.244 - } catch (ClassCastException ex) {
1.245 - }
1.246 - throw new IllegalArgumentException("not a wrapper instance");
1.247 - }
1.248 -
1.249 - /**
1.250 - * Produces or recovers a target method handle which is behaviorally
1.251 - * equivalent to the unique method of this wrapper instance.
1.252 - * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
1.253 - * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
1.254 - * @param x any reference
1.255 - * @return a method handle implementing the unique method
1.256 - * @throws IllegalArgumentException if the reference x is not to a wrapper instance
1.257 - */
1.258 - public static
1.259 - MethodHandle wrapperInstanceTarget(Object x) {
1.260 - return asWrapperInstance(x).getWrapperInstanceTarget();
1.261 - }
1.262 -
1.263 - /**
1.264 - * Recovers the unique single-method interface type for which this wrapper instance was created.
1.265 - * The object {@code x} must have been produced by a call to {@link #asInterfaceInstance asInterfaceInstance}.
1.266 - * This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
1.267 - * @param x any reference
1.268 - * @return the single-method interface type for which the wrapper was created
1.269 - * @throws IllegalArgumentException if the reference x is not to a wrapper instance
1.270 - */
1.271 - public static
1.272 - Class<?> wrapperInstanceType(Object x) {
1.273 - return asWrapperInstance(x).getWrapperInstanceType();
1.274 - }
1.275 -
1.276 - private static
1.277 - boolean isObjectMethod(Method m) {
1.278 - switch (m.getName()) {
1.279 - case "toString":
1.280 - return (m.getReturnType() == String.class
1.281 - && m.getParameterTypes().length == 0);
1.282 - case "hashCode":
1.283 - return (m.getReturnType() == int.class
1.284 - && m.getParameterTypes().length == 0);
1.285 - case "equals":
1.286 - return (m.getReturnType() == boolean.class
1.287 - && m.getParameterTypes().length == 1
1.288 - && m.getParameterTypes()[0] == Object.class);
1.289 - }
1.290 - return false;
1.291 - }
1.292 -
1.293 - private static
1.294 - Object callObjectMethod(Object self, Method m, Object[] args) {
1.295 - assert(isObjectMethod(m)) : m;
1.296 - switch (m.getName()) {
1.297 - case "toString":
1.298 - return self.getClass().getName() + "@" + Integer.toHexString(self.hashCode());
1.299 - case "hashCode":
1.300 - return System.identityHashCode(self);
1.301 - case "equals":
1.302 - return (self == args[0]);
1.303 - }
1.304 - return null;
1.305 - }
1.306 -
1.307 - private static
1.308 - Method[] getSingleNameMethods(Class<?> intfc) {
1.309 - ArrayList<Method> methods = new ArrayList<Method>();
1.310 - String uniqueName = null;
1.311 - for (Method m : intfc.getMethods()) {
1.312 - if (isObjectMethod(m)) continue;
1.313 - if (!Modifier.isAbstract(m.getModifiers())) continue;
1.314 - String mname = m.getName();
1.315 - if (uniqueName == null)
1.316 - uniqueName = mname;
1.317 - else if (!uniqueName.equals(mname))
1.318 - return null; // too many abstract methods
1.319 - methods.add(m);
1.320 - }
1.321 - if (uniqueName == null) return null;
1.322 - return methods.toArray(new Method[methods.size()]);
1.323 - }
1.324 -}