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.LambdaForm.Kind.*; 31 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual; 32 import static java.lang.invoke.MethodHandleStatics.*; 33 34 /** 35 * A method handle whose invocation behavior is determined by a target. 36 * The delegating MH itself can hold extra "intentions" beyond the simple behavior. 37 * @author jrose 38 */ 39 /*non-public*/ 40 abstract class DelegatingMethodHandle extends MethodHandle { DelegatingMethodHandle(MethodHandle target)41 protected DelegatingMethodHandle(MethodHandle target) { 42 this(target.type(), target); 43 } 44 DelegatingMethodHandle(MethodType type, MethodHandle target)45 protected DelegatingMethodHandle(MethodType type, MethodHandle target) { 46 super(type, chooseDelegatingForm(target)); 47 } 48 DelegatingMethodHandle(MethodType type, LambdaForm form)49 protected DelegatingMethodHandle(MethodType type, LambdaForm form) { 50 super(type, form); 51 } 52 53 /** Define this to extract the delegated target which supplies the invocation behavior. */ getTarget()54 protected abstract MethodHandle getTarget(); 55 56 @Override asTypeUncached(MethodType newType)57 abstract MethodHandle asTypeUncached(MethodType newType); 58 59 @Override internalMemberName()60 MemberName internalMemberName() { 61 return getTarget().internalMemberName(); 62 } 63 64 @Override isInvokeSpecial()65 boolean isInvokeSpecial() { 66 return getTarget().isInvokeSpecial(); 67 } 68 69 @Override internalCallerClass()70 Class<?> internalCallerClass() { 71 return getTarget().internalCallerClass(); 72 } 73 74 @Override copyWith(MethodType mt, LambdaForm lf)75 MethodHandle copyWith(MethodType mt, LambdaForm lf) { 76 // FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs 77 throw newIllegalArgumentException("do not use this"); 78 } 79 80 @Override internalProperties()81 String internalProperties() { 82 return "\n& Class="+getClass().getSimpleName()+ 83 "\n& Target="+getTarget().debugString(); 84 } 85 86 @Override rebind()87 BoundMethodHandle rebind() { 88 return getTarget().rebind(); 89 } 90 chooseDelegatingForm(MethodHandle target)91 private static LambdaForm chooseDelegatingForm(MethodHandle target) { 92 if (target instanceof SimpleMethodHandle) 93 return target.internalForm(); // no need for an indirection 94 return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); 95 } 96 makeReinvokerForm(MethodHandle target, int whichCache, Object constraint, NamedFunction getTargetFn)97 static LambdaForm makeReinvokerForm(MethodHandle target, 98 int whichCache, 99 Object constraint, 100 NamedFunction getTargetFn) { 101 // No pre-action needed. 102 return makeReinvokerForm(target, whichCache, constraint, true, getTargetFn, null); 103 } 104 /** Create a LF which simply reinvokes a target of the given basic type. */ makeReinvokerForm(MethodHandle target, int whichCache, Object constraint, boolean forceInline, NamedFunction getTargetFn, NamedFunction preActionFn)105 static LambdaForm makeReinvokerForm(MethodHandle target, 106 int whichCache, 107 Object constraint, 108 boolean forceInline, 109 NamedFunction getTargetFn, 110 NamedFunction preActionFn) { 111 MethodType mtype = target.type().basicType(); 112 Kind kind = whichKind(whichCache); 113 boolean customized = (whichCache < 0 || 114 mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY); 115 boolean hasPreAction = (preActionFn != null); 116 LambdaForm form; 117 if (!customized) { 118 form = mtype.form().cachedLambdaForm(whichCache); 119 if (form != null) return form; 120 } 121 final int THIS_DMH = 0; 122 final int ARG_BASE = 1; 123 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); 124 int nameCursor = ARG_LIMIT; 125 final int PRE_ACTION = hasPreAction ? nameCursor++ : -1; 126 final int NEXT_MH = customized ? -1 : nameCursor++; 127 final int REINVOKE = nameCursor++; 128 LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); 129 assert(names.length == nameCursor); 130 names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint); 131 Object[] targetArgs; 132 if (hasPreAction) { 133 names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]); 134 } 135 if (customized) { 136 targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); 137 names[REINVOKE] = new LambdaForm.Name(target, targetArgs); // the invoker is the target itself 138 } else { 139 names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]); 140 targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class); 141 targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH 142 names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs); 143 } 144 form = new LambdaForm(ARG_LIMIT, names, forceInline, kind); 145 if (!customized) { 146 form = mtype.form().setCachedLambdaForm(whichCache, form); 147 } 148 return form; 149 } 150 whichKind(int whichCache)151 private static Kind whichKind(int whichCache) { 152 switch(whichCache) { 153 case MethodTypeForm.LF_REBIND: return BOUND_REINVOKER; 154 case MethodTypeForm.LF_DELEGATE: return DELEGATE; 155 default: return REINVOKER; 156 } 157 } 158 159 static final NamedFunction NF_getTarget; 160 static { 161 try { 162 MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget", 163 MethodType.methodType(MethodHandle.class), REF_invokeVirtual); 164 NF_getTarget = new NamedFunction( 165 MemberName.getFactory() 166 .resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class)); 167 } catch (ReflectiveOperationException ex) { 168 throw newInternalError(ex); 169 } 170 // The Holder class will contain pre-generated DelegatingMethodHandles resolved 171 // speculatively using MemberName.getFactory().resolveOrNull. However, that 172 // doesn't initialize the class, which subtly breaks inlining etc. By forcing 173 // initialization of the Holder class we avoid these issues. 174 UNSAFE.ensureClassInitialized(Holder.class); 175 } 176 177 /* Placeholder class for DelegatingMethodHandles generated ahead of time */ 178 final class Holder {} 179 } 180