139 // Find last non-trivial conversion (if any). |
139 // Find last non-trivial conversion (if any). |
140 int lastConv = newType.parameterCount()-1; |
140 int lastConv = newType.parameterCount()-1; |
141 while (lastConv >= 0) { |
141 while (lastConv >= 0) { |
142 Class<?> src = newType.parameterType(lastConv); // source type |
142 Class<?> src = newType.parameterType(lastConv); // source type |
143 Class<?> dst = oldType.parameterType(lastConv); // destination type |
143 Class<?> dst = oldType.parameterType(lastConv); // destination type |
144 if (VerifyType.isNullConversion(src, dst)) { |
144 if (isTrivialConversion(src, dst, level)) { |
145 --lastConv; |
145 --lastConv; |
146 } else { |
146 } else { |
147 break; |
147 break; |
148 } |
148 } |
149 } |
149 } |
150 |
150 |
151 Class<?> needReturn = newType.returnType(); |
151 Class<?> needReturn = newType.returnType(); |
152 Class<?> haveReturn = oldType.returnType(); |
152 Class<?> haveReturn = oldType.returnType(); |
153 boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn); |
153 boolean retConv = !isTrivialConversion(haveReturn, needReturn, level); |
154 |
154 |
155 // Now build a chain of one or more adapters. |
155 // Now build a chain of one or more adapters. |
156 MethodHandle adapter = target, adapter2; |
156 MethodHandle adapter = target, adapter2; |
157 MethodType midType = oldType; |
157 MethodType midType = oldType; |
158 for (int i = 0; i <= lastConv; i++) { |
158 for (int i = 0; i <= lastConv; i++) { |
159 Class<?> src = newType.parameterType(i); // source type |
159 Class<?> src = newType.parameterType(i); // source type |
160 Class<?> dst = midType.parameterType(i); // destination type |
160 Class<?> dst = midType.parameterType(i); // destination type |
161 if (VerifyType.isNullConversion(src, dst)) { |
161 if (isTrivialConversion(src, dst, level)) { |
162 // do nothing: difference is trivial |
162 // do nothing: difference is trivial |
163 continue; |
163 continue; |
164 } |
164 } |
165 // Work the current type backward toward the desired caller type: |
165 // Work the current type backward toward the desired caller type: |
166 midType = midType.changeParameterType(i, src); |
166 midType = midType.changeParameterType(i, src); |
217 } |
217 } |
218 assert(adapter.type() == newType); |
218 assert(adapter.type() == newType); |
219 return adapter; |
219 return adapter; |
220 } |
220 } |
221 |
221 |
|
222 private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) { |
|
223 if (src == dst || dst == void.class) return true; |
|
224 if (!VerifyType.isNullConversion(src, dst)) return false; |
|
225 if (level > 1) return true; // explicitCastArguments |
|
226 boolean sp = src.isPrimitive(); |
|
227 boolean dp = dst.isPrimitive(); |
|
228 if (sp != dp) return false; |
|
229 if (sp) { |
|
230 // in addition to being a null conversion, forbid boolean->int etc. |
|
231 return Wrapper.forPrimitiveType(dst) |
|
232 .isConvertibleFrom(Wrapper.forPrimitiveType(src)); |
|
233 } else { |
|
234 return dst.isAssignableFrom(src); |
|
235 } |
|
236 } |
|
237 |
222 private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) { |
238 private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) { |
223 MethodHandle adjustReturn; |
239 MethodHandle adjustReturn; |
224 if (haveReturn == void.class) { |
240 if (haveReturn == void.class) { |
225 // synthesize a zero value for the given void |
241 // synthesize a zero value for the given void |
226 Object zero = Wrapper.forBasicType(needReturn).zero(); |
242 Object zero = Wrapper.forBasicType(needReturn).zero(); |
594 Class<?> dst = targetType.parameterType(arg); |
610 Class<?> dst = targetType.parameterType(arg); |
595 if (!canCheckCast(src, castType) |
611 if (!canCheckCast(src, castType) |
596 || !VerifyType.isNullConversion(castType, dst)) |
612 || !VerifyType.isNullConversion(castType, dst)) |
597 return false; |
613 return false; |
598 int diff = diffTypes(newType, targetType, false); |
614 int diff = diffTypes(newType, targetType, false); |
599 return (diff == arg+1); // arg is sole non-trivial diff |
615 return (diff == arg+1) || (diff == 0); // arg is sole non-trivial diff |
600 } |
616 } |
601 /** Can an primitive conversion adapter validly convert src to dst? */ |
617 /** Can an primitive conversion adapter validly convert src to dst? */ |
602 static boolean canCheckCast(Class<?> src, Class<?> dst) { |
618 static boolean canCheckCast(Class<?> src, Class<?> dst) { |
603 return (!src.isPrimitive() && !dst.isPrimitive()); |
619 return (!src.isPrimitive() && !dst.isPrimitive()); |
604 } |
620 } |
1031 /** Factory method: Spread selected argument. */ |
1047 /** Factory method: Spread selected argument. */ |
1032 static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target, |
1048 static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target, |
1033 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { |
1049 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { |
1034 // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType |
1050 // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType |
1035 MethodType targetType = target.type(); |
1051 MethodType targetType = target.type(); |
1036 if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) |
1052 assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) |
1037 return null; |
1053 : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = " |
|
1054 + Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount); |
1038 // dest is not significant; remove? |
1055 // dest is not significant; remove? |
1039 int dest = T_VOID; |
1056 int dest = T_VOID; |
1040 for (int i = 0; i < spreadArgCount; i++) { |
1057 for (int i = 0; i < spreadArgCount; i++) { |
1041 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); |
1058 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); |
1042 if (arg == null) arg = Object.class; |
1059 if (arg == null) arg = Object.class; |