1 /*
   2  * Copyright (c) 2014, 2016, 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.Wrapper;
  29 
  30 import java.lang.ref.SoftReference;
  31 import java.util.Arrays;
  32 import java.util.Collections;
  33 import java.util.concurrent.ConcurrentHashMap;
  34 
  35 import static java.lang.invoke.LambdaForm.*;
  36 import static java.lang.invoke.LambdaForm.BasicType.*;
  37 import static java.lang.invoke.MethodHandleImpl.Intrinsic;
  38 import static java.lang.invoke.MethodHandleImpl.NF_loop;
  39 
  40 /** Transforms on LFs.
  41  *  A lambda-form editor can derive new LFs from its base LF.
  42  *  The editor can cache derived LFs, which simplifies the reuse of their underlying bytecodes.
  43  *  To support this caching, a LF has an optional pointer to its editor.
  44  */
  45 class LambdaFormEditor {
  46     final LambdaForm lambdaForm;
  47 
  48     private LambdaFormEditor(LambdaForm lambdaForm) {
  49         this.lambdaForm = lambdaForm;
  50     }
  51 
  52     // Factory method.
  53     static LambdaFormEditor lambdaFormEditor(LambdaForm lambdaForm) {
  54         // TO DO:  Consider placing intern logic here, to cut down on duplication.
  55         // lambdaForm = findPreexistingEquivalent(lambdaForm)
  56 
  57         // Always use uncustomized version for editing.
  58         // It helps caching and customized LambdaForms reuse transformCache field to keep a link to uncustomized version.
  59         return new LambdaFormEditor(lambdaForm.uncustomize());
  60     }
  61 
  62     /** A description of a cached transform, possibly associated with the result of the transform.
  63      *  The logical content is a sequence of byte values, starting with a kind value.
  64      *  The sequence is unterminated, ending with an indefinite number of zero bytes.
  65      *  Sequences that are simple (short enough and with small enough values) pack into a 64-bit long.
  66      */
  67     private static final class Transform extends SoftReference<LambdaForm> {
  68         final long packedBytes;
  69         final byte[] fullBytes;
  70 
  71         // maybe add more for guard with test, catch exception, pointwise type conversions
  72         private static final byte
  73                 BIND_ARG = 1,
  74                 ADD_ARG = 2,
  75                 DUP_ARG = 3,
  76                 SPREAD_ARGS = 4,
  77                 FILTER_ARG = 5,
  78                 FILTER_RETURN = 6,
  79                 FILTER_RETURN_TO_ZERO = 7,
  80                 COLLECT_ARGS = 8,
  81                 COLLECT_ARGS_TO_VOID = 9,
  82                 COLLECT_ARGS_TO_ARRAY = 10,
  83                 FOLD_ARGS = 11,
  84                 FOLD_ARGS_TO_VOID = 12,
  85                 PERMUTE_ARGS = 13,
  86                 LOCAL_TYPES = 14,
  87                 FOLD_SELECT_ARGS = 15,
  88                 FOLD_SELECT_ARGS_TO_VOID = 16;
  89 
  90         private static final boolean STRESS_TEST = false; // turn on to disable most packing
  91         private static final int
  92                 PACKED_BYTE_SIZE = (STRESS_TEST ? 2 : 4),
  93                 PACKED_BYTE_MASK = (1 << PACKED_BYTE_SIZE) - 1,
  94                 PACKED_BYTE_MAX_LENGTH = (STRESS_TEST ? 3 : 64 / PACKED_BYTE_SIZE);
  95 
  96         private static long packedBytes(byte[] bytes) {
  97             if (bytes.length > PACKED_BYTE_MAX_LENGTH)  return 0;
  98             long pb = 0;
  99             int bitset = 0;
 100             for (int i = 0; i < bytes.length; i++) {
 101                 int b = bytes[i] & 0xFF;
 102                 bitset |= b;
 103                 pb |= (long)b << (i * PACKED_BYTE_SIZE);
 104             }
 105             if (!inRange(bitset))
 106                 return 0;
 107             return pb;
 108         }
 109         private static long packedBytes(int b0, int b1) {
 110             assert(inRange(b0 | b1));
 111             return (  (b0 << 0*PACKED_BYTE_SIZE)
 112                     | (b1 << 1*PACKED_BYTE_SIZE));
 113         }
 114         private static long packedBytes(int b0, int b1, int b2) {
 115             assert(inRange(b0 | b1 | b2));
 116             return (  (b0 << 0*PACKED_BYTE_SIZE)
 117                     | (b1 << 1*PACKED_BYTE_SIZE)
 118                     | (b2 << 2*PACKED_BYTE_SIZE));
 119         }
 120         private static long packedBytes(int b0, int b1, int b2, int b3) {
 121             assert(inRange(b0 | b1 | b2 | b3));
 122             return (  (b0 << 0*PACKED_BYTE_SIZE)
 123                     | (b1 << 1*PACKED_BYTE_SIZE)
 124                     | (b2 << 2*PACKED_BYTE_SIZE)
 125                     | (b3 << 3*PACKED_BYTE_SIZE));
 126         }
 127         private static boolean inRange(int bitset) {
 128             assert((bitset & 0xFF) == bitset);  // incoming values must fit in *unsigned* byte
 129             return ((bitset & ~PACKED_BYTE_MASK) == 0);
 130         }
 131         private static byte[] fullBytes(int... byteValues) {
 132             byte[] bytes = new byte[byteValues.length];
 133             int i = 0;
 134             for (int bv : byteValues) {
 135                 bytes[i++] = bval(bv);
 136             }
 137             assert(packedBytes(bytes) == 0);
 138             return bytes;
 139         }
 140 
 141         private Transform(long packedBytes, byte[] fullBytes, LambdaForm result) {
 142             super(result);
 143             this.packedBytes = packedBytes;
 144             this.fullBytes = fullBytes;
 145         }
 146         private Transform(long packedBytes) {
 147             this(packedBytes, null, null);
 148             assert(packedBytes != 0);
 149         }
 150         private Transform(byte[] fullBytes) {
 151             this(0, fullBytes, null);
 152         }
 153 
 154         private static byte bval(int b) {
 155             assert((b & 0xFF) == b);  // incoming value must fit in *unsigned* byte
 156             return (byte)b;
 157         }
 158         static Transform of(byte k, int b1) {
 159             byte b0 = bval(k);
 160             if (inRange(b0 | b1))
 161                 return new Transform(packedBytes(b0, b1));
 162             else
 163                 return new Transform(fullBytes(b0, b1));
 164         }
 165         static Transform of(byte b0, int b1, int b2) {
 166             if (inRange(b0 | b1 | b2))
 167                 return new Transform(packedBytes(b0, b1, b2));
 168             else
 169                 return new Transform(fullBytes(b0, b1, b2));
 170         }
 171         static Transform of(byte b0, int b1, int b2, int b3) {
 172             if (inRange(b0 | b1 | b2 | b3))
 173                 return new Transform(packedBytes(b0, b1, b2, b3));
 174             else
 175                 return new Transform(fullBytes(b0, b1, b2, b3));
 176         }
 177         private static final byte[] NO_BYTES = {};
 178         static Transform of(byte kind, int... b123) {
 179             return ofBothArrays(kind, b123, NO_BYTES);
 180         }
 181         static Transform of(byte kind, int b1, byte[] b234) {
 182             return ofBothArrays(kind, new int[]{ b1 }, b234);
 183         }
 184         static Transform of(byte kind, int b1, int b2, byte[] b345) {
 185             return ofBothArrays(kind, new int[]{ b1, b2 }, b345);
 186         }
 187         private static Transform ofBothArrays(byte kind, int[] b123, byte[] b456) {
 188             byte[] fullBytes = new byte[1 + b123.length + b456.length];
 189             int i = 0;
 190             fullBytes[i++] = bval(kind);
 191             for (int bv : b123) {
 192                 fullBytes[i++] = bval(bv);
 193             }
 194             for (byte bv : b456) {
 195                 fullBytes[i++] = bv;
 196             }
 197             long packedBytes = packedBytes(fullBytes);
 198             if (packedBytes != 0)
 199                 return new Transform(packedBytes);
 200             else
 201                 return new Transform(fullBytes);
 202         }
 203 
 204         Transform withResult(LambdaForm result) {
 205             return new Transform(this.packedBytes, this.fullBytes, result);
 206         }
 207 
 208         @Override
 209         public boolean equals(Object obj) {
 210             return obj instanceof Transform && equals((Transform)obj);
 211         }
 212         public boolean equals(Transform that) {
 213             return this.packedBytes == that.packedBytes && Arrays.equals(this.fullBytes, that.fullBytes);
 214         }
 215         @Override
 216         public int hashCode() {
 217             if (packedBytes != 0) {
 218                 assert(fullBytes == null);
 219                 return Long.hashCode(packedBytes);
 220             }
 221             return Arrays.hashCode(fullBytes);
 222         }
 223         @Override
 224         public String toString() {
 225             StringBuilder buf = new StringBuilder();
 226             long bits = packedBytes;
 227             if (bits != 0) {
 228                 buf.append("(");
 229                 while (bits != 0) {
 230                     buf.append(bits & PACKED_BYTE_MASK);
 231                     bits >>>= PACKED_BYTE_SIZE;
 232                     if (bits != 0)  buf.append(",");
 233                 }
 234                 buf.append(")");
 235             }
 236             if (fullBytes != null) {
 237                 buf.append("unpacked");
 238                 buf.append(Arrays.toString(fullBytes));
 239             }
 240             LambdaForm result = get();
 241             if (result != null) {
 242                 buf.append(" result=");
 243                 buf.append(result);
 244             }
 245             return buf.toString();
 246         }
 247     }
 248 
 249     /** Find a previously cached transform equivalent to the given one, and return its result. */
 250     private LambdaForm getInCache(Transform key) {
 251         assert(key.get() == null);
 252         // The transformCache is one of null, Transform, Transform[], or ConcurrentHashMap.
 253         Object c = lambdaForm.transformCache;
 254         Transform k = null;
 255         if (c instanceof ConcurrentHashMap) {
 256             @SuppressWarnings("unchecked")
 257             ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
 258             k = m.get(key);
 259         } else if (c == null) {
 260             return null;
 261         } else if (c instanceof Transform) {
 262             // one-element cache avoids overhead of an array
 263             Transform t = (Transform)c;
 264             if (t.equals(key))  k = t;
 265         } else {
 266             Transform[] ta = (Transform[])c;
 267             for (int i = 0; i < ta.length; i++) {
 268                 Transform t = ta[i];
 269                 if (t == null)  break;
 270                 if (t.equals(key)) { k = t; break; }
 271             }
 272         }
 273         assert(k == null || key.equals(k));
 274         return (k != null) ? k.get() : null;
 275     }
 276 
 277     /** Arbitrary but reasonable limits on Transform[] size for cache. */
 278     private static final int MIN_CACHE_ARRAY_SIZE = 4, MAX_CACHE_ARRAY_SIZE = 16;
 279 
 280     /** Cache a transform with its result, and return that result.
 281      *  But if an equivalent transform has already been cached, return its result instead.
 282      */
 283     private LambdaForm putInCache(Transform key, LambdaForm form) {
 284         key = key.withResult(form);
 285         for (int pass = 0; ; pass++) {
 286             Object c = lambdaForm.transformCache;
 287             if (c instanceof ConcurrentHashMap) {
 288                 @SuppressWarnings("unchecked")
 289                 ConcurrentHashMap<Transform,Transform> m = (ConcurrentHashMap<Transform,Transform>) c;
 290                 Transform k = m.putIfAbsent(key, key);
 291                 if (k == null) return form;
 292                 LambdaForm result = k.get();
 293                 if (result != null) {
 294                     return result;
 295                 } else {
 296                     if (m.replace(key, k, key)) {
 297                         return form;
 298                     } else {
 299                         continue;
 300                     }
 301                 }
 302             }
 303             assert(pass == 0);
 304             synchronized (lambdaForm) {
 305                 c = lambdaForm.transformCache;
 306                 if (c instanceof ConcurrentHashMap)
 307                     continue;
 308                 if (c == null) {
 309                     lambdaForm.transformCache = key;
 310                     return form;
 311                 }
 312                 Transform[] ta;
 313                 if (c instanceof Transform) {
 314                     Transform k = (Transform)c;
 315                     if (k.equals(key)) {
 316                         LambdaForm result = k.get();
 317                         if (result == null) {
 318                             lambdaForm.transformCache = key;
 319                             return form;
 320                         } else {
 321                             return result;
 322                         }
 323                     } else if (k.get() == null) { // overwrite stale entry
 324                         lambdaForm.transformCache = key;
 325                         return form;
 326                     }
 327                     // expand one-element cache to small array
 328                     ta = new Transform[MIN_CACHE_ARRAY_SIZE];
 329                     ta[0] = k;
 330                     lambdaForm.transformCache = ta;
 331                 } else {
 332                     // it is already expanded
 333                     ta = (Transform[])c;
 334                 }
 335                 int len = ta.length;
 336                 int stale = -1;
 337                 int i;
 338                 for (i = 0; i < len; i++) {
 339                     Transform k = ta[i];
 340                     if (k == null) {
 341                         break;
 342                     }
 343                     if (k.equals(key)) {
 344                         LambdaForm result = k.get();
 345                         if (result == null) {
 346                             ta[i] = key;
 347                             return form;
 348                         } else {
 349                             return result;
 350                         }
 351                     } else if (stale < 0 && k.get() == null) {
 352                         stale = i; // remember 1st stale entry index
 353                     }
 354                 }
 355                 if (i < len || stale >= 0) {
 356                     // just fall through to cache update
 357                 } else if (len < MAX_CACHE_ARRAY_SIZE) {
 358                     len = Math.min(len * 2, MAX_CACHE_ARRAY_SIZE);
 359                     ta = Arrays.copyOf(ta, len);
 360                     lambdaForm.transformCache = ta;
 361                 } else {
 362                     ConcurrentHashMap<Transform, Transform> m = new ConcurrentHashMap<>(MAX_CACHE_ARRAY_SIZE * 2);
 363                     for (Transform k : ta) {
 364                         m.put(k, k);
 365                     }
 366                     lambdaForm.transformCache = m;
 367                     // The second iteration will update for this query, concurrently.
 368                     continue;
 369                 }
 370                 int idx = (stale >= 0) ? stale : i;
 371                 ta[idx] = key;
 372                 return form;
 373             }
 374         }
 375     }
 376 
 377     private LambdaFormBuffer buffer() {
 378         return new LambdaFormBuffer(lambdaForm);
 379     }
 380 
 381     /// Editing methods for method handles.  These need to have fast paths.
 382 
 383     private BoundMethodHandle.SpeciesData oldSpeciesData() {
 384         return BoundMethodHandle.speciesData(lambdaForm);
 385     }
 386     private BoundMethodHandle.SpeciesData newSpeciesData(BasicType type) {
 387         return oldSpeciesData().extendWith(type);
 388     }
 389 
 390     BoundMethodHandle bindArgumentQ(BoundMethodHandle mh, int pos, Object value, MethodHandle unbox) {
 391         assert(mh.speciesData() == oldSpeciesData());
 392         BasicType bt = Q_TYPE;
 393         MethodType type2 = bindArgumentType(mh, pos, bt);
 394         LambdaForm form2 = bindArgumentForm(1+pos);
 395         return mh.copyWithExtendL(type2, form2, value)
 396                  .copyWithExtendL(type2, form2, unbox);
 397     }
 398     BoundMethodHandle bindArgumentL(BoundMethodHandle mh, int pos, Object value) {
 399         assert(mh.speciesData() == oldSpeciesData());
 400         BasicType bt = L_TYPE;
 401         MethodType type2 = bindArgumentType(mh, pos, bt);
 402         LambdaForm form2 = bindArgumentForm(1+pos);
 403         return mh.copyWithExtendL(type2, form2, value);
 404     }
 405     BoundMethodHandle bindArgumentI(BoundMethodHandle mh, int pos, int value) {
 406         assert(mh.speciesData() == oldSpeciesData());
 407         BasicType bt = I_TYPE;
 408         MethodType type2 = bindArgumentType(mh, pos, bt);
 409         LambdaForm form2 = bindArgumentForm(1+pos);
 410         return mh.copyWithExtendI(type2, form2, value);
 411     }
 412 
 413     BoundMethodHandle bindArgumentJ(BoundMethodHandle mh, int pos, long value) {
 414         assert(mh.speciesData() == oldSpeciesData());
 415         BasicType bt = J_TYPE;
 416         MethodType type2 = bindArgumentType(mh, pos, bt);
 417         LambdaForm form2 = bindArgumentForm(1+pos);
 418         return mh.copyWithExtendJ(type2, form2, value);
 419     }
 420 
 421     BoundMethodHandle bindArgumentF(BoundMethodHandle mh, int pos, float value) {
 422         assert(mh.speciesData() == oldSpeciesData());
 423         BasicType bt = F_TYPE;
 424         MethodType type2 = bindArgumentType(mh, pos, bt);
 425         LambdaForm form2 = bindArgumentForm(1+pos);
 426         return mh.copyWithExtendF(type2, form2, value);
 427     }
 428 
 429     BoundMethodHandle bindArgumentD(BoundMethodHandle mh, int pos, double value) {
 430         assert(mh.speciesData() == oldSpeciesData());
 431         BasicType bt = D_TYPE;
 432         MethodType type2 = bindArgumentType(mh, pos, bt);
 433         LambdaForm form2 = bindArgumentForm(1+pos);
 434         return mh.copyWithExtendD(type2, form2, value);
 435     }
 436 
 437     private MethodType bindArgumentType(BoundMethodHandle mh, int pos, BasicType bt) {
 438         assert(mh.form.uncustomize() == lambdaForm);
 439         assert(mh.form.names[1+pos].type == bt);
 440         assert(BasicType.basicType(mh.type().parameterType(pos)) == bt);
 441         return mh.type().dropParameterTypes(pos, pos+1);
 442     }
 443 
 444     /// Editing methods for lambda forms.
 445     // Each editing method can (potentially) cache the edited LF so that it can be reused later.
 446 
 447     LambdaForm bindArgumentForm(int pos) {
 448         Transform key = Transform.of(Transform.BIND_ARG, pos);
 449         LambdaForm form = getInCache(key);
 450         if (form != null) {
 451             assert(form.parameterConstraint(0) == newSpeciesData(lambdaForm.parameterType(pos)));
 452             return form;
 453         }
 454         LambdaFormBuffer buf = buffer();
 455         buf.startEdit();
 456 
 457         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 458         BasicType ptype = lambdaForm.parameterType(pos);
 459         BoundMethodHandle.SpeciesData newData = (ptype != Q_TYPE) ? newSpeciesData(ptype)
 460                                                                   : oldData.extendWith(L_TYPE).extendWith(L_TYPE); // value + unbox MH
 461         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 462         Name newBaseAddress;
 463         NamedFunction getter = newData.getterFunction(oldData.fieldCount());
 464 
 465         if (pos != 0) {
 466             // The newly created LF will run with a different BMH.
 467             // Switch over any pre-existing BMH field references to the new BMH class.
 468             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 469             newBaseAddress = oldBaseAddress.withConstraint(newData);
 470             buf.renameParameter(0, newBaseAddress);
 471             if (ptype == Q_TYPE) {
 472                 // Q-types are stored in boxed form. Unboxing step is required.
 473                 int exprPos = lambdaForm.arity();
 474                 int UNBOX_MH      = exprPos++;
 475                 int BOXED_VALUE   = exprPos++;
 476                 int UNBOXED_VALUE = exprPos++;
 477                 NamedFunction unboxGetter = newData.getterFunction(oldData.fieldCount()+1);
 478                 buf.insertExpression(UNBOX_MH, new Name(unboxGetter, newBaseAddress));
 479                 buf.insertExpression(BOXED_VALUE, new Name(getter, newBaseAddress));
 480                 MethodType unboxInvokerType = MethodType.methodType(Q_TYPE.basicTypeClass(), L_TYPE.basicTypeClass());
 481                 Name unbox = new Name(unboxInvokerType, buf.name(UNBOX_MH), buf.name(BOXED_VALUE));
 482                 buf.insertExpression(UNBOXED_VALUE, unbox);
 483                 buf.replaceParameterByCopy(pos, UNBOXED_VALUE);
 484             } else {
 485                 buf.replaceParameterByNewExpression(pos, new Name(getter, newBaseAddress));
 486             }
 487         } else {
 488             // cannot bind the MH arg itself, unless oldData is empty
 489             assert(oldData == BoundMethodHandle.SpeciesData.EMPTY);
 490             newBaseAddress = new Name(L_TYPE).withConstraint(newData);
 491             buf.replaceParameterByNewExpression(0, new Name(getter, newBaseAddress));
 492             buf.insertParameter(0, newBaseAddress);
 493         }
 494 
 495         form = buf.endEdit();
 496         return putInCache(key, form);
 497     }
 498 
 499     LambdaForm addArgumentForm(int pos, BasicType type) {
 500         Transform key = Transform.of(Transform.ADD_ARG, pos, type.ordinal());
 501         LambdaForm form = getInCache(key);
 502         if (form != null) {
 503             assert(form.arity == lambdaForm.arity+1);
 504             assert(form.parameterType(pos) == type);
 505             return form;
 506         }
 507         LambdaFormBuffer buf = buffer();
 508         buf.startEdit();
 509 
 510         buf.insertParameter(pos, new Name(type));
 511 
 512         form = buf.endEdit();
 513         return putInCache(key, form);
 514     }
 515 
 516     LambdaForm dupArgumentForm(int srcPos, int dstPos) {
 517         Transform key = Transform.of(Transform.DUP_ARG, srcPos, dstPos);
 518         LambdaForm form = getInCache(key);
 519         if (form != null) {
 520             assert(form.arity == lambdaForm.arity-1);
 521             return form;
 522         }
 523         LambdaFormBuffer buf = buffer();
 524         buf.startEdit();
 525 
 526         assert(lambdaForm.parameter(srcPos).constraint == null);
 527         assert(lambdaForm.parameter(dstPos).constraint == null);
 528         buf.replaceParameterByCopy(dstPos, srcPos);
 529 
 530         form = buf.endEdit();
 531         return putInCache(key, form);
 532     }
 533 
 534     LambdaForm spreadArgumentsForm(int pos, Class<?> arrayType, int arrayLength) {
 535         Class<?> elementType = arrayType.getComponentType();
 536         Class<?> erasedArrayType = arrayType;
 537         if (!elementType.isPrimitive())
 538             erasedArrayType = Object[].class;
 539         BasicType bt = basicType(elementType);
 540         int elementTypeKey = bt.ordinal();
 541         if (bt.basicTypeClass() != elementType) {
 542             if (elementType.isPrimitive()) {
 543                 elementTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
 544             }
 545         }
 546         Transform key = Transform.of(Transform.SPREAD_ARGS, pos, elementTypeKey, arrayLength);
 547         LambdaForm form = getInCache(key);
 548         if (form != null) {
 549             assert(form.arity == lambdaForm.arity - arrayLength + 1);
 550             return form;
 551         }
 552         LambdaFormBuffer buf = buffer();
 553         buf.startEdit();
 554 
 555         assert(pos <= MethodType.MAX_JVM_ARITY);
 556         assert(pos + arrayLength <= lambdaForm.arity);
 557         assert(pos > 0);  // cannot spread the MH arg itself
 558 
 559         Name spreadParam = new Name(L_TYPE);
 560         Name checkSpread = new Name(MethodHandleImpl.getFunction(MethodHandleImpl.NF_checkSpreadArgument),
 561                 spreadParam, arrayLength);
 562 
 563         // insert the new expressions
 564         int exprPos = lambdaForm.arity();
 565         buf.insertExpression(exprPos++, checkSpread);
 566         // adjust the arguments
 567         MethodHandle aload = MethodHandles.arrayElementGetter(erasedArrayType);
 568         for (int i = 0; i < arrayLength; i++) {
 569             Name loadArgument = new Name(aload, spreadParam, i);
 570             buf.insertExpression(exprPos + i, loadArgument);
 571             buf.replaceParameterByCopy(pos + i, exprPos + i);
 572         }
 573         buf.insertParameter(pos, spreadParam);
 574 
 575         form = buf.endEdit();
 576         return putInCache(key, form);
 577     }
 578 
 579     LambdaForm collectArgumentsForm(int pos, MethodType collectorType) {
 580         int collectorArity = collectorType.parameterCount();
 581         boolean dropResult = (collectorType.returnType() == void.class);
 582         if (collectorArity == 1 && !dropResult) {
 583             return filterArgumentForm(pos, basicType(collectorType.parameterType(0)));
 584         }
 585         byte[] newTypes = BasicType.basicTypesOrd(collectorType.parameterArray());
 586         byte kind = (dropResult
 587                 ? Transform.COLLECT_ARGS_TO_VOID
 588                 : Transform.COLLECT_ARGS);
 589         if (dropResult && collectorArity == 0)  pos = 1;  // pure side effect
 590         Transform key = Transform.of(kind, pos, collectorArity, newTypes);
 591         LambdaForm form = getInCache(key);
 592         if (form != null) {
 593             assert(form.arity == lambdaForm.arity - (dropResult ? 0 : 1) + collectorArity);
 594             return form;
 595         }
 596         form = makeArgumentCombinationForm(pos, collectorType, false, dropResult);
 597         return putInCache(key, form);
 598     }
 599 
 600     LambdaForm collectArgumentArrayForm(int pos, MethodHandle arrayCollector) {
 601         MethodType collectorType = arrayCollector.type();
 602         int collectorArity = collectorType.parameterCount();
 603         assert(arrayCollector.intrinsicName() == Intrinsic.NEW_ARRAY);
 604         Class<?> arrayType = collectorType.returnType();
 605         Class<?> elementType = arrayType.getComponentType();
 606         BasicType argType = basicType(elementType);
 607         int argTypeKey = argType.ordinal();
 608         if (argType.basicTypeClass() != elementType) {
 609             // return null if it requires more metadata (like String[].class)
 610             if (!elementType.isPrimitive())
 611                 return null;
 612             argTypeKey = TYPE_LIMIT + Wrapper.forPrimitiveType(elementType).ordinal();
 613         }
 614         assert(collectorType.parameterList().equals(Collections.nCopies(collectorArity, elementType)));
 615         byte kind = Transform.COLLECT_ARGS_TO_ARRAY;
 616         Transform key = Transform.of(kind, pos, collectorArity, argTypeKey);
 617         LambdaForm form = getInCache(key);
 618         if (form != null) {
 619             assert(form.arity == lambdaForm.arity - 1 + collectorArity);
 620             return form;
 621         }
 622         LambdaFormBuffer buf = buffer();
 623         buf.startEdit();
 624 
 625         assert(pos + 1 <= lambdaForm.arity);
 626         assert(pos > 0);  // cannot filter the MH arg itself
 627 
 628         Name[] newParams = new Name[collectorArity];
 629         for (int i = 0; i < collectorArity; i++) {
 630             newParams[i] = new Name(pos + i, argType);
 631         }
 632         Name callCombiner = new Name(arrayCollector, (Object[]) /*...*/ newParams);
 633 
 634         // insert the new expression
 635         int exprPos = lambdaForm.arity();
 636         buf.insertExpression(exprPos, callCombiner);
 637 
 638         // insert new arguments
 639         int argPos = pos + 1;  // skip result parameter
 640         for (Name newParam : newParams) {
 641             buf.insertParameter(argPos++, newParam);
 642         }
 643         assert(buf.lastIndexOf(callCombiner) == exprPos+newParams.length);
 644         buf.replaceParameterByCopy(pos, exprPos+newParams.length);
 645 
 646         form = buf.endEdit();
 647         return putInCache(key, form);
 648     }
 649 
 650     LambdaForm filterArgumentForm(int pos, BasicType newType) {
 651         Transform key = Transform.of(Transform.FILTER_ARG, pos, newType.ordinal());
 652         LambdaForm form = getInCache(key);
 653         if (form != null) {
 654             assert(form.arity == lambdaForm.arity);
 655             assert(form.parameterType(pos) == newType);
 656             return form;
 657         }
 658 
 659         BasicType oldType = lambdaForm.parameterType(pos);
 660         MethodType filterType = MethodType.methodType(oldType.basicTypeClass(),
 661                 newType.basicTypeClass());
 662         form = makeArgumentCombinationForm(pos, filterType, false, false);
 663         return putInCache(key, form);
 664     }
 665 
 666     private LambdaForm makeArgumentCombinationForm(int pos,
 667                                                    MethodType combinerType,
 668                                                    boolean keepArguments, boolean dropResult) {
 669         LambdaFormBuffer buf = buffer();
 670         buf.startEdit();
 671         int combinerArity = combinerType.parameterCount();
 672         int resultArity = (dropResult ? 0 : 1);
 673 
 674         assert(pos <= MethodType.MAX_JVM_ARITY);
 675         assert(pos + resultArity + (keepArguments ? combinerArity : 0) <= lambdaForm.arity);
 676         assert(pos > 0);  // cannot filter the MH arg itself
 677         assert(combinerType == combinerType.basicType());
 678         assert(combinerType.returnType() != void.class || dropResult);
 679 
 680         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 681         BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 682 
 683         // The newly created LF will run with a different BMH.
 684         // Switch over any pre-existing BMH field references to the new BMH class.
 685         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 686         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 687         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 688         buf.renameParameter(0, newBaseAddress);
 689 
 690         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 691         Object[] combinerArgs = new Object[1 + combinerArity];
 692         combinerArgs[0] = getCombiner;
 693         Name[] newParams;
 694         if (keepArguments) {
 695             newParams = new Name[0];
 696             System.arraycopy(lambdaForm.names, pos + resultArity,
 697                              combinerArgs, 1, combinerArity);
 698         } else {
 699             newParams = new Name[combinerArity];
 700             for (int i = 0; i < newParams.length; i++) {
 701                 newParams[i] = new Name(pos + i, basicType(combinerType.parameterType(i)));
 702             }
 703             System.arraycopy(newParams, 0,
 704                              combinerArgs, 1, combinerArity);
 705         }
 706         Name callCombiner = new Name(combinerType, combinerArgs);
 707 
 708         // insert the two new expressions
 709         int exprPos = lambdaForm.arity();
 710         buf.insertExpression(exprPos+0, getCombiner);
 711         buf.insertExpression(exprPos+1, callCombiner);
 712 
 713         // insert new arguments, if needed
 714         int argPos = pos + resultArity;  // skip result parameter
 715         for (Name newParam : newParams) {
 716             buf.insertParameter(argPos++, newParam);
 717         }
 718         assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
 719         if (!dropResult) {
 720             buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
 721         }
 722 
 723         return buf.endEdit();
 724     }
 725 
 726     private LambdaForm makeArgumentCombinationForm(int pos,
 727                                                    MethodType combinerType,
 728                                                    int[] argPositions,
 729                                                    boolean keepArguments,
 730                                                    boolean dropResult) {
 731         LambdaFormBuffer buf = buffer();
 732         buf.startEdit();
 733         int combinerArity = combinerType.parameterCount();
 734         assert(combinerArity == argPositions.length);
 735 
 736         int resultArity = (dropResult ? 0 : 1);
 737 
 738         assert(pos <= lambdaForm.arity);
 739         assert(pos > 0);  // cannot filter the MH arg itself
 740         assert(combinerType == combinerType.basicType());
 741         assert(combinerType.returnType() != void.class || dropResult);
 742 
 743         BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 744         BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 745 
 746         // The newly created LF will run with a different BMH.
 747         // Switch over any pre-existing BMH field references to the new BMH class.
 748         Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 749         buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 750         Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 751         buf.renameParameter(0, newBaseAddress);
 752 
 753         Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 754         Object[] combinerArgs = new Object[1 + combinerArity];
 755         combinerArgs[0] = getCombiner;
 756         Name[] newParams;
 757         if (keepArguments) {
 758             newParams = new Name[0];
 759             for (int i = 0; i < combinerArity; i++) {
 760                 combinerArgs[i + 1] = lambdaForm.parameter(1 + argPositions[i]);
 761                 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
 762             }
 763         } else {
 764             newParams = new Name[combinerArity];
 765             for (int i = 0; i < newParams.length; i++) {
 766                 newParams[i] = lambdaForm.parameter(1 + argPositions[i]);
 767                 assert (basicType(combinerType.parameterType(i)) == lambdaForm.parameterType(1 + argPositions[i]));
 768             }
 769             System.arraycopy(newParams, 0,
 770                              combinerArgs, 1, combinerArity);
 771         }
 772         Name callCombiner = new Name(combinerType, combinerArgs);
 773 
 774         // insert the two new expressions
 775         int exprPos = lambdaForm.arity();
 776         buf.insertExpression(exprPos+0, getCombiner);
 777         buf.insertExpression(exprPos+1, callCombiner);
 778 
 779         // insert new arguments, if needed
 780         int argPos = pos + resultArity;  // skip result parameter
 781         for (Name newParam : newParams) {
 782             buf.insertParameter(argPos++, newParam);
 783         }
 784         assert(buf.lastIndexOf(callCombiner) == exprPos+1+newParams.length);
 785         if (!dropResult) {
 786             buf.replaceParameterByCopy(pos, exprPos+1+newParams.length);
 787         }
 788 
 789         return buf.endEdit();
 790     }
 791 
 792     LambdaForm filterReturnForm(BasicType newType, boolean constantZero) {
 793         byte kind = (constantZero ? Transform.FILTER_RETURN_TO_ZERO : Transform.FILTER_RETURN);
 794         Transform key = Transform.of(kind, newType.ordinal());
 795         LambdaForm form = getInCache(key);
 796         if (form != null) {
 797             assert(form.arity == lambdaForm.arity);
 798             assert(form.returnType() == newType);
 799             return form;
 800         }
 801         LambdaFormBuffer buf = buffer();
 802         buf.startEdit();
 803 
 804         int insPos = lambdaForm.names.length;
 805         Name callFilter;
 806         if (constantZero) {
 807             // Synthesize a constant zero value for the given type.
 808             if (newType == V_TYPE)
 809                 callFilter = null;
 810             else
 811                 callFilter = new Name(constantZero(newType));
 812         } else {
 813             BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
 814             BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
 815 
 816             // The newly created LF will run with a different BMH.
 817             // Switch over any pre-existing BMH field references to the new BMH class.
 818             Name oldBaseAddress = lambdaForm.parameter(0);  // BMH holding the values
 819             buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
 820             Name newBaseAddress = oldBaseAddress.withConstraint(newData);
 821             buf.renameParameter(0, newBaseAddress);
 822 
 823             Name getFilter = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
 824             buf.insertExpression(insPos++, getFilter);
 825             BasicType oldType = lambdaForm.returnType();
 826             if (oldType == V_TYPE) {
 827                 MethodType filterType = MethodType.methodType(newType.basicTypeClass());
 828                 callFilter = new Name(filterType, getFilter);
 829             } else {
 830                 MethodType filterType = MethodType.methodType(newType.basicTypeClass(), oldType.basicTypeClass());
 831                 callFilter = new Name(filterType, getFilter, lambdaForm.names[lambdaForm.result]);
 832             }
 833         }
 834 
 835         if (callFilter != null)
 836             buf.insertExpression(insPos++, callFilter);
 837         buf.setResult(callFilter);
 838 
 839         form = buf.endEdit();
 840         return putInCache(key, form);
 841     }
 842 
 843     LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
 844         int combinerArity = combinerType.parameterCount();
 845         byte kind = (dropResult ? Transform.FOLD_ARGS_TO_VOID : Transform.FOLD_ARGS);
 846         Transform key = Transform.of(kind, foldPos, combinerArity);
 847         LambdaForm form = getInCache(key);
 848         if (form != null) {
 849             assert(form.arity == lambdaForm.arity - (kind == Transform.FOLD_ARGS ? 1 : 0));
 850             return form;
 851         }
 852         form = makeArgumentCombinationForm(foldPos, combinerType, true, dropResult);
 853         return putInCache(key, form);
 854     }
 855 
 856     LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType, int ... argPositions) {
 857         byte kind = (dropResult ? Transform.FOLD_SELECT_ARGS_TO_VOID
 858                                 : Transform.FOLD_SELECT_ARGS);
 859         int[] keyArgs = Arrays.copyOf(argPositions, argPositions.length + 1);
 860         keyArgs[argPositions.length] = foldPos;
 861         Transform key = Transform.of(kind, keyArgs);
 862         LambdaForm form = getInCache(key);
 863         if (form != null) {
 864             assert(form.arity == lambdaForm.arity - (kind == Transform.FOLD_SELECT_ARGS ? 1 : 0));
 865             return form;
 866         }
 867         form = makeArgumentCombinationForm(foldPos, combinerType, argPositions, true, dropResult);
 868         return putInCache(key, form);
 869     }
 870 
 871     LambdaForm permuteArgumentsForm(int skip, int[] reorder) {
 872         assert(skip == 1);  // skip only the leading MH argument, names[0]
 873         int length = lambdaForm.names.length;
 874         int outArgs = reorder.length;
 875         int inTypes = 0;
 876         boolean nullPerm = true;
 877         for (int i = 0; i < reorder.length; i++) {
 878             int inArg = reorder[i];
 879             if (inArg != i)  nullPerm = false;
 880             inTypes = Math.max(inTypes, inArg+1);
 881         }
 882         assert(skip + reorder.length == lambdaForm.arity);
 883         if (nullPerm)  return lambdaForm;  // do not bother to cache
 884         Transform key = Transform.of(Transform.PERMUTE_ARGS, reorder);
 885         LambdaForm form = getInCache(key);
 886         if (form != null) {
 887             assert(form.arity == skip+inTypes) : form;
 888             return form;
 889         }
 890 
 891         BasicType[] types = new BasicType[inTypes];
 892         for (int i = 0; i < outArgs; i++) {
 893             int inArg = reorder[i];
 894             types[inArg] = lambdaForm.names[skip + i].type;
 895         }
 896         assert (skip + outArgs == lambdaForm.arity);
 897         assert (permutedTypesMatch(reorder, types, lambdaForm.names, skip));
 898         int pos = 0;
 899         while (pos < outArgs && reorder[pos] == pos) {
 900             pos += 1;
 901         }
 902         Name[] names2 = new Name[length - outArgs + inTypes];
 903         System.arraycopy(lambdaForm.names, 0, names2, 0, skip + pos);
 904         int bodyLength = length - lambdaForm.arity;
 905         System.arraycopy(lambdaForm.names, skip + outArgs, names2, skip + inTypes, bodyLength);
 906         int arity2 = names2.length - bodyLength;
 907         int result2 = lambdaForm.result;
 908         if (result2 >= 0) {
 909             if (result2 < skip + outArgs) {
 910                 result2 = reorder[result2 - skip];
 911             } else {
 912                 result2 = result2 - outArgs + inTypes;
 913             }
 914         }
 915         for (int j = pos; j < outArgs; j++) {
 916             Name n = lambdaForm.names[skip + j];
 917             int i = reorder[j];
 918             Name n2 = names2[skip + i];
 919             if (n2 == null) {
 920                 names2[skip + i] = n2 = new Name(types[i]);
 921             } else {
 922                 assert (n2.type == types[i]);
 923             }
 924             for (int k = arity2; k < names2.length; k++) {
 925                 names2[k] = names2[k].replaceName(n, n2);
 926             }
 927         }
 928         for (int i = skip + pos; i < arity2; i++) {
 929             if (names2[i] == null) {
 930                 names2[i] = argument(i, types[i - skip]);
 931             }
 932         }
 933         for (int j = lambdaForm.arity; j < lambdaForm.names.length; j++) {
 934             int i = j - lambdaForm.arity + arity2;
 935             Name n = lambdaForm.names[j];
 936             Name n2 = names2[i];
 937             if (n != n2) {
 938                 for (int k = i + 1; k < names2.length; k++) {
 939                     names2[k] = names2[k].replaceName(n, n2);
 940                 }
 941             }
 942         }
 943 
 944         form = new LambdaForm(arity2, names2, result2);
 945         return putInCache(key, form);
 946     }
 947 
 948     LambdaForm noteLoopLocalTypesForm(int pos, BasicType[] localTypes) {
 949         assert(lambdaForm.isLoop(pos));
 950         int[] desc = BasicType.basicTypeOrds(localTypes);
 951         desc = Arrays.copyOf(desc, desc.length + 1);
 952         desc[desc.length - 1] = pos;
 953         Transform key = Transform.of(Transform.LOCAL_TYPES, desc);
 954         LambdaForm form = getInCache(key);
 955         if (form != null) {
 956             return form;
 957         }
 958 
 959         // replace the null entry in the MHImpl.loop invocation with localTypes
 960         Name invokeLoop = lambdaForm.names[pos + 1];
 961         assert(invokeLoop.function.equals(MethodHandleImpl.getFunction(NF_loop)));
 962         Object[] args = Arrays.copyOf(invokeLoop.arguments, invokeLoop.arguments.length);
 963         assert(args[0] == null);
 964         args[0] = localTypes;
 965 
 966         LambdaFormBuffer buf = buffer();
 967         buf.startEdit();
 968         buf.changeName(pos + 1, new Name(MethodHandleImpl.getFunction(NF_loop), args));
 969         form = buf.endEdit();
 970 
 971         return putInCache(key, form);
 972     }
 973 
 974     static boolean permutedTypesMatch(int[] reorder, BasicType[] types, Name[] names, int skip) {
 975         for (int i = 0; i < reorder.length; i++) {
 976             assert (names[skip + i].isParam());
 977             assert (names[skip + i].type == types[reorder[i]]);
 978         }
 979         return true;
 980     }
 981 }