DefaultInternalObjectFilter.java revision 1551:f3b883bec2d0
11573Srgrimes/* 214287Spst * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 31573Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41573Srgrimes * 51573Srgrimes * This code is free software; you can redistribute it and/or modify it 61573Srgrimes * under the terms of the GNU General Public License version 2 only, as 71573Srgrimes * published by the Free Software Foundation. Oracle designates this 81573Srgrimes * particular file as subject to the "Classpath" exception as provided 91573Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101573Srgrimes * 111573Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121573Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131573Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141573Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151573Srgrimes * accompanied this code). 161573Srgrimes * 171573Srgrimes * You should have received a copy of the GNU General Public License version 181573Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191573Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201573Srgrimes * 211573Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221573Srgrimes * or visit www.oracle.com if you need additional information or have any 231573Srgrimes * questions. 241573Srgrimes */ 251573Srgrimes 261573Srgrimes/* 271573Srgrimes * This file is available under and governed by the GNU General Public 281573Srgrimes * License version 2 only, as published by the Free Software Foundation. 291573Srgrimes * However, the following notice accompanied the original version of this 301573Srgrimes * file, and Oracle licenses the original version of this file under the BSD 3114287Spst * license: 321573Srgrimes */ 3392986Sobrien/* 3492986Sobrien Copyright 2009-2015 Attila Szegedi 351573Srgrimes 361573Srgrimes Licensed under both the Apache License, Version 2.0 (the "Apache License") 371573Srgrimes and the BSD License (the "BSD License"), with licensee being free to 381573Srgrimes choose either of the two at their discretion. 391573Srgrimes 401573Srgrimes You may not use this file except in compliance with either the Apache 411573Srgrimes License or the BSD License. 421573Srgrimes 431573Srgrimes If you choose to use this file in compliance with the Apache License, the 441573Srgrimes following notice applies to you: 451573Srgrimes 461573Srgrimes You may obtain a copy of the Apache License at 471573Srgrimes 481573Srgrimes http://www.apache.org/licenses/LICENSE-2.0 491573Srgrimes 501573Srgrimes Unless required by applicable law or agreed to in writing, software 511573Srgrimes distributed under the License is distributed on an "AS IS" BASIS, 521573Srgrimes WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 531573Srgrimes implied. See the License for the specific language governing 541573Srgrimes permissions and limitations under the License. 551573Srgrimes 561573Srgrimes If you choose to use this file in compliance with the BSD License, the 571573Srgrimes following notice applies to you: 581573Srgrimes 591573Srgrimes Redistribution and use in source and binary forms, with or without 60189291Sdelphij modification, are permitted provided that the following conditions are 611573Srgrimes met: 621573Srgrimes * Redistributions of source code must retain the above copyright 6314287Spst notice, this list of conditions and the following disclaimer. 641573Srgrimes * Redistributions in binary form must reproduce the above copyright 651573Srgrimes notice, this list of conditions and the following disclaimer in the 661573Srgrimes documentation and/or other materials provided with the distribution. 671573Srgrimes * Neither the name of the copyright holder nor the names of 681573Srgrimes contributors may be used to endorse or promote products derived from 691573Srgrimes this software without specific prior written permission. 701573Srgrimes 711573Srgrimes THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 721573Srgrimes IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 731573Srgrimes TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 741573Srgrimes PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 7514287Spst BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 7614287Spst CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 7714287Spst SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 7814287Spst BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 7914287Spst WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 8014287Spst OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 8114287Spst ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 8214287Spst*/ 8314287Spst 8414287Spstpackage jdk.dynalink.linker.support; 8539327Simp 8639327Simpimport java.lang.invoke.MethodHandle; 8714287Spstimport java.lang.invoke.MethodHandles; 8814287Spstimport java.lang.invoke.MethodType; 8914287Spstimport jdk.dynalink.DynamicLinkerFactory; 9014287Spstimport jdk.dynalink.linker.MethodHandleTransformer; 9114287Spst 9214287Spst/** 9314287Spst * Default implementation for a 9414287Spst * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)} 9514287Spst * that delegates to a pair of filtering method handles. It takes a method 9614287Spst * handle of {@code Object(Object)} type for filtering parameter values and 9714287Spst * another one of the same type for filtering return values. It applies them as 9814287Spst * parameter and return value filters on method handles passed to its 9914287Spst * {@link #transform(MethodHandle)} method, on those parameters and return values 10014287Spst * that are declared to have type {@link Object}. Also handles 1011573Srgrimes * {@link MethodHandle#isVarargsCollector() method handles that support variable 1021573Srgrimes * arity calls} with a last {@code Object[]} parameter. You can broadly think of 10314287Spst * the parameter filter as being a wrapping method for exposing internal runtime 1041573Srgrimes * objects wrapped into an adapter with some public interface, and the return 10514287Spst * value filter as being its inverse unwrapping method. 1061573Srgrimes */ 1071573Srgrimespublic class DefaultInternalObjectFilter implements MethodHandleTransformer { 1081573Srgrimes private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic( 1091573Srgrimes DefaultInternalObjectFilter.class, "filterVarArgs", MethodType.methodType(Object[].class, MethodHandle.class, Object[].class)); 1101573Srgrimes 1111573Srgrimes private final MethodHandle parameterFilter; 1121573Srgrimes private final MethodHandle returnFilter; 1131573Srgrimes private final MethodHandle varArgFilter; 1141573Srgrimes 1151573Srgrimes /** 1161573Srgrimes * Creates a new filter. 1171573Srgrimes * @param parameterFilter the filter for method parameters. Must be of type 1181573Srgrimes * {@code Object(Object)}, or {@code null}. 1191573Srgrimes * @param returnFilter the filter for return values. Must be of type 1201573Srgrimes * {@code Object(Object)}, or {@code null}. 1211573Srgrimes * @throws IllegalArgumentException if one or both filters are not of the 1221573Srgrimes * expected type. 1231573Srgrimes */ 1241573Srgrimes public DefaultInternalObjectFilter(final MethodHandle parameterFilter, final MethodHandle returnFilter) { 1251573Srgrimes this.parameterFilter = checkHandle(parameterFilter, "parameterFilter"); 1261573Srgrimes this.returnFilter = checkHandle(returnFilter, "returnFilter"); 1271573Srgrimes this.varArgFilter = parameterFilter == null ? null : FILTER_VARARGS.bindTo(parameterFilter); 1281573Srgrimes } 1291573Srgrimes 1301573Srgrimes @Override 1311573Srgrimes public MethodHandle transform(final MethodHandle target) { 1321573Srgrimes assert target != null; 1331573Srgrimes MethodHandle[] filters = null; 1341573Srgrimes final MethodType type = target.type(); 1351573Srgrimes final boolean isVarArg = target.isVarargsCollector(); 1361573Srgrimes final int paramCount = type.parameterCount(); 1371573Srgrimes final MethodHandle paramsFiltered; 13814287Spst // Filter parameters 1391573Srgrimes if (parameterFilter != null) { 1401573Srgrimes int firstFilter = -1; 1411573Srgrimes // Ignore receiver, start from argument 1 14214287Spst for(int i = 1; i < paramCount; ++i) { 1431573Srgrimes final Class<?> paramType = type.parameterType(i); 1441573Srgrimes final boolean filterVarArg = isVarArg && i == paramCount - 1 && paramType == Object[].class; 1451573Srgrimes if (filterVarArg || paramType == Object.class) { 1461573Srgrimes if (filters == null) { 1471573Srgrimes firstFilter = i; 1481573Srgrimes filters = new MethodHandle[paramCount - firstFilter]; 1491573Srgrimes } 1501573Srgrimes filters[i - firstFilter] = filterVarArg ? varArgFilter : parameterFilter; 1511573Srgrimes } 1521573Srgrimes } 1531573Srgrimes paramsFiltered = filters != null ? MethodHandles.filterArguments(target, firstFilter, filters) : target; 1541573Srgrimes } else { 1551573Srgrimes paramsFiltered = target; 15614287Spst } 1571573Srgrimes // Filter return value if needed 1581573Srgrimes final MethodHandle returnFiltered = returnFilter != null && type.returnType() == Object.class ? MethodHandles.filterReturnValue(paramsFiltered, returnFilter) : paramsFiltered; 1591573Srgrimes // Preserve varargs collector state 1601573Srgrimes return isVarArg && !returnFiltered.isVarargsCollector() ? returnFiltered.asVarargsCollector(type.parameterType(paramCount - 1)) : returnFiltered; 16114287Spst 1621573Srgrimes } 1631573Srgrimes 16464381Sgreen private static MethodHandle checkHandle(final MethodHandle handle, final String handleKind) { 16564381Sgreen if (handle != null) { 16664381Sgreen final MethodType objectObjectType = MethodType.methodType(Object.class, Object.class); 16764381Sgreen if (!handle.type().equals(objectObjectType)) { 16864381Sgreen throw new IllegalArgumentException("Method type for " + handleKind + " must be " + objectObjectType); 16914287Spst } 17064381Sgreen } 17164381Sgreen return handle; 172189327Sdelphij } 17314287Spst 1741573Srgrimes @SuppressWarnings("unused") 1751573Srgrimes private static Object[] filterVarArgs(final MethodHandle parameterFilter, final Object[] args) throws Throwable { 1761573Srgrimes Object[] newArgs = null; 1771573Srgrimes for(int i = 0; i < args.length; ++i) { 1781573Srgrimes final Object arg = args[i]; 1791573Srgrimes final Object newArg = parameterFilter.invokeExact(arg); 1801573Srgrimes if (arg != newArg) { 1811573Srgrimes if (newArgs == null) { 1821573Srgrimes newArgs = args.clone(); 1831573Srgrimes } 1841573Srgrimes newArgs[i] = newArg; 1851573Srgrimes } 1861573Srgrimes } 1871573Srgrimes return newArgs == null ? args : newArgs; 1881573Srgrimes } 189189291Sdelphij} 1901573Srgrimes