35 import sun.invoke.util.Wrapper;
36 import sun.reflect.CallerSensitive;
37 import sun.reflect.Reflection;
38 import static java.lang.invoke.LambdaForm.*;
39 import static java.lang.invoke.MethodHandleStatics.*;
40 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
41
42 /**
43 * Trusted implementation code for MethodHandle.
44 * @author jrose
45 */
46 /*non-public*/ abstract class MethodHandleImpl {
47 /// Factory methods to create method handles:
48
49 static void initStatics() {
50 // Trigger selected static initializations.
51 MemberName.Factory.INSTANCE.getClass();
52 }
53
54 static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
55 if (!arrayClass.isArray())
56 throw newIllegalArgumentException("not an array: "+arrayClass);
57 MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
58 MethodType srcType = accessor.type().erase();
59 MethodType lambdaType = srcType.invokerType();
60 Name[] names = arguments(1, lambdaType);
61 Name[] args = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
62 names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
63 LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
64 MethodHandle mh = SimpleMethodHandle.make(srcType, form);
65 if (ArrayAccessor.needCast(arrayClass)) {
66 mh = mh.bindTo(arrayClass);
67 }
68 mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
69 return mh;
70 }
71
72 static final class ArrayAccessor {
73 /// Support for array element access
74 static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>(); // TODO use it
75 static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>(); // TODO use it
76
77 static int getElementI(int[] a, int i) { return a[i]; }
78 static long getElementJ(long[] a, int i) { return a[i]; }
79 static float getElementF(float[] a, int i) { return a[i]; }
80 static double getElementD(double[] a, int i) { return a[i]; }
81 static boolean getElementZ(boolean[] a, int i) { return a[i]; }
82 static byte getElementB(byte[] a, int i) { return a[i]; }
83 static short getElementS(short[] a, int i) { return a[i]; }
84 static char getElementC(char[] a, int i) { return a[i]; }
85 static Object getElementL(Object[] a, int i) { return a[i]; }
86
87 static void setElementI(int[] a, int i, int x) { a[i] = x; }
88 static void setElementJ(long[] a, int i, long x) { a[i] = x; }
89 static void setElementF(float[] a, int i, float x) { a[i] = x; }
90 static void setElementD(double[] a, int i, double x) { a[i] = x; }
91 static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
92 static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
93 static void setElementS(short[] a, int i, short x) { a[i] = x; }
94 static void setElementC(char[] a, int i, char x) { a[i] = x; }
95 static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
96
97 static Object getElementL(Class<?> arrayClass, Object[] a, int i) { arrayClass.cast(a); return a[i]; }
98 static void setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
99
100 // Weakly typed wrappers of Object[] accessors:
101 static Object getElementL(Object a, int i) { return getElementL((Object[])a, i); }
102 static void setElementL(Object a, int i, Object x) { setElementL((Object[]) a, i, x); }
103 static Object getElementL(Object arrayClass, Object a, int i) { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
104 static void setElementL(Object arrayClass, Object a, int i, Object x) { setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
105
106 static boolean needCast(Class<?> arrayClass) {
107 Class<?> elemClass = arrayClass.getComponentType();
108 return !elemClass.isPrimitive() && elemClass != Object.class;
109 }
110 static String name(Class<?> arrayClass, boolean isSetter) {
111 Class<?> elemClass = arrayClass.getComponentType();
112 if (elemClass == null) throw new IllegalArgumentException();
113 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
114 }
115 static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
116 static MethodType type(Class<?> arrayClass, boolean isSetter) {
117 Class<?> elemClass = arrayClass.getComponentType();
118 Class<?> arrayArgClass = arrayClass;
119 if (!elemClass.isPrimitive()) {
120 arrayArgClass = Object[].class;
121 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
122 arrayArgClass = Object.class;
123 }
124 if (!needCast(arrayClass)) {
125 return !isSetter ?
126 MethodType.methodType(elemClass, arrayArgClass, int.class) :
127 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
128 } else {
129 Class<?> classArgClass = Class.class;
130 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
131 classArgClass = Object.class;
132 return !isSetter ?
133 MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
134 MethodType.methodType(void.class, classArgClass, arrayArgClass, int.class, Object.class);
135 }
136 }
137 static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
138 Class<?> elemClass = arrayClass.getComponentType();
139 return !isSetter ?
140 MethodType.methodType(elemClass, arrayClass, int.class) :
141 MethodType.methodType(void.class, arrayClass, int.class, elemClass);
142 }
143 static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
144 String name = name(arrayClass, isSetter);
145 MethodType type = type(arrayClass, isSetter);
146 try {
147 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
148 } catch (ReflectiveOperationException ex) {
149 throw uncaughtException(ex);
150 }
151 }
152 }
153
154 /**
155 * Create a JVM-level adapter method handle to conform the given method
162 * @param level which strength of conversion is allowed
163 * @return an adapter to the original handle with the desired new type,
164 * or the original target if the types are already identical
165 * or null if the adaptation cannot be made
166 */
167 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
168 assert(level >= 0 && level <= 2);
169 MethodType dstType = target.type();
170 assert(dstType.parameterCount() == target.type().parameterCount());
171 if (srcType == dstType)
172 return target;
173
174 // Calculate extra arguments (temporaries) required in the names array.
175 // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
176 final int INARG_COUNT = srcType.parameterCount();
177 int conversions = 0;
178 boolean[] needConv = new boolean[1+INARG_COUNT];
179 for (int i = 0; i <= INARG_COUNT; i++) {
180 Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
181 Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
182 if (!VerifyType.isNullConversion(src, dst) ||
183 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
184 needConv[i] = true;
185 conversions++;
186 }
187 }
188 boolean retConv = needConv[INARG_COUNT];
189
190 final int IN_MH = 0;
191 final int INARG_BASE = 1;
192 final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
193 final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
194 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
195 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
196
197 // Now build a LambdaForm.
198 MethodType lambdaType = srcType.basicType().invokerType();
199 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
200
201 // Collect the arguments to the outgoing call, maybe with conversions:
202 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
203 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
204
205 int nameCursor = INARG_LIMIT;
206 for (int i = 0; i < INARG_COUNT; i++) {
207 Class<?> src = srcType.parameterType(i);
208 Class<?> dst = dstType.parameterType(i);
209
210 if (!needConv[i]) {
211 // do nothing: difference is trivial
212 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
213 continue;
214 }
215
216 // Tricky case analysis follows.
217 MethodHandle fn = null;
218 if (src.isPrimitive()) {
219 if (dst.isPrimitive()) {
220 fn = ValueConversions.convertPrimitive(src, dst);
221 } else {
222 Wrapper w = Wrapper.forPrimitiveType(src);
223 MethodHandle boxMethod = ValueConversions.box(w);
224 if (dst == w.wrapperType())
225 fn = boxMethod;
226 else
227 fn = boxMethod.asType(MethodType.methodType(dst, src));
228 }
229 } else {
230 if (dst.isPrimitive()) {
231 // Caller has boxed a primitive. Unbox it for the target.
232 Wrapper w = Wrapper.forPrimitiveType(dst);
233 if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
234 fn = ValueConversions.unbox(dst);
235 } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
236 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
237 // must include additional conversions
238 // src must be examined at runtime, to detect Byte, Character, etc.
239 MethodHandle unboxMethod = (level == 1
240 ? ValueConversions.unbox(dst)
241 : ValueConversions.unboxCast(dst));
242 fn = unboxMethod;
243 } else {
244 // Example: Byte->int
245 // Do this by reformulating the problem to Byte->byte.
246 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
247 MethodHandle unbox = ValueConversions.unbox(srcPrim);
248 // Compose the two conversions. FIXME: should make two Names for this job
249 fn = unbox.asType(MethodType.methodType(dst, src));
250 }
251 } else {
252 // Simple reference conversion.
253 // Note: Do not check for a class hierarchy relation
272 } else {
273 Class<?> needReturn = srcType.returnType();
274 Class<?> haveReturn = dstType.returnType();
275 MethodHandle fn;
276 Object[] arg = { names[OUT_CALL] };
277 if (haveReturn == void.class) {
278 // synthesize a zero value for the given void
279 Object zero = Wrapper.forBasicType(needReturn).zero();
280 fn = MethodHandles.constant(needReturn, zero);
281 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
282 } else {
283 MethodHandle identity = MethodHandles.identity(needReturn);
284 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
285 fn = makePairwiseConvert(identity, needConversion, level);
286 }
287 assert(names[RETURN_CONV] == null);
288 names[RETURN_CONV] = new Name(fn, arg);
289 assert(RETURN_CONV == names.length-1);
290 }
291
292 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
293 return SimpleMethodHandle.make(srcType, form);
294 }
295
296 /**
297 * Identity function, with reference cast.
298 * @param t an arbitrary reference type
299 * @param x an arbitrary reference value
300 * @return the same value x
301 */
302 @ForceInline
303 @SuppressWarnings("unchecked")
304 static <T,U> T castReference(Class<? extends T> t, U x) {
305 // inlined Class.cast because we can't ForceInline it
306 if (x != null && !t.isInstance(x))
307 throw newClassCastException(t, x);
308 return (T) x;
309 }
310
311 private static ClassCastException newClassCastException(Class<?> t, Object obj) {
312 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
|
35 import sun.invoke.util.Wrapper;
36 import sun.reflect.CallerSensitive;
37 import sun.reflect.Reflection;
38 import static java.lang.invoke.LambdaForm.*;
39 import static java.lang.invoke.MethodHandleStatics.*;
40 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
41
42 /**
43 * Trusted implementation code for MethodHandle.
44 * @author jrose
45 */
46 /*non-public*/ abstract class MethodHandleImpl {
47 /// Factory methods to create method handles:
48
49 static void initStatics() {
50 // Trigger selected static initializations.
51 MemberName.Factory.INSTANCE.getClass();
52 }
53
54 static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
55 if (arrayClass == Object[].class)
56 return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER);
57 if (!arrayClass.isArray())
58 throw newIllegalArgumentException("not an array: "+arrayClass);
59 MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass);
60 int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX);
61 MethodHandle mh = cache[cacheIndex];
62 if (mh != null) return mh;
63 mh = ArrayAccessor.getAccessor(arrayClass, isSetter);
64 MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter);
65 if (mh.type() != correctType) {
66 assert(mh.type().parameterType(0) == Object[].class);
67 assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class);
68 assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType());
69 // safe to view non-strictly, because element type follows from array type
70 mh = mh.viewAsType(correctType);
71 }
72 cache[cacheIndex] = mh;
73 return mh;
74 }
75
76 static final class ArrayAccessor {
77 /// Support for array element access
78 static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2;
79 static final ClassValue<MethodHandle[]> TYPED_ACCESSORS
80 = new ClassValue<MethodHandle[]>() {
81 @Override
82 protected MethodHandle[] computeValue(Class<?> type) {
83 return new MethodHandle[INDEX_LIMIT];
84 }
85 };
86 static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER;
87 static {
88 MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class);
89 cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = getAccessor(Object[].class, false);
90 cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = getAccessor(Object[].class, true);
91 }
92
93 static int getElementI(int[] a, int i) { return a[i]; }
94 static long getElementJ(long[] a, int i) { return a[i]; }
95 static float getElementF(float[] a, int i) { return a[i]; }
96 static double getElementD(double[] a, int i) { return a[i]; }
97 static boolean getElementZ(boolean[] a, int i) { return a[i]; }
98 static byte getElementB(byte[] a, int i) { return a[i]; }
99 static short getElementS(short[] a, int i) { return a[i]; }
100 static char getElementC(char[] a, int i) { return a[i]; }
101 static Object getElementL(Object[] a, int i) { return a[i]; }
102
103 static void setElementI(int[] a, int i, int x) { a[i] = x; }
104 static void setElementJ(long[] a, int i, long x) { a[i] = x; }
105 static void setElementF(float[] a, int i, float x) { a[i] = x; }
106 static void setElementD(double[] a, int i, double x) { a[i] = x; }
107 static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
108 static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
109 static void setElementS(short[] a, int i, short x) { a[i] = x; }
110 static void setElementC(char[] a, int i, char x) { a[i] = x; }
111 static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
112
113 static String name(Class<?> arrayClass, boolean isSetter) {
114 Class<?> elemClass = arrayClass.getComponentType();
115 if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass);
116 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
117 }
118 static MethodType type(Class<?> arrayClass, boolean isSetter) {
119 Class<?> elemClass = arrayClass.getComponentType();
120 Class<?> arrayArgClass = arrayClass;
121 if (!elemClass.isPrimitive()) {
122 arrayArgClass = Object[].class;
123 elemClass = Object.class;
124 }
125 return !isSetter ?
126 MethodType.methodType(elemClass, arrayArgClass, int.class) :
127 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
128 }
129 static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
130 Class<?> elemClass = arrayClass.getComponentType();
131 return !isSetter ?
132 MethodType.methodType(elemClass, arrayClass, int.class) :
133 MethodType.methodType(void.class, arrayClass, int.class, elemClass);
134 }
135 static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
136 String name = name(arrayClass, isSetter);
137 MethodType type = type(arrayClass, isSetter);
138 try {
139 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
140 } catch (ReflectiveOperationException ex) {
141 throw uncaughtException(ex);
142 }
143 }
144 }
145
146 /**
147 * Create a JVM-level adapter method handle to conform the given method
154 * @param level which strength of conversion is allowed
155 * @return an adapter to the original handle with the desired new type,
156 * or the original target if the types are already identical
157 * or null if the adaptation cannot be made
158 */
159 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
160 assert(level >= 0 && level <= 2);
161 MethodType dstType = target.type();
162 assert(dstType.parameterCount() == target.type().parameterCount());
163 if (srcType == dstType)
164 return target;
165
166 // Calculate extra arguments (temporaries) required in the names array.
167 // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
168 final int INARG_COUNT = srcType.parameterCount();
169 int conversions = 0;
170 boolean[] needConv = new boolean[1+INARG_COUNT];
171 for (int i = 0; i <= INARG_COUNT; i++) {
172 Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
173 Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
174 if (!VerifyType.isNullConversion(src, dst, false) ||
175 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
176 needConv[i] = true;
177 conversions++;
178 }
179 }
180 boolean retConv = needConv[INARG_COUNT];
181 if (retConv && srcType.returnType() == void.class) {
182 retConv = false;
183 conversions--;
184 }
185
186 final int IN_MH = 0;
187 final int INARG_BASE = 1;
188 final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
189 final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
190 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
191 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
192 final int RESULT = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
193
194 // Now build a LambdaForm.
195 MethodType lambdaType = srcType.basicType().invokerType();
196 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
197
198 // Collect the arguments to the outgoing call, maybe with conversions:
199 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
200 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
201
202 int nameCursor = INARG_LIMIT;
203 for (int i = 0; i < INARG_COUNT; i++) {
204 Class<?> src = srcType.parameterType(i);
205 Class<?> dst = dstType.parameterType(i);
206
207 if (!needConv[i]) {
208 // do nothing: difference is trivial
209 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
210 continue;
211 }
212
213 // Tricky case analysis follows.
214 MethodHandle fn = null;
215 if (src.isPrimitive()) {
216 if (dst.isPrimitive()) {
217 fn = ValueConversions.convertPrimitive(src, dst);
218 } else {
219 Wrapper w = Wrapper.forPrimitiveType(src);
220 MethodHandle boxMethod = ValueConversions.box(w);
221 if (dst == w.wrapperType())
222 fn = boxMethod;
223 else
224 fn = boxMethod.asType(MethodType.methodType(dst, src));
225 }
226 } else {
227 if (dst.isPrimitive()) {
228 // Caller has boxed a primitive. Unbox it for the target.
229 Wrapper w = Wrapper.forPrimitiveType(dst);
230 if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
231 fn = ValueConversions.unbox(dst);
232 } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
233 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
234 // must include additional conversions
235 // src must be examined at runtime, to detect Byte, Character, etc.
236 MethodHandle unboxMethod = (level == 1
237 ? ValueConversions.unbox(dst)
238 : ValueConversions.unboxCast(dst));
239 fn = unboxMethod;
240 } else {
241 // Example: Byte->int
242 // Do this by reformulating the problem to Byte->byte.
243 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
244 MethodHandle unbox = ValueConversions.unbox(srcPrim);
245 // Compose the two conversions. FIXME: should make two Names for this job
246 fn = unbox.asType(MethodType.methodType(dst, src));
247 }
248 } else {
249 // Simple reference conversion.
250 // Note: Do not check for a class hierarchy relation
269 } else {
270 Class<?> needReturn = srcType.returnType();
271 Class<?> haveReturn = dstType.returnType();
272 MethodHandle fn;
273 Object[] arg = { names[OUT_CALL] };
274 if (haveReturn == void.class) {
275 // synthesize a zero value for the given void
276 Object zero = Wrapper.forBasicType(needReturn).zero();
277 fn = MethodHandles.constant(needReturn, zero);
278 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
279 } else {
280 MethodHandle identity = MethodHandles.identity(needReturn);
281 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
282 fn = makePairwiseConvert(identity, needConversion, level);
283 }
284 assert(names[RETURN_CONV] == null);
285 names[RETURN_CONV] = new Name(fn, arg);
286 assert(RETURN_CONV == names.length-1);
287 }
288
289 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
290 return SimpleMethodHandle.make(srcType, form);
291 }
292
293 /**
294 * Identity function, with reference cast.
295 * @param t an arbitrary reference type
296 * @param x an arbitrary reference value
297 * @return the same value x
298 */
299 @ForceInline
300 @SuppressWarnings("unchecked")
301 static <T,U> T castReference(Class<? extends T> t, U x) {
302 // inlined Class.cast because we can't ForceInline it
303 if (x != null && !t.isInstance(x))
304 throw newClassCastException(t, x);
305 return (T) x;
306 }
307
308 private static ClassCastException newClassCastException(Class<?> t, Object obj) {
309 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
|