1/*
2 * Copyright (c) 2008, 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
26package java.lang.invoke;
27
28import jdk.internal.loader.BootLoader;
29import jdk.internal.org.objectweb.asm.ClassWriter;
30import jdk.internal.org.objectweb.asm.FieldVisitor;
31import jdk.internal.org.objectweb.asm.MethodVisitor;
32import jdk.internal.vm.annotation.Stable;
33import sun.invoke.util.ValueConversions;
34import sun.invoke.util.Wrapper;
35
36import java.lang.invoke.LambdaForm.NamedFunction;
37import java.lang.invoke.MethodHandles.Lookup;
38import java.lang.reflect.Field;
39import java.util.concurrent.ConcurrentHashMap;
40import java.util.concurrent.ConcurrentMap;
41import java.util.function.Function;
42
43import static java.lang.invoke.LambdaForm.BasicType;
44import static java.lang.invoke.LambdaForm.BasicType.*;
45import static java.lang.invoke.MethodHandleStatics.*;
46import static jdk.internal.org.objectweb.asm.Opcodes.*;
47
48/**
49 * The flavor of method handle which emulates an invoke instruction
50 * on a predetermined argument.  The JVM dispatches to the correct method
51 * when the handle is created, not when it is invoked.
52 *
53 * All bound arguments are encapsulated in dedicated species.
54 */
55/*non-public*/ abstract class BoundMethodHandle extends MethodHandle {
56
57    /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) {
58        super(type, form);
59        assert(speciesData() == speciesData(form));
60    }
61
62    //
63    // BMH API and internals
64    //
65
66    static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, BasicType xtype, Object x) {
67        // for some type signatures, there exist pre-defined concrete BMH classes
68        try {
69            switch (xtype) {
70            case L_TYPE:
71                return bindSingle(type, form, x);  // Use known fast path.
72            case I_TYPE:
73                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(I_TYPE).constructor().invokeBasic(type, form, ValueConversions.widenSubword(x));
74            case J_TYPE:
75                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(J_TYPE).constructor().invokeBasic(type, form, (long) x);
76            case F_TYPE:
77                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(F_TYPE).constructor().invokeBasic(type, form, (float) x);
78            case D_TYPE:
79                return (BoundMethodHandle) SpeciesData.EMPTY.extendWith(D_TYPE).constructor().invokeBasic(type, form, (double) x);
80            default : throw newInternalError("unexpected xtype: " + xtype);
81            }
82        } catch (Throwable t) {
83            throw uncaughtException(t);
84        }
85    }
86
87    /*non-public*/
88    LambdaFormEditor editor() {
89        return form.editor();
90    }
91
92    static BoundMethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
93        return Species_L.make(type, form, x);
94    }
95
96    @Override // there is a default binder in the super class, for 'L' types only
97    /*non-public*/
98    BoundMethodHandle bindArgumentL(int pos, Object value) {
99        return editor().bindArgumentL(this, pos, value);
100    }
101    /*non-public*/
102    BoundMethodHandle bindArgumentI(int pos, int value) {
103        return editor().bindArgumentI(this, pos, value);
104    }
105    /*non-public*/
106    BoundMethodHandle bindArgumentJ(int pos, long value) {
107        return editor().bindArgumentJ(this, pos, value);
108    }
109    /*non-public*/
110    BoundMethodHandle bindArgumentF(int pos, float value) {
111        return editor().bindArgumentF(this, pos, value);
112    }
113    /*non-public*/
114    BoundMethodHandle bindArgumentD(int pos, double value) {
115        return editor().bindArgumentD(this, pos, value);
116    }
117
118    @Override
119    BoundMethodHandle rebind() {
120        if (!tooComplex()) {
121            return this;
122        }
123        return makeReinvoker(this);
124    }
125
126    private boolean tooComplex() {
127        return (fieldCount() > FIELD_COUNT_THRESHOLD ||
128                form.expressionCount() > FORM_EXPRESSION_THRESHOLD);
129    }
130    private static final int FIELD_COUNT_THRESHOLD = 12;      // largest convenient BMH field count
131    private static final int FORM_EXPRESSION_THRESHOLD = 24;  // largest convenient BMH expression count
132
133    /**
134     * A reinvoker MH has this form:
135     * {@code lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }}
136     */
137    static BoundMethodHandle makeReinvoker(MethodHandle target) {
138        LambdaForm form = DelegatingMethodHandle.makeReinvokerForm(
139                target, MethodTypeForm.LF_REBIND,
140                Species_L.SPECIES_DATA, Species_L.SPECIES_DATA.getterFunction(0));
141        return Species_L.make(target.type(), form, target);
142    }
143
144    /**
145     * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
146     * static field containing this value, and they must accordingly implement this method.
147     */
148    /*non-public*/ abstract SpeciesData speciesData();
149
150    /*non-public*/ static SpeciesData speciesData(LambdaForm form) {
151        Object c = form.names[0].constraint;
152        if (c instanceof SpeciesData)
153            return (SpeciesData) c;
154        // if there is no BMH constraint, then use the null constraint
155        return SpeciesData.EMPTY;
156    }
157
158    /**
159     * Return the number of fields in this BMH.  Equivalent to speciesData().fieldCount().
160     */
161    /*non-public*/ abstract int fieldCount();
162
163    @Override
164    Object internalProperties() {
165        return "\n& BMH="+internalValues();
166    }
167
168    @Override
169    final String internalValues() {
170        int count = speciesData().fieldCount();
171        if (count == 1) {
172            return "[" + arg(0) + "]";
173        }
174        StringBuilder sb = new StringBuilder("[");
175        for (int i = 0; i < count; ++i) {
176            sb.append("\n  ").append(i).append(": ( ").append(arg(i)).append(" )");
177        }
178        return sb.append("\n]").toString();
179    }
180
181    /*non-public*/ final Object arg(int i) {
182        try {
183            switch (speciesData().fieldType(i)) {
184            case L_TYPE: return          speciesData().getters[i].invokeBasic(this);
185            case I_TYPE: return (int)    speciesData().getters[i].invokeBasic(this);
186            case J_TYPE: return (long)   speciesData().getters[i].invokeBasic(this);
187            case F_TYPE: return (float)  speciesData().getters[i].invokeBasic(this);
188            case D_TYPE: return (double) speciesData().getters[i].invokeBasic(this);
189            }
190        } catch (Throwable ex) {
191            throw uncaughtException(ex);
192        }
193        throw new InternalError("unexpected type: " + speciesData().typeChars+"."+i);
194    }
195
196    //
197    // cloning API
198    //
199
200    /*non-public*/ abstract BoundMethodHandle copyWith(MethodType mt, LambdaForm lf);
201    /*non-public*/ abstract BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg);
202    /*non-public*/ abstract BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int    narg);
203    /*non-public*/ abstract BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long   narg);
204    /*non-public*/ abstract BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float  narg);
205    /*non-public*/ abstract BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg);
206
207    //
208    // concrete BMH classes required to close bootstrap loops
209    //
210
211    private  // make it private to force users to access the enclosing class first
212    static final class Species_L extends BoundMethodHandle {
213        final Object argL0;
214        private Species_L(MethodType mt, LambdaForm lf, Object argL0) {
215            super(mt, lf);
216            this.argL0 = argL0;
217        }
218        @Override
219        /*non-public*/ SpeciesData speciesData() {
220            return SPECIES_DATA;
221        }
222        @Override
223        /*non-public*/ int fieldCount() {
224            return 1;
225        }
226        /*non-public*/ static final SpeciesData SPECIES_DATA = new SpeciesData("L", Species_L.class);
227        /*non-public*/ static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0) {
228            return new Species_L(mt, lf, argL0);
229        }
230        @Override
231        /*non-public*/ final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
232            return new Species_L(mt, lf, argL0);
233        }
234        @Override
235        /*non-public*/ final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
236            try {
237                return (BoundMethodHandle) SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
238            } catch (Throwable ex) {
239                throw uncaughtException(ex);
240            }
241        }
242        @Override
243        /*non-public*/ final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
244            try {
245                return (BoundMethodHandle) SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
246            } catch (Throwable ex) {
247                throw uncaughtException(ex);
248            }
249        }
250        @Override
251        /*non-public*/ final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
252            try {
253                return (BoundMethodHandle) SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
254            } catch (Throwable ex) {
255                throw uncaughtException(ex);
256            }
257        }
258        @Override
259        /*non-public*/ final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
260            try {
261                return (BoundMethodHandle) SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
262            } catch (Throwable ex) {
263                throw uncaughtException(ex);
264            }
265        }
266        @Override
267        /*non-public*/ final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
268            try {
269                return (BoundMethodHandle) SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, narg);
270            } catch (Throwable ex) {
271                throw uncaughtException(ex);
272            }
273        }
274    }
275
276    //
277    // BMH species meta-data
278    //
279
280    /**
281     * Meta-data wrapper for concrete BMH types.
282     * Each BMH type corresponds to a given sequence of basic field types (LIJFD).
283     * The fields are immutable; their values are fully specified at object construction.
284     * Each BMH type supplies an array of getter functions which may be used in lambda forms.
285     * A BMH is constructed by cloning a shorter BMH and adding one or more new field values.
286     * The shortest possible BMH has zero fields; its class is SimpleMethodHandle.
287     * BMH species are not interrelated by subtyping, even though it would appear that
288     * a shorter BMH could serve as a supertype of a longer one which extends it.
289     */
290    static class SpeciesData {
291        private final String                             typeChars;
292        private final BasicType[]                        typeCodes;
293        private final Class<? extends BoundMethodHandle> clazz;
294        // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
295        // Therefore, we need a non-final link in the chain.  Use array elements.
296        @Stable private final MethodHandle[]             constructor;
297        @Stable private final MethodHandle[]             getters;
298        @Stable private final NamedFunction[]            nominalGetters;
299        @Stable private final SpeciesData[]              extensions;
300
301        /*non-public*/ int fieldCount() {
302            return typeCodes.length;
303        }
304        /*non-public*/ BasicType fieldType(int i) {
305            return typeCodes[i];
306        }
307        /*non-public*/ char fieldTypeChar(int i) {
308            return typeChars.charAt(i);
309        }
310        String fieldSignature() {
311            return typeChars;
312        }
313        public Class<? extends BoundMethodHandle> fieldHolder() {
314            return clazz;
315        }
316        public String toString() {
317            return "SpeciesData<"+fieldSignature()+">";
318        }
319
320        /**
321         * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
322         * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
323         * getter.
324         */
325        NamedFunction getterFunction(int i) {
326            NamedFunction nf = nominalGetters[i];
327            assert(nf.memberDeclaringClassOrNull() == fieldHolder());
328            assert(nf.returnType() == fieldType(i));
329            return nf;
330        }
331
332        NamedFunction[] getterFunctions() {
333            return nominalGetters;
334        }
335
336        MethodHandle[] getterHandles() { return getters; }
337
338        MethodHandle constructor() {
339            return constructor[0];
340        }
341
342        static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
343
344        SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
345            this.typeChars = types;
346            this.typeCodes = basicTypes(types);
347            this.clazz = clazz;
348            if (!INIT_DONE) {
349                this.constructor = new MethodHandle[1];  // only one ctor
350                this.getters = new MethodHandle[types.length()];
351                this.nominalGetters = new NamedFunction[types.length()];
352            } else {
353                this.constructor = Factory.makeCtors(clazz, types, null);
354                this.getters = Factory.makeGetters(clazz, types, null);
355                this.nominalGetters = Factory.makeNominalGetters(types, null, this.getters);
356            }
357            this.extensions = new SpeciesData[ARG_TYPE_LIMIT];
358        }
359
360        private void initForBootstrap() {
361            assert(!INIT_DONE);
362            if (constructor() == null) {
363                String types = typeChars;
364                CACHE.put(types, this);
365                Factory.makeCtors(clazz, types, this.constructor);
366                Factory.makeGetters(clazz, types, this.getters);
367                Factory.makeNominalGetters(types, this.nominalGetters, this.getters);
368            }
369        }
370
371        private static final ConcurrentMap<String, SpeciesData> CACHE = new ConcurrentHashMap<>();
372        private static final boolean INIT_DONE;  // set after <clinit> finishes...
373
374        SpeciesData extendWith(byte type) {
375            return extendWith(BasicType.basicType(type));
376        }
377
378        SpeciesData extendWith(BasicType type) {
379            int ord = type.ordinal();
380            SpeciesData d = extensions[ord];
381            if (d != null)  return d;
382            extensions[ord] = d = get(typeChars+type.basicTypeChar());
383            return d;
384        }
385
386        private static SpeciesData get(String types) {
387            return CACHE.computeIfAbsent(types, new Function<String, SpeciesData>() {
388                @Override
389                public SpeciesData apply(String types) {
390                    Class<? extends BoundMethodHandle> bmhcl = Factory.getConcreteBMHClass(types);
391                    // SpeciesData instantiation may throw VirtualMachineError because of
392                    // code cache overflow...
393                    SpeciesData speciesData = new SpeciesData(types, bmhcl);
394                    // CHM.computeIfAbsent ensures only one SpeciesData will be set
395                    // successfully on the concrete BMH class if ever
396                    Factory.setSpeciesDataToConcreteBMHClass(bmhcl, speciesData);
397                    // the concrete BMH class is published via SpeciesData instance
398                    // returned here only after it's SPECIES_DATA field is set
399                    return speciesData;
400                }
401            });
402        }
403
404        /**
405         * This is to be called when assertions are enabled. It checks whether SpeciesData for all of the statically
406         * defined species subclasses of BoundMethodHandle has been added to the SpeciesData cache. See below in the
407         * static initializer for
408         */
409        static boolean speciesDataCachePopulated() {
410            Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
411            for (Class<?> c : rootCls.getDeclaredClasses()) {
412                if (rootCls.isAssignableFrom(c)) {
413                    final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
414                    SpeciesData d = Factory.getSpeciesDataFromConcreteBMHClass(cbmh);
415                    assert(d != null) : cbmh.getName();
416                    assert(d.clazz == cbmh);
417                    assert(CACHE.get(d.typeChars) == d);
418                }
419            }
420            return true;
421        }
422
423        static {
424            // Pre-fill the BMH species-data cache with EMPTY and all BMH's inner subclasses.
425            EMPTY.initForBootstrap();
426            Species_L.SPECIES_DATA.initForBootstrap();
427            // check that all static SpeciesData instances have been initialized
428            assert speciesDataCachePopulated();
429            // Note:  Do not simplify this, because INIT_DONE must not be
430            // a compile-time constant during bootstrapping.
431            INIT_DONE = Boolean.TRUE;
432        }
433    }
434
435    static SpeciesData getSpeciesData(String types) {
436        return SpeciesData.get(types);
437    }
438
439    /**
440     * Generation of concrete BMH classes.
441     *
442     * A concrete BMH species is fit for binding a number of values adhering to a
443     * given type pattern. Reference types are erased.
444     *
445     * BMH species are cached by type pattern.
446     *
447     * A BMH species has a number of fields with the concrete (possibly erased) types of
448     * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
449     * which can be included as names in lambda forms.
450     */
451    static class Factory {
452
453        private static final String JLO_SIG  = "Ljava/lang/Object;";
454        private static final String MH       = "java/lang/invoke/MethodHandle";
455        private static final String MH_SIG   = "L"+MH+";";
456        private static final String BMH      = "java/lang/invoke/BoundMethodHandle";
457        private static final String BMH_NAME = "java.lang.invoke.BoundMethodHandle";
458        private static final String BMH_SIG  = "L"+BMH+";";
459        private static final String SPECIES_DATA     = "java/lang/invoke/BoundMethodHandle$SpeciesData";
460        private static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
461        private static final String STABLE_SIG       = "Ljdk/internal/vm/annotation/Stable;";
462
463        private static final String SPECIES_PREFIX_NAME = "Species_";
464        private static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
465        private static final String SPECIES_CLASS_PREFIX = BMH_NAME + "$" + SPECIES_PREFIX_NAME;
466
467        private static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
468        private static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
469        private static final String INT_SIG    = "()I";
470
471        private static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
472
473        private static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
474
475        private static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
476
477        /**
478         * Get a concrete subclass of BMH for a given combination of bound types.
479         *
480         * @param types the type signature, wherein reference types are erased to 'L'
481         * @return the concrete BMH class
482         */
483        static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
484            // CHM.computeIfAbsent ensures generateConcreteBMHClass is called
485            // only once per key.
486            return CLASS_CACHE.computeIfAbsent(
487                types, new Function<String, Class<? extends BoundMethodHandle>>() {
488                    @Override
489                    public Class<? extends BoundMethodHandle> apply(String types) {
490                        String shortTypes = LambdaForm.shortenSignature(types);
491                        String className = SPECIES_CLASS_PREFIX + shortTypes;
492                        Class<?> c = BootLoader.loadClassOrNull(className);
493                        if (TRACE_RESOLVE) {
494                            System.out.println("[BMH_RESOLVE] " + shortTypes +
495                                    (c != null ? " (success)" : " (fail)") );
496                        }
497                        if (c != null) {
498                            return c.asSubclass(BoundMethodHandle.class);
499                        } else {
500                            // Not pregenerated, generate the class
501                            return generateConcreteBMHClass(shortTypes, types);
502                        }
503                    }
504                });
505        }
506
507        /**
508         * Generate a concrete subclass of BMH for a given combination of bound types.
509         *
510         * A concrete BMH species adheres to the following schema:
511         *
512         * <pre>
513         * class Species_[[types]] extends BoundMethodHandle {
514         *     [[fields]]
515         *     final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
516         * }
517         * </pre>
518         *
519         * The {@code [[types]]} signature is precisely the string that is passed to this
520         * method.
521         *
522         * The {@code [[fields]]} section consists of one field definition per character in
523         * the type signature, adhering to the naming schema described in the definition of
524         * {@link #makeFieldName}.
525         *
526         * For example, a concrete BMH species for two reference and one integral bound values
527         * would have the following shape:
528         *
529         * <pre>
530         * class BoundMethodHandle { ... private static
531         * final class Species_LLI extends BoundMethodHandle {
532         *     final Object argL0;
533         *     final Object argL1;
534         *     final int argI2;
535         *     private Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
536         *         super(mt, lf);
537         *         this.argL0 = argL0;
538         *         this.argL1 = argL1;
539         *         this.argI2 = argI2;
540         *     }
541         *     final SpeciesData speciesData() { return SPECIES_DATA; }
542         *     final int fieldCount() { return 3; }
543         *     &#64;Stable static SpeciesData SPECIES_DATA; // injected afterwards
544         *     static BoundMethodHandle make(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
545         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
546         *     }
547         *     final BoundMethodHandle copyWith(MethodType mt, LambdaForm lf) {
548         *         return new Species_LLI(mt, lf, argL0, argL1, argI2);
549         *     }
550         *     final BoundMethodHandle copyWithExtendL(MethodType mt, LambdaForm lf, Object narg) {
551         *         return SPECIES_DATA.extendWith(L_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
552         *     }
553         *     final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
554         *         return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
555         *     }
556         *     final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
557         *         return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
558         *     }
559         *     final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
560         *         return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
561         *     }
562         *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
563         *         return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
564         *     }
565         * }
566         * </pre>
567         *
568         * @param types the type signature, wherein reference types are erased to 'L'
569         * @return the generated concrete BMH class
570         */
571        static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String shortTypes,
572                String types) {
573            final String className  = speciesInternalClassName(shortTypes);
574            byte[] classFile = generateConcreteBMHClassBytes(shortTypes, types, className);
575
576            // load class
577            InvokerBytecodeGenerator.maybeDump(className, classFile);
578            Class<? extends BoundMethodHandle> bmhClass =
579                UNSAFE.defineClass(className, classFile, 0, classFile.length,
580                                   BoundMethodHandle.class.getClassLoader(), null)
581                    .asSubclass(BoundMethodHandle.class);
582
583            return bmhClass;
584        }
585
586        static String speciesInternalClassName(String shortTypes) {
587            return SPECIES_PREFIX_PATH + shortTypes;
588        }
589
590        static byte[] generateConcreteBMHClassBytes(final String shortTypes,
591                final String types, final String className) {
592            final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
593
594            final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
595            final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
596            cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
597            cw.visitSource(sourceFile, null);
598
599            // emit static types and SPECIES_DATA fields
600            FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
601            fw.visitAnnotation(STABLE_SIG, true);
602            fw.visitEnd();
603
604            // emit bound argument fields
605            for (int i = 0; i < types.length(); ++i) {
606                final char t = types.charAt(i);
607                final String fieldName = makeFieldName(types, i);
608                final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
609                cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
610            }
611
612            MethodVisitor mv;
613
614            // emit constructor
615            mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
616            mv.visitCode();
617            mv.visitVarInsn(ALOAD, 0); // this
618            mv.visitVarInsn(ALOAD, 1); // type
619            mv.visitVarInsn(ALOAD, 2); // form
620
621            mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
622
623            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
624                // i counts the arguments, j counts corresponding argument slots
625                char t = types.charAt(i);
626                mv.visitVarInsn(ALOAD, 0);
627                mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
628                mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
629                if (t == 'J' || t == 'D') {
630                    ++j; // adjust argument register access
631                }
632            }
633
634            mv.visitInsn(RETURN);
635            mv.visitMaxs(0, 0);
636            mv.visitEnd();
637
638            // emit implementation of speciesData()
639            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
640            mv.visitCode();
641            mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
642            mv.visitInsn(ARETURN);
643            mv.visitMaxs(0, 0);
644            mv.visitEnd();
645
646            // emit implementation of fieldCount()
647            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
648            mv.visitCode();
649            int fc = types.length();
650            if (fc <= (ICONST_5 - ICONST_0)) {
651                mv.visitInsn(ICONST_0 + fc);
652            } else {
653                mv.visitIntInsn(SIPUSH, fc);
654            }
655            mv.visitInsn(IRETURN);
656            mv.visitMaxs(0, 0);
657            mv.visitEnd();
658            // emit make()  ...factory method wrapping constructor
659            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
660            mv.visitCode();
661            // make instance
662            mv.visitTypeInsn(NEW, className);
663            mv.visitInsn(DUP);
664            // load mt, lf
665            mv.visitVarInsn(ALOAD, 0);  // type
666            mv.visitVarInsn(ALOAD, 1);  // form
667            // load factory method arguments
668            for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
669                // i counts the arguments, j counts corresponding argument slots
670                char t = types.charAt(i);
671                mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
672                if (t == 'J' || t == 'D') {
673                    ++j; // adjust argument register access
674                }
675            }
676
677            // finally, invoke the constructor and return
678            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
679            mv.visitInsn(ARETURN);
680            mv.visitMaxs(0, 0);
681            mv.visitEnd();
682
683            // emit copyWith()
684            mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
685            mv.visitCode();
686            // make instance
687            mv.visitTypeInsn(NEW, className);
688            mv.visitInsn(DUP);
689            // load mt, lf
690            mv.visitVarInsn(ALOAD, 1);
691            mv.visitVarInsn(ALOAD, 2);
692            // put fields on the stack
693            emitPushFields(types, className, mv);
694            // finally, invoke the constructor and return
695            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
696            mv.visitInsn(ARETURN);
697            mv.visitMaxs(0, 0);
698            mv.visitEnd();
699
700            // for each type, emit copyWithExtendT()
701            for (BasicType type : BasicType.ARG_TYPES) {
702                int ord = type.ordinal();
703                char btChar = type.basicTypeChar();
704                mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
705                mv.visitCode();
706                // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
707                // obtain constructor
708                mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
709                int iconstInsn = ICONST_0 + ord;
710                assert(iconstInsn <= ICONST_5);
711                mv.visitInsn(iconstInsn);
712                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
713                mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
714                // load mt, lf
715                mv.visitVarInsn(ALOAD, 1);
716                mv.visitVarInsn(ALOAD, 2);
717                // put fields on the stack
718                emitPushFields(types, className, mv);
719                // put narg on stack
720                mv.visitVarInsn(typeLoadOp(btChar), 3);
721                // finally, invoke the constructor and return
722                mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
723                mv.visitInsn(ARETURN);
724                mv.visitMaxs(0, 0);
725                mv.visitEnd();
726            }
727
728            cw.visitEnd();
729
730            return cw.toByteArray();
731        }
732
733        private static int typeLoadOp(char t) {
734            switch (t) {
735            case 'L': return ALOAD;
736            case 'I': return ILOAD;
737            case 'J': return LLOAD;
738            case 'F': return FLOAD;
739            case 'D': return DLOAD;
740            default : throw newInternalError("unrecognized type " + t);
741            }
742        }
743
744        private static void emitPushFields(String types, String className, MethodVisitor mv) {
745            for (int i = 0; i < types.length(); ++i) {
746                char tc = types.charAt(i);
747                mv.visitVarInsn(ALOAD, 0);
748                mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
749            }
750        }
751
752        static String typeSig(char t) {
753            return t == 'L' ? JLO_SIG : String.valueOf(t);
754        }
755
756        //
757        // Getter MH generation.
758        //
759
760        private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
761            String fieldName = makeFieldName(types, index);
762            Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
763            try {
764                return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
765            } catch (NoSuchFieldException | IllegalAccessException e) {
766                throw newInternalError(e);
767            }
768        }
769
770        static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
771            if (mhs == null)  mhs = new MethodHandle[types.length()];
772            for (int i = 0; i < mhs.length; ++i) {
773                mhs[i] = makeGetter(cbmhClass, types, i);
774                assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
775            }
776            return mhs;
777        }
778
779        static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
780            if (mhs == null)  mhs = new MethodHandle[1];
781            if (types.equals(""))  return mhs;  // hack for empty BMH species
782            mhs[0] = makeCbmhCtor(cbmh, types);
783            return mhs;
784        }
785
786        static NamedFunction[] makeNominalGetters(String types, NamedFunction[] nfs, MethodHandle[] getters) {
787            if (nfs == null)  nfs = new NamedFunction[types.length()];
788            for (int i = 0; i < nfs.length; ++i) {
789                nfs[i] = new NamedFunction(getters[i]);
790            }
791            return nfs;
792        }
793
794        //
795        // Auxiliary methods.
796        //
797
798        static SpeciesData getSpeciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
799            try {
800                Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
801                return (SpeciesData) F_SPECIES_DATA.get(null);
802            } catch (ReflectiveOperationException ex) {
803                throw newInternalError(ex);
804            }
805        }
806
807        static void setSpeciesDataToConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh, SpeciesData speciesData) {
808            try {
809                Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
810                // ## FIXME: annotation parser can't create proxy classes until module system is fully initialzed
811                // assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
812                F_SPECIES_DATA.set(null, speciesData);
813            } catch (ReflectiveOperationException ex) {
814                throw newInternalError(ex);
815            }
816        }
817
818        /**
819         * Field names in concrete BMHs adhere to this pattern:
820         * arg + type + index
821         * where type is a single character (L, I, J, F, D).
822         */
823        private static String makeFieldName(String types, int index) {
824            assert index >= 0 && index < types.length();
825            return "arg" + types.charAt(index) + index;
826        }
827
828        private static String makeSignature(String types, boolean ctor) {
829            StringBuilder buf = new StringBuilder(SIG_INCIPIT);
830            int len = types.length();
831            for (int i = 0; i < len; i++) {
832                buf.append(typeSig(types.charAt(i)));
833            }
834            return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
835        }
836
837        private static MethodType makeConstructorType(String types) {
838            int length = types.length();
839            Class<?> ptypes[] = new Class<?>[length + 2];
840            ptypes[0] = MethodType.class;
841            ptypes[1] = LambdaForm.class;
842            for (int i = 0; i < length; i++) {
843                ptypes[i + 2] = BasicType.basicType(types.charAt(i)).basicTypeClass();
844            }
845            return MethodType.makeImpl(BoundMethodHandle.class, ptypes, true);
846        }
847
848        static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
849            try {
850                return LOOKUP.findStatic(cbmh, "make", makeConstructorType(types));
851            } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
852                throw newInternalError(e);
853            }
854        }
855    }
856
857    static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
858
859    /**
860     * All subclasses must provide such a value describing their type signature.
861     */
862    static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;
863
864    private static final SpeciesData[] SPECIES_DATA_CACHE = new SpeciesData[6];
865    private static SpeciesData checkCache(int size, String types) {
866        int idx = size - 1;
867        SpeciesData data = SPECIES_DATA_CACHE[idx];
868        if (data != null)  return data;
869        SPECIES_DATA_CACHE[idx] = data = getSpeciesData(types);
870        return data;
871    }
872    static SpeciesData speciesData_L()      { return checkCache(1, "L"); }
873    static SpeciesData speciesData_LL()     { return checkCache(2, "LL"); }
874    static SpeciesData speciesData_LLL()    { return checkCache(3, "LLL"); }
875    static SpeciesData speciesData_LLLL()   { return checkCache(4, "LLLL"); }
876    static SpeciesData speciesData_LLLLL()  { return checkCache(5, "LLLLL"); }
877}
878