/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.lang.invoke;
import java.util.
Arrays;
import static java.lang.invoke.
LambdaForm.*;
import static java.lang.invoke.
MethodHandleStatics.*;
/**
* A method handle whose invocation behavior is determined by a target.
* The delegating MH itself can hold extra "intentions" beyond the simple behavior.
* @author jrose
*/
/*non-public*/
abstract class
DelegatingMethodHandle extends
MethodHandle {
protected
DelegatingMethodHandle(
MethodHandle target) {
this(
target.
type(),
target);
}
protected
DelegatingMethodHandle(
MethodType type,
MethodHandle target) {
super(
type,
chooseDelegatingForm(
target));
}
protected
DelegatingMethodHandle(
MethodType type,
LambdaForm form) {
super(
type,
form);
}
/** Define this to extract the delegated target which supplies the invocation behavior. */
abstract protected
MethodHandle getTarget();
@
Override
abstract
MethodHandle asTypeUncached(
MethodType newType);
@
Override
MemberName internalMemberName() {
return
getTarget().
internalMemberName();
}
@
Override
boolean
isInvokeSpecial() {
return
getTarget().
isInvokeSpecial();
}
@
Override
Class<?>
internalCallerClass() {
return
getTarget().
internalCallerClass();
}
@
Override
MethodHandle copyWith(
MethodType mt,
LambdaForm lf) {
// FIXME: rethink 'copyWith' protocol; it is too low-level for use on all MHs
throw
newIllegalArgumentException("do not use this");
}
@
Override
String internalProperties() {
return "\n& Class="+
getClass().
getSimpleName()+
"\n& Target="+
getTarget().
debugString();
}
@
Override
BoundMethodHandle rebind() {
return
getTarget().
rebind();
}
private static
LambdaForm chooseDelegatingForm(
MethodHandle target) {
if (
target instanceof
SimpleMethodHandle)
return
target.
internalForm(); // no need for an indirection
return
makeReinvokerForm(
target,
MethodTypeForm.
LF_DELEGATE,
DelegatingMethodHandle.class,
NF_getTarget);
}
static
LambdaForm makeReinvokerForm(
MethodHandle target,
int
whichCache,
Object constraint,
NamedFunction getTargetFn) {
String debugString;
switch(
whichCache) {
case
MethodTypeForm.
LF_REBIND:
debugString = "BMH.reinvoke"; break;
case
MethodTypeForm.
LF_DELEGATE:
debugString = "MH.delegate"; break;
default:
debugString = "MH.reinvoke"; break;
}
// No pre-action needed.
return
makeReinvokerForm(
target,
whichCache,
constraint,
debugString, true,
getTargetFn, null);
}
/** Create a LF which simply reinvokes a target of the given basic type. */
static
LambdaForm makeReinvokerForm(
MethodHandle target,
int
whichCache,
Object constraint,
String debugString,
boolean
forceInline,
NamedFunction getTargetFn,
NamedFunction preActionFn) {
MethodType mtype =
target.
type().
basicType();
boolean
customized = (
whichCache < 0 ||
mtype.
parameterSlotCount() >
MethodType.
MAX_MH_INVOKER_ARITY);
boolean
hasPreAction = (
preActionFn != null);
LambdaForm form;
if (!
customized) {
form =
mtype.
form().
cachedLambdaForm(
whichCache);
if (
form != null) return
form;
}
final int
THIS_DMH = 0;
final int
ARG_BASE = 1;
final int
ARG_LIMIT =
ARG_BASE +
mtype.
parameterCount();
int
nameCursor =
ARG_LIMIT;
final int
PRE_ACTION =
hasPreAction ?
nameCursor++ : -1;
final int
NEXT_MH =
customized ? -1 :
nameCursor++;
final int
REINVOKE =
nameCursor++;
LambdaForm.
Name[]
names =
LambdaForm.
arguments(
nameCursor -
ARG_LIMIT,
mtype.
invokerType());
assert(
names.length ==
nameCursor);
names[
THIS_DMH] =
names[
THIS_DMH].
withConstraint(
constraint);
Object[]
targetArgs;
if (
hasPreAction) {
names[
PRE_ACTION] = new
LambdaForm.
Name(
preActionFn,
names[
THIS_DMH]);
}
if (
customized) {
targetArgs =
Arrays.
copyOfRange(
names,
ARG_BASE,
ARG_LIMIT,
Object[].class);
names[
REINVOKE] = new
LambdaForm.
Name(
target,
targetArgs); // the invoker is the target itself
} else {
names[
NEXT_MH] = new
LambdaForm.
Name(
getTargetFn,
names[
THIS_DMH]);
targetArgs =
Arrays.
copyOfRange(
names,
THIS_DMH,
ARG_LIMIT,
Object[].class);
targetArgs[0] =
names[
NEXT_MH]; // overwrite this MH with next MH
names[
REINVOKE] = new
LambdaForm.
Name(
mtype,
targetArgs);
}
form = new
LambdaForm(
debugString,
ARG_LIMIT,
names,
forceInline);
if (!
customized) {
form =
mtype.
form().
setCachedLambdaForm(
whichCache,
form);
}
return
form;
}
static final
NamedFunction NF_getTarget;
static {
try {
NF_getTarget = new
NamedFunction(
DelegatingMethodHandle.class
.
getDeclaredMethod("getTarget"));
} catch (
ReflectiveOperationException ex) {
throw
newInternalError(
ex);
}
}
}