Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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.
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
26 package java.lang.invoke;
28 import static jdk.internal.org.objectweb.asm.Opcodes.*;
29 import static java.lang.invoke.LambdaForm.basicTypes;
30 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
31 import static java.lang.invoke.MethodHandleStatics.*;
33 import java.lang.invoke.LambdaForm.Name;
34 import java.lang.invoke.LambdaForm.NamedFunction;
35 import java.lang.invoke.MethodHandles.Lookup;
36 import java.lang.reflect.Field;
37 import java.util.Arrays;
38 import java.util.HashMap;
40 import sun.invoke.util.ValueConversions;
41 import sun.invoke.util.Wrapper;
43 import jdk.internal.org.objectweb.asm.ClassWriter;
44 import jdk.internal.org.objectweb.asm.MethodVisitor;
45 import jdk.internal.org.objectweb.asm.Type;
48 * The flavor of method handle which emulates an invoke instruction
49 * on a predetermined argument. The JVM dispatches to the correct method
50 * when the handle is created, not when it is invoked.
52 * All bound arguments are encapsulated in dedicated species.
54 /* non-public */ abstract class BoundMethodHandle extends MethodHandle {
56 /* non-public */ BoundMethodHandle(MethodType type, LambdaForm form) {
61 // BMH API and internals
64 static MethodHandle bindSingle(MethodType type, LambdaForm form, char xtype, Object x) {
65 // for some type signatures, there exist pre-defined concrete BMH classes
69 if (true) return bindSingle(type, form, x); // Use known fast path.
70 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('L').constructor[0].invokeBasic(type, form, x);
72 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('I').constructor[0].invokeBasic(type, form, ValueConversions.widenSubword(x));
74 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('J').constructor[0].invokeBasic(type, form, (long) x);
76 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('F').constructor[0].invokeBasic(type, form, (float) x);
78 return (BoundMethodHandle) SpeciesData.EMPTY.extendWithType('D').constructor[0].invokeBasic(type, form, (double) x);
79 default : throw new InternalError("unexpected xtype: " + xtype);
81 } catch (Throwable t) {
82 throw newInternalError(t);
86 static MethodHandle bindSingle(MethodType type, LambdaForm form, Object x) {
87 return new Species_L(type, form, x);
90 MethodHandle cloneExtend(MethodType type, LambdaForm form, char xtype, Object x) {
93 case 'L': return cloneExtendL(type, form, x);
94 case 'I': return cloneExtendI(type, form, ValueConversions.widenSubword(x));
95 case 'J': return cloneExtendJ(type, form, (long) x);
96 case 'F': return cloneExtendF(type, form, (float) x);
97 case 'D': return cloneExtendD(type, form, (double) x);
99 } catch (Throwable t) {
100 throw newInternalError(t);
102 throw new InternalError("unexpected type: " + xtype);
106 MethodHandle bindArgument(int pos, char basicType, Object value) {
107 MethodType type = type().dropParameterTypes(pos, pos+1);
108 LambdaForm form = internalForm().bind(1+pos, speciesData());
109 return cloneExtend(type, form, basicType, value);
113 MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
114 LambdaForm form = internalForm().addArguments(pos, srcType.parameterList().subList(pos, pos+drops));
116 return clone(srcType, form);
117 } catch (Throwable t) {
118 throw newInternalError(t);
123 MethodHandle permuteArguments(MethodType newType, int[] reorder) {
125 return clone(newType, form.permuteArguments(1, reorder, basicTypes(newType.parameterList())));
126 } catch (Throwable t) {
127 throw newInternalError(t);
131 static final String EXTENSION_TYPES = "LIJFD";
132 static final byte INDEX_L = 0, INDEX_I = 1, INDEX_J = 2, INDEX_F = 3, INDEX_D = 4;
133 static byte extensionIndex(char type) {
134 int i = EXTENSION_TYPES.indexOf(type);
135 if (i < 0) throw new InternalError();
140 * Return the {@link SpeciesData} instance representing this BMH species. All subclasses must provide a
141 * static field containing this value, and they must accordingly implement this method.
143 protected abstract SpeciesData speciesData();
146 final Object internalProperties() {
147 return "/BMH="+internalValues();
151 final Object internalValues() {
152 Object[] boundValues = new Object[speciesData().fieldCount()];
153 for (int i = 0; i < boundValues.length; ++i) {
154 boundValues[i] = arg(i);
156 return Arrays.asList(boundValues);
159 public final Object arg(int i) {
161 switch (speciesData().fieldType(i)) {
162 case 'L': return argL(i);
163 case 'I': return argI(i);
164 case 'F': return argF(i);
165 case 'D': return argD(i);
166 case 'J': return argJ(i);
168 } catch (Throwable ex) {
169 throw newInternalError(ex);
171 throw new InternalError("unexpected type: " + speciesData().types+"."+i);
173 public final Object argL(int i) throws Throwable { return speciesData().getters[i].invokeBasic(this); }
174 public final int argI(int i) throws Throwable { return (int) speciesData().getters[i].invokeBasic(this); }
175 public final float argF(int i) throws Throwable { return (float) speciesData().getters[i].invokeBasic(this); }
176 public final double argD(int i) throws Throwable { return (double) speciesData().getters[i].invokeBasic(this); }
177 public final long argJ(int i) throws Throwable { return (long) speciesData().getters[i].invokeBasic(this); }
183 public abstract BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable;
184 public abstract BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable;
185 public abstract BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable;
186 public abstract BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable;
187 public abstract BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable;
188 public abstract BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable;
190 // The following is a grossly irregular hack:
191 @Override MethodHandle reinvokerTarget() {
193 return (MethodHandle) argL(0);
194 } catch (Throwable ex) {
195 throw newInternalError(ex);
200 // concrete BMH classes required to close bootstrap loops
203 private // make it private to force users to access the enclosing class first
204 static final class Species_L extends BoundMethodHandle {
206 public Species_L(MethodType mt, LambdaForm lf, Object argL0) {
210 // The following is a grossly irregular hack:
211 @Override MethodHandle reinvokerTarget() { return (MethodHandle) argL0; }
213 public SpeciesData speciesData() {
216 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("L", Species_L.class);
218 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
219 return new Species_L(mt, lf, argL0);
222 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
223 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, narg);
226 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
227 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, narg);
230 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
231 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, narg);
234 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
235 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, narg);
238 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
239 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, narg);
244 static final class Species_LL extends BoundMethodHandle {
247 public Species_LL(MethodType mt, LambdaForm lf, Object argL0, Object argL1) {
253 public SpeciesData speciesData() {
256 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LL", Species_LL.class);
258 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
259 return new Species_LL(mt, lf, argL0, argL1);
262 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
263 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
266 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
267 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
270 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
271 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
274 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
275 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
278 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
279 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, narg);
283 static final class Species_JL extends BoundMethodHandle {
286 public Species_JL(MethodType mt, LambdaForm lf, long argJ0, Object argL1) {
292 public SpeciesData speciesData() {
295 public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("JL", Species_JL.class);
296 @Override public final long argJ0() { return argJ0; }
297 @Override public final Object argL1() { return argL1; }
299 public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) throws Throwable {
300 return new Species_JL(mt, lf, argJ0, argL1);
303 public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) throws Throwable {
304 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
307 public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) throws Throwable {
308 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
311 public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) throws Throwable {
312 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
315 public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) throws Throwable {
316 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
319 public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) throws Throwable {
320 return (BoundMethodHandle) SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argJ0, argL1, narg);
326 // BMH species meta-data
330 * Meta-data wrapper for concrete BMH classes.
332 static class SpeciesData {
334 final Class<? extends BoundMethodHandle> clazz;
335 // Bootstrapping requires circular relations MH -> BMH -> SpeciesData -> MH
336 // Therefore, we need a non-final link in the chain. Use array elements.
337 final MethodHandle[] constructor;
338 final MethodHandle[] getters;
339 final SpeciesData[] extensions;
341 public int fieldCount() {
342 return types.length();
344 public char fieldType(int i) {
345 return types.charAt(i);
348 public String toString() {
349 return "SpeciesData["+(isPlaceholder() ? "<placeholder>" : clazz.getSimpleName())+":"+types+"]";
353 * Return a {@link LambdaForm.Name} containing a {@link LambdaForm.NamedFunction} that
354 * represents a MH bound to a generic invoker, which in turn forwards to the corresponding
357 Name getterName(Name mhName, int i) {
358 MethodHandle mh = getters[i];
359 assert(mh != null) : this+"."+i;
360 return new Name(mh, mhName);
363 NamedFunction getterFunction(int i) {
364 return new NamedFunction(getters[i]);
367 static final SpeciesData EMPTY = new SpeciesData("", BoundMethodHandle.class);
369 private SpeciesData(String types, Class<? extends BoundMethodHandle> clazz) {
373 this.constructor = new MethodHandle[1];
374 this.getters = new MethodHandle[types.length()];
376 this.constructor = Factory.makeCtors(clazz, types, null);
377 this.getters = Factory.makeGetters(clazz, types, null);
379 this.extensions = new SpeciesData[EXTENSION_TYPES.length()];
382 private void initForBootstrap() {
384 if (constructor[0] == null) {
385 Factory.makeCtors(clazz, types, this.constructor);
386 Factory.makeGetters(clazz, types, this.getters);
390 private SpeciesData(String types) {
394 this.constructor = null;
396 this.extensions = null;
398 private boolean isPlaceholder() { return clazz == null; }
400 private static final HashMap<String, SpeciesData> CACHE = new HashMap<>();
401 static { CACHE.put("", EMPTY); } // make bootstrap predictable
402 private static final boolean INIT_DONE; // set after <clinit> finishes...
404 SpeciesData extendWithType(char type) {
405 int i = extensionIndex(type);
406 SpeciesData d = extensions[i];
407 if (d != null) return d;
408 extensions[i] = d = get(types+type);
412 SpeciesData extendWithIndex(byte index) {
413 SpeciesData d = extensions[index];
414 if (d != null) return d;
415 extensions[index] = d = get(types+EXTENSION_TYPES.charAt(index));
419 private static SpeciesData get(String types) {
420 // Acquire cache lock for query.
421 SpeciesData d = lookupCache(types);
422 if (!d.isPlaceholder())
425 // Use synch. on the placeholder to prevent multiple instantiation of one species.
426 // Creating this class forces a recursive call to getForClass.
427 if (lookupCache(types).isPlaceholder())
428 Factory.generateConcreteBMHClass(types);
430 // Reacquire cache lock.
431 d = lookupCache(types);
432 // Class loading must have upgraded the cache.
433 assert(d != null && !d.isPlaceholder());
436 static SpeciesData getForClass(String types, Class<? extends BoundMethodHandle> clazz) {
437 // clazz is a new class which is initializing its SPECIES_DATA field
438 return updateCache(types, new SpeciesData(types, clazz));
440 private static synchronized SpeciesData lookupCache(String types) {
441 SpeciesData d = CACHE.get(types);
442 if (d != null) return d;
443 d = new SpeciesData(types);
444 assert(d.isPlaceholder());
448 private static synchronized SpeciesData updateCache(String types, SpeciesData d) {
450 assert((d2 = CACHE.get(types)) == null || d2.isPlaceholder());
451 assert(!d.isPlaceholder());
457 // pre-fill the BMH speciesdata cache with BMH's inner classes
458 final Class<BoundMethodHandle> rootCls = BoundMethodHandle.class;
459 SpeciesData d0 = BoundMethodHandle.SPECIES_DATA; // trigger class init
460 assert(d0 == null || d0 == lookupCache("")) : d0;
462 for (Class<?> c : rootCls.getDeclaredClasses()) {
463 if (rootCls.isAssignableFrom(c)) {
464 final Class<? extends BoundMethodHandle> cbmh = c.asSubclass(BoundMethodHandle.class);
465 SpeciesData d = Factory.speciesDataFromConcreteBMHClass(cbmh);
466 assert(d != null) : cbmh.getName();
467 assert(d.clazz == cbmh);
468 assert(d == lookupCache(d.types));
471 } catch (Throwable e) {
472 throw newInternalError(e);
475 for (SpeciesData d : CACHE.values()) {
476 d.initForBootstrap();
478 // Note: Do not simplify this, because INIT_DONE must not be
479 // a compile-time constant during bootstrapping.
480 INIT_DONE = Boolean.TRUE;
484 static SpeciesData getSpeciesData(String types) {
485 return SpeciesData.get(types);
489 * Generation of concrete BMH classes.
491 * A concrete BMH species is fit for binding a number of values adhering to a
492 * given type pattern. Reference types are erased.
494 * BMH species are cached by type pattern.
496 * A BMH species has a number of fields with the concrete (possibly erased) types of
497 * bound values. Setters are provided as an API in BMH. Getters are exposed as MHs,
498 * which can be included as names in lambda forms.
500 static class Factory {
502 static final String JLO_SIG = "Ljava/lang/Object;";
503 static final String JLS_SIG = "Ljava/lang/String;";
504 static final String JLC_SIG = "Ljava/lang/Class;";
505 static final String MH = "java/lang/invoke/MethodHandle";
506 static final String MH_SIG = "L"+MH+";";
507 static final String BMH = "java/lang/invoke/BoundMethodHandle";
508 static final String BMH_SIG = "L"+BMH+";";
509 static final String SPECIES_DATA = "java/lang/invoke/BoundMethodHandle$SpeciesData";
510 static final String SPECIES_DATA_SIG = "L"+SPECIES_DATA+";";
512 static final String SPECIES_PREFIX_NAME = "Species_";
513 static final String SPECIES_PREFIX_PATH = BMH + "$" + SPECIES_PREFIX_NAME;
515 static final String BMHSPECIES_DATA_EWI_SIG = "(B)" + SPECIES_DATA_SIG;
516 static final String BMHSPECIES_DATA_GFC_SIG = "(" + JLS_SIG + JLC_SIG + ")" + SPECIES_DATA_SIG;
517 static final String MYSPECIES_DATA_SIG = "()" + SPECIES_DATA_SIG;
518 static final String VOID_SIG = "()V";
520 static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
522 static final Class<?>[] TYPES = new Class<?>[] { Object.class, int.class, long.class, float.class, double.class };
524 static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
527 * Generate a concrete subclass of BMH for a given combination of bound types.
529 * A concrete BMH species adheres to the following schema:
532 * class Species_[[types]] extends BoundMethodHandle {
534 * final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
538 * The {@code [[types]]} signature is precisely the string that is passed to this
541 * The {@code [[fields]]} section consists of one field definition per character in
542 * the type signature, adhering to the naming schema described in the definition of
543 * {@link #makeFieldName}.
545 * For example, a concrete BMH species for two reference and one integral bound values
546 * would have the following shape:
549 * class BoundMethodHandle { ... private static
550 * final class Species_LLI extends BoundMethodHandle {
551 * final Object argL0;
552 * final Object argL1;
554 * public Species_LLI(MethodType mt, LambdaForm lf, Object argL0, Object argL1, int argI2) {
556 * this.argL0 = argL0;
557 * this.argL1 = argL1;
558 * this.argI2 = argI2;
560 * public final SpeciesData speciesData() { return SPECIES_DATA; }
561 * public static final SpeciesData SPECIES_DATA = SpeciesData.getForClass("LLI", Species_LLI.class);
562 * public final BoundMethodHandle clone(MethodType mt, LambdaForm lf) {
563 * return SPECIES_DATA.constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2);
565 * public final BoundMethodHandle cloneExtendL(MethodType mt, LambdaForm lf, Object narg) {
566 * return SPECIES_DATA.extendWithIndex(INDEX_L).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
568 * public final BoundMethodHandle cloneExtendI(MethodType mt, LambdaForm lf, int narg) {
569 * return SPECIES_DATA.extendWithIndex(INDEX_I).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
571 * public final BoundMethodHandle cloneExtendJ(MethodType mt, LambdaForm lf, long narg) {
572 * return SPECIES_DATA.extendWithIndex(INDEX_J).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
574 * public final BoundMethodHandle cloneExtendF(MethodType mt, LambdaForm lf, float narg) {
575 * return SPECIES_DATA.extendWithIndex(INDEX_F).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
577 * public final BoundMethodHandle cloneExtendD(MethodType mt, LambdaForm lf, double narg) {
578 * return SPECIES_DATA.extendWithIndex(INDEX_D).constructor[0].invokeBasic(mt, lf, argL0, argL1, argI2, narg);
583 * @param types the type signature, wherein reference types are erased to 'L'
584 * @return the generated concrete BMH class
586 static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
587 final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
589 final String className = SPECIES_PREFIX_PATH + types;
590 final String sourceFile = SPECIES_PREFIX_NAME + types;
591 cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
592 cw.visitSource(sourceFile, null);
594 // emit static types and SPECIES_DATA fields
595 cw.visitField(ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null).visitEnd();
597 // emit bound argument fields
598 for (int i = 0; i < types.length(); ++i) {
599 final char t = types.charAt(i);
600 final String fieldName = makeFieldName(types, i);
601 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
602 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
608 mv = cw.visitMethod(ACC_PUBLIC, "<init>", makeSignature(types, true), null, null);
610 mv.visitVarInsn(ALOAD, 0);
611 mv.visitVarInsn(ALOAD, 1);
612 mv.visitVarInsn(ALOAD, 2);
614 mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true));
616 for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
617 // i counts the arguments, j counts corresponding argument slots
618 char t = types.charAt(i);
619 mv.visitVarInsn(ALOAD, 0);
620 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
621 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
622 if (t == 'J' || t == 'D') {
623 ++j; // adjust argument register access
627 mv.visitInsn(RETURN);
631 // emit implementation of reinvokerTarget()
632 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "reinvokerTarget", "()" + MH_SIG, null, null);
634 mv.visitVarInsn(ALOAD, 0);
635 mv.visitFieldInsn(GETFIELD, className, "argL0", JLO_SIG);
636 mv.visitTypeInsn(CHECKCAST, MH);
637 mv.visitInsn(ARETURN);
641 // emit implementation of speciesData()
642 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
644 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
645 mv.visitInsn(ARETURN);
650 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "clone", makeSignature("", false), null, E_THROWABLE);
652 // return speciesData().constructor[0].invokeBasic(mt, lf, argL0, ...)
653 // obtain constructor
654 mv.visitVarInsn(ALOAD, 0);
655 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
656 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
657 mv.visitInsn(ICONST_0);
658 mv.visitInsn(AALOAD);
660 mv.visitVarInsn(ALOAD, 1);
661 mv.visitVarInsn(ALOAD, 2);
662 // put fields on the stack
663 emitPushFields(types, className, mv);
664 // finally, invoke the constructor and return
665 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types, false));
666 mv.visitInsn(ARETURN);
670 // for each type, emit cloneExtendT()
671 for (Class<?> c : TYPES) {
672 char t = Wrapper.basicTypeChar(c);
673 mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "cloneExtend" + t, makeSignature(String.valueOf(t), false), null, E_THROWABLE);
675 // return SPECIES_DATA.extendWithIndex(extensionIndex(t)).constructor[0].invokeBasic(mt, lf, argL0, ..., narg)
676 // obtain constructor
677 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
678 int iconstInsn = ICONST_0 + extensionIndex(t);
679 assert(iconstInsn <= ICONST_5);
680 mv.visitInsn(iconstInsn);
681 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWithIndex", BMHSPECIES_DATA_EWI_SIG);
682 mv.visitFieldInsn(GETFIELD, SPECIES_DATA, "constructor", "[" + MH_SIG);
683 mv.visitInsn(ICONST_0);
684 mv.visitInsn(AALOAD);
686 mv.visitVarInsn(ALOAD, 1);
687 mv.visitVarInsn(ALOAD, 2);
688 // put fields on the stack
689 emitPushFields(types, className, mv);
691 mv.visitVarInsn(typeLoadOp(t), 3);
692 // finally, invoke the constructor and return
693 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + t, false));
694 mv.visitInsn(ARETURN);
699 // emit class initializer
700 mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "<clinit>", VOID_SIG, null, null);
702 mv.visitLdcInsn(types);
703 mv.visitLdcInsn(Type.getObjectType(className));
704 mv.visitMethodInsn(INVOKESTATIC, SPECIES_DATA, "getForClass", BMHSPECIES_DATA_GFC_SIG);
705 mv.visitFieldInsn(PUTSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
706 mv.visitInsn(RETURN);
713 final byte[] classFile = cw.toByteArray();
714 InvokerBytecodeGenerator.maybeDump(className, classFile);
715 Class<? extends BoundMethodHandle> bmhClass =
716 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
717 UNSAFE.defineClass(className, classFile, 0, classFile.length,
718 BoundMethodHandle.class.getClassLoader(), null)
719 .asSubclass(BoundMethodHandle.class);
720 UNSAFE.ensureClassInitialized(bmhClass);
725 private static int typeLoadOp(char t) {
727 case 'L': return ALOAD;
728 case 'I': return ILOAD;
729 case 'J': return LLOAD;
730 case 'F': return FLOAD;
731 case 'D': return DLOAD;
732 default : throw new InternalError("unrecognized type " + t);
736 private static void emitPushFields(String types, String className, MethodVisitor mv) {
737 for (int i = 0; i < types.length(); ++i) {
738 char tc = types.charAt(i);
739 mv.visitVarInsn(ALOAD, 0);
740 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
744 static String typeSig(char t) {
745 return t == 'L' ? JLO_SIG : String.valueOf(t);
749 // Getter MH generation.
752 private static MethodHandle makeGetter(Class<?> cbmhClass, String types, int index) {
753 String fieldName = makeFieldName(types, index);
754 Class<?> fieldType = Wrapper.forBasicType(types.charAt(index)).primitiveType();
756 return LOOKUP.findGetter(cbmhClass, fieldName, fieldType);
757 } catch (NoSuchFieldException | IllegalAccessException e) {
758 throw newInternalError(e);
762 static MethodHandle[] makeGetters(Class<?> cbmhClass, String types, MethodHandle[] mhs) {
763 if (mhs == null) mhs = new MethodHandle[types.length()];
764 for (int i = 0; i < mhs.length; ++i) {
765 mhs[i] = makeGetter(cbmhClass, types, i);
766 assert(mhs[i].internalMemberName().getDeclaringClass() == cbmhClass);
771 static MethodHandle[] makeCtors(Class<? extends BoundMethodHandle> cbmh, String types, MethodHandle mhs[]) {
772 if (mhs == null) mhs = new MethodHandle[1];
773 mhs[0] = makeCbmhCtor(cbmh, types);
778 // Auxiliary methods.
781 static SpeciesData speciesDataFromConcreteBMHClass(Class<? extends BoundMethodHandle> cbmh) {
783 Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA");
784 return (SpeciesData) F_SPECIES_DATA.get(null);
785 } catch (ReflectiveOperationException ex) {
786 throw newInternalError(ex);
791 * Field names in concrete BMHs adhere to this pattern:
793 * where type is a single character (L, I, J, F, D).
795 private static String makeFieldName(String types, int index) {
796 assert index >= 0 && index < types.length();
797 return "arg" + types.charAt(index) + index;
800 private static String makeSignature(String types, boolean ctor) {
801 StringBuilder buf = new StringBuilder(SIG_INCIPIT);
802 for (char c : types.toCharArray()) {
803 buf.append(typeSig(c));
805 return buf.append(')').append(ctor ? "V" : BMH_SIG).toString();
808 static MethodHandle makeCbmhCtor(Class<? extends BoundMethodHandle> cbmh, String types) {
810 return linkConstructor(LOOKUP.findConstructor(cbmh, MethodType.fromMethodDescriptorString(makeSignature(types, true), null)));
811 } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | TypeNotPresentException e) {
812 throw newInternalError(e);
817 * Wrap a constructor call in a {@link LambdaForm}.
819 * If constructors ({@code <init>} methods) are called in LFs, problems might arise if the LFs
820 * are turned into bytecode, because the call to the allocator is routed through an MH, and the
821 * verifier cannot find a {@code NEW} instruction preceding the {@code INVOKESPECIAL} to
822 * {@code <init>}. To avoid this, we add an indirection by invoking {@code <init>} through
823 * {@link MethodHandle#linkToSpecial}.
825 * The last {@link LambdaForm.Name Name} in the argument's form is expected to be the {@code void}
826 * result of the {@code <init>} invocation. This entry is replaced.
828 private static MethodHandle linkConstructor(MethodHandle cmh) {
829 final LambdaForm lf = cmh.form;
830 final int initNameIndex = lf.names.length - 1;
831 final Name initName = lf.names[initNameIndex];
832 final MemberName ctorMN = initName.function.member;
833 final MethodType ctorMT = ctorMN.getInvocationType();
835 // obtain function member (call target)
836 // linker method type replaces initial parameter (BMH species) with BMH to avoid naming a species (anonymous class!)
837 final MethodType linkerMT = ctorMT.changeParameterType(0, BoundMethodHandle.class).appendParameterTypes(MemberName.class);
838 MemberName linkerMN = new MemberName(MethodHandle.class, "linkToSpecial", linkerMT, REF_invokeStatic);
840 linkerMN = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linkerMN, null, NoSuchMethodException.class);
841 assert(linkerMN.isStatic());
842 } catch (ReflectiveOperationException ex) {
843 throw newInternalError(ex);
845 // extend arguments array
846 Object[] newArgs = Arrays.copyOf(initName.arguments, initName.arguments.length + 1);
847 newArgs[newArgs.length - 1] = ctorMN;
849 final NamedFunction nf = new NamedFunction(linkerMN);
850 final Name linkedCtor = new Name(nf, newArgs);
851 linkedCtor.initIndex(initNameIndex);
852 lf.names[initNameIndex] = linkedCtor;
858 private static final Lookup LOOKUP = Lookup.IMPL_LOOKUP;
861 * All subclasses must provide such a value describing their type signature.
863 static final SpeciesData SPECIES_DATA = SpeciesData.EMPTY;