Path: blob/jdk8u272-b10-aarch32-20201026/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java
48797 views
/*1* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* This file is available under and governed by the GNU General Public27* License version 2 only, as published by the Free Software Foundation.28* However, the following notice accompanied the original version of this29* file, and Oracle licenses the original version of this file under the BSD30* license:31*/32/*33Copyright 2009-2013 Attila Szegedi3435Licensed under both the Apache License, Version 2.0 (the "Apache License")36and the BSD License (the "BSD License"), with licensee being free to37choose either of the two at their discretion.3839You may not use this file except in compliance with either the Apache40License or the BSD License.4142If you choose to use this file in compliance with the Apache License, the43following notice applies to you:4445You may obtain a copy of the Apache License at4647http://www.apache.org/licenses/LICENSE-2.04849Unless required by applicable law or agreed to in writing, software50distributed under the License is distributed on an "AS IS" BASIS,51WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or52implied. See the License for the specific language governing53permissions and limitations under the License.5455If you choose to use this file in compliance with the BSD License, the56following notice applies to you:5758Redistribution and use in source and binary forms, with or without59modification, are permitted provided that the following conditions are60met:61* Redistributions of source code must retain the above copyright62notice, this list of conditions and the following disclaimer.63* Redistributions in binary form must reproduce the above copyright64notice, this list of conditions and the following disclaimer in the65documentation and/or other materials provided with the distribution.66* Neither the name of the copyright holder nor the names of67contributors may be used to endorse or promote products derived from68this software without specific prior written permission.6970THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS71IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED72TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A73PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER74BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR75CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF76SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR77BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,78WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR79OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF80ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.81*/8283package jdk.internal.dynalink.beans;8485import java.lang.invoke.MethodHandle;86import java.lang.invoke.MethodHandles;87import java.lang.invoke.MethodType;88import java.util.ArrayList;89import java.util.Iterator;90import java.util.List;91import java.util.Map;92import java.util.concurrent.ConcurrentHashMap;93import jdk.internal.dynalink.linker.LinkerServices;94import jdk.internal.dynalink.support.Lookup;95import jdk.internal.dynalink.support.TypeUtilities;9697/**98* Represents a subset of overloaded methods for a certain method name on a certain class. It can be either a fixarg or99* a vararg subset depending on the subclass. The method is for a fixed number of arguments though (as it is generated100* for a concrete call site). As such, all methods in the subset can be invoked with the specified number of arguments101* (exactly matching for fixargs, or having less than or equal fixed arguments, for varargs).102*103* @author Attila Szegedi104*/105class OverloadedMethod {106private final Map<ClassString, MethodHandle> argTypesToMethods = new ConcurrentHashMap<>();107private final OverloadedDynamicMethod parent;108private final MethodType callSiteType;109private final MethodHandle invoker;110private final LinkerServices linkerServices;111private final ArrayList<MethodHandle> fixArgMethods;112private final ArrayList<MethodHandle> varArgMethods;113114OverloadedMethod(final List<MethodHandle> methodHandles, final OverloadedDynamicMethod parent, final MethodType callSiteType,115final LinkerServices linkerServices) {116this.parent = parent;117final Class<?> commonRetType = getCommonReturnType(methodHandles);118this.callSiteType = callSiteType.changeReturnType(commonRetType);119this.linkerServices = linkerServices;120121fixArgMethods = new ArrayList<>(methodHandles.size());122varArgMethods = new ArrayList<>(methodHandles.size());123final int argNum = callSiteType.parameterCount();124for(MethodHandle mh: methodHandles) {125if(mh.isVarargsCollector()) {126final MethodHandle asFixed = mh.asFixedArity();127if(argNum == asFixed.type().parameterCount()) {128fixArgMethods.add(asFixed);129}130varArgMethods.add(mh);131} else {132fixArgMethods.add(mh);133}134}135fixArgMethods.trimToSize();136varArgMethods.trimToSize();137138final MethodHandle bound = SELECT_METHOD.bindTo(this);139final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(140callSiteType.changeReturnType(MethodHandle.class));141invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(142MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);143}144145MethodHandle getInvoker() {146return invoker;147}148149private static final MethodHandle SELECT_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(), "selectMethod",150MethodHandle.class, Object[].class);151152@SuppressWarnings("unused")153private MethodHandle selectMethod(final Object[] args) throws NoSuchMethodException {154final Class<?>[] argTypes = new Class<?>[args.length];155for(int i = 0; i < argTypes.length; ++i) {156final Object arg = args[i];157argTypes[i] = arg == null ? ClassString.NULL_CLASS : arg.getClass();158}159final ClassString classString = new ClassString(argTypes);160MethodHandle method = argTypesToMethods.get(classString);161if(method == null) {162List<MethodHandle> methods = classString.getMaximallySpecifics(fixArgMethods, linkerServices, false);163if(methods.isEmpty()) {164methods = classString.getMaximallySpecifics(varArgMethods, linkerServices, true);165}166switch(methods.size()) {167case 0: {168method = getNoSuchMethodThrower(argTypes);169break;170}171case 1: {172method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices);173break;174}175default: {176// This is unfortunate - invocation time ambiguity. We can still save the day if177method = getAmbiguousMethodThrower(argTypes, methods);178break;179}180}181// Avoid keeping references to unrelated classes; this ruins the performance a bit, but avoids class loader182// memory leaks.183if(classString.isVisibleFrom(parent.getClassLoader())) {184argTypesToMethods.put(classString, method);185}186}187return method;188}189190private MethodHandle getNoSuchMethodThrower(final Class<?>[] argTypes) {191return adaptThrower(MethodHandles.insertArguments(THROW_NO_SUCH_METHOD, 0, this, argTypes));192}193194private static final MethodHandle THROW_NO_SUCH_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(),195"throwNoSuchMethod", void.class, Class[].class);196197@SuppressWarnings("unused")198private void throwNoSuchMethod(final Class<?>[] argTypes) throws NoSuchMethodException {199if(varArgMethods.isEmpty()) {200throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) +201" of method " + parent.getName() + " match the argument types " + argTypesString(argTypes));202}203throw new NoSuchMethodException("None of the fixed arity signatures " + getSignatureList(fixArgMethods) +204" or the variable arity signatures " + getSignatureList(varArgMethods) + " of the method " +205parent.getName() + " match the argument types " + argTypesString(argTypes));206}207208private MethodHandle getAmbiguousMethodThrower(final Class<?>[] argTypes, final List<MethodHandle> methods) {209return adaptThrower(MethodHandles.insertArguments(THROW_AMBIGUOUS_METHOD, 0, this, argTypes, methods));210}211212private MethodHandle adaptThrower(final MethodHandle rawThrower) {213return MethodHandles.dropArguments(rawThrower, 0, callSiteType.parameterList()).asType(callSiteType);214}215216private static final MethodHandle THROW_AMBIGUOUS_METHOD = Lookup.findOwnSpecial(MethodHandles.lookup(),217"throwAmbiguousMethod", void.class, Class[].class, List.class);218219@SuppressWarnings("unused")220private void throwAmbiguousMethod(final Class<?>[] argTypes, final List<MethodHandle> methods) throws NoSuchMethodException {221final String arity = methods.get(0).isVarargsCollector() ? "variable" : "fixed";222throw new NoSuchMethodException("Can't unambiguously select between " + arity + " arity signatures " +223getSignatureList(methods) + " of the method " + parent.getName() + " for argument types " +224argTypesString(argTypes));225}226227private static String argTypesString(final Class<?>[] classes) {228final StringBuilder b = new StringBuilder().append('[');229appendTypes(b, classes, false);230return b.append(']').toString();231}232233private static String getSignatureList(final List<MethodHandle> methods) {234final StringBuilder b = new StringBuilder().append('[');235final Iterator<MethodHandle> it = methods.iterator();236if(it.hasNext()) {237appendSig(b, it.next());238while(it.hasNext()) {239appendSig(b.append(", "), it.next());240}241}242return b.append(']').toString();243}244245private static void appendSig(final StringBuilder b, final MethodHandle m) {246b.append('(');247appendTypes(b, m.type().parameterArray(), m.isVarargsCollector());248b.append(')');249}250251private static void appendTypes(final StringBuilder b, final Class<?>[] classes, final boolean varArg) {252final int l = classes.length;253if(!varArg) {254if(l > 1) {255b.append(classes[1].getCanonicalName());256for(int i = 2; i < l; ++i) {257b.append(", ").append(classes[i].getCanonicalName());258}259}260} else {261for(int i = 1; i < l - 1; ++i) {262b.append(classes[i].getCanonicalName()).append(", ");263}264b.append(classes[l - 1].getComponentType().getCanonicalName()).append("...");265}266}267268private static Class<?> getCommonReturnType(final List<MethodHandle> methodHandles) {269final Iterator<MethodHandle> it = methodHandles.iterator();270Class<?> retType = it.next().type().returnType();271while(it.hasNext()) {272retType = TypeUtilities.getCommonLosslessConversionType(retType, it.next().type().returnType());273}274return retType;275}276}277278279