1 /* 2 * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang.invoke; 27 28 import sun.invoke.util.VerifyType; 29 import sun.invoke.util.Wrapper; 30 import sun.invoke.util.ValueConversions; 31 import java.util.Arrays; 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import static java.lang.invoke.MethodHandleNatives.Constants.*; 35 import static java.lang.invoke.MethodHandleStatics.*; 36 37 /** 38 * This method handle performs simple conversion or checking of a single argument. 39 * @author jrose 40 */ 41 class AdapterMethodHandle extends BoundMethodHandle { 42 43 //MethodHandle vmtarget; // next AMH or BMH in chain or final DMH 44 //Object argument; // parameter to the conversion if needed 45 //int vmargslot; // which argument slot is affected 46 private final int conversion; // the type of conversion: RETYPE_ONLY, etc. 47 48 // Constructors in this class *must* be package scoped or private. 49 private AdapterMethodHandle(MethodHandle target, MethodType newType, 50 long conv, Object convArg) { 51 super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv))); 52 this.conversion = convCode(conv); 53 // JVM might update VM-specific bits of conversion (ignore) 54 MethodHandleNatives.init(this, target, convArgPos(conv)); 55 } 56 AdapterMethodHandle(MethodHandle target, MethodType newType, 57 long conv) { 58 this(target, newType, conv, null); 59 } 60 61 int getConversion() { return conversion; } 62 63 // TO DO: When adapting another MH with a null conversion, clone 64 // the target and change its type, instead of adding another layer. 65 66 /** Can a JVM-level adapter directly implement the proposed 67 * argument conversions, as if by fixed-arity MethodHandle.asType? 68 */ 69 static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) { 70 // same number of args, of course 71 int len = newType.parameterCount(); 72 if (len != oldType.parameterCount()) 73 return false; 74 75 // Check return type. 76 Class<?> exp = newType.returnType(); 77 Class<?> ret = oldType.returnType(); 78 if (!VerifyType.isNullConversion(ret, exp)) { 79 if (!convOpSupported(OP_COLLECT_ARGS)) 80 return false; 81 if (!canConvertArgument(ret, exp, level)) 82 return false; 83 } 84 85 // Check args pairwise. 86 for (int i = 0; i < len; i++) { 87 Class<?> src = newType.parameterType(i); // source type 88 Class<?> dst = oldType.parameterType(i); // destination type 89 if (!canConvertArgument(src, dst, level)) 90 return false; 91 } 92 93 return true; 94 } 95 96 /** Can a JVM-level adapter directly implement the proposed 97 * argument conversion, as if by fixed-arity MethodHandle.asType? 98 */ 99 static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) { 100 // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes, 101 // so we don't need to repeat so much decision making. 102 if (VerifyType.isNullConversion(src, dst)) { 103 return true; 104 } else if (convOpSupported(OP_COLLECT_ARGS)) { 105 // If we can build filters, we can convert anything to anything. 106 return true; 107 } else if (src.isPrimitive()) { 108 if (dst.isPrimitive()) 109 return canPrimCast(src, dst); 110 else 111 return canBoxArgument(src, dst); 112 } else { 113 if (dst.isPrimitive()) 114 return canUnboxArgument(src, dst, level); 115 else 116 return true; // any two refs can be interconverted 117 } 118 } 119 120 /** 121 * Create a JVM-level adapter method handle to conform the given method 122 * handle to the similar newType, using only pairwise argument conversions. 123 * For each argument, convert incoming argument to the exact type needed. 124 * The argument conversions allowed are casting, boxing and unboxing, 125 * integral widening or narrowing, and floating point widening or narrowing. 126 * @param newType required call type 127 * @param target original method handle 128 * @param level which strength of conversion is allowed 129 * @return an adapter to the original handle with the desired new type, 130 * or the original target if the types are already identical 131 * or null if the adaptation cannot be made 132 */ 133 static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target, int level) { 134 MethodType oldType = target.type(); 135 if (newType == oldType) return target; 136 137 if (!canPairwiseConvert(newType, oldType, level)) 138 return null; 139 // (after this point, it is an assertion error to fail to convert) 140 141 // Find last non-trivial conversion (if any). 142 int lastConv = newType.parameterCount()-1; 143 while (lastConv >= 0) { 144 Class<?> src = newType.parameterType(lastConv); // source type 145 Class<?> dst = oldType.parameterType(lastConv); // destination type 146 if (isTrivialConversion(src, dst, level)) { 147 --lastConv; 148 } else { 149 break; 150 } 151 } 152 153 Class<?> needReturn = newType.returnType(); 154 Class<?> haveReturn = oldType.returnType(); 155 boolean retConv = !isTrivialConversion(haveReturn, needReturn, level); 156 157 // Now build a chain of one or more adapters. 158 MethodHandle adapter = target, adapter2; 159 MethodType midType = oldType; 160 for (int i = 0; i <= lastConv; i++) { 161 Class<?> src = newType.parameterType(i); // source type 162 Class<?> dst = midType.parameterType(i); // destination type 163 if (isTrivialConversion(src, dst, level)) { 164 // do nothing: difference is trivial 165 continue; 166 } 167 // Work the current type backward toward the desired caller type: 168 midType = midType.changeParameterType(i, src); 169 if (i == lastConv) { 170 // When doing the last (or only) real conversion, 171 // force all remaining null conversions to happen also. 172 MethodType lastMidType = newType; 173 if (retConv) lastMidType = lastMidType.changeReturnType(haveReturn); 174 assert(VerifyType.isNullConversion(lastMidType, midType)); 175 midType = lastMidType; 176 } 177 178 // Tricky case analysis follows. 179 // It parallels canConvertArgument() above. 180 if (src.isPrimitive()) { 181 if (dst.isPrimitive()) { 182 adapter2 = makePrimCast(midType, adapter, i, dst); 183 } else { 184 adapter2 = makeBoxArgument(midType, adapter, i, src); 185 } 186 } else { 187 if (dst.isPrimitive()) { 188 // Caller has boxed a primitive. Unbox it for the target. 189 // The box type must correspond exactly to the primitive type. 190 // This is simpler than the powerful set of widening 191 // conversions supported by reflect.Method.invoke. 192 // Those conversions require a big nest of if/then/else logic, 193 // which we prefer to make a user responsibility. 194 adapter2 = makeUnboxArgument(midType, adapter, i, dst, level); 195 } else { 196 // Simple reference conversion. 197 // Note: Do not check for a class hierarchy relation 198 // between src and dst. In all cases a 'null' argument 199 // will pass the cast conversion. 200 adapter2 = makeCheckCast(midType, adapter, i, dst); 201 } 202 } 203 assert(adapter2 != null) : Arrays.asList(src, dst, midType, adapter, i, target, newType); 204 assert(adapter2.type() == midType); 205 adapter = adapter2; 206 } 207 if (retConv) { 208 adapter2 = makeReturnConversion(adapter, haveReturn, needReturn); 209 assert(adapter2 != null); 210 adapter = adapter2; 211 } 212 if (adapter.type() != newType) { 213 // Only trivial conversions remain. 214 adapter2 = makeRetypeOnly(newType, adapter); 215 assert(adapter2 != null); 216 adapter = adapter2; 217 // Actually, that's because there were no non-trivial ones: 218 assert(lastConv == -1 || retConv); 219 } 220 assert(adapter.type() == newType); 221 return adapter; 222 } 223 224 private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) { 225 if (src == dst || dst == void.class) return true; 226 if (!VerifyType.isNullConversion(src, dst)) return false; 227 if (level > 1) return true; // explicitCastArguments 228 boolean sp = src.isPrimitive(); 229 boolean dp = dst.isPrimitive(); 230 if (sp != dp) return false; 231 if (sp) { 232 // in addition to being a null conversion, forbid boolean->int etc. 233 return Wrapper.forPrimitiveType(dst) 234 .isConvertibleFrom(Wrapper.forPrimitiveType(src)); 235 } else { 236 return dst.isAssignableFrom(src); 237 } 238 } 239 240 private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) { 241 MethodHandle adjustReturn; 242 if (haveReturn == void.class) { 243 // synthesize a zero value for the given void 244 Object zero = Wrapper.forBasicType(needReturn).zero(); 245 adjustReturn = MethodHandles.constant(needReturn, zero); 246 } else { 247 MethodType needConversion = MethodType.methodType(needReturn, haveReturn); 248 adjustReturn = MethodHandles.identity(needReturn).asType(needConversion); 249 } 250 return makeCollectArguments(adjustReturn, target, 0, false); 251 } 252 253 /** 254 * Create a JVM-level adapter method handle to permute the arguments 255 * of the given method. 256 * @param newType required call type 257 * @param target original method handle 258 * @param argumentMap for each target argument, position of its source in newType 259 * @return an adapter to the original handle with the desired new type, 260 * or the original target if the types are already identical 261 * and the permutation is null 262 * @throws IllegalArgumentException if the adaptation cannot be made 263 * directly by a JVM-level adapter, without help from Java code 264 */ 265 static MethodHandle makePermutation(MethodType newType, MethodHandle target, 266 int[] argumentMap) { 267 MethodType oldType = target.type(); 268 boolean nullPermutation = true; 269 for (int i = 0; i < argumentMap.length; i++) { 270 int pos = argumentMap[i]; 271 if (pos != i) 272 nullPermutation = false; 273 if (pos < 0 || pos >= newType.parameterCount()) { 274 argumentMap = new int[0]; break; 275 } 276 } 277 if (argumentMap.length != oldType.parameterCount()) 278 throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap)); 279 if (nullPermutation) { 280 MethodHandle res = makePairwiseConvert(newType, target, 0); 281 // well, that was easy 282 if (res == null) 283 throw newIllegalArgumentException("cannot convert pairwise: "+newType); 284 return res; 285 } 286 287 // Check return type. (Not much can be done with it.) 288 Class<?> exp = newType.returnType(); 289 Class<?> ret = oldType.returnType(); 290 if (!VerifyType.isNullConversion(ret, exp)) 291 throw newIllegalArgumentException("bad return conversion for "+newType); 292 293 // See if the argument types match up. 294 for (int i = 0; i < argumentMap.length; i++) { 295 int j = argumentMap[i]; 296 Class<?> src = newType.parameterType(j); 297 Class<?> dst = oldType.parameterType(i); 298 if (!VerifyType.isNullConversion(src, dst)) 299 throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType); 300 } 301 302 // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters. 303 // A workable greedy algorithm is as follows: 304 // Drop unused outgoing arguments (right to left: shallowest first). 305 // Duplicate doubly-used outgoing arguments (left to right: deepest first). 306 // Then the remaining problem is a true argument permutation. 307 // Marshal the outgoing arguments as required from left to right. 308 // That is, find the deepest outgoing stack position that does not yet 309 // have the correct argument value, and correct at least that position 310 // by swapping or rotating in the misplaced value (from a shallower place). 311 // If the misplaced value is followed by one or more consecutive values 312 // (also misplaced) issue a rotation which brings as many as possible 313 // into position. Otherwise make progress with either a swap or a 314 // rotation. Prefer the swap as cheaper, but do not use it if it 315 // breaks a slot pair. Prefer the rotation over the swap if it would 316 // preserve more consecutive values shallower than the target position. 317 // When more than one rotation will work (because the required value 318 // is already adjacent to the target position), then use a rotation 319 // which moves the old value in the target position adjacent to 320 // one of its consecutive values. Also, prefer shorter rotation 321 // spans, since they use fewer memory cycles for shuffling. 322 323 throw new UnsupportedOperationException("NYI"); 324 } 325 326 private static byte basicType(Class<?> type) { 327 if (type == null) return T_VOID; 328 switch (Wrapper.forBasicType(type)) { 329 case BOOLEAN: return T_BOOLEAN; 330 case CHAR: return T_CHAR; 331 case FLOAT: return T_FLOAT; 332 case DOUBLE: return T_DOUBLE; 333 case BYTE: return T_BYTE; 334 case SHORT: return T_SHORT; 335 case INT: return T_INT; 336 case LONG: return T_LONG; 337 case OBJECT: return T_OBJECT; 338 case VOID: return T_VOID; 339 } 340 return 99; // T_ILLEGAL or some such 341 } 342 343 /** Number of stack slots for the given type. 344 * Two for T_DOUBLE and T_FLOAT, one for the rest. 345 */ 346 private static int type2size(int type) { 347 assert(type >= T_BOOLEAN && type <= T_OBJECT); 348 return (type == T_LONG || type == T_DOUBLE) ? 2 : 1; 349 } 350 private static int type2size(Class<?> type) { 351 return type2size(basicType(type)); 352 } 353 354 /** The given stackMove is the number of slots pushed. 355 * It might be negative. Scale it (multiply) by the 356 * VM's notion of how an address changes with a push, 357 * to get the raw SP change for stackMove. 358 * Then shift and mask it into the correct field. 359 */ 360 private static long insertStackMove(int stackMove) { 361 // following variable must be long to avoid sign extension after '<<' 362 long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT; 363 return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT; 364 } 365 366 static int extractStackMove(int convOp) { 367 int spChange = convOp >> CONV_STACK_MOVE_SHIFT; 368 return spChange / MethodHandleNatives.JVM_STACK_MOVE_UNIT; 369 } 370 371 static int extractStackMove(MethodHandle target) { 372 if (target instanceof AdapterMethodHandle) { 373 AdapterMethodHandle amh = (AdapterMethodHandle) target; 374 return extractStackMove(amh.getConversion()); 375 } else { 376 return 0; 377 } 378 } 379 380 /** Construct an adapter conversion descriptor for a single-argument conversion. */ 381 private static long makeConv(int convOp, int argnum, int src, int dest) { 382 assert(src == (src & CONV_TYPE_MASK)); 383 assert(dest == (dest & CONV_TYPE_MASK)); 384 assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF || convOp == OP_COLLECT_ARGS); 385 int stackMove = type2size(dest) - type2size(src); 386 return ((long) argnum << 32 | 387 (long) convOp << CONV_OP_SHIFT | 388 (int) src << CONV_SRC_TYPE_SHIFT | 389 (int) dest << CONV_DEST_TYPE_SHIFT | 390 insertStackMove(stackMove) 391 ); 392 } 393 private static long makeDupConv(int convOp, int argnum, int stackMove) { 394 // simple argument motion, requiring one slot to specify 395 assert(convOp == OP_DUP_ARGS || convOp == OP_DROP_ARGS); 396 byte src = 0, dest = 0; 397 return ((long) argnum << 32 | 398 (long) convOp << CONV_OP_SHIFT | 399 (int) src << CONV_SRC_TYPE_SHIFT | 400 (int) dest << CONV_DEST_TYPE_SHIFT | 401 insertStackMove(stackMove) 402 ); 403 } 404 private static long makeSwapConv(int convOp, int srcArg, byte srcType, int destSlot, byte destType) { 405 // more complex argument motion, requiring two slots to specify 406 assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS); 407 return ((long) srcArg << 32 | 408 (long) convOp << CONV_OP_SHIFT | 409 (int) srcType << CONV_SRC_TYPE_SHIFT | 410 (int) destType << CONV_DEST_TYPE_SHIFT | 411 (int) destSlot << CONV_VMINFO_SHIFT 412 ); 413 } 414 private static long makeSpreadConv(int convOp, int argnum, int src, int dest, int stackMove) { 415 // spreading or collecting, at a particular slot location 416 assert(convOp == OP_SPREAD_ARGS || convOp == OP_COLLECT_ARGS || convOp == OP_FOLD_ARGS); 417 // src = spread ? T_OBJECT (for array) : common type of collected args (else void) 418 // dest = spread ? element type of array : result type of collector (can be void) 419 return ((long) argnum << 32 | 420 (long) convOp << CONV_OP_SHIFT | 421 (int) src << CONV_SRC_TYPE_SHIFT | 422 (int) dest << CONV_DEST_TYPE_SHIFT | 423 insertStackMove(stackMove) 424 ); 425 } 426 static long makeConv(int convOp) { 427 assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW); 428 return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT); // stackMove, src, dst all zero 429 } 430 private static int convCode(long conv) { 431 return (int)conv; 432 } 433 private static int convArgPos(long conv) { 434 return (int)(conv >>> 32); 435 } 436 private static boolean convOpSupported(int convOp) { 437 assert(convOp >= 0 && convOp <= CONV_OP_LIMIT); 438 return ((1<<convOp) & MethodHandleNatives.CONV_OP_IMPLEMENTED_MASK) != 0; 439 } 440 441 /** One of OP_RETYPE_ONLY, etc. */ 442 int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; } 443 444 /* Return one plus the position of the first non-trivial difference 445 * between the given types. This is not a symmetric operation; 446 * we are considering adapting the targetType to adapterType. 447 * Trivial differences are those which could be ignored by the JVM 448 * without subverting the verifier. Otherwise, adaptable differences 449 * are ones for which we could create an adapter to make the type change. 450 * Return zero if there are no differences (other than trivial ones). 451 * Return 1+N if N is the only adaptable argument difference. 452 * Return the -2-N where N is the first of several adaptable 453 * argument differences. 454 * Return -1 if there there are differences which are not adaptable. 455 */ 456 private static int diffTypes(MethodType adapterType, 457 MethodType targetType, 458 boolean raw) { 459 int diff; 460 diff = diffReturnTypes(adapterType, targetType, raw); 461 if (diff != 0) return diff; 462 int nargs = adapterType.parameterCount(); 463 if (nargs != targetType.parameterCount()) 464 return -1; 465 diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw); 466 //System.out.println("diff "+adapterType); 467 //System.out.println(" "+diff+" "+targetType); 468 return diff; 469 } 470 private static int diffReturnTypes(MethodType adapterType, 471 MethodType targetType, 472 boolean raw) { 473 Class<?> src = targetType.returnType(); 474 Class<?> dst = adapterType.returnType(); 475 if ((!raw 476 ? VerifyType.canPassUnchecked(src, dst) 477 : VerifyType.canPassRaw(src, dst) 478 ) > 0) 479 return 0; // no significant difference 480 if (raw && !src.isPrimitive() && !dst.isPrimitive()) 481 return 0; // can force a reference return (very carefully!) 482 //if (false) return 1; // never adaptable! 483 return -1; // some significant difference 484 } 485 private static int diffParamTypes(MethodType adapterType, int astart, 486 MethodType targetType, int tstart, 487 int nargs, boolean raw) { 488 assert(nargs >= 0); 489 int res = 0; 490 for (int i = 0; i < nargs; i++) { 491 Class<?> src = adapterType.parameterType(astart+i); 492 Class<?> dest = targetType.parameterType(tstart+i); 493 if ((!raw 494 ? VerifyType.canPassUnchecked(src, dest) 495 : VerifyType.canPassRaw(src, dest) 496 ) <= 0) { 497 // found a difference; is it the only one so far? 498 if (res != 0) 499 return -1-res; // return -2-i for prev. i 500 res = 1+i; 501 } 502 } 503 return res; 504 } 505 506 /** Can a retyping adapter (alone) validly convert the target to newType? */ 507 static boolean canRetypeOnly(MethodType newType, MethodType targetType) { 508 return canRetype(newType, targetType, false); 509 } 510 /** Can a retyping adapter (alone) convert the target to newType? 511 * It is allowed to widen subword types and void to int, to make bitwise 512 * conversions between float/int and double/long, and to perform unchecked 513 * reference conversions on return. This last feature requires that the 514 * caller be trusted, and perform explicit cast conversions on return values. 515 */ 516 static boolean canRetypeRaw(MethodType newType, MethodType targetType) { 517 return canRetype(newType, targetType, true); 518 } 519 static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) { 520 if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)) return false; 521 int diff = diffTypes(newType, targetType, raw); 522 // %%% This assert is too strong. Factor diff into VerifyType and reconcile. 523 assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType)); 524 return diff == 0; 525 } 526 527 /** Factory method: Performs no conversions; simply retypes the adapter. 528 * Allows unchecked argument conversions pairwise, if they are safe. 529 * Returns null if not possible. 530 */ 531 static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) { 532 return makeRetype(newType, target, false); 533 } 534 static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) { 535 return makeRetype(newType, target, true); 536 } 537 static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) { 538 MethodType oldType = target.type(); 539 if (oldType == newType) return target; 540 if (!canRetype(newType, oldType, raw)) 541 return null; 542 // TO DO: clone the target guy, whatever he is, with new type. 543 return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY)); 544 } 545 546 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { 547 MethodType type = target.type(); 548 int last = type.parameterCount() - 1; 549 if (type.parameterType(last) != arrayType) 550 target = target.asType(type.changeParameterType(last, arrayType)); 551 target = target.asFixedArity(); // make sure this attribute is turned off 552 return new AsVarargsCollector(target, arrayType); 553 } 554 555 static class AsVarargsCollector extends AdapterMethodHandle { 556 final MethodHandle target; 557 final Class<?> arrayType; 558 MethodHandle cache; 559 560 AsVarargsCollector(MethodHandle target, Class<?> arrayType) { 561 super(target, target.type(), makeConv(OP_RETYPE_ONLY)); 562 this.target = target; 563 this.arrayType = arrayType; 564 this.cache = target.asCollector(arrayType, 0); 565 } 566 567 @Override 568 public boolean isVarargsCollector() { 569 return true; 570 } 571 572 @Override 573 public MethodHandle asFixedArity() { 574 return target; 575 } 576 577 @Override 578 public MethodHandle asType(MethodType newType) { 579 MethodType type = this.type(); 580 int collectArg = type.parameterCount() - 1; 581 int newArity = newType.parameterCount(); 582 if (newArity == collectArg+1 && 583 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { 584 // if arity and trailing parameter are compatible, do normal thing 585 return super.asType(newType); 586 } 587 // check cache 588 if (cache.type().parameterCount() == newArity) 589 return cache.asType(newType); 590 // build and cache a collector 591 int arrayLength = newArity - collectArg; 592 MethodHandle collector; 593 try { 594 collector = target.asCollector(arrayType, arrayLength); 595 } catch (IllegalArgumentException ex) { 596 throw new WrongMethodTypeException("cannot build collector"); 597 } 598 cache = collector; 599 return collector.asType(newType); 600 } 601 } 602 603 /** Can a checkcast adapter validly convert the target to newType? 604 * The JVM supports all kind of reference casts, even silly ones. 605 */ 606 static boolean canCheckCast(MethodType newType, MethodType targetType, 607 int arg, Class<?> castType) { 608 if (!convOpSupported(OP_CHECK_CAST)) return false; 609 Class<?> src = newType.parameterType(arg); 610 Class<?> dst = targetType.parameterType(arg); 611 if (!canCheckCast(src, castType) 612 || !VerifyType.isNullConversion(castType, dst)) 613 return false; 614 int diff = diffTypes(newType, targetType, false); 615 return (diff == arg+1) || (diff == 0); // arg is sole non-trivial diff 616 } 617 /** Can an primitive conversion adapter validly convert src to dst? */ 618 static boolean canCheckCast(Class<?> src, Class<?> dst) { 619 return (!src.isPrimitive() && !dst.isPrimitive()); 620 } 621 622 /** Factory method: Forces a cast at the given argument. 623 * The castType is the target of the cast, and can be any type 624 * with a null conversion to the corresponding target parameter. 625 * Return null if this cannot be done. 626 */ 627 static MethodHandle makeCheckCast(MethodType newType, MethodHandle target, 628 int arg, Class<?> castType) { 629 if (!canCheckCast(newType, target.type(), arg, castType)) 630 return null; 631 long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT); 632 return new AdapterMethodHandle(target, newType, conv, castType); 633 } 634 635 /** Can an primitive conversion adapter validly convert the target to newType? 636 * The JVM currently supports all conversions except those between 637 * floating and integral types. 638 */ 639 static boolean canPrimCast(MethodType newType, MethodType targetType, 640 int arg, Class<?> convType) { 641 if (!convOpSupported(OP_PRIM_TO_PRIM)) return false; 642 Class<?> src = newType.parameterType(arg); 643 Class<?> dst = targetType.parameterType(arg); 644 if (!canPrimCast(src, convType) 645 || !VerifyType.isNullConversion(convType, dst)) 646 return false; 647 int diff = diffTypes(newType, targetType, false); 648 return (diff == arg+1); // arg is sole non-trivial diff 649 } 650 /** Can an primitive conversion adapter validly convert src to dst? */ 651 static boolean canPrimCast(Class<?> src, Class<?> dst) { 652 if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) { 653 return false; 654 } else { 655 boolean sflt = Wrapper.forPrimitiveType(src).isFloating(); 656 boolean dflt = Wrapper.forPrimitiveType(dst).isFloating(); 657 return !(sflt | dflt); // no float support at present 658 } 659 } 660 661 /** Factory method: Truncate the given argument with zero or sign extension, 662 * and/or convert between single and doubleword versions of integer or float. 663 * The convType is the target of the conversion, and can be any type 664 * with a null conversion to the corresponding target parameter. 665 * Return null if this cannot be done. 666 */ 667 static MethodHandle makePrimCast(MethodType newType, MethodHandle target, 668 int arg, Class<?> convType) { 669 Class<?> src = newType.parameterType(arg); 670 if (canPrimCast(src, convType)) 671 return makePrimCastOnly(newType, target, arg, convType); 672 Class<?> dst = convType; 673 boolean sflt = Wrapper.forPrimitiveType(src).isFloating(); 674 boolean dflt = Wrapper.forPrimitiveType(dst).isFloating(); 675 if (sflt | dflt) { 676 MethodHandle convMethod; 677 if (sflt) 678 convMethod = ((src == double.class) 679 ? ValueConversions.convertFromDouble(dst) 680 : ValueConversions.convertFromFloat(dst)); 681 else 682 convMethod = ((dst == double.class) 683 ? ValueConversions.convertToDouble(src) 684 : ValueConversions.convertToFloat(src)); 685 long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst)); 686 return new AdapterMethodHandle(target, newType, conv, convMethod); 687 } 688 throw new InternalError("makePrimCast"); 689 } 690 static MethodHandle makePrimCastOnly(MethodType newType, MethodHandle target, 691 int arg, Class<?> convType) { 692 MethodType oldType = target.type(); 693 if (!canPrimCast(newType, oldType, arg, convType)) 694 return null; 695 Class<?> src = newType.parameterType(arg); 696 long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType)); 697 return new AdapterMethodHandle(target, newType, conv); 698 } 699 700 /** Can an unboxing conversion validly convert src to dst? 701 * The JVM currently supports all kinds of casting and unboxing. 702 * The convType is the unboxed type; it can be either a primitive or wrapper. 703 */ 704 static boolean canUnboxArgument(MethodType newType, MethodType targetType, 705 int arg, Class<?> convType, int level) { 706 if (!convOpSupported(OP_REF_TO_PRIM)) return false; 707 Class<?> src = newType.parameterType(arg); 708 Class<?> dst = targetType.parameterType(arg); 709 Class<?> boxType = Wrapper.asWrapperType(convType); 710 convType = Wrapper.asPrimitiveType(convType); 711 if (!canCheckCast(src, boxType) 712 || boxType == convType 713 || !VerifyType.isNullConversion(convType, dst)) 714 return false; 715 int diff = diffTypes(newType, targetType, false); 716 return (diff == arg+1); // arg is sole non-trivial diff 717 } 718 /** Can an primitive unboxing adapter validly convert src to dst? */ 719 static boolean canUnboxArgument(Class<?> src, Class<?> dst, int level) { 720 assert(dst.isPrimitive()); 721 // if we have JVM support for boxing, we can also do complex unboxing 722 if (convOpSupported(OP_PRIM_TO_REF)) return true; 723 Wrapper dw = Wrapper.forPrimitiveType(dst); 724 // Level 0 means cast and unbox. This works on any reference. 725 if (level == 0) return !src.isPrimitive(); 726 assert(level >= 0 && level <= 2); 727 // Levels 1 and 2 allow widening and/or narrowing conversions. 728 // These are not supported directly by the JVM. 729 // But if the input reference is monomorphic, we can do it. 730 return dw.wrapperType() == src; 731 } 732 733 /** Factory method: Unbox the given argument. 734 * Return null if this cannot be done. 735 */ 736 static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target, 737 int arg, Class<?> convType, int level) { 738 MethodType oldType = target.type(); 739 Class<?> src = newType.parameterType(arg); 740 Class<?> dst = oldType.parameterType(arg); 741 Class<?> boxType = Wrapper.asWrapperType(convType); 742 Class<?> primType = Wrapper.asPrimitiveType(convType); 743 if (!canUnboxArgument(newType, oldType, arg, convType, level)) 744 return null; 745 MethodType castDone = newType; 746 if (!VerifyType.isNullConversion(src, boxType)) { 747 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int 748 if (level != 0) { 749 // must include additional conversions 750 if (src == Object.class || !Wrapper.isWrapperType(src)) { 751 // src must be examined at runtime, to detect Byte, Character, etc. 752 MethodHandle unboxMethod = (level == 1 753 ? ValueConversions.unbox(dst) 754 : ValueConversions.unboxCast(dst)); 755 long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst)); 756 return new AdapterMethodHandle(target, newType, conv, unboxMethod); 757 } 758 // Example: Byte->int 759 // Do this by reformulating the problem to Byte->byte. 760 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType(); 761 MethodType midType = newType.changeParameterType(arg, srcPrim); 762 MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0); 763 if (canPrimCast(midType, oldType, arg, dst)) 764 fixPrim = makePrimCast(midType, target, arg, dst); 765 else 766 fixPrim = target; 767 return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0); 768 } 769 castDone = newType.changeParameterType(arg, boxType); 770 } 771 long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType)); 772 MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType); 773 if (castDone == newType) 774 return adapter; 775 return makeCheckCast(newType, adapter, arg, boxType); 776 } 777 778 /** Can a boxing conversion validly convert src to dst? */ 779 static boolean canBoxArgument(MethodType newType, MethodType targetType, 780 int arg, Class<?> convType) { 781 if (!convOpSupported(OP_PRIM_TO_REF)) return false; 782 Class<?> src = newType.parameterType(arg); 783 Class<?> dst = targetType.parameterType(arg); 784 Class<?> boxType = Wrapper.asWrapperType(convType); 785 convType = Wrapper.asPrimitiveType(convType); 786 if (!canCheckCast(boxType, dst) 787 || boxType == convType 788 || !VerifyType.isNullConversion(src, convType)) 789 return false; 790 int diff = diffTypes(newType, targetType, false); 791 return (diff == arg+1); // arg is sole non-trivial diff 792 } 793 794 /** Can an primitive boxing adapter validly convert src to dst? */ 795 static boolean canBoxArgument(Class<?> src, Class<?> dst) { 796 if (!convOpSupported(OP_PRIM_TO_REF)) return false; 797 return (src.isPrimitive() && !dst.isPrimitive()); 798 } 799 800 /** Factory method: Box the given argument. 801 * Return null if this cannot be done. 802 */ 803 static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target, 804 int arg, Class<?> convType) { 805 MethodType oldType = target.type(); 806 Class<?> src = newType.parameterType(arg); 807 Class<?> dst = oldType.parameterType(arg); 808 Class<?> boxType = Wrapper.asWrapperType(convType); 809 Class<?> primType = Wrapper.asPrimitiveType(convType); 810 if (!canBoxArgument(newType, oldType, arg, convType)) { 811 return null; 812 } 813 if (!VerifyType.isNullConversion(boxType, dst)) 814 target = makeCheckCast(oldType.changeParameterType(arg, boxType), target, arg, dst); 815 MethodHandle boxerMethod = ValueConversions.box(Wrapper.forPrimitiveType(primType)); 816 long conv = makeConv(OP_PRIM_TO_REF, arg, basicType(primType), T_OBJECT); 817 return new AdapterMethodHandle(target, newType, conv, boxerMethod); 818 } 819 820 /** Can an adapter simply drop arguments to convert the target to newType? */ 821 static boolean canDropArguments(MethodType newType, MethodType targetType, 822 int dropArgPos, int dropArgCount) { 823 if (dropArgCount == 0) 824 return canRetypeOnly(newType, targetType); 825 if (!convOpSupported(OP_DROP_ARGS)) return false; 826 if (diffReturnTypes(newType, targetType, false) != 0) 827 return false; 828 int nptypes = newType.parameterCount(); 829 // parameter types must be the same up to the drop point 830 if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0) 831 return false; 832 int afterPos = dropArgPos + dropArgCount; 833 int afterCount = nptypes - afterPos; 834 if (dropArgPos < 0 || dropArgPos >= nptypes || 835 dropArgCount < 1 || afterPos > nptypes || 836 targetType.parameterCount() != nptypes - dropArgCount) 837 return false; 838 // parameter types after the drop point must also be the same 839 if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0) 840 return false; 841 return true; 842 } 843 844 /** Factory method: Drop selected arguments. 845 * Allow unchecked retyping of remaining arguments, pairwise. 846 * Return null if this is not possible. 847 */ 848 static MethodHandle makeDropArguments(MethodType newType, MethodHandle target, 849 int dropArgPos, int dropArgCount) { 850 if (dropArgCount == 0) 851 return makeRetypeOnly(newType, target); 852 if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount)) 853 return null; 854 // in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ] 855 // out arglist: [0: ...keep1 | dpos: keep2... ] 856 int keep2InPos = dropArgPos + dropArgCount; 857 int dropSlot = newType.parameterSlotDepth(keep2InPos); 858 int keep1InSlot = newType.parameterSlotDepth(dropArgPos); 859 int slotCount = keep1InSlot - dropSlot; 860 assert(slotCount >= dropArgCount); 861 assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount()); 862 long conv = makeDupConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount); 863 return new AdapterMethodHandle(target, newType, conv); 864 } 865 866 /** Can an adapter duplicate an argument to convert the target to newType? */ 867 static boolean canDupArguments(MethodType newType, MethodType targetType, 868 int dupArgPos, int dupArgCount) { 869 if (!convOpSupported(OP_DUP_ARGS)) return false; 870 if (diffReturnTypes(newType, targetType, false) != 0) 871 return false; 872 int nptypes = newType.parameterCount(); 873 if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes) 874 return false; 875 if (targetType.parameterCount() != nptypes + dupArgCount) 876 return false; 877 // parameter types must be the same up to the duplicated arguments 878 if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0) 879 return false; 880 // duplicated types must be, well, duplicates 881 if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0) 882 return false; 883 return true; 884 } 885 886 /** Factory method: Duplicate the selected argument. 887 * Return null if this is not possible. 888 */ 889 static MethodHandle makeDupArguments(MethodType newType, MethodHandle target, 890 int dupArgPos, int dupArgCount) { 891 if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount)) 892 return null; 893 if (dupArgCount == 0) 894 return target; 895 // in arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ] 896 // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ] 897 int keep2InPos = dupArgPos + dupArgCount; 898 int dupSlot = newType.parameterSlotDepth(keep2InPos); 899 int keep1InSlot = newType.parameterSlotDepth(dupArgPos); 900 int slotCount = keep1InSlot - dupSlot; 901 assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount()); 902 long conv = makeDupConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount); 903 return new AdapterMethodHandle(target, newType, conv); 904 } 905 906 /** Can an adapter swap two arguments to convert the target to newType? */ 907 static boolean canSwapArguments(MethodType newType, MethodType targetType, 908 int swapArg1, int swapArg2) { 909 if (!convOpSupported(OP_SWAP_ARGS)) return false; 910 if (diffReturnTypes(newType, targetType, false) != 0) 911 return false; 912 if (swapArg1 >= swapArg2) return false; // caller resp 913 int nptypes = newType.parameterCount(); 914 if (targetType.parameterCount() != nptypes) 915 return false; 916 if (swapArg1 < 0 || swapArg2 >= nptypes) 917 return false; 918 if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0) 919 return false; 920 if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0) 921 return false; 922 if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0) 923 return false; 924 if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0) 925 return false; 926 if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0) 927 return false; 928 return true; 929 } 930 931 /** Factory method: Swap the selected arguments. 932 * Return null if this is not possible. 933 */ 934 static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target, 935 int swapArg1, int swapArg2) { 936 if (swapArg1 == swapArg2) 937 return target; 938 if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; } 939 if (type2size(newType.parameterType(swapArg1)) != 940 type2size(newType.parameterType(swapArg2))) { 941 // turn a swap into a pair of rotates: 942 // [x a b c y] rot2(-1,argc=5) => [a b c y x] rot1(+1,argc=4) => target[y a b c x] 943 int argc = swapArg2 - swapArg1 + 1; 944 final int ROT = 1; 945 ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList()); 946 Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT); 947 MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params); 948 MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT); 949 assert(rot1 != null); 950 if (argc == 2) return rot1; 951 MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT); 952 assert(rot2 != null); 953 return rot2; 954 } 955 if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2)) 956 return null; 957 Class<?> type1 = newType.parameterType(swapArg1); 958 Class<?> type2 = newType.parameterType(swapArg2); 959 // in arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ] 960 // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ] 961 int swapSlot2 = newType.parameterSlotDepth(swapArg2 + 1); 962 long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(type1), swapSlot2, basicType(type2)); 963 return new AdapterMethodHandle(target, newType, conv); 964 } 965 966 static int positiveRotation(int argCount, int rotateBy) { 967 assert(argCount > 0); 968 if (rotateBy >= 0) { 969 if (rotateBy < argCount) 970 return rotateBy; 971 return rotateBy % argCount; 972 } else if (rotateBy >= -argCount) { 973 return rotateBy + argCount; 974 } else { 975 return (-1-((-1-rotateBy) % argCount)) + argCount; 976 } 977 } 978 979 final static int MAX_ARG_ROTATION = 1; 980 981 /** Can an adapter rotate arguments to convert the target to newType? */ 982 static boolean canRotateArguments(MethodType newType, MethodType targetType, 983 int firstArg, int argCount, int rotateBy) { 984 if (!convOpSupported(OP_ROT_ARGS)) return false; 985 rotateBy = positiveRotation(argCount, rotateBy); 986 if (rotateBy == 0) return false; // no rotation 987 if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION) 988 return false; // too many argument positions 989 // Rotate incoming args right N to the out args, N in 1..(argCouunt-1). 990 if (diffReturnTypes(newType, targetType, false) != 0) 991 return false; 992 int nptypes = newType.parameterCount(); 993 if (targetType.parameterCount() != nptypes) 994 return false; 995 if (firstArg < 0 || firstArg >= nptypes) return false; 996 int argLimit = firstArg + argCount; 997 if (argLimit > nptypes) return false; 998 if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0) 999 return false; 1000 int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy; 1001 // swap new chunk1 with target chunk2 1002 if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0) 1003 return false; 1004 // swap new chunk2 with target chunk1 1005 if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0) 1006 return false; 1007 return true; 1008 } 1009 1010 /** Factory method: Rotate the selected argument range. 1011 * Return null if this is not possible. 1012 */ 1013 static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target, 1014 int firstArg, int argCount, int rotateBy) { 1015 rotateBy = positiveRotation(argCount, rotateBy); 1016 if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy)) 1017 return null; 1018 // Decide whether it should be done as a right or left rotation, 1019 // on the JVM stack. Return the number of stack slots to rotate by, 1020 // positive if right, negative if left. 1021 int limit = firstArg + argCount; 1022 int depth0 = newType.parameterSlotDepth(firstArg); 1023 int depth1 = newType.parameterSlotDepth(limit-rotateBy); 1024 int depth2 = newType.parameterSlotDepth(limit); 1025 int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0); 1026 int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0); 1027 // From here on out, it assumes a single-argument shift. 1028 assert(MAX_ARG_ROTATION == 1); 1029 int srcArg, dstArg; 1030 int dstSlot; 1031 int moveChunk; 1032 if (rotateBy == 1) { 1033 // Rotate right/down N (rotateBy = +N, N small, c2 small): 1034 // in arglist: [0: ...keep1 | arg1: c1... | limit-N: c2 | limit: keep2... ] 1035 // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1... | limit: keep2... ] 1036 srcArg = limit-1; 1037 dstArg = firstArg; 1038 //dstSlot = depth0 - chunk2Slots; //chunk2Slots is not relevant 1039 dstSlot = depth0 + MethodHandleNatives.OP_ROT_ARGS_DOWN_LIMIT_BIAS; 1040 moveChunk = chunk2Slots; 1041 } else { 1042 // Rotate left/up N (rotateBy = -N, N small, c1 small): 1043 // in arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2... | limit: keep2... ] 1044 // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ] 1045 srcArg = firstArg; 1046 dstArg = limit-1; 1047 dstSlot = depth2; 1048 moveChunk = chunk1Slots; 1049 } 1050 byte srcType = basicType(newType.parameterType(srcArg)); 1051 byte dstType = basicType(newType.parameterType(dstArg)); 1052 assert(moveChunk == type2size(srcType)); 1053 long conv = makeSwapConv(OP_ROT_ARGS, srcArg, srcType, dstSlot, dstType); 1054 return new AdapterMethodHandle(target, newType, conv); 1055 } 1056 1057 /** Can an adapter spread an argument to convert the target to newType? */ 1058 static boolean canSpreadArguments(MethodType newType, MethodType targetType, 1059 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 1060 if (!convOpSupported(OP_SPREAD_ARGS)) return false; 1061 if (diffReturnTypes(newType, targetType, false) != 0) 1062 return false; 1063 int nptypes = newType.parameterCount(); 1064 // parameter types must be the same up to the spread point 1065 if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0) 1066 return false; 1067 int afterPos = spreadArgPos + spreadArgCount; 1068 int afterCount = nptypes - (spreadArgPos + 1); 1069 if (spreadArgPos < 0 || spreadArgPos >= nptypes || 1070 spreadArgCount < 0 || 1071 targetType.parameterCount() != afterPos + afterCount) 1072 return false; 1073 // parameter types after the spread point must also be the same 1074 if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0) 1075 return false; 1076 // match the array element type to the spread arg types 1077 Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos); 1078 if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType)) 1079 return false; 1080 for (int i = 0; i < spreadArgCount; i++) { 1081 Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i); 1082 Class<?> dst = targetType.parameterType(spreadArgPos + i); 1083 if (src == null || !canConvertArgument(src, dst, 1)) 1084 return false; 1085 } 1086 return true; 1087 } 1088 1089 1090 /** Factory method: Spread selected argument. */ 1091 static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target, 1092 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 1093 // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType 1094 MethodType targetType = target.type(); 1095 assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount)) 1096 : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = " 1097 + Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount); 1098 // dest is not significant; remove? 1099 int dest = T_VOID; 1100 for (int i = 0; i < spreadArgCount; i++) { 1101 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 1102 if (arg == null) arg = Object.class; 1103 int dest2 = basicType(arg); 1104 if (dest == T_VOID) dest = dest2; 1105 else if (dest != dest2) dest = T_VOID; 1106 if (dest == T_VOID) break; 1107 targetType = targetType.changeParameterType(spreadArgPos + i, arg); 1108 } 1109 target = target.asType(targetType); 1110 int arrayArgSize = 1; // always a reference 1111 // in arglist: [0: ...keep1 | spos: spreadArg | spos+1: keep2... ] 1112 // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ] 1113 int keep2OutPos = spreadArgPos + spreadArgCount; 1114 int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos); // leading edge of |spread...| 1115 int spreadSlot = targetType.parameterSlotDepth(keep2OutPos); // trailing edge of |spread...| 1116 assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+arrayArgSize)); 1117 int slotCount = keep1OutSlot - spreadSlot; // slots in |spread...| 1118 assert(slotCount >= spreadArgCount); 1119 int stackMove = - arrayArgSize + slotCount; // pop array, push N slots 1120 long conv = makeSpreadConv(OP_SPREAD_ARGS, spreadArgPos, T_OBJECT, dest, stackMove); 1121 MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType); 1122 assert(res.type().parameterType(spreadArgPos) == spreadArgType); 1123 return res; 1124 } 1125 1126 /** Can an adapter collect a series of arguments, replacing them by zero or one results? */ 1127 static boolean canCollectArguments(MethodType targetType, 1128 MethodType collectorType, int collectArgPos, boolean retainOriginalArgs) { 1129 if (!convOpSupported(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS)) return false; 1130 int collectArgCount = collectorType.parameterCount(); 1131 Class<?> rtype = collectorType.returnType(); 1132 assert(rtype == void.class || targetType.parameterType(collectArgPos) == rtype) 1133 // [(Object)Object[], (Object[])Object[], 0, 1] 1134 : Arrays.asList(targetType, collectorType, collectArgPos, collectArgCount) 1135 ; 1136 return true; 1137 } 1138 1139 /** Factory method: Collect or filter selected argument(s). */ 1140 static MethodHandle makeCollectArguments(MethodHandle target, 1141 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 1142 assert(canCollectArguments(target.type(), collector.type(), collectArgPos, retainOriginalArgs)); 1143 MethodType targetType = target.type(); 1144 MethodType collectorType = collector.type(); 1145 int collectArgCount = collectorType.parameterCount(); 1146 Class<?> collectValType = collectorType.returnType(); 1147 int collectValCount = (collectValType == void.class ? 0 : 1); 1148 int collectValSlots = collectorType.returnSlotCount(); 1149 MethodType newType = targetType 1150 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 1151 if (!retainOriginalArgs) { 1152 newType = newType 1153 .insertParameterTypes(collectArgPos, collectorType.parameterList()); 1154 } else { 1155 // parameter types at the fold point must be the same 1156 assert(diffParamTypes(newType, collectArgPos, targetType, collectValCount, collectArgCount, false) == 0) 1157 : Arrays.asList(target, collector, collectArgPos, retainOriginalArgs); 1158 } 1159 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 1160 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 1161 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 1162 int keep2InPos = collectArgPos + collectArgCount; 1163 int keep1InSlot = newType.parameterSlotDepth(collectArgPos); // leading edge of |collect...| 1164 int collectSlot = newType.parameterSlotDepth(keep2InPos); // trailing edge of |collect...| 1165 int slotCount = keep1InSlot - collectSlot; // slots in |collect...| 1166 assert(slotCount >= collectArgCount); 1167 assert(collectSlot == targetType.parameterSlotDepth( 1168 collectArgPos + collectValCount + (retainOriginalArgs ? collectArgCount : 0) )); 1169 int dest = basicType(collectValType); 1170 int src = T_VOID; 1171 // src is not significant; remove? 1172 for (int i = 0; i < collectArgCount; i++) { 1173 int src2 = basicType(collectorType.parameterType(i)); 1174 if (src == T_VOID) src = src2; 1175 else if (src != src2) src = T_VOID; 1176 if (src == T_VOID) break; 1177 } 1178 int stackMove = collectValSlots; // push 0..2 results 1179 if (!retainOriginalArgs) stackMove -= slotCount; // pop N arguments 1180 int lastCollectArg = keep2InPos-1; 1181 long conv = makeSpreadConv(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS, 1182 lastCollectArg, src, dest, stackMove); 1183 MethodHandle res = new AdapterMethodHandle(target, newType, conv, collector); 1184 assert(res.type().parameterList().subList(collectArgPos, collectArgPos+collectArgCount) 1185 .equals(collector.type().parameterList())); 1186 return res; 1187 } 1188 1189 @Override 1190 String debugString() { 1191 return getNameString(nonAdapter((MethodHandle)vmtarget), this); 1192 } 1193 1194 private static MethodHandle nonAdapter(MethodHandle mh) { 1195 while (mh instanceof AdapterMethodHandle) { 1196 mh = (MethodHandle) mh.vmtarget; 1197 } 1198 return mh; 1199 } 1200 }