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