1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import java.util.Arrays; 29 import static java.lang.invoke.LambdaForm.*; 30 import static java.lang.invoke.MethodHandleStatics.*; 31 32 /** 33 * A method handle whose invocation behavior is determined by a target. 34 * The delegating MH itself can hold extra "intentions" beyond the simple behavior. 35 * @author jrose 36 */ 37 /*non-public*/ 38 abstract class DelegatingMethodHandle extends MethodHandle { 39 protected DelegatingMethodHandle(MethodHandle target) { 40 this(target.type(), target); 41 } 42 43 protected DelegatingMethodHandle(MethodType type, MethodHandle target) { 44 super(type, chooseDelegatingForm(target)); 45 } 46 47 /** Define this to extract the delegated target which supplies the invocation behavior. */ 48 abstract protected MethodHandle getTarget(); 49 50 @Override 51 abstract MethodHandle asTypeUncached(MethodType newType); 52 53 @Override 54 MemberName internalMemberName() { 55 return getTarget().internalMemberName(); 56 } 57 58 @Override 59 boolean isInvokeSpecial() { 60 return getTarget().isInvokeSpecial(); 61 } 62 63 @Override 64 Class<?> internalCallerClass() { 65 return getTarget().internalCallerClass(); 66 } 67 68 @Override 69 MethodHandle copyWith(MethodType mt, LambdaForm lf) { 70 // FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs 71 throw newIllegalArgumentException("do not use this"); 72 } 73 74 @Override 75 String internalProperties() { 76 return "\n& Class="+getClass().getSimpleName()+ 77 "\n& Target="+getTarget().debugString(); 78 } 79 80 @Override 81 BoundMethodHandle rebind() { 82 return getTarget().rebind(); 83 } 84 85 private static LambdaForm chooseDelegatingForm(MethodHandle target) { 86 if (target instanceof SimpleMethodHandle) 87 return target.internalForm(); // no need for an indirection 88 return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, NF_getTarget); 89 } 90 91 /** Create a LF which simply reinvokes a target of the given basic type. */ 92 static LambdaForm makeReinvokerForm(MethodHandle target, 93 int whichCache, 94 NamedFunction getTargetFn) { 95 MethodType mtype = target.type().basicType(); 96 boolean customized = (whichCache < 0 || 97 mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY); 98 LambdaForm form; 99 if (!customized) { 100 form = mtype.form().cachedLambdaForm(whichCache); 101 if (form != null) return form; 102 } 103 final int THIS_DMH = 0; 104 final int ARG_BASE = 1; 105 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); 106 int nameCursor = ARG_LIMIT; 107 final int NEXT_MH = customized ? -1 : nameCursor++; 108 final int REINVOKE = nameCursor++; 109 LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); 110 assert(names.length == nameCursor); 111 Object[] targetArgs; 112 if (customized) { 113 targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); 114 names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself 115 } else { 116 names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]); 117 targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class); 118 targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH 119 names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); 120 } 121 String debugString; 122 switch(whichCache) { 123 case MethodTypeForm.LF_REBIND: debugString = "BMH.reinvoke"; break; 124 case MethodTypeForm.LF_DELEGATE: debugString = "MH.delegate"; break; 125 default: debugString = "MH.reinvoke"; break; 126 } 127 form = new LambdaForm(debugString, ARG_LIMIT, names); 128 if (!customized) { 129 form = mtype.form().setCachedLambdaForm(whichCache, form); 130 } 131 return form; 132 } 133 134 private static final NamedFunction NF_getTarget; 135 static { 136 try { 137 NF_getTarget = new NamedFunction(DelegatingMethodHandle.class 138 .getDeclaredMethod("getTarget")); 139 } catch (ReflectiveOperationException ex) { 140 throw newInternalError(ex); 141 } 142 } 143 }