rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java
branchjdk8-b132
changeset 1646 c880a8a8803b
child 1653 bd151459ee4f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/lang/invoke/LambdaForm.java	Sat Aug 09 11:11:13 2014 +0200
     1.3 @@ -0,0 +1,1646 @@
     1.4 +/*
     1.5 + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.lang.invoke;
    1.30 +
    1.31 +import java.lang.annotation.*;
    1.32 +import java.lang.reflect.Method;
    1.33 +import java.util.Map;
    1.34 +import java.util.List;
    1.35 +import java.util.Arrays;
    1.36 +import java.util.ArrayList;
    1.37 +import java.util.HashMap;
    1.38 +import java.util.concurrent.ConcurrentHashMap;
    1.39 +import sun.invoke.util.Wrapper;
    1.40 +import static java.lang.invoke.MethodHandleStatics.*;
    1.41 +import static java.lang.invoke.MethodHandleNatives.Constants.*;
    1.42 +import java.lang.reflect.Field;
    1.43 +import java.util.Objects;
    1.44 +
    1.45 +/**
    1.46 + * The symbolic, non-executable form of a method handle's invocation semantics.
    1.47 + * It consists of a series of names.
    1.48 + * The first N (N=arity) names are parameters,
    1.49 + * while any remaining names are temporary values.
    1.50 + * Each temporary specifies the application of a function to some arguments.
    1.51 + * The functions are method handles, while the arguments are mixes of
    1.52 + * constant values and local names.
    1.53 + * The result of the lambda is defined as one of the names, often the last one.
    1.54 + * <p>
    1.55 + * Here is an approximate grammar:
    1.56 + * <blockquote><pre>{@code
    1.57 + * LambdaForm = "(" ArgName* ")=>{" TempName* Result "}"
    1.58 + * ArgName = "a" N ":" T
    1.59 + * TempName = "t" N ":" T "=" Function "(" Argument* ");"
    1.60 + * Function = ConstantValue
    1.61 + * Argument = NameRef | ConstantValue
    1.62 + * Result = NameRef | "void"
    1.63 + * NameRef = "a" N | "t" N
    1.64 + * N = (any whole number)
    1.65 + * T = "L" | "I" | "J" | "F" | "D" | "V"
    1.66 + * }</pre></blockquote>
    1.67 + * Names are numbered consecutively from left to right starting at zero.
    1.68 + * (The letters are merely a taste of syntax sugar.)
    1.69 + * Thus, the first temporary (if any) is always numbered N (where N=arity).
    1.70 + * Every occurrence of a name reference in an argument list must refer to
    1.71 + * a name previously defined within the same lambda.
    1.72 + * A lambda has a void result if and only if its result index is -1.
    1.73 + * If a temporary has the type "V", it cannot be the subject of a NameRef,
    1.74 + * even though possesses a number.
    1.75 + * Note that all reference types are erased to "L", which stands for {@code Object}.
    1.76 + * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
    1.77 + * The other types stand for the usual primitive types.
    1.78 + * <p>
    1.79 + * Function invocation closely follows the static rules of the Java verifier.
    1.80 + * Arguments and return values must exactly match when their "Name" types are
    1.81 + * considered.
    1.82 + * Conversions are allowed only if they do not change the erased type.
    1.83 + * <ul>
    1.84 + * <li>L = Object: casts are used freely to convert into and out of reference types
    1.85 + * <li>I = int: subword types are forcibly narrowed when passed as arguments (see {@code explicitCastArguments})
    1.86 + * <li>J = long: no implicit conversions
    1.87 + * <li>F = float: no implicit conversions
    1.88 + * <li>D = double: no implicit conversions
    1.89 + * <li>V = void: a function result may be void if and only if its Name is of type "V"
    1.90 + * </ul>
    1.91 + * Although implicit conversions are not allowed, explicit ones can easily be
    1.92 + * encoded by using temporary expressions which call type-transformed identity functions.
    1.93 + * <p>
    1.94 + * Examples:
    1.95 + * <blockquote><pre>{@code
    1.96 + * (a0:J)=>{ a0 }
    1.97 + *     == identity(long)
    1.98 + * (a0:I)=>{ t1:V = System.out#println(a0); void }
    1.99 + *     == System.out#println(int)
   1.100 + * (a0:L)=>{ t1:V = System.out#println(a0); a0 }
   1.101 + *     == identity, with printing side-effect
   1.102 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
   1.103 + *                 t3:L = BoundMethodHandle#target(a0);
   1.104 + *                 t4:L = MethodHandle#invoke(t3, t2, a1); t4 }
   1.105 + *     == general invoker for unary insertArgument combination
   1.106 + * (a0:L, a1:L)=>{ t2:L = FilterMethodHandle#filter(a0);
   1.107 + *                 t3:L = MethodHandle#invoke(t2, a1);
   1.108 + *                 t4:L = FilterMethodHandle#target(a0);
   1.109 + *                 t5:L = MethodHandle#invoke(t4, t3); t5 }
   1.110 + *     == general invoker for unary filterArgument combination
   1.111 + * (a0:L, a1:L)=>{ ...(same as previous example)...
   1.112 + *                 t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
   1.113 + *     == general invoker for unary/unary foldArgument combination
   1.114 + * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
   1.115 + *     == invoker for identity method handle which performs i2l
   1.116 + * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
   1.117 + *                 t3:L = Class#cast(t2,a1); t3 }
   1.118 + *     == invoker for identity method handle which performs cast
   1.119 + * }</pre></blockquote>
   1.120 + * <p>
   1.121 + * @author John Rose, JSR 292 EG
   1.122 + */
   1.123 +class LambdaForm {
   1.124 +    final int arity;
   1.125 +    final int result;
   1.126 +    @Stable final Name[] names;
   1.127 +    final String debugName;
   1.128 +    MemberName vmentry;   // low-level behavior, or null if not yet prepared
   1.129 +    private boolean isCompiled;
   1.130 +
   1.131 +    // Caches for common structural transforms:
   1.132 +    LambdaForm[] bindCache;
   1.133 +
   1.134 +    public static final int VOID_RESULT = -1, LAST_RESULT = -2;
   1.135 +
   1.136 +    LambdaForm(String debugName,
   1.137 +               int arity, Name[] names, int result) {
   1.138 +        assert(namesOK(arity, names));
   1.139 +        this.arity = arity;
   1.140 +        this.result = fixResult(result, names);
   1.141 +        this.names = names.clone();
   1.142 +        this.debugName = debugName;
   1.143 +        normalize();
   1.144 +    }
   1.145 +
   1.146 +    LambdaForm(String debugName,
   1.147 +               int arity, Name[] names) {
   1.148 +        this(debugName,
   1.149 +             arity, names, LAST_RESULT);
   1.150 +    }
   1.151 +
   1.152 +    LambdaForm(String debugName,
   1.153 +               Name[] formals, Name[] temps, Name result) {
   1.154 +        this(debugName,
   1.155 +             formals.length, buildNames(formals, temps, result), LAST_RESULT);
   1.156 +    }
   1.157 +
   1.158 +    private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
   1.159 +        int arity = formals.length;
   1.160 +        int length = arity + temps.length + (result == null ? 0 : 1);
   1.161 +        Name[] names = Arrays.copyOf(formals, length);
   1.162 +        System.arraycopy(temps, 0, names, arity, temps.length);
   1.163 +        if (result != null)
   1.164 +            names[length - 1] = result;
   1.165 +        return names;
   1.166 +    }
   1.167 +
   1.168 +    private LambdaForm(String sig) {
   1.169 +        // Make a blank lambda form, which returns a constant zero or null.
   1.170 +        // It is used as a template for managing the invocation of similar forms that are non-empty.
   1.171 +        // Called only from getPreparedForm.
   1.172 +        assert(isValidSignature(sig));
   1.173 +        this.arity = signatureArity(sig);
   1.174 +        this.result = (signatureReturn(sig) == 'V' ? -1 : arity);
   1.175 +        this.names = buildEmptyNames(arity, sig);
   1.176 +        this.debugName = "LF.zero";
   1.177 +        assert(nameRefsAreLegal());
   1.178 +        assert(isEmpty());
   1.179 +        assert(sig.equals(basicTypeSignature()));
   1.180 +    }
   1.181 +
   1.182 +    private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
   1.183 +        assert(isValidSignature(basicTypeSignature));
   1.184 +        int resultPos = arity + 1;  // skip '_'
   1.185 +        if (arity < 0 || basicTypeSignature.length() != resultPos+1)
   1.186 +            throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
   1.187 +        int numRes = (basicTypeSignature.charAt(resultPos) == 'V' ? 0 : 1);
   1.188 +        Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
   1.189 +        for (int i = 0; i < numRes; i++) {
   1.190 +            names[arity + i] = constantZero(arity + i, basicTypeSignature.charAt(resultPos + i));
   1.191 +        }
   1.192 +        return names;
   1.193 +    }
   1.194 +
   1.195 +    private static int fixResult(int result, Name[] names) {
   1.196 +        if (result >= 0) {
   1.197 +            if (names[result].type == 'V')
   1.198 +                return -1;
   1.199 +        } else if (result == LAST_RESULT) {
   1.200 +            return names.length - 1;
   1.201 +        }
   1.202 +        return result;
   1.203 +    }
   1.204 +
   1.205 +    private static boolean namesOK(int arity, Name[] names) {
   1.206 +        for (int i = 0; i < names.length; i++) {
   1.207 +            Name n = names[i];
   1.208 +            assert(n != null) : "n is null";
   1.209 +            if (i < arity)
   1.210 +                assert( n.isParam()) : n + " is not param at " + i;
   1.211 +            else
   1.212 +                assert(!n.isParam()) : n + " is param at " + i;
   1.213 +        }
   1.214 +        return true;
   1.215 +    }
   1.216 +
   1.217 +    /** Renumber and/or replace params so that they are interned and canonically numbered. */
   1.218 +    private void normalize() {
   1.219 +        Name[] oldNames = null;
   1.220 +        int changesStart = 0;
   1.221 +        for (int i = 0; i < names.length; i++) {
   1.222 +            Name n = names[i];
   1.223 +            if (!n.initIndex(i)) {
   1.224 +                if (oldNames == null) {
   1.225 +                    oldNames = names.clone();
   1.226 +                    changesStart = i;
   1.227 +                }
   1.228 +                names[i] = n.cloneWithIndex(i);
   1.229 +            }
   1.230 +        }
   1.231 +        if (oldNames != null) {
   1.232 +            int startFixing = arity;
   1.233 +            if (startFixing <= changesStart)
   1.234 +                startFixing = changesStart+1;
   1.235 +            for (int i = startFixing; i < names.length; i++) {
   1.236 +                Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
   1.237 +                names[i] = fixed.newIndex(i);
   1.238 +            }
   1.239 +        }
   1.240 +        assert(nameRefsAreLegal());
   1.241 +        int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
   1.242 +        boolean needIntern = false;
   1.243 +        for (int i = 0; i < maxInterned; i++) {
   1.244 +            Name n = names[i], n2 = internArgument(n);
   1.245 +            if (n != n2) {
   1.246 +                names[i] = n2;
   1.247 +                needIntern = true;
   1.248 +            }
   1.249 +        }
   1.250 +        if (needIntern) {
   1.251 +            for (int i = arity; i < names.length; i++) {
   1.252 +                names[i].internArguments();
   1.253 +            }
   1.254 +            assert(nameRefsAreLegal());
   1.255 +        }
   1.256 +    }
   1.257 +
   1.258 +    /**
   1.259 +     * Check that all embedded Name references are localizable to this lambda,
   1.260 +     * and are properly ordered after their corresponding definitions.
   1.261 +     * <p>
   1.262 +     * Note that a Name can be local to multiple lambdas, as long as
   1.263 +     * it possesses the same index in each use site.
   1.264 +     * This allows Name references to be freely reused to construct
   1.265 +     * fresh lambdas, without confusion.
   1.266 +     */
   1.267 +    private boolean nameRefsAreLegal() {
   1.268 +        assert(arity >= 0 && arity <= names.length);
   1.269 +        assert(result >= -1 && result < names.length);
   1.270 +        // Do all names possess an index consistent with their local definition order?
   1.271 +        for (int i = 0; i < arity; i++) {
   1.272 +            Name n = names[i];
   1.273 +            assert(n.index() == i) : Arrays.asList(n.index(), i);
   1.274 +            assert(n.isParam());
   1.275 +        }
   1.276 +        // Also, do all local name references
   1.277 +        for (int i = arity; i < names.length; i++) {
   1.278 +            Name n = names[i];
   1.279 +            assert(n.index() == i);
   1.280 +            for (Object arg : n.arguments) {
   1.281 +                if (arg instanceof Name) {
   1.282 +                    Name n2 = (Name) arg;
   1.283 +                    int i2 = n2.index;
   1.284 +                    assert(0 <= i2 && i2 < names.length) : n.debugString() + ": 0 <= i2 && i2 < names.length: 0 <= " + i2 + " < " + names.length;
   1.285 +                    assert(names[i2] == n2) : Arrays.asList("-1-", i, "-2-", n.debugString(), "-3-", i2, "-4-", n2.debugString(), "-5-", names[i2].debugString(), "-6-", this);
   1.286 +                    assert(i2 < i);  // ref must come after def!
   1.287 +                }
   1.288 +            }
   1.289 +        }
   1.290 +        return true;
   1.291 +    }
   1.292 +
   1.293 +    /** Invoke this form on the given arguments. */
   1.294 +    // final Object invoke(Object... args) throws Throwable {
   1.295 +    //     // NYI: fit this into the fast path?
   1.296 +    //     return interpretWithArguments(args);
   1.297 +    // }
   1.298 +
   1.299 +    /** Report the return type. */
   1.300 +    char returnType() {
   1.301 +        if (result < 0)  return 'V';
   1.302 +        Name n = names[result];
   1.303 +        return n.type;
   1.304 +    }
   1.305 +
   1.306 +    /** Report the N-th argument type. */
   1.307 +    char parameterType(int n) {
   1.308 +        assert(n < arity);
   1.309 +        return names[n].type;
   1.310 +    }
   1.311 +
   1.312 +    /** Report the arity. */
   1.313 +    int arity() {
   1.314 +        return arity;
   1.315 +    }
   1.316 +
   1.317 +    /** Return the method type corresponding to my basic type signature. */
   1.318 +    MethodType methodType() {
   1.319 +        return signatureType(basicTypeSignature());
   1.320 +    }
   1.321 +    /** Return ABC_Z, where the ABC are parameter type characters, and Z is the return type character. */
   1.322 +    final String basicTypeSignature() {
   1.323 +        StringBuilder buf = new StringBuilder(arity() + 3);
   1.324 +        for (int i = 0, a = arity(); i < a; i++)
   1.325 +            buf.append(parameterType(i));
   1.326 +        return buf.append('_').append(returnType()).toString();
   1.327 +    }
   1.328 +    static int signatureArity(String sig) {
   1.329 +        assert(isValidSignature(sig));
   1.330 +        return sig.indexOf('_');
   1.331 +    }
   1.332 +    static char signatureReturn(String sig) {
   1.333 +        return sig.charAt(signatureArity(sig)+1);
   1.334 +    }
   1.335 +    static boolean isValidSignature(String sig) {
   1.336 +        int arity = sig.indexOf('_');
   1.337 +        if (arity < 0)  return false;  // must be of the form *_*
   1.338 +        int siglen = sig.length();
   1.339 +        if (siglen != arity + 2)  return false;  // *_X
   1.340 +        for (int i = 0; i < siglen; i++) {
   1.341 +            if (i == arity)  continue;  // skip '_'
   1.342 +            char c = sig.charAt(i);
   1.343 +            if (c == 'V')
   1.344 +                return (i == siglen - 1 && arity == siglen - 2);
   1.345 +            if (ALL_TYPES.indexOf(c) < 0)  return false; // must be [LIJFD]
   1.346 +        }
   1.347 +        return true;  // [LIJFD]*_[LIJFDV]
   1.348 +    }
   1.349 +    static Class<?> typeClass(char t) {
   1.350 +        switch (t) {
   1.351 +        case 'I': return int.class;
   1.352 +        case 'J': return long.class;
   1.353 +        case 'F': return float.class;
   1.354 +        case 'D': return double.class;
   1.355 +        case 'L': return Object.class;
   1.356 +        case 'V': return void.class;
   1.357 +        default: assert false;
   1.358 +        }
   1.359 +        return null;
   1.360 +    }
   1.361 +    static MethodType signatureType(String sig) {
   1.362 +        Class<?>[] ptypes = new Class<?>[signatureArity(sig)];
   1.363 +        for (int i = 0; i < ptypes.length; i++)
   1.364 +            ptypes[i] = typeClass(sig.charAt(i));
   1.365 +        Class<?> rtype = typeClass(signatureReturn(sig));
   1.366 +        return MethodType.methodType(rtype, ptypes);
   1.367 +    }
   1.368 +
   1.369 +    /*
   1.370 +     * Code generation issues:
   1.371 +     *
   1.372 +     * Compiled LFs should be reusable in general.
   1.373 +     * The biggest issue is how to decide when to pull a name into
   1.374 +     * the bytecode, versus loading a reified form from the MH data.
   1.375 +     *
   1.376 +     * For example, an asType wrapper may require execution of a cast
   1.377 +     * after a call to a MH.  The target type of the cast can be placed
   1.378 +     * as a constant in the LF itself.  This will force the cast type
   1.379 +     * to be compiled into the bytecodes and native code for the MH.
   1.380 +     * Or, the target type of the cast can be erased in the LF, and
   1.381 +     * loaded from the MH data.  (Later on, if the MH as a whole is
   1.382 +     * inlined, the data will flow into the inlined instance of the LF,
   1.383 +     * as a constant, and the end result will be an optimal cast.)
   1.384 +     *
   1.385 +     * This erasure of cast types can be done with any use of
   1.386 +     * reference types.  It can also be done with whole method
   1.387 +     * handles.  Erasing a method handle might leave behind
   1.388 +     * LF code that executes correctly for any MH of a given
   1.389 +     * type, and load the required MH from the enclosing MH's data.
   1.390 +     * Or, the erasure might even erase the expected MT.
   1.391 +     *
   1.392 +     * Also, for direct MHs, the MemberName of the target
   1.393 +     * could be erased, and loaded from the containing direct MH.
   1.394 +     * As a simple case, a LF for all int-valued non-static
   1.395 +     * field getters would perform a cast on its input argument
   1.396 +     * (to non-constant base type derived from the MemberName)
   1.397 +     * and load an integer value from the input object
   1.398 +     * (at a non-constant offset also derived from the MemberName).
   1.399 +     * Such MN-erased LFs would be inlinable back to optimized
   1.400 +     * code, whenever a constant enclosing DMH is available
   1.401 +     * to supply a constant MN from its data.
   1.402 +     *
   1.403 +     * The main problem here is to keep LFs reasonably generic,
   1.404 +     * while ensuring that hot spots will inline good instances.
   1.405 +     * "Reasonably generic" means that we don't end up with
   1.406 +     * repeated versions of bytecode or machine code that do
   1.407 +     * not differ in their optimized form.  Repeated versions
   1.408 +     * of machine would have the undesirable overheads of
   1.409 +     * (a) redundant compilation work and (b) extra I$ pressure.
   1.410 +     * To control repeated versions, we need to be ready to
   1.411 +     * erase details from LFs and move them into MH data,
   1.412 +     * whevener those details are not relevant to significant
   1.413 +     * optimization.  "Significant" means optimization of
   1.414 +     * code that is actually hot.
   1.415 +     *
   1.416 +     * Achieving this may require dynamic splitting of MHs, by replacing
   1.417 +     * a generic LF with a more specialized one, on the same MH,
   1.418 +     * if (a) the MH is frequently executed and (b) the MH cannot
   1.419 +     * be inlined into a containing caller, such as an invokedynamic.
   1.420 +     *
   1.421 +     * Compiled LFs that are no longer used should be GC-able.
   1.422 +     * If they contain non-BCP references, they should be properly
   1.423 +     * interlinked with the class loader(s) that their embedded types
   1.424 +     * depend on.  This probably means that reusable compiled LFs
   1.425 +     * will be tabulated (indexed) on relevant class loaders,
   1.426 +     * or else that the tables that cache them will have weak links.
   1.427 +     */
   1.428 +
   1.429 +    /**
   1.430 +     * Make this LF directly executable, as part of a MethodHandle.
   1.431 +     * Invariant:  Every MH which is invoked must prepare its LF
   1.432 +     * before invocation.
   1.433 +     * (In principle, the JVM could do this very lazily,
   1.434 +     * as a sort of pre-invocation linkage step.)
   1.435 +     */
   1.436 +    public void prepare() {
   1.437 +        if (COMPILE_THRESHOLD == 0) {
   1.438 +            compileToBytecode();
   1.439 +        }
   1.440 +        if (this.vmentry != null) {
   1.441 +            // already prepared (e.g., a primitive DMH invoker form)
   1.442 +            return;
   1.443 +        }
   1.444 +        LambdaForm prep = getPreparedForm(basicTypeSignature());
   1.445 +        this.vmentry = prep.vmentry;
   1.446 +        // TO DO: Maybe add invokeGeneric, invokeWithArguments
   1.447 +    }
   1.448 +
   1.449 +    /** Generate optimizable bytecode for this form. */
   1.450 +    MemberName compileToBytecode() {
   1.451 +        MethodType invokerType = methodType();
   1.452 +        assert(vmentry == null || vmentry.getMethodType().basicType().equals(invokerType));
   1.453 +        if (vmentry != null && isCompiled) {
   1.454 +            return vmentry;  // already compiled somehow
   1.455 +        }
   1.456 +        try {
   1.457 +            vmentry = InvokerBytecodeGenerator.generateCustomizedCode(this, invokerType);
   1.458 +            if (TRACE_INTERPRETER)
   1.459 +                traceInterpreter("compileToBytecode", this);
   1.460 +            isCompiled = true;
   1.461 +            return vmentry;
   1.462 +        } catch (Error | Exception ex) {
   1.463 +            throw newInternalError("compileToBytecode", ex);
   1.464 +        }
   1.465 +    }
   1.466 +
   1.467 +    private static final ConcurrentHashMap<String,LambdaForm> PREPARED_FORMS;
   1.468 +    static {
   1.469 +        int   capacity   = 512;    // expect many distinct signatures over time
   1.470 +        float loadFactor = 0.75f;  // normal default
   1.471 +        int   writers    = 1;
   1.472 +        PREPARED_FORMS = new ConcurrentHashMap<>(capacity, loadFactor, writers);
   1.473 +    }
   1.474 +
   1.475 +    private static Map<String,LambdaForm> computeInitialPreparedForms() {
   1.476 +        // Find all predefined invokers and associate them with canonical empty lambda forms.
   1.477 +        HashMap<String,LambdaForm> forms = new HashMap<>();
   1.478 +        for (MemberName m : MemberName.getFactory().getMethods(LambdaForm.class, false, null, null, null)) {
   1.479 +            if (!m.isStatic() || !m.isPackage())  continue;
   1.480 +            MethodType mt = m.getMethodType();
   1.481 +            if (mt.parameterCount() > 0 &&
   1.482 +                mt.parameterType(0) == MethodHandle.class &&
   1.483 +                m.getName().startsWith("interpret_")) {
   1.484 +                String sig = basicTypeSignature(mt);
   1.485 +                assert(m.getName().equals("interpret" + sig.substring(sig.indexOf('_'))));
   1.486 +                LambdaForm form = new LambdaForm(sig);
   1.487 +                form.vmentry = m;
   1.488 +                mt.form().setCachedLambdaForm(MethodTypeForm.LF_COUNTER, form);
   1.489 +                // FIXME: get rid of PREPARED_FORMS; use MethodTypeForm cache only
   1.490 +                forms.put(sig, form);
   1.491 +            }
   1.492 +        }
   1.493 +        //System.out.println("computeInitialPreparedForms => "+forms);
   1.494 +        return forms;
   1.495 +    }
   1.496 +
   1.497 +    // Set this false to disable use of the interpret_L methods defined in this file.
   1.498 +    private static final boolean USE_PREDEFINED_INTERPRET_METHODS = true;
   1.499 +
   1.500 +    // The following are predefined exact invokers.  The system must build
   1.501 +    // a separate invoker for each distinct signature.
   1.502 +    static Object interpret_L(MethodHandle mh) throws Throwable {
   1.503 +        Object[] av = {mh};
   1.504 +        String sig = null;
   1.505 +        assert(argumentTypesMatch(sig = "L_L", av));
   1.506 +        Object res = mh.form.interpretWithArguments(av);
   1.507 +        assert(returnTypesMatch(sig, av, res));
   1.508 +        return res;
   1.509 +    }
   1.510 +    static Object interpret_L(MethodHandle mh, Object x1) throws Throwable {
   1.511 +        Object[] av = {mh, x1};
   1.512 +        String sig = null;
   1.513 +        assert(argumentTypesMatch(sig = "LL_L", av));
   1.514 +        Object res = mh.form.interpretWithArguments(av);
   1.515 +        assert(returnTypesMatch(sig, av, res));
   1.516 +        return res;
   1.517 +    }
   1.518 +    static Object interpret_L(MethodHandle mh, Object x1, Object x2) throws Throwable {
   1.519 +        Object[] av = {mh, x1, x2};
   1.520 +        String sig = null;
   1.521 +        assert(argumentTypesMatch(sig = "LLL_L", av));
   1.522 +        Object res = mh.form.interpretWithArguments(av);
   1.523 +        assert(returnTypesMatch(sig, av, res));
   1.524 +        return res;
   1.525 +    }
   1.526 +    private static LambdaForm getPreparedForm(String sig) {
   1.527 +        MethodType mtype = signatureType(sig);
   1.528 +        //LambdaForm prep = PREPARED_FORMS.get(sig);
   1.529 +        LambdaForm prep =  mtype.form().cachedLambdaForm(MethodTypeForm.LF_INTERPRET);
   1.530 +        if (prep != null)  return prep;
   1.531 +        assert(isValidSignature(sig));
   1.532 +        prep = new LambdaForm(sig);
   1.533 +        prep.vmentry = InvokerBytecodeGenerator.generateLambdaFormInterpreterEntryPoint(sig);
   1.534 +        //LambdaForm prep2 = PREPARED_FORMS.putIfAbsent(sig.intern(), prep);
   1.535 +        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_INTERPRET, prep);
   1.536 +    }
   1.537 +
   1.538 +    // The next few routines are called only from assert expressions
   1.539 +    // They verify that the built-in invokers process the correct raw data types.
   1.540 +    private static boolean argumentTypesMatch(String sig, Object[] av) {
   1.541 +        int arity = signatureArity(sig);
   1.542 +        assert(av.length == arity) : "av.length == arity: av.length=" + av.length + ", arity=" + arity;
   1.543 +        assert(av[0] instanceof MethodHandle) : "av[0] not instace of MethodHandle: " + av[0];
   1.544 +        MethodHandle mh = (MethodHandle) av[0];
   1.545 +        MethodType mt = mh.type();
   1.546 +        assert(mt.parameterCount() == arity-1);
   1.547 +        for (int i = 0; i < av.length; i++) {
   1.548 +            Class<?> pt = (i == 0 ? MethodHandle.class : mt.parameterType(i-1));
   1.549 +            assert(valueMatches(sig.charAt(i), pt, av[i]));
   1.550 +        }
   1.551 +        return true;
   1.552 +    }
   1.553 +    private static boolean valueMatches(char tc, Class<?> type, Object x) {
   1.554 +        // The following line is needed because (...)void method handles can use non-void invokers
   1.555 +        if (type == void.class)  tc = 'V';   // can drop any kind of value
   1.556 +        assert tc == basicType(type) : tc + " == basicType(" + type + ")=" + basicType(type);
   1.557 +        switch (tc) {
   1.558 +        case 'I': assert checkInt(type, x)   : "checkInt(" + type + "," + x +")";   break;
   1.559 +        case 'J': assert x instanceof Long   : "instanceof Long: " + x;             break;
   1.560 +        case 'F': assert x instanceof Float  : "instanceof Float: " + x;            break;
   1.561 +        case 'D': assert x instanceof Double : "instanceof Double: " + x;           break;
   1.562 +        case 'L': assert checkRef(type, x)   : "checkRef(" + type + "," + x + ")";  break;
   1.563 +        case 'V': break;  // allow anything here; will be dropped
   1.564 +        default:  assert(false);
   1.565 +        }
   1.566 +        return true;
   1.567 +    }
   1.568 +    private static boolean returnTypesMatch(String sig, Object[] av, Object res) {
   1.569 +        MethodHandle mh = (MethodHandle) av[0];
   1.570 +        return valueMatches(signatureReturn(sig), mh.type().returnType(), res);
   1.571 +    }
   1.572 +    private static boolean checkInt(Class<?> type, Object x) {
   1.573 +        assert(x instanceof Integer);
   1.574 +        if (type == int.class)  return true;
   1.575 +        Wrapper w = Wrapper.forBasicType(type);
   1.576 +        assert(w.isSubwordOrInt());
   1.577 +        Object x1 = Wrapper.INT.wrap(w.wrap(x));
   1.578 +        return x.equals(x1);
   1.579 +    }
   1.580 +    private static boolean checkRef(Class<?> type, Object x) {
   1.581 +        assert(!type.isPrimitive());
   1.582 +        if (x == null)  return true;
   1.583 +        if (type.isInterface())  return true;
   1.584 +        return type.isInstance(x);
   1.585 +    }
   1.586 +
   1.587 +    /** If the invocation count hits the threshold we spin bytecodes and call that subsequently. */
   1.588 +    private static final int COMPILE_THRESHOLD;
   1.589 +    static {
   1.590 +        if (MethodHandleStatics.COMPILE_THRESHOLD != null)
   1.591 +            COMPILE_THRESHOLD = MethodHandleStatics.COMPILE_THRESHOLD;
   1.592 +        else
   1.593 +            COMPILE_THRESHOLD = 30;  // default value
   1.594 +    }
   1.595 +    private int invocationCounter = 0;
   1.596 +
   1.597 +    @Hidden
   1.598 +    @DontInline
   1.599 +    /** Interpretively invoke this form on the given arguments. */
   1.600 +    Object interpretWithArguments(Object... argumentValues) throws Throwable {
   1.601 +        if (TRACE_INTERPRETER)
   1.602 +            return interpretWithArgumentsTracing(argumentValues);
   1.603 +        checkInvocationCounter();
   1.604 +        assert(arityCheck(argumentValues));
   1.605 +        Object[] values = Arrays.copyOf(argumentValues, names.length);
   1.606 +        for (int i = argumentValues.length; i < values.length; i++) {
   1.607 +            values[i] = interpretName(names[i], values);
   1.608 +        }
   1.609 +        return (result < 0) ? null : values[result];
   1.610 +    }
   1.611 +
   1.612 +    @Hidden
   1.613 +    @DontInline
   1.614 +    /** Evaluate a single Name within this form, applying its function to its arguments. */
   1.615 +    Object interpretName(Name name, Object[] values) throws Throwable {
   1.616 +        if (TRACE_INTERPRETER)
   1.617 +            traceInterpreter("| interpretName", name.debugString(), (Object[]) null);
   1.618 +        Object[] arguments = Arrays.copyOf(name.arguments, name.arguments.length, Object[].class);
   1.619 +        for (int i = 0; i < arguments.length; i++) {
   1.620 +            Object a = arguments[i];
   1.621 +            if (a instanceof Name) {
   1.622 +                int i2 = ((Name)a).index();
   1.623 +                assert(names[i2] == a);
   1.624 +                a = values[i2];
   1.625 +                arguments[i] = a;
   1.626 +            }
   1.627 +        }
   1.628 +        return name.function.invokeWithArguments(arguments);
   1.629 +    }
   1.630 +
   1.631 +    private void checkInvocationCounter() {
   1.632 +        if (COMPILE_THRESHOLD != 0 &&
   1.633 +            invocationCounter < COMPILE_THRESHOLD) {
   1.634 +            invocationCounter++;  // benign race
   1.635 +            if (invocationCounter >= COMPILE_THRESHOLD) {
   1.636 +                // Replace vmentry with a bytecode version of this LF.
   1.637 +                compileToBytecode();
   1.638 +            }
   1.639 +        }
   1.640 +    }
   1.641 +    Object interpretWithArgumentsTracing(Object... argumentValues) throws Throwable {
   1.642 +        traceInterpreter("[ interpretWithArguments", this, argumentValues);
   1.643 +        if (invocationCounter < COMPILE_THRESHOLD) {
   1.644 +            int ctr = invocationCounter++;  // benign race
   1.645 +            traceInterpreter("| invocationCounter", ctr);
   1.646 +            if (invocationCounter >= COMPILE_THRESHOLD) {
   1.647 +                compileToBytecode();
   1.648 +            }
   1.649 +        }
   1.650 +        Object rval;
   1.651 +        try {
   1.652 +            assert(arityCheck(argumentValues));
   1.653 +            Object[] values = Arrays.copyOf(argumentValues, names.length);
   1.654 +            for (int i = argumentValues.length; i < values.length; i++) {
   1.655 +                values[i] = interpretName(names[i], values);
   1.656 +            }
   1.657 +            rval = (result < 0) ? null : values[result];
   1.658 +        } catch (Throwable ex) {
   1.659 +            traceInterpreter("] throw =>", ex);
   1.660 +            throw ex;
   1.661 +        }
   1.662 +        traceInterpreter("] return =>", rval);
   1.663 +        return rval;
   1.664 +    }
   1.665 +
   1.666 +    //** This transform is applied (statically) to every name.function. */
   1.667 +    /*
   1.668 +    private static MethodHandle eraseSubwordTypes(MethodHandle mh) {
   1.669 +        MethodType mt = mh.type();
   1.670 +        if (mt.hasPrimitives()) {
   1.671 +            mt = mt.changeReturnType(eraseSubwordType(mt.returnType()));
   1.672 +            for (int i = 0; i < mt.parameterCount(); i++) {
   1.673 +                mt = mt.changeParameterType(i, eraseSubwordType(mt.parameterType(i)));
   1.674 +            }
   1.675 +            mh = MethodHandles.explicitCastArguments(mh, mt);
   1.676 +        }
   1.677 +        return mh;
   1.678 +    }
   1.679 +    private static Class<?> eraseSubwordType(Class<?> type) {
   1.680 +        if (!type.isPrimitive())  return type;
   1.681 +        if (type == int.class)  return type;
   1.682 +        Wrapper w = Wrapper.forPrimitiveType(type);
   1.683 +        if (w.isSubwordOrInt())  return int.class;
   1.684 +        return type;
   1.685 +    }
   1.686 +    */
   1.687 +
   1.688 +    static void traceInterpreter(String event, Object obj, Object... args) {
   1.689 +        if (TRACE_INTERPRETER) {
   1.690 +            System.out.println("LFI: "+event+" "+(obj != null ? obj : "")+(args != null && args.length != 0 ? Arrays.asList(args) : ""));
   1.691 +        }
   1.692 +    }
   1.693 +    static void traceInterpreter(String event, Object obj) {
   1.694 +        traceInterpreter(event, obj, (Object[])null);
   1.695 +    }
   1.696 +    private boolean arityCheck(Object[] argumentValues) {
   1.697 +        assert(argumentValues.length == arity) : arity+"!="+Arrays.asList(argumentValues)+".length";
   1.698 +        // also check that the leading (receiver) argument is somehow bound to this LF:
   1.699 +        assert(argumentValues[0] instanceof MethodHandle) : "not MH: " + argumentValues[0];
   1.700 +        assert(((MethodHandle)argumentValues[0]).internalForm() == this);
   1.701 +        // note:  argument #0 could also be an interface wrapper, in the future
   1.702 +        return true;
   1.703 +    }
   1.704 +
   1.705 +    private boolean isEmpty() {
   1.706 +        if (result < 0)
   1.707 +            return (names.length == arity);
   1.708 +        else if (result == arity && names.length == arity + 1)
   1.709 +            return names[arity].isConstantZero();
   1.710 +        else
   1.711 +            return false;
   1.712 +    }
   1.713 +
   1.714 +    public String toString() {
   1.715 +        StringBuilder buf = new StringBuilder(debugName+"=Lambda(");
   1.716 +        for (int i = 0; i < names.length; i++) {
   1.717 +            if (i == arity)  buf.append(")=>{");
   1.718 +            Name n = names[i];
   1.719 +            if (i >= arity)  buf.append("\n    ");
   1.720 +            buf.append(n);
   1.721 +            if (i < arity) {
   1.722 +                if (i+1 < arity)  buf.append(",");
   1.723 +                continue;
   1.724 +            }
   1.725 +            buf.append("=").append(n.exprString());
   1.726 +            buf.append(";");
   1.727 +        }
   1.728 +        buf.append(result < 0 ? "void" : names[result]).append("}");
   1.729 +        if (TRACE_INTERPRETER) {
   1.730 +            // Extra verbosity:
   1.731 +            buf.append(":").append(basicTypeSignature());
   1.732 +            buf.append("/").append(vmentry);
   1.733 +        }
   1.734 +        return buf.toString();
   1.735 +    }
   1.736 +
   1.737 +    /**
   1.738 +     * Apply immediate binding for a Name in this form indicated by its position relative to the form.
   1.739 +     * The first parameter to a LambdaForm, a0:L, always represents the form's method handle, so 0 is not
   1.740 +     * accepted as valid.
   1.741 +     */
   1.742 +    LambdaForm bindImmediate(int pos, char basicType, Object value) {
   1.743 +        // must be an argument, and the types must match
   1.744 +        assert pos > 0 && pos < arity && names[pos].type == basicType && Name.typesMatch(basicType, value);
   1.745 +
   1.746 +        int arity2 = arity - 1;
   1.747 +        Name[] names2 = new Name[names.length - 1];
   1.748 +        for (int r = 0, w = 0; r < names.length; ++r, ++w) { // (r)ead from names, (w)rite to names2
   1.749 +            Name n = names[r];
   1.750 +            if (n.isParam()) {
   1.751 +                if (n.index == pos) {
   1.752 +                    // do not copy over the argument that is to be replaced with a literal,
   1.753 +                    // but adjust the write index
   1.754 +                    --w;
   1.755 +                } else {
   1.756 +                    names2[w] = new Name(w, n.type);
   1.757 +                }
   1.758 +            } else {
   1.759 +                Object[] arguments2 = new Object[n.arguments.length];
   1.760 +                for (int i = 0; i < n.arguments.length; ++i) {
   1.761 +                    Object arg = n.arguments[i];
   1.762 +                    if (arg instanceof Name) {
   1.763 +                        int ni = ((Name) arg).index;
   1.764 +                        if (ni == pos) {
   1.765 +                            arguments2[i] = value;
   1.766 +                        } else if (ni < pos) {
   1.767 +                            // replacement position not yet passed
   1.768 +                            arguments2[i] = names2[ni];
   1.769 +                        } else {
   1.770 +                            // replacement position passed
   1.771 +                            arguments2[i] = names2[ni - 1];
   1.772 +                        }
   1.773 +                    } else {
   1.774 +                        arguments2[i] = arg;
   1.775 +                    }
   1.776 +                }
   1.777 +                names2[w] = new Name(n.function, arguments2);
   1.778 +                names2[w].initIndex(w);
   1.779 +            }
   1.780 +        }
   1.781 +
   1.782 +        int result2 = result == -1 ? -1 : result - 1;
   1.783 +        return new LambdaForm(debugName, arity2, names2, result2);
   1.784 +    }
   1.785 +
   1.786 +    LambdaForm bind(int namePos, BoundMethodHandle.SpeciesData oldData) {
   1.787 +        Name name = names[namePos];
   1.788 +        BoundMethodHandle.SpeciesData newData = oldData.extendWithType(name.type);
   1.789 +        return bind(name, newData.getterName(names[0], oldData.fieldCount()), oldData, newData);
   1.790 +    }
   1.791 +    LambdaForm bind(Name name, Name binding,
   1.792 +                    BoundMethodHandle.SpeciesData oldData,
   1.793 +                    BoundMethodHandle.SpeciesData newData) {
   1.794 +        int pos = name.index;
   1.795 +        assert(name.isParam());
   1.796 +        assert(!binding.isParam());
   1.797 +        assert(name.type == binding.type);
   1.798 +        assert(0 <= pos && pos < arity && names[pos] == name);
   1.799 +        assert(binding.function.memberDeclaringClassOrNull() == newData.clazz);
   1.800 +        assert(oldData.getters.length == newData.getters.length-1);
   1.801 +        if (bindCache != null) {
   1.802 +            LambdaForm form = bindCache[pos];
   1.803 +            if (form != null) {
   1.804 +                assert(form.contains(binding)) : "form << " + form + " >> does not contain binding << " + binding + " >>";
   1.805 +                return form;
   1.806 +            }
   1.807 +        } else {
   1.808 +            bindCache = new LambdaForm[arity];
   1.809 +        }
   1.810 +        assert(nameRefsAreLegal());
   1.811 +        int arity2 = arity-1;
   1.812 +        Name[] names2 = names.clone();
   1.813 +        names2[pos] = binding;  // we might move this in a moment
   1.814 +
   1.815 +        // The newly created LF will run with a different BMH.
   1.816 +        // Switch over any pre-existing BMH field references to the new BMH class.
   1.817 +        int firstOldRef = -1;
   1.818 +        for (int i = 0; i < names2.length; i++) {
   1.819 +            Name n = names[i];
   1.820 +            if (n.function != null &&
   1.821 +                n.function.memberDeclaringClassOrNull() == oldData.clazz) {
   1.822 +                MethodHandle oldGetter = n.function.resolvedHandle;
   1.823 +                MethodHandle newGetter = null;
   1.824 +                for (int j = 0; j < oldData.getters.length; j++) {
   1.825 +                    if (oldGetter == oldData.getters[j])
   1.826 +                        newGetter =  newData.getters[j];
   1.827 +                }
   1.828 +                if (newGetter != null) {
   1.829 +                    if (firstOldRef < 0)  firstOldRef = i;
   1.830 +                    Name n2 = new Name(newGetter, n.arguments);
   1.831 +                    names2[i] = n2;
   1.832 +                }
   1.833 +            }
   1.834 +        }
   1.835 +
   1.836 +        // Walk over the new list of names once, in forward order.
   1.837 +        // Replace references to 'name' with 'binding'.
   1.838 +        // Replace data structure references to the old BMH species with the new.
   1.839 +        // This might cause a ripple effect, but it will settle in one pass.
   1.840 +        assert(firstOldRef < 0 || firstOldRef > pos);
   1.841 +        for (int i = pos+1; i < names2.length; i++) {
   1.842 +            if (i <= arity2)  continue;
   1.843 +            names2[i] = names2[i].replaceNames(names, names2, pos, i);
   1.844 +        }
   1.845 +
   1.846 +        //  (a0, a1, name=a2, a3, a4)  =>  (a0, a1, a3, a4, binding)
   1.847 +        int insPos = pos;
   1.848 +        for (; insPos+1 < names2.length; insPos++) {
   1.849 +            Name n = names2[insPos+1];
   1.850 +            if (n.isSiblingBindingBefore(binding)) {
   1.851 +                names2[insPos] = n;
   1.852 +            } else {
   1.853 +                break;
   1.854 +            }
   1.855 +        }
   1.856 +        names2[insPos] = binding;
   1.857 +
   1.858 +        // Since we moved some stuff, maybe update the result reference:
   1.859 +        int result2 = result;
   1.860 +        if (result2 == pos)
   1.861 +            result2 = insPos;
   1.862 +        else if (result2 > pos && result2 <= insPos)
   1.863 +            result2 -= 1;
   1.864 +
   1.865 +        return bindCache[pos] = new LambdaForm(debugName, arity2, names2, result2);
   1.866 +    }
   1.867 +
   1.868 +    boolean contains(Name name) {
   1.869 +        int pos = name.index();
   1.870 +        if (pos >= 0) {
   1.871 +            return pos < names.length && name.equals(names[pos]);
   1.872 +        }
   1.873 +        for (int i = arity; i < names.length; i++) {
   1.874 +            if (name.equals(names[i]))
   1.875 +                return true;
   1.876 +        }
   1.877 +        return false;
   1.878 +    }
   1.879 +
   1.880 +    LambdaForm addArguments(int pos, char... types) {
   1.881 +        assert(pos <= arity);
   1.882 +        int length = names.length;
   1.883 +        int inTypes = types.length;
   1.884 +        Name[] names2 = Arrays.copyOf(names, length + inTypes);
   1.885 +        int arity2 = arity + inTypes;
   1.886 +        int result2 = result;
   1.887 +        if (result2 >= arity)
   1.888 +            result2 += inTypes;
   1.889 +        // names array has MH in slot 0; skip it.
   1.890 +        int argpos = pos + 1;
   1.891 +        // Note:  The LF constructor will rename names2[argpos...].
   1.892 +        // Make space for new arguments (shift temporaries).
   1.893 +        System.arraycopy(names, argpos, names2, argpos + inTypes, length - argpos);
   1.894 +        for (int i = 0; i < inTypes; i++) {
   1.895 +            names2[argpos + i] = new Name(types[i]);
   1.896 +        }
   1.897 +        return new LambdaForm(debugName, arity2, names2, result2);
   1.898 +    }
   1.899 +
   1.900 +    LambdaForm addArguments(int pos, List<Class<?>> types) {
   1.901 +        char[] basicTypes = new char[types.size()];
   1.902 +        for (int i = 0; i < basicTypes.length; i++)
   1.903 +            basicTypes[i] = basicType(types.get(i));
   1.904 +        return addArguments(pos, basicTypes);
   1.905 +    }
   1.906 +
   1.907 +    LambdaForm permuteArguments(int skip, int[] reorder, char[] types) {
   1.908 +        // Note:  When inArg = reorder[outArg], outArg is fed by a copy of inArg.
   1.909 +        // The types are the types of the new (incoming) arguments.
   1.910 +        int length = names.length;
   1.911 +        int inTypes = types.length;
   1.912 +        int outArgs = reorder.length;
   1.913 +        assert(skip+outArgs == arity);
   1.914 +        assert(permutedTypesMatch(reorder, types, names, skip));
   1.915 +        int pos = 0;
   1.916 +        // skip trivial first part of reordering:
   1.917 +        while (pos < outArgs && reorder[pos] == pos)  pos += 1;
   1.918 +        Name[] names2 = new Name[length - outArgs + inTypes];
   1.919 +        System.arraycopy(names, 0, names2, 0, skip+pos);
   1.920 +        // copy the body:
   1.921 +        int bodyLength = length - arity;
   1.922 +        System.arraycopy(names, skip+outArgs, names2, skip+inTypes, bodyLength);
   1.923 +        int arity2 = names2.length - bodyLength;
   1.924 +        int result2 = result;
   1.925 +        if (result2 >= 0) {
   1.926 +            if (result2 < skip+outArgs) {
   1.927 +                // return the corresponding inArg
   1.928 +                result2 = reorder[result2-skip];
   1.929 +            } else {
   1.930 +                result2 = result2 - outArgs + inTypes;
   1.931 +            }
   1.932 +        }
   1.933 +        // rework names in the body:
   1.934 +        for (int j = pos; j < outArgs; j++) {
   1.935 +            Name n = names[skip+j];
   1.936 +            int i = reorder[j];
   1.937 +            // replace names[skip+j] by names2[skip+i]
   1.938 +            Name n2 = names2[skip+i];
   1.939 +            if (n2 == null)
   1.940 +                names2[skip+i] = n2 = new Name(types[i]);
   1.941 +            else
   1.942 +                assert(n2.type == types[i]);
   1.943 +            for (int k = arity2; k < names2.length; k++) {
   1.944 +                names2[k] = names2[k].replaceName(n, n2);
   1.945 +            }
   1.946 +        }
   1.947 +        // some names are unused, but must be filled in
   1.948 +        for (int i = skip+pos; i < arity2; i++) {
   1.949 +            if (names2[i] == null)
   1.950 +                names2[i] = argument(i, types[i - skip]);
   1.951 +        }
   1.952 +        for (int j = arity; j < names.length; j++) {
   1.953 +            int i = j - arity + arity2;
   1.954 +            // replace names2[i] by names[j]
   1.955 +            Name n = names[j];
   1.956 +            Name n2 = names2[i];
   1.957 +            if (n != n2) {
   1.958 +                for (int k = i+1; k < names2.length; k++) {
   1.959 +                    names2[k] = names2[k].replaceName(n, n2);
   1.960 +                }
   1.961 +            }
   1.962 +        }
   1.963 +        return new LambdaForm(debugName, arity2, names2, result2);
   1.964 +    }
   1.965 +
   1.966 +    static boolean permutedTypesMatch(int[] reorder, char[] types, Name[] names, int skip) {
   1.967 +        int inTypes = types.length;
   1.968 +        int outArgs = reorder.length;
   1.969 +        for (int i = 0; i < outArgs; i++) {
   1.970 +            assert(names[skip+i].isParam());
   1.971 +            assert(names[skip+i].type == types[reorder[i]]);
   1.972 +        }
   1.973 +        return true;
   1.974 +    }
   1.975 +
   1.976 +    static class NamedFunction {
   1.977 +        final MemberName member;
   1.978 +        @Stable MethodHandle resolvedHandle;
   1.979 +        @Stable MethodHandle invoker;
   1.980 +
   1.981 +        NamedFunction(MethodHandle resolvedHandle) {
   1.982 +            this(resolvedHandle.internalMemberName(), resolvedHandle);
   1.983 +        }
   1.984 +        NamedFunction(MemberName member, MethodHandle resolvedHandle) {
   1.985 +            this.member = member;
   1.986 +            //resolvedHandle = eraseSubwordTypes(resolvedHandle);
   1.987 +            this.resolvedHandle = resolvedHandle;
   1.988 +        }
   1.989 +        NamedFunction(MethodType basicInvokerType) {
   1.990 +            assert(basicInvokerType == basicInvokerType.basicType()) : basicInvokerType;
   1.991 +            if (basicInvokerType.parameterSlotCount() < MethodType.MAX_MH_INVOKER_ARITY) {
   1.992 +                this.resolvedHandle = basicInvokerType.invokers().basicInvoker();
   1.993 +                this.member = resolvedHandle.internalMemberName();
   1.994 +            } else {
   1.995 +                // necessary to pass BigArityTest
   1.996 +                this.member = Invokers.invokeBasicMethod(basicInvokerType);
   1.997 +            }
   1.998 +        }
   1.999 +
  1.1000 +        // The next 3 constructors are used to break circular dependencies on MH.invokeStatic, etc.
  1.1001 +        // Any LambdaForm containing such a member is not interpretable.
  1.1002 +        // This is OK, since all such LFs are prepared with special primitive vmentry points.
  1.1003 +        // And even without the resolvedHandle, the name can still be compiled and optimized.
  1.1004 +        NamedFunction(Method method) {
  1.1005 +            this(new MemberName(method));
  1.1006 +        }
  1.1007 +        NamedFunction(Field field) {
  1.1008 +            this(new MemberName(field));
  1.1009 +        }
  1.1010 +        NamedFunction(MemberName member) {
  1.1011 +            this.member = member;
  1.1012 +            this.resolvedHandle = null;
  1.1013 +        }
  1.1014 +
  1.1015 +        MethodHandle resolvedHandle() {
  1.1016 +            if (resolvedHandle == null)  resolve();
  1.1017 +            return resolvedHandle;
  1.1018 +        }
  1.1019 +
  1.1020 +        void resolve() {
  1.1021 +            resolvedHandle = DirectMethodHandle.make(member);
  1.1022 +        }
  1.1023 +
  1.1024 +        @Override
  1.1025 +        public boolean equals(Object other) {
  1.1026 +            if (this == other) return true;
  1.1027 +            if (other == null) return false;
  1.1028 +            if (!(other instanceof NamedFunction)) return false;
  1.1029 +            NamedFunction that = (NamedFunction) other;
  1.1030 +            return this.member != null && this.member.equals(that.member);
  1.1031 +        }
  1.1032 +
  1.1033 +        @Override
  1.1034 +        public int hashCode() {
  1.1035 +            if (member != null)
  1.1036 +                return member.hashCode();
  1.1037 +            return super.hashCode();
  1.1038 +        }
  1.1039 +
  1.1040 +        // Put the predefined NamedFunction invokers into the table.
  1.1041 +        static void initializeInvokers() {
  1.1042 +            for (MemberName m : MemberName.getFactory().getMethods(NamedFunction.class, false, null, null, null)) {
  1.1043 +                if (!m.isStatic() || !m.isPackage())  continue;
  1.1044 +                MethodType type = m.getMethodType();
  1.1045 +                if (type.equals(INVOKER_METHOD_TYPE) &&
  1.1046 +                    m.getName().startsWith("invoke_")) {
  1.1047 +                    String sig = m.getName().substring("invoke_".length());
  1.1048 +                    int arity = LambdaForm.signatureArity(sig);
  1.1049 +                    MethodType srcType = MethodType.genericMethodType(arity);
  1.1050 +                    if (LambdaForm.signatureReturn(sig) == 'V')
  1.1051 +                        srcType = srcType.changeReturnType(void.class);
  1.1052 +                    MethodTypeForm typeForm = srcType.form();
  1.1053 +                    typeForm.namedFunctionInvoker = DirectMethodHandle.make(m);
  1.1054 +                }
  1.1055 +            }
  1.1056 +        }
  1.1057 +
  1.1058 +        // The following are predefined NamedFunction invokers.  The system must build
  1.1059 +        // a separate invoker for each distinct signature.
  1.1060 +        /** void return type invokers. */
  1.1061 +        @Hidden
  1.1062 +        static Object invoke__V(MethodHandle mh, Object[] a) throws Throwable {
  1.1063 +            assert(a.length == 0);
  1.1064 +            mh.invokeBasic();
  1.1065 +            return null;
  1.1066 +        }
  1.1067 +        @Hidden
  1.1068 +        static Object invoke_L_V(MethodHandle mh, Object[] a) throws Throwable {
  1.1069 +            assert(a.length == 1);
  1.1070 +            mh.invokeBasic(a[0]);
  1.1071 +            return null;
  1.1072 +        }
  1.1073 +        @Hidden
  1.1074 +        static Object invoke_LL_V(MethodHandle mh, Object[] a) throws Throwable {
  1.1075 +            assert(a.length == 2);
  1.1076 +            mh.invokeBasic(a[0], a[1]);
  1.1077 +            return null;
  1.1078 +        }
  1.1079 +        @Hidden
  1.1080 +        static Object invoke_LLL_V(MethodHandle mh, Object[] a) throws Throwable {
  1.1081 +            assert(a.length == 3);
  1.1082 +            mh.invokeBasic(a[0], a[1], a[2]);
  1.1083 +            return null;
  1.1084 +        }
  1.1085 +        @Hidden
  1.1086 +        static Object invoke_LLLL_V(MethodHandle mh, Object[] a) throws Throwable {
  1.1087 +            assert(a.length == 4);
  1.1088 +            mh.invokeBasic(a[0], a[1], a[2], a[3]);
  1.1089 +            return null;
  1.1090 +        }
  1.1091 +        @Hidden
  1.1092 +        static Object invoke_LLLLL_V(MethodHandle mh, Object[] a) throws Throwable {
  1.1093 +            assert(a.length == 5);
  1.1094 +            mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
  1.1095 +            return null;
  1.1096 +        }
  1.1097 +        /** Object return type invokers. */
  1.1098 +        @Hidden
  1.1099 +        static Object invoke__L(MethodHandle mh, Object[] a) throws Throwable {
  1.1100 +            assert(a.length == 0);
  1.1101 +            return mh.invokeBasic();
  1.1102 +        }
  1.1103 +        @Hidden
  1.1104 +        static Object invoke_L_L(MethodHandle mh, Object[] a) throws Throwable {
  1.1105 +            assert(a.length == 1);
  1.1106 +            return mh.invokeBasic(a[0]);
  1.1107 +        }
  1.1108 +        @Hidden
  1.1109 +        static Object invoke_LL_L(MethodHandle mh, Object[] a) throws Throwable {
  1.1110 +            assert(a.length == 2);
  1.1111 +            return mh.invokeBasic(a[0], a[1]);
  1.1112 +        }
  1.1113 +        @Hidden
  1.1114 +        static Object invoke_LLL_L(MethodHandle mh, Object[] a) throws Throwable {
  1.1115 +            assert(a.length == 3);
  1.1116 +            return mh.invokeBasic(a[0], a[1], a[2]);
  1.1117 +        }
  1.1118 +        @Hidden
  1.1119 +        static Object invoke_LLLL_L(MethodHandle mh, Object[] a) throws Throwable {
  1.1120 +            assert(a.length == 4);
  1.1121 +            return mh.invokeBasic(a[0], a[1], a[2], a[3]);
  1.1122 +        }
  1.1123 +        @Hidden
  1.1124 +        static Object invoke_LLLLL_L(MethodHandle mh, Object[] a) throws Throwable {
  1.1125 +            assert(a.length == 5);
  1.1126 +            return mh.invokeBasic(a[0], a[1], a[2], a[3], a[4]);
  1.1127 +        }
  1.1128 +
  1.1129 +        static final MethodType INVOKER_METHOD_TYPE =
  1.1130 +            MethodType.methodType(Object.class, MethodHandle.class, Object[].class);
  1.1131 +
  1.1132 +        private static MethodHandle computeInvoker(MethodTypeForm typeForm) {
  1.1133 +            MethodHandle mh = typeForm.namedFunctionInvoker;
  1.1134 +            if (mh != null)  return mh;
  1.1135 +            MemberName invoker = InvokerBytecodeGenerator.generateNamedFunctionInvoker(typeForm);  // this could take a while
  1.1136 +            mh = DirectMethodHandle.make(invoker);
  1.1137 +            MethodHandle mh2 = typeForm.namedFunctionInvoker;
  1.1138 +            if (mh2 != null)  return mh2;  // benign race
  1.1139 +            if (!mh.type().equals(INVOKER_METHOD_TYPE))
  1.1140 +                throw new InternalError(mh.debugString());
  1.1141 +            return typeForm.namedFunctionInvoker = mh;
  1.1142 +        }
  1.1143 +
  1.1144 +        @Hidden
  1.1145 +        Object invokeWithArguments(Object... arguments) throws Throwable {
  1.1146 +            // If we have a cached invoker, call it right away.
  1.1147 +            // NOTE: The invoker always returns a reference value.
  1.1148 +            if (TRACE_INTERPRETER)  return invokeWithArgumentsTracing(arguments);
  1.1149 +            assert(checkArgumentTypes(arguments, methodType()));
  1.1150 +            return invoker().invokeBasic(resolvedHandle(), arguments);
  1.1151 +        }
  1.1152 +
  1.1153 +        @Hidden
  1.1154 +        Object invokeWithArgumentsTracing(Object[] arguments) throws Throwable {
  1.1155 +            Object rval;
  1.1156 +            try {
  1.1157 +                traceInterpreter("[ call", this, arguments);
  1.1158 +                if (invoker == null) {
  1.1159 +                    traceInterpreter("| getInvoker", this);
  1.1160 +                    invoker();
  1.1161 +                }
  1.1162 +                if (resolvedHandle == null) {
  1.1163 +                    traceInterpreter("| resolve", this);
  1.1164 +                    resolvedHandle();
  1.1165 +                }
  1.1166 +                assert(checkArgumentTypes(arguments, methodType()));
  1.1167 +                rval = invoker().invokeBasic(resolvedHandle(), arguments);
  1.1168 +            } catch (Throwable ex) {
  1.1169 +                traceInterpreter("] throw =>", ex);
  1.1170 +                throw ex;
  1.1171 +            }
  1.1172 +            traceInterpreter("] return =>", rval);
  1.1173 +            return rval;
  1.1174 +        }
  1.1175 +
  1.1176 +        private MethodHandle invoker() {
  1.1177 +            if (invoker != null)  return invoker;
  1.1178 +            // Get an invoker and cache it.
  1.1179 +            return invoker = computeInvoker(methodType().form());
  1.1180 +        }
  1.1181 +
  1.1182 +        private static boolean checkArgumentTypes(Object[] arguments, MethodType methodType) {
  1.1183 +            if (true)  return true;  // FIXME
  1.1184 +            MethodType dstType = methodType.form().erasedType();
  1.1185 +            MethodType srcType = dstType.basicType().wrap();
  1.1186 +            Class<?>[] ptypes = new Class<?>[arguments.length];
  1.1187 +            for (int i = 0; i < arguments.length; i++) {
  1.1188 +                Object arg = arguments[i];
  1.1189 +                Class<?> ptype = arg == null ? Object.class : arg.getClass();
  1.1190 +                // If the dest. type is a primitive we keep the
  1.1191 +                // argument type.
  1.1192 +                ptypes[i] = dstType.parameterType(i).isPrimitive() ? ptype : Object.class;
  1.1193 +            }
  1.1194 +            MethodType argType = MethodType.methodType(srcType.returnType(), ptypes).wrap();
  1.1195 +            assert(argType.isConvertibleTo(srcType)) : "wrong argument types: cannot convert " + argType + " to " + srcType;
  1.1196 +            return true;
  1.1197 +        }
  1.1198 +
  1.1199 +        String basicTypeSignature() {
  1.1200 +            //return LambdaForm.basicTypeSignature(resolvedHandle.type());
  1.1201 +            return LambdaForm.basicTypeSignature(methodType());
  1.1202 +        }
  1.1203 +
  1.1204 +        MethodType methodType() {
  1.1205 +            if (resolvedHandle != null)
  1.1206 +                return resolvedHandle.type();
  1.1207 +            else
  1.1208 +                // only for certain internal LFs during bootstrapping
  1.1209 +                return member.getInvocationType();
  1.1210 +        }
  1.1211 +
  1.1212 +        MemberName member() {
  1.1213 +            assert(assertMemberIsConsistent());
  1.1214 +            return member;
  1.1215 +        }
  1.1216 +
  1.1217 +        // Called only from assert.
  1.1218 +        private boolean assertMemberIsConsistent() {
  1.1219 +            if (resolvedHandle instanceof DirectMethodHandle) {
  1.1220 +                MemberName m = resolvedHandle.internalMemberName();
  1.1221 +                assert(m.equals(member));
  1.1222 +            }
  1.1223 +            return true;
  1.1224 +        }
  1.1225 +
  1.1226 +        Class<?> memberDeclaringClassOrNull() {
  1.1227 +            return (member == null) ? null : member.getDeclaringClass();
  1.1228 +        }
  1.1229 +
  1.1230 +        char returnType() {
  1.1231 +            return basicType(methodType().returnType());
  1.1232 +        }
  1.1233 +
  1.1234 +        char parameterType(int n) {
  1.1235 +            return basicType(methodType().parameterType(n));
  1.1236 +        }
  1.1237 +
  1.1238 +        int arity() {
  1.1239 +            //int siglen = member.getMethodType().parameterCount();
  1.1240 +            //if (!member.isStatic())  siglen += 1;
  1.1241 +            //return siglen;
  1.1242 +            return methodType().parameterCount();
  1.1243 +        }
  1.1244 +
  1.1245 +        public String toString() {
  1.1246 +            if (member == null)  return String.valueOf(resolvedHandle);
  1.1247 +            return member.getDeclaringClass().getSimpleName()+"."+member.getName();
  1.1248 +        }
  1.1249 +    }
  1.1250 +
  1.1251 +    void resolve() {
  1.1252 +        for (Name n : names) n.resolve();
  1.1253 +    }
  1.1254 +
  1.1255 +    public static char basicType(Class<?> type) {
  1.1256 +        char c = Wrapper.basicTypeChar(type);
  1.1257 +        if ("ZBSC".indexOf(c) >= 0)  c = 'I';
  1.1258 +        assert("LIJFDV".indexOf(c) >= 0);
  1.1259 +        return c;
  1.1260 +    }
  1.1261 +    public static char[] basicTypes(List<Class<?>> types) {
  1.1262 +        char[] btypes = new char[types.size()];
  1.1263 +        for (int i = 0; i < btypes.length; i++) {
  1.1264 +            btypes[i] = basicType(types.get(i));
  1.1265 +        }
  1.1266 +        return btypes;
  1.1267 +    }
  1.1268 +    public static String basicTypeSignature(MethodType type) {
  1.1269 +        char[] sig = new char[type.parameterCount() + 2];
  1.1270 +        int sigp = 0;
  1.1271 +        for (Class<?> pt : type.parameterList()) {
  1.1272 +            sig[sigp++] = basicType(pt);
  1.1273 +        }
  1.1274 +        sig[sigp++] = '_';
  1.1275 +        sig[sigp++] = basicType(type.returnType());
  1.1276 +        assert(sigp == sig.length);
  1.1277 +        return String.valueOf(sig);
  1.1278 +    }
  1.1279 +
  1.1280 +    static final class Name {
  1.1281 +        final char type;
  1.1282 +        private short index;
  1.1283 +        final NamedFunction function;
  1.1284 +        @Stable final Object[] arguments;
  1.1285 +
  1.1286 +        private Name(int index, char type, NamedFunction function, Object[] arguments) {
  1.1287 +            this.index = (short)index;
  1.1288 +            this.type = type;
  1.1289 +            this.function = function;
  1.1290 +            this.arguments = arguments;
  1.1291 +            assert(this.index == index);
  1.1292 +        }
  1.1293 +        Name(MethodHandle function, Object... arguments) {
  1.1294 +            this(new NamedFunction(function), arguments);
  1.1295 +        }
  1.1296 +        Name(MethodType functionType, Object... arguments) {
  1.1297 +            this(new NamedFunction(functionType), arguments);
  1.1298 +            assert(arguments[0] instanceof Name && ((Name)arguments[0]).type == 'L');
  1.1299 +        }
  1.1300 +        Name(MemberName function, Object... arguments) {
  1.1301 +            this(new NamedFunction(function), arguments);
  1.1302 +        }
  1.1303 +        Name(NamedFunction function, Object... arguments) {
  1.1304 +            this(-1, function.returnType(), function, arguments = arguments.clone());
  1.1305 +            assert(arguments.length == function.arity()) : "arity mismatch: arguments.length=" + arguments.length + " == function.arity()=" + function.arity() + " in " + debugString();
  1.1306 +            for (int i = 0; i < arguments.length; i++)
  1.1307 +                assert(typesMatch(function.parameterType(i), arguments[i])) : "types don't match: function.parameterType(" + i + ")=" + function.parameterType(i) + ", arguments[" + i + "]=" + arguments[i] + " in " + debugString();
  1.1308 +        }
  1.1309 +        Name(int index, char type) {
  1.1310 +            this(index, type, null, null);
  1.1311 +        }
  1.1312 +        Name(char type) {
  1.1313 +            this(-1, type);
  1.1314 +        }
  1.1315 +
  1.1316 +        char type() { return type; }
  1.1317 +        int index() { return index; }
  1.1318 +        boolean initIndex(int i) {
  1.1319 +            if (index != i) {
  1.1320 +                if (index != -1)  return false;
  1.1321 +                index = (short)i;
  1.1322 +            }
  1.1323 +            return true;
  1.1324 +        }
  1.1325 +
  1.1326 +
  1.1327 +        void resolve() {
  1.1328 +            if (function != null)
  1.1329 +                function.resolve();
  1.1330 +        }
  1.1331 +
  1.1332 +        Name newIndex(int i) {
  1.1333 +            if (initIndex(i))  return this;
  1.1334 +            return cloneWithIndex(i);
  1.1335 +        }
  1.1336 +        Name cloneWithIndex(int i) {
  1.1337 +            Object[] newArguments = (arguments == null) ? null : arguments.clone();
  1.1338 +            return new Name(i, type, function, newArguments);
  1.1339 +        }
  1.1340 +        Name replaceName(Name oldName, Name newName) {  // FIXME: use replaceNames uniformly
  1.1341 +            if (oldName == newName)  return this;
  1.1342 +            @SuppressWarnings("LocalVariableHidesMemberVariable")
  1.1343 +            Object[] arguments = this.arguments;
  1.1344 +            if (arguments == null)  return this;
  1.1345 +            boolean replaced = false;
  1.1346 +            for (int j = 0; j < arguments.length; j++) {
  1.1347 +                if (arguments[j] == oldName) {
  1.1348 +                    if (!replaced) {
  1.1349 +                        replaced = true;
  1.1350 +                        arguments = arguments.clone();
  1.1351 +                    }
  1.1352 +                    arguments[j] = newName;
  1.1353 +                }
  1.1354 +            }
  1.1355 +            if (!replaced)  return this;
  1.1356 +            return new Name(function, arguments);
  1.1357 +        }
  1.1358 +        Name replaceNames(Name[] oldNames, Name[] newNames, int start, int end) {
  1.1359 +            @SuppressWarnings("LocalVariableHidesMemberVariable")
  1.1360 +            Object[] arguments = this.arguments;
  1.1361 +            boolean replaced = false;
  1.1362 +        eachArg:
  1.1363 +            for (int j = 0; j < arguments.length; j++) {
  1.1364 +                if (arguments[j] instanceof Name) {
  1.1365 +                    Name n = (Name) arguments[j];
  1.1366 +                    int check = n.index;
  1.1367 +                    // harmless check to see if the thing is already in newNames:
  1.1368 +                    if (check >= 0 && check < newNames.length && n == newNames[check])
  1.1369 +                        continue eachArg;
  1.1370 +                    // n might not have the correct index: n != oldNames[n.index].
  1.1371 +                    for (int i = start; i < end; i++) {
  1.1372 +                        if (n == oldNames[i]) {
  1.1373 +                            if (n == newNames[i])
  1.1374 +                                continue eachArg;
  1.1375 +                            if (!replaced) {
  1.1376 +                                replaced = true;
  1.1377 +                                arguments = arguments.clone();
  1.1378 +                            }
  1.1379 +                            arguments[j] = newNames[i];
  1.1380 +                            continue eachArg;
  1.1381 +                        }
  1.1382 +                    }
  1.1383 +                }
  1.1384 +            }
  1.1385 +            if (!replaced)  return this;
  1.1386 +            return new Name(function, arguments);
  1.1387 +        }
  1.1388 +        void internArguments() {
  1.1389 +            @SuppressWarnings("LocalVariableHidesMemberVariable")
  1.1390 +            Object[] arguments = this.arguments;
  1.1391 +            for (int j = 0; j < arguments.length; j++) {
  1.1392 +                if (arguments[j] instanceof Name) {
  1.1393 +                    Name n = (Name) arguments[j];
  1.1394 +                    if (n.isParam() && n.index < INTERNED_ARGUMENT_LIMIT)
  1.1395 +                        arguments[j] = internArgument(n);
  1.1396 +                }
  1.1397 +            }
  1.1398 +        }
  1.1399 +        boolean isParam() {
  1.1400 +            return function == null;
  1.1401 +        }
  1.1402 +        boolean isConstantZero() {
  1.1403 +            return !isParam() && arguments.length == 0 && function.equals(constantZero(0, type).function);
  1.1404 +        }
  1.1405 +
  1.1406 +        public String toString() {
  1.1407 +            return (isParam()?"a":"t")+(index >= 0 ? index : System.identityHashCode(this))+":"+type;
  1.1408 +        }
  1.1409 +        public String debugString() {
  1.1410 +            String s = toString();
  1.1411 +            return (function == null) ? s : s + "=" + exprString();
  1.1412 +        }
  1.1413 +        public String exprString() {
  1.1414 +            if (function == null)  return "null";
  1.1415 +            StringBuilder buf = new StringBuilder(function.toString());
  1.1416 +            buf.append("(");
  1.1417 +            String cma = "";
  1.1418 +            for (Object a : arguments) {
  1.1419 +                buf.append(cma); cma = ",";
  1.1420 +                if (a instanceof Name || a instanceof Integer)
  1.1421 +                    buf.append(a);
  1.1422 +                else
  1.1423 +                    buf.append("(").append(a).append(")");
  1.1424 +            }
  1.1425 +            buf.append(")");
  1.1426 +            return buf.toString();
  1.1427 +        }
  1.1428 +
  1.1429 +        private static boolean typesMatch(char parameterType, Object object) {
  1.1430 +            if (object instanceof Name) {
  1.1431 +                return ((Name)object).type == parameterType;
  1.1432 +            }
  1.1433 +            switch (parameterType) {
  1.1434 +                case 'I':  return object instanceof Integer;
  1.1435 +                case 'J':  return object instanceof Long;
  1.1436 +                case 'F':  return object instanceof Float;
  1.1437 +                case 'D':  return object instanceof Double;
  1.1438 +            }
  1.1439 +            assert(parameterType == 'L');
  1.1440 +            return true;
  1.1441 +        }
  1.1442 +
  1.1443 +        /**
  1.1444 +         * Does this Name precede the given binding node in some canonical order?
  1.1445 +         * This predicate is used to order data bindings (via insertion sort)
  1.1446 +         * with some stability.
  1.1447 +         */
  1.1448 +        boolean isSiblingBindingBefore(Name binding) {
  1.1449 +            assert(!binding.isParam());
  1.1450 +            if (isParam())  return true;
  1.1451 +            if (function.equals(binding.function) &&
  1.1452 +                arguments.length == binding.arguments.length) {
  1.1453 +                boolean sawInt = false;
  1.1454 +                for (int i = 0; i < arguments.length; i++) {
  1.1455 +                    Object a1 = arguments[i];
  1.1456 +                    Object a2 = binding.arguments[i];
  1.1457 +                    if (!a1.equals(a2)) {
  1.1458 +                        if (a1 instanceof Integer && a2 instanceof Integer) {
  1.1459 +                            if (sawInt)  continue;
  1.1460 +                            sawInt = true;
  1.1461 +                            if ((int)a1 < (int)a2)  continue;  // still might be true
  1.1462 +                        }
  1.1463 +                        return false;
  1.1464 +                    }
  1.1465 +                }
  1.1466 +                return sawInt;
  1.1467 +            }
  1.1468 +            return false;
  1.1469 +        }
  1.1470 +
  1.1471 +        public boolean equals(Name that) {
  1.1472 +            if (this == that)  return true;
  1.1473 +            if (isParam())
  1.1474 +                // each parameter is a unique atom
  1.1475 +                return false;  // this != that
  1.1476 +            return
  1.1477 +                //this.index == that.index &&
  1.1478 +                this.type == that.type &&
  1.1479 +                this.function.equals(that.function) &&
  1.1480 +                Arrays.equals(this.arguments, that.arguments);
  1.1481 +        }
  1.1482 +        @Override
  1.1483 +        public boolean equals(Object x) {
  1.1484 +            return x instanceof Name && equals((Name)x);
  1.1485 +        }
  1.1486 +        @Override
  1.1487 +        public int hashCode() {
  1.1488 +            if (isParam())
  1.1489 +                return index | (type << 8);
  1.1490 +            return function.hashCode() ^ Arrays.hashCode(arguments);
  1.1491 +        }
  1.1492 +    }
  1.1493 +
  1.1494 +    static Name argument(int which, char type) {
  1.1495 +        int tn = ALL_TYPES.indexOf(type);
  1.1496 +        if (tn < 0 || which >= INTERNED_ARGUMENT_LIMIT)
  1.1497 +            return new Name(which, type);
  1.1498 +        return INTERNED_ARGUMENTS[tn][which];
  1.1499 +    }
  1.1500 +    static Name internArgument(Name n) {
  1.1501 +        assert(n.isParam()) : "not param: " + n;
  1.1502 +        assert(n.index < INTERNED_ARGUMENT_LIMIT);
  1.1503 +        return argument(n.index, n.type);
  1.1504 +    }
  1.1505 +    static Name[] arguments(int extra, String types) {
  1.1506 +        int length = types.length();
  1.1507 +        Name[] names = new Name[length + extra];
  1.1508 +        for (int i = 0; i < length; i++)
  1.1509 +            names[i] = argument(i, types.charAt(i));
  1.1510 +        return names;
  1.1511 +    }
  1.1512 +    static Name[] arguments(int extra, char... types) {
  1.1513 +        int length = types.length;
  1.1514 +        Name[] names = new Name[length + extra];
  1.1515 +        for (int i = 0; i < length; i++)
  1.1516 +            names[i] = argument(i, types[i]);
  1.1517 +        return names;
  1.1518 +    }
  1.1519 +    static Name[] arguments(int extra, List<Class<?>> types) {
  1.1520 +        int length = types.size();
  1.1521 +        Name[] names = new Name[length + extra];
  1.1522 +        for (int i = 0; i < length; i++)
  1.1523 +            names[i] = argument(i, basicType(types.get(i)));
  1.1524 +        return names;
  1.1525 +    }
  1.1526 +    static Name[] arguments(int extra, Class<?>... types) {
  1.1527 +        int length = types.length;
  1.1528 +        Name[] names = new Name[length + extra];
  1.1529 +        for (int i = 0; i < length; i++)
  1.1530 +            names[i] = argument(i, basicType(types[i]));
  1.1531 +        return names;
  1.1532 +    }
  1.1533 +    static Name[] arguments(int extra, MethodType types) {
  1.1534 +        int length = types.parameterCount();
  1.1535 +        Name[] names = new Name[length + extra];
  1.1536 +        for (int i = 0; i < length; i++)
  1.1537 +            names[i] = argument(i, basicType(types.parameterType(i)));
  1.1538 +        return names;
  1.1539 +    }
  1.1540 +    static final String ALL_TYPES = "LIJFD";  // omit V, not an argument type
  1.1541 +    static final int INTERNED_ARGUMENT_LIMIT = 10;
  1.1542 +    private static final Name[][] INTERNED_ARGUMENTS
  1.1543 +            = new Name[ALL_TYPES.length()][INTERNED_ARGUMENT_LIMIT];
  1.1544 +    static {
  1.1545 +        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
  1.1546 +            for (int i = 0; i < INTERNED_ARGUMENTS[tn].length; i++) {
  1.1547 +                char type = ALL_TYPES.charAt(tn);
  1.1548 +                INTERNED_ARGUMENTS[tn][i] = new Name(i, type);
  1.1549 +            }
  1.1550 +        }
  1.1551 +    }
  1.1552 +
  1.1553 +    private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
  1.1554 +
  1.1555 +    static Name constantZero(int which, char type) {
  1.1556 +        return CONSTANT_ZERO[ALL_TYPES.indexOf(type)].newIndex(which);
  1.1557 +    }
  1.1558 +    private static final Name[] CONSTANT_ZERO
  1.1559 +            = new Name[ALL_TYPES.length()];
  1.1560 +    static {
  1.1561 +        for (int tn = 0; tn < ALL_TYPES.length(); tn++) {
  1.1562 +            char bt = ALL_TYPES.charAt(tn);
  1.1563 +            Wrapper wrap = Wrapper.forBasicType(bt);
  1.1564 +            MemberName zmem = new MemberName(LambdaForm.class, "zero"+bt, MethodType.methodType(wrap.primitiveType()), REF_invokeStatic);
  1.1565 +            try {
  1.1566 +                zmem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zmem, null, NoSuchMethodException.class);
  1.1567 +            } catch (IllegalAccessException|NoSuchMethodException ex) {
  1.1568 +                throw newInternalError(ex);
  1.1569 +            }
  1.1570 +            NamedFunction zcon = new NamedFunction(zmem);
  1.1571 +            Name n = new Name(zcon).newIndex(0);
  1.1572 +            assert(n.type == ALL_TYPES.charAt(tn));
  1.1573 +            CONSTANT_ZERO[tn] = n;
  1.1574 +            assert(n.isConstantZero());
  1.1575 +        }
  1.1576 +    }
  1.1577 +
  1.1578 +    // Avoid appealing to ValueConversions at bootstrap time:
  1.1579 +    private static int zeroI() { return 0; }
  1.1580 +    private static long zeroJ() { return 0; }
  1.1581 +    private static float zeroF() { return 0; }
  1.1582 +    private static double zeroD() { return 0; }
  1.1583 +    private static Object zeroL() { return null; }
  1.1584 +
  1.1585 +    // Put this last, so that previous static inits can run before.
  1.1586 +    static {
  1.1587 +        if (USE_PREDEFINED_INTERPRET_METHODS)
  1.1588 +            PREPARED_FORMS.putAll(computeInitialPreparedForms());
  1.1589 +    }
  1.1590 +
  1.1591 +    /**
  1.1592 +     * Internal marker for byte-compiled LambdaForms.
  1.1593 +     */
  1.1594 +    /*non-public*/
  1.1595 +    @Target(ElementType.METHOD)
  1.1596 +    @Retention(RetentionPolicy.RUNTIME)
  1.1597 +    @interface Compiled {
  1.1598 +    }
  1.1599 +
  1.1600 +    /**
  1.1601 +     * Internal marker for LambdaForm interpreter frames.
  1.1602 +     */
  1.1603 +    /*non-public*/
  1.1604 +    @Target(ElementType.METHOD)
  1.1605 +    @Retention(RetentionPolicy.RUNTIME)
  1.1606 +    @interface Hidden {
  1.1607 +    }
  1.1608 +
  1.1609 +
  1.1610 +/*
  1.1611 +    // Smoke-test for the invokers used in this file.
  1.1612 +    static void testMethodHandleLinkers() throws Throwable {
  1.1613 +        MemberName.Factory lookup = MemberName.getFactory();
  1.1614 +        MemberName asList_MN = new MemberName(Arrays.class, "asList",
  1.1615 +                                              MethodType.methodType(List.class, Object[].class),
  1.1616 +                                              REF_invokeStatic);
  1.1617 +        //MethodHandleNatives.resolve(asList_MN, null);
  1.1618 +        asList_MN = lookup.resolveOrFail(asList_MN, REF_invokeStatic, null, NoSuchMethodException.class);
  1.1619 +        System.out.println("about to call "+asList_MN);
  1.1620 +        Object[] abc = { "a", "bc" };
  1.1621 +        List<?> lst = (List<?>) MethodHandle.linkToStatic(abc, asList_MN);
  1.1622 +        System.out.println("lst="+lst);
  1.1623 +        MemberName toString_MN = new MemberName(Object.class.getMethod("toString"));
  1.1624 +        String s1 = (String) MethodHandle.linkToVirtual(lst, toString_MN);
  1.1625 +        toString_MN = new MemberName(Object.class.getMethod("toString"), true);
  1.1626 +        String s2 = (String) MethodHandle.linkToSpecial(lst, toString_MN);
  1.1627 +        System.out.println("[s1,s2,lst]="+Arrays.asList(s1, s2, lst.toString()));
  1.1628 +        MemberName toArray_MN = new MemberName(List.class.getMethod("toArray"));
  1.1629 +        Object[] arr = (Object[]) MethodHandle.linkToInterface(lst, toArray_MN);
  1.1630 +        System.out.println("toArray="+Arrays.toString(arr));
  1.1631 +    }
  1.1632 +    static { try { testMethodHandleLinkers(); } catch (Throwable ex) { throw new RuntimeException(ex); } }
  1.1633 +    // Requires these definitions in MethodHandle:
  1.1634 +    static final native Object linkToStatic(Object x1, MemberName mn) throws Throwable;
  1.1635 +    static final native Object linkToVirtual(Object x1, MemberName mn) throws Throwable;
  1.1636 +    static final native Object linkToSpecial(Object x1, MemberName mn) throws Throwable;
  1.1637 +    static final native Object linkToInterface(Object x1, MemberName mn) throws Throwable;
  1.1638 + */
  1.1639 +
  1.1640 +    static { NamedFunction.initializeInvokers(); }
  1.1641 +
  1.1642 +    // The following hack is necessary in order to suppress TRACE_INTERPRETER
  1.1643 +    // during execution of the static initializes of this class.
  1.1644 +    // Turning on TRACE_INTERPRETER too early will cause
  1.1645 +    // stack overflows and other misbehavior during attempts to trace events
  1.1646 +    // that occur during LambdaForm.<clinit>.
  1.1647 +    // Therefore, do not move this line higher in this file, and do not remove.
  1.1648 +    private static final boolean TRACE_INTERPRETER = MethodHandleStatics.TRACE_INTERPRETER;
  1.1649 +}