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 ?
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());
|
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 static boolean needCast(Class<?> arrayClass) {
101 Class<?> elemClass = arrayClass.getComponentType();
102 return !elemClass.isPrimitive() && elemClass != Object.class;
103 }
104 static String name(Class<?> arrayClass, boolean isSetter) {
105 Class<?> elemClass = arrayClass.getComponentType();
106 if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass);
107 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
108 }
109 static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false; // FIXME: decide
110 static MethodType type(Class<?> arrayClass, boolean isSetter) {
111 Class<?> elemClass = arrayClass.getComponentType();
112 Class<?> arrayArgClass = arrayClass;
113 if (!elemClass.isPrimitive()) {
114 arrayArgClass = Object[].class;
115 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
116 arrayArgClass = Object.class;
117 }
118 if (!needCast(arrayClass)) {
119 return !isSetter ?
120 MethodType.methodType(elemClass, arrayArgClass, int.class) :
121 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
122 } else {
123 Class<?> classArgClass = Class.class;
124 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
125 classArgClass = Object.class;
126 return !isSetter ?
156 * @param level which strength of conversion is allowed
157 * @return an adapter to the original handle with the desired new type,
158 * or the original target if the types are already identical
159 * or null if the adaptation cannot be made
160 */
161 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
162 assert(level >= 0 && level <= 2);
163 MethodType dstType = target.type();
164 assert(dstType.parameterCount() == target.type().parameterCount());
165 if (srcType == dstType)
166 return target;
167
168 // Calculate extra arguments (temporaries) required in the names array.
169 // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step.
170 final int INARG_COUNT = srcType.parameterCount();
171 int conversions = 0;
172 boolean[] needConv = new boolean[1+INARG_COUNT];
173 for (int i = 0; i <= INARG_COUNT; i++) {
174 Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i);
175 Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i);
176 if (!VerifyType.isNullConversion(src, dst, false) ||
177 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) {
178 needConv[i] = true;
179 conversions++;
180 }
181 }
182 boolean retConv = needConv[INARG_COUNT];
183 if (retConv && srcType.returnType() == void.class) {
184 retConv = false;
185 conversions--;
186 }
187
188 final int IN_MH = 0;
189 final int INARG_BASE = 1;
190 final int INARG_LIMIT = INARG_BASE + INARG_COUNT;
191 final int NAME_LIMIT = INARG_LIMIT + conversions + 1;
192 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1);
193 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1;
194 final int RESULT = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1);
195
196 // Now build a LambdaForm.
197 MethodType lambdaType = srcType.basicType().invokerType();
198 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
199
200 // Collect the arguments to the outgoing call, maybe with conversions:
201 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
202 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
203
204 int nameCursor = INARG_LIMIT;
205 for (int i = 0; i < INARG_COUNT; i++) {
206 Class<?> src = srcType.parameterType(i);
207 Class<?> dst = dstType.parameterType(i);
208
209 if (!needConv[i]) {
210 // do nothing: difference is trivial
211 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
212 continue;
213 }
214
215 // Tricky case analysis follows.
216 MethodHandle fn = null;
217 if (src.isPrimitive()) {
218 if (dst.isPrimitive()) {
219 fn = ValueConversions.convertPrimitive(src, dst);
220 } else {
221 Wrapper w = Wrapper.forPrimitiveType(src);
222 MethodHandle boxMethod = ValueConversions.box(w);
223 if (dst == w.wrapperType())
224 fn = boxMethod;
225 else
226 fn = boxMethod.asType(MethodType.methodType(dst, src));
227 }
228 } else {
229 if (dst.isPrimitive()) {
230 // Caller has boxed a primitive. Unbox it for the target.
231 Wrapper w = Wrapper.forPrimitiveType(dst);
232 if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) {
233 fn = ValueConversions.unbox(dst);
234 } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
235 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int
236 // must include additional conversions
237 // src must be examined at runtime, to detect Byte, Character, etc.
238 MethodHandle unboxMethod = (level == 1
239 ? ValueConversions.unbox(dst)
240 : ValueConversions.unboxCast(dst));
241 fn = unboxMethod;
242 } else {
243 // Example: Byte->int
244 // Do this by reformulating the problem to Byte->byte.
245 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
246 MethodHandle unbox = ValueConversions.unbox(srcPrim);
247 // Compose the two conversions. FIXME: should make two Names for this job
248 fn = unbox.asType(MethodType.methodType(dst, src));
249 }
250 } else {
251 // Simple reference conversion.
252 // Note: Do not check for a class hierarchy relation
271 } else {
272 Class<?> needReturn = srcType.returnType();
273 Class<?> haveReturn = dstType.returnType();
274 MethodHandle fn;
275 Object[] arg = { names[OUT_CALL] };
276 if (haveReturn == void.class) {
277 // synthesize a zero value for the given void
278 Object zero = Wrapper.forBasicType(needReturn).zero();
279 fn = MethodHandles.constant(needReturn, zero);
280 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion
281 } else {
282 MethodHandle identity = MethodHandles.identity(needReturn);
283 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
284 fn = makePairwiseConvert(identity, needConversion, level);
285 }
286 assert(names[RETURN_CONV] == null);
287 names[RETURN_CONV] = new Name(fn, arg);
288 assert(RETURN_CONV == names.length-1);
289 }
290
291 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
292 return SimpleMethodHandle.make(srcType, form);
293 }
294
295 /**
296 * Identity function, with reference cast.
297 * @param t an arbitrary reference type
298 * @param x an arbitrary reference value
299 * @return the same value x
300 */
301 @ForceInline
302 @SuppressWarnings("unchecked")
303 static <T,U> T castReference(Class<? extends T> t, U x) {
304 // inlined Class.cast because we can't ForceInline it
305 if (x != null && !t.isInstance(x))
306 throw newClassCastException(t, x);
307 return (T) x;
308 }
309
310 private static ClassCastException newClassCastException(Class<?> t, Object obj) {
311 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
|