26 package sun.dyn; |
26 package sun.dyn; |
27 |
27 |
28 import sun.dyn.util.VerifyType; |
28 import sun.dyn.util.VerifyType; |
29 import sun.dyn.util.Wrapper; |
29 import sun.dyn.util.Wrapper; |
30 import java.dyn.*; |
30 import java.dyn.*; |
|
31 import java.util.List; |
|
32 import sun.dyn.MethodHandleNatives.Constants; |
|
33 import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP; |
|
34 import static sun.dyn.MemberName.newIllegalArgumentException; |
31 |
35 |
32 /** |
36 /** |
33 * The flavor of method handle which emulates an invoke instruction |
37 * The flavor of method handle which emulates an invoke instruction |
34 * on a predetermined argument. The JVM dispatches to the correct method |
38 * on a predetermined argument. The JVM dispatches to the correct method |
35 * when the handle is created, not when it is invoked. |
39 * when the handle is created, not when it is invoked. |
36 * @author jrose |
40 * @author jrose |
37 */ |
41 */ |
38 public class BoundMethodHandle extends MethodHandle { |
42 public class BoundMethodHandle extends MethodHandle { |
39 //MethodHandle vmtarget; // next BMH or final DMH or methodOop |
43 //MethodHandle vmtarget; // next BMH or final DMH or methodOop |
40 private final Object argument; // argument to insert |
44 private final Object argument; // argument to insert |
41 private final int vmargslot; // position at which it is inserted |
45 private final int vmargslot; // position at which it is inserted |
42 |
46 |
|
47 private static final Access IMPL_TOKEN = Access.getToken(); |
|
48 private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN); |
|
49 |
43 // Constructors in this class *must* be package scoped or private. |
50 // Constructors in this class *must* be package scoped or private. |
|
51 // Exception: JavaMethodHandle constructors are protected. |
|
52 // (The link between JMH and BMH is temporary.) |
44 |
53 |
45 /** Bind a direct MH to its receiver (or first ref. argument). |
54 /** Bind a direct MH to its receiver (or first ref. argument). |
46 * The JVM will pre-dispatch the MH if it is not already static. |
55 * The JVM will pre-dispatch the MH if it is not already static. |
47 */ |
56 */ |
48 BoundMethodHandle(DirectMethodHandle mh, Object argument) { |
57 BoundMethodHandle(DirectMethodHandle mh, Object argument) { |
49 super(Access.TOKEN, mh.type().dropParameterType(0)); |
58 super(Access.TOKEN, mh.type().dropParameterTypes(0, 1)); |
50 // check the type now, once for all: |
59 // check the type now, once for all: |
51 this.argument = checkReferenceArgument(argument, mh, 0); |
60 this.argument = checkReferenceArgument(argument, mh, 0); |
52 this.vmargslot = this.type().parameterSlotCount(); |
61 this.vmargslot = this.type().parameterSlotCount(); |
53 if (MethodHandleNatives.JVM_SUPPORT) { |
62 if (MethodHandleNatives.JVM_SUPPORT) { |
54 this.vmtarget = null; // maybe updated by JVM |
63 this.vmtarget = null; // maybe updated by JVM |
55 MethodHandleNatives.init(this, mh, 0); |
64 MethodHandleNatives.init(this, mh, 0); |
56 } else { |
65 } else { |
57 this.vmtarget = mh; |
66 this.vmtarget = mh; |
58 } |
67 } |
59 } |
68 } |
60 |
|
61 private static final int REF_ARG = 0, PRIM_ARG = 1, SELF_ARG = 2; |
|
62 |
69 |
63 /** Insert an argument into an arbitrary method handle. |
70 /** Insert an argument into an arbitrary method handle. |
64 * If argnum is zero, inserts the first argument, etc. |
71 * If argnum is zero, inserts the first argument, etc. |
65 * The argument type must be a reference. |
72 * The argument type must be a reference. |
66 */ |
73 */ |
67 BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { |
74 BoundMethodHandle(MethodHandle mh, Object argument, int argnum) { |
68 this(mh, argument, argnum, mh.type().parameterType(argnum).isPrimitive() ? PRIM_ARG : REF_ARG); |
75 this(mh.type().dropParameterTypes(argnum, argnum+1), |
|
76 mh, argument, argnum); |
69 } |
77 } |
70 |
78 |
71 /** Insert an argument into an arbitrary method handle. |
79 /** Insert an argument into an arbitrary method handle. |
72 * If argnum is zero, inserts the first argument, etc. |
80 * If argnum is zero, inserts the first argument, etc. |
73 */ |
81 */ |
74 BoundMethodHandle(MethodHandle mh, Object argument, int argnum, int whichArg) { |
82 BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) { |
75 super(Access.TOKEN, mh.type().dropParameterType(argnum)); |
83 super(Access.TOKEN, type); |
76 if (whichArg == PRIM_ARG) |
84 if (mh.type().parameterType(argnum).isPrimitive()) |
77 this.argument = bindPrimitiveArgument(argument, mh, argnum); |
85 this.argument = bindPrimitiveArgument(argument, mh, argnum); |
78 else { |
86 else { |
79 if (whichArg == SELF_ARG) argument = this; |
|
80 this.argument = checkReferenceArgument(argument, mh, argnum); |
87 this.argument = checkReferenceArgument(argument, mh, argnum); |
81 } |
88 } |
82 this.vmargslot = this.type().parameterSlotDepth(argnum); |
89 this.vmargslot = type.parameterSlotDepth(argnum); |
|
90 initTarget(mh, argnum); |
|
91 } |
|
92 |
|
93 private void initTarget(MethodHandle mh, int argnum) { |
83 if (MethodHandleNatives.JVM_SUPPORT) { |
94 if (MethodHandleNatives.JVM_SUPPORT) { |
84 this.vmtarget = null; // maybe updated by JVM |
95 this.vmtarget = null; // maybe updated by JVM |
85 MethodHandleNatives.init(this, mh, argnum); |
96 MethodHandleNatives.init(this, mh, argnum); |
86 } else { |
97 } else { |
87 this.vmtarget = mh; |
98 this.vmtarget = mh; |
88 } |
99 } |
89 } |
100 } |
95 this.argument = argument; |
106 this.argument = argument; |
96 this.vmargslot = vmargslot; |
107 this.vmargslot = vmargslot; |
97 assert(this.getClass() == AdapterMethodHandle.class); |
108 assert(this.getClass() == AdapterMethodHandle.class); |
98 } |
109 } |
99 |
110 |
100 /** Initialize the current object as a method handle, binding it |
111 /** Initialize the current object as a Java method handle, binding it |
101 * as the {@code argnum}th argument of the method handle {@code entryPoint}. |
|
102 * The invocation type of the resulting method handle will be the |
|
103 * same as {@code entryPoint}, except that the {@code argnum}th argument |
|
104 * type will be dropped. |
|
105 */ |
|
106 public BoundMethodHandle(MethodHandle entryPoint, int argnum) { |
|
107 this(entryPoint, null, argnum, SELF_ARG); |
|
108 |
|
109 // Note: If the conversion fails, perhaps because of a bad entryPoint, |
|
110 // the MethodHandle.type field will not be filled in, and therefore |
|
111 // no MH.invoke call will ever succeed. The caller may retain a pointer |
|
112 // to the broken method handle, but no harm can be done with it. |
|
113 } |
|
114 |
|
115 /** Initialize the current object as a method handle, binding it |
|
116 * as the first argument of the method handle {@code entryPoint}. |
112 * as the first argument of the method handle {@code entryPoint}. |
117 * The invocation type of the resulting method handle will be the |
113 * The invocation type of the resulting method handle will be the |
118 * same as {@code entryPoint}, except that the first argument |
114 * same as {@code entryPoint}, except that the first argument |
119 * type will be dropped. |
115 * type will be dropped. |
120 */ |
116 */ |
121 public BoundMethodHandle(MethodHandle entryPoint) { |
117 protected BoundMethodHandle(MethodHandle entryPoint) { |
122 this(entryPoint, null, 0, SELF_ARG); |
118 super(Access.TOKEN, entryPoint.type().dropParameterTypes(0, 1)); |
|
119 this.argument = this; // kludge; get rid of |
|
120 this.vmargslot = this.type().parameterSlotDepth(0); |
|
121 initTarget(entryPoint, 0); |
|
122 assert(this instanceof JavaMethodHandle); |
|
123 } |
|
124 |
|
125 /** Initialize the current object as a Java method handle. |
|
126 */ |
|
127 protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) { |
|
128 super(Access.TOKEN, null); |
|
129 MethodHandle entryPoint |
|
130 = findJavaMethodHandleEntryPoint(this.getClass(), |
|
131 entryPointName, type, matchArity); |
|
132 MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1)); |
|
133 this.argument = this; // kludge; get rid of |
|
134 this.vmargslot = this.type().parameterSlotDepth(0); |
|
135 initTarget(entryPoint, 0); |
|
136 assert(this instanceof JavaMethodHandle); |
|
137 } |
|
138 |
|
139 private static |
|
140 MethodHandle findJavaMethodHandleEntryPoint(Class<?> caller, |
|
141 String name, |
|
142 MethodType type, |
|
143 boolean matchArity) { |
|
144 if (matchArity) type.getClass(); // elicit NPE |
|
145 List<MemberName> methods = IMPL_NAMES.getMethods(caller, true, name, null, caller); |
|
146 MethodType foundType = null; |
|
147 MemberName foundMethod = null; |
|
148 for (MemberName method : methods) { |
|
149 MethodType mtype = method.getMethodType(); |
|
150 if (type != null && type.parameterCount() != mtype.parameterCount()) |
|
151 continue; |
|
152 else if (foundType == null) |
|
153 foundType = mtype; |
|
154 else if (foundType != mtype) |
|
155 throw newIllegalArgumentException("more than one method named "+name+" in "+caller.getName()); |
|
156 // discard overrides |
|
157 if (foundMethod == null) |
|
158 foundMethod = method; |
|
159 else if (foundMethod.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) |
|
160 foundMethod = method; |
|
161 } |
|
162 if (foundMethod == null) |
|
163 throw newIllegalArgumentException("no method named "+name+" in "+caller.getName()); |
|
164 MethodHandle entryPoint = MethodHandleImpl.findMethod(IMPL_TOKEN, foundMethod, true, caller); |
|
165 if (type != null) { |
|
166 MethodType epType = type.insertParameterTypes(0, entryPoint.type().parameterType(0)); |
|
167 entryPoint = MethodHandles.convertArguments(entryPoint, epType); |
|
168 } |
|
169 return entryPoint; |
123 } |
170 } |
124 |
171 |
125 /** Make sure the given {@code argument} can be used as {@code argnum}-th |
172 /** Make sure the given {@code argument} can be used as {@code argnum}-th |
126 * parameter of the given method handle {@code mh}, which must be a reference. |
173 * parameter of the given method handle {@code mh}, which must be a reference. |
127 * <p> |
174 * <p> |