DelegatingMethodHandle.java revision 12745:f068a4ffddd2
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
26package java.lang.invoke;
27
28import java.util.Arrays;
29import static java.lang.invoke.LambdaForm.*;
30import 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*/
38abstract 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    protected DelegatingMethodHandle(MethodType type, LambdaForm form) {
48        super(type, form);
49    }
50
51    /** Define this to extract the delegated target which supplies the invocation behavior. */
52    protected abstract MethodHandle getTarget();
53
54    @Override
55    abstract MethodHandle asTypeUncached(MethodType newType);
56
57    @Override
58    MemberName internalMemberName() {
59        return getTarget().internalMemberName();
60    }
61
62    @Override
63    boolean isInvokeSpecial() {
64        return getTarget().isInvokeSpecial();
65    }
66
67    @Override
68    Class<?> internalCallerClass() {
69        return getTarget().internalCallerClass();
70    }
71
72    @Override
73    MethodHandle copyWith(MethodType mt, LambdaForm lf) {
74        // FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs
75        throw newIllegalArgumentException("do not use this");
76    }
77
78    @Override
79    String internalProperties() {
80        return "\n& Class="+getClass().getSimpleName()+
81               "\n& Target="+getTarget().debugString();
82    }
83
84    @Override
85    BoundMethodHandle rebind() {
86        return getTarget().rebind();
87    }
88
89    private static LambdaForm chooseDelegatingForm(MethodHandle target) {
90        if (target instanceof SimpleMethodHandle)
91            return target.internalForm();  // no need for an indirection
92        return makeReinvokerForm(target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget);
93    }
94
95    static LambdaForm makeReinvokerForm(MethodHandle target,
96                                        int whichCache,
97                                        Object constraint,
98                                        NamedFunction getTargetFn) {
99        String debugString;
100        switch(whichCache) {
101            case MethodTypeForm.LF_REBIND:            debugString = "BMH.reinvoke";      break;
102            case MethodTypeForm.LF_DELEGATE:          debugString = "MH.delegate";       break;
103            default:                                  debugString = "MH.reinvoke";       break;
104        }
105        // No pre-action needed.
106        return makeReinvokerForm(target, whichCache, constraint, debugString, true, getTargetFn, null);
107    }
108    /** Create a LF which simply reinvokes a target of the given basic type. */
109    static LambdaForm makeReinvokerForm(MethodHandle target,
110                                        int whichCache,
111                                        Object constraint,
112                                        String debugString,
113                                        boolean forceInline,
114                                        NamedFunction getTargetFn,
115                                        NamedFunction preActionFn) {
116        MethodType mtype = target.type().basicType();
117        boolean customized = (whichCache < 0 ||
118                mtype.parameterSlotCount() > MethodType.MAX_MH_INVOKER_ARITY);
119        boolean hasPreAction = (preActionFn != null);
120        LambdaForm form;
121        if (!customized) {
122            form = mtype.form().cachedLambdaForm(whichCache);
123            if (form != null)  return form;
124        }
125        final int THIS_DMH    = 0;
126        final int ARG_BASE    = 1;
127        final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
128        int nameCursor = ARG_LIMIT;
129        final int PRE_ACTION   = hasPreAction ? nameCursor++ : -1;
130        final int NEXT_MH     = customized ? -1 : nameCursor++;
131        final int REINVOKE    = nameCursor++;
132        LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
133        assert(names.length == nameCursor);
134        names[THIS_DMH] = names[THIS_DMH].withConstraint(constraint);
135        Object[] targetArgs;
136        if (hasPreAction) {
137            names[PRE_ACTION] = new LambdaForm.Name(preActionFn, names[THIS_DMH]);
138        }
139        if (customized) {
140            targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
141            names[REINVOKE] = new LambdaForm.Name(target, targetArgs);  // the invoker is the target itself
142        } else {
143            names[NEXT_MH] = new LambdaForm.Name(getTargetFn, names[THIS_DMH]);
144            targetArgs = Arrays.copyOfRange(names, THIS_DMH, ARG_LIMIT, Object[].class);
145            targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
146            names[REINVOKE] = new LambdaForm.Name(mtype, targetArgs);
147        }
148        form = new LambdaForm(debugString, ARG_LIMIT, names, forceInline);
149        if (!customized) {
150            form = mtype.form().setCachedLambdaForm(whichCache, form);
151        }
152        return form;
153    }
154
155    static final NamedFunction NF_getTarget;
156    static {
157        try {
158            NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
159                                             .getDeclaredMethod("getTarget"));
160        } catch (ReflectiveOperationException ex) {
161            throw newInternalError(ex);
162        }
163    }
164}
165