< prev index next >

src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java

Print this page
rev 13951 : 8152641: Plugin to generate BMH$Species classes ahead-of-time
Reviewed-by: TBD


 471         static final String INT_SIG    = "()I";
 472 
 473         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
 474 
 475         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
 476 
 477         static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
 478 
 479         /**
 480          * Get a concrete subclass of BMH for a given combination of bound types.
 481          *
 482          * @param types the type signature, wherein reference types are erased to 'L'
 483          * @return the concrete BMH class
 484          */
 485         static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
 486             // CHM.computeIfAbsent ensures generateConcreteBMHClass is called
 487             // only once per key.
 488             return CLASS_CACHE.computeIfAbsent(
 489                 types, new Function<String, Class<? extends BoundMethodHandle>>() {
 490                     @Override

 491                     public Class<? extends BoundMethodHandle> apply(String types) {





 492                         return generateConcreteBMHClass(types);
 493                     }

 494                 });
 495         }
 496 
 497         /**
 498          * Generate a concrete subclass of BMH for a given combination of bound types.
 499          *
 500          * A concrete BMH species adheres to the following schema:
 501          *
 502          * <pre>
 503          * class Species_[[types]] extends BoundMethodHandle {
 504          *     [[fields]]
 505          *     final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
 506          * }
 507          * </pre>
 508          *
 509          * The {@code [[types]]} signature is precisely the string that is passed to this
 510          * method.
 511          *
 512          * The {@code [[fields]]} section consists of one field definition per character in
 513          * the type signature, adhering to the naming schema described in the definition of


 542          *     }
 543          *     final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
 544          *         return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 545          *     }
 546          *     final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
 547          *         return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 548          *     }
 549          *     final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
 550          *         return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 551          *     }
 552          *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
 553          *         return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 554          *     }
 555          * }
 556          * </pre>
 557          *
 558          * @param types the type signature, wherein reference types are erased to 'L'
 559          * @return the generated concrete BMH class
 560          */
 561         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {
 562             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 563 
 564             String shortTypes = LambdaForm.shortenSignature(types);
 565             final String className  = SPECIES_PREFIX_PATH + shortTypes;
 566             final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
















 567             final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
 568             cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
 569             cw.visitSource(sourceFile, null);
 570 
 571             // emit static types and SPECIES_DATA fields
 572             FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
 573             fw.visitAnnotation(STABLE_SIG, true);
 574             fw.visitEnd();
 575 
 576             // emit bound argument fields
 577             for (int i = 0; i < types.length(); ++i) {
 578                 final char t = types.charAt(i);
 579                 final String fieldName = makeFieldName(types, i);
 580                 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
 581                 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
 582             }
 583 
 584             MethodVisitor mv;
 585 
 586             // emit constructor
 587             mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
 588             mv.visitCode();
 589             mv.visitVarInsn(ALOAD, 0); // this
 590             mv.visitVarInsn(ALOAD, 1); // type
 591             mv.visitVarInsn(ALOAD, 2); // form
 592 
 593             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);
 594 
 595             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
 596                 // i counts the arguments, j counts corresponding argument slots
 597                 char t = types.charAt(i);
 598                 mv.visitVarInsn(ALOAD, 0);
 599                 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
 600                 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
 601                 if (t == 'J' || t == 'D') {
 602                     ++j; // adjust argument register access
 603                 }
 604             }
 605 
 606             mv.visitInsn(RETURN);
 607             mv.visitMaxs(0, 0);
 608             mv.visitEnd();
 609 
 610             // emit implementation of speciesData()
 611             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
 612             mv.visitCode();
 613             mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
 614             mv.visitInsn(ARETURN);
 615             mv.visitMaxs(0, 0);
 616             mv.visitEnd();
 617 
 618             // emit implementation of fieldCount()
 619             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
 620             mv.visitCode();
 621             int fc = types.length();
 622             if (fc <= (ICONST_5 - ICONST_0)) {
 623                 mv.visitInsn(ICONST_0 + fc);
 624             } else {
 625                 mv.visitIntInsn(SIPUSH, fc);
 626             }
 627             mv.visitInsn(IRETURN);
 628             mv.visitMaxs(0, 0);
 629             mv.visitEnd();
 630             // emit make()  ...factory method wrapping constructor
 631             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
 632             mv.visitCode();
 633             // make instance
 634             mv.visitTypeInsn(NEW, className);
 635             mv.visitInsn(DUP);
 636             // load mt, lf
 637             mv.visitVarInsn(ALOAD, 0);  // type
 638             mv.visitVarInsn(ALOAD, 1);  // form
 639             // load factory method arguments
 640             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
 641                 // i counts the arguments, j counts corresponding argument slots
 642                 char t = types.charAt(i);
 643                 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
 644                 if (t == 'J' || t == 'D') {
 645                     ++j; // adjust argument register access
 646                 }
 647             }
 648 
 649             // finally, invoke the constructor and return
 650             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
 651             mv.visitInsn(ARETURN);
 652             mv.visitMaxs(0, 0);
 653             mv.visitEnd();
 654 
 655             // emit copyWith()
 656             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
 657             mv.visitCode();
 658             // make instance
 659             mv.visitTypeInsn(NEW, className);
 660             mv.visitInsn(DUP);
 661             // load mt, lf
 662             mv.visitVarInsn(ALOAD, 1);
 663             mv.visitVarInsn(ALOAD, 2);
 664             // put fields on the stack
 665             emitPushFields(types, className, mv);
 666             // finally, invoke the constructor and return
 667             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
 668             mv.visitInsn(ARETURN);
 669             mv.visitMaxs(0, 0);
 670             mv.visitEnd();
 671 
 672             // for each type, emit copyWithExtendT()
 673             for (BasicType type : BasicType.ARG_TYPES) {
 674                 int ord = type.ordinal();
 675                 char btChar = type.basicTypeChar();
 676                 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
 677                 mv.visitCode();
 678                 // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
 679                 // obtain constructor
 680                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
 681                 int iconstInsn = ICONST_0 + ord;
 682                 assert(iconstInsn <= ICONST_5);
 683                 mv.visitInsn(iconstInsn);
 684                 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
 685                 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
 686                 // load mt, lf
 687                 mv.visitVarInsn(ALOAD, 1);
 688                 mv.visitVarInsn(ALOAD, 2);
 689                 // put fields on the stack
 690                 emitPushFields(types, className, mv);
 691                 // put narg on stack
 692                 mv.visitVarInsn(typeLoadOp(btChar), 3);
 693                 // finally, invoke the constructor and return
 694                 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
 695                 mv.visitInsn(ARETURN);
 696                 mv.visitMaxs(0, 0);
 697                 mv.visitEnd();
 698             }
 699 
 700             cw.visitEnd();
 701 
 702             // load class
 703             final byte[] classFile = cw.toByteArray();
 704             InvokerBytecodeGenerator.maybeDump(className, classFile);
 705             Class<? extends BoundMethodHandle> bmhClass =
 706                 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
 707                 UNSAFE.defineClass(className, classFile, 0, classFile.length,
 708                                    BoundMethodHandle.class.getClassLoader(), null)
 709                     .asSubclass(BoundMethodHandle.class);
 710 
 711             return bmhClass;
 712         }
 713 
 714         private static int typeLoadOp(char t) {
 715             switch (t) {
 716             case 'L': return ALOAD;
 717             case 'I': return ILOAD;
 718             case 'J': return LLOAD;
 719             case 'F': return FLOAD;
 720             case 'D': return DLOAD;
 721             default : throw newInternalError("unrecognized type " + t);
 722             }
 723         }
 724 
 725         private static void emitPushFields(String types, String className, MethodVisitor mv) {
 726             for (int i = 0; i < types.length(); ++i) {
 727                 char tc = types.charAt(i);
 728                 mv.visitVarInsn(ALOAD, 0);
 729                 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
 730             }
 731         }




 471         static final String INT_SIG    = "()I";
 472 
 473         static final String SIG_INCIPIT = "(Ljava/lang/invoke/MethodType;Ljava/lang/invoke/LambdaForm;";
 474 
 475         static final String[] E_THROWABLE = new String[] { "java/lang/Throwable" };
 476 
 477         static final ConcurrentMap<String, Class<? extends BoundMethodHandle>> CLASS_CACHE = new ConcurrentHashMap<>();
 478 
 479         /**
 480          * Get a concrete subclass of BMH for a given combination of bound types.
 481          *
 482          * @param types the type signature, wherein reference types are erased to 'L'
 483          * @return the concrete BMH class
 484          */
 485         static Class<? extends BoundMethodHandle> getConcreteBMHClass(String types) {
 486             // CHM.computeIfAbsent ensures generateConcreteBMHClass is called
 487             // only once per key.
 488             return CLASS_CACHE.computeIfAbsent(
 489                 types, new Function<String, Class<? extends BoundMethodHandle>>() {
 490                     @Override
 491                     @SuppressWarnings("unchecked")
 492                     public Class<? extends BoundMethodHandle> apply(String types) {
 493                         try {
 494                             return (Class<? extends BoundMethodHandle>)
 495                                     Class.forName("java.lang.invoke.BoundMethodHandle$Species_" + LambdaForm.shortenSignature(types));
 496                         } catch (ClassNotFoundException cnf) {
 497                             // Not pregenerated, generate the class
 498                             return generateConcreteBMHClass(types);
 499                         }
 500                     }
 501                 });
 502         }
 503 
 504         /**
 505          * Generate a concrete subclass of BMH for a given combination of bound types.
 506          *
 507          * A concrete BMH species adheres to the following schema:
 508          *
 509          * <pre>
 510          * class Species_[[types]] extends BoundMethodHandle {
 511          *     [[fields]]
 512          *     final SpeciesData speciesData() { return SpeciesData.get("[[types]]"); }
 513          * }
 514          * </pre>
 515          *
 516          * The {@code [[types]]} signature is precisely the string that is passed to this
 517          * method.
 518          *
 519          * The {@code [[fields]]} section consists of one field definition per character in
 520          * the type signature, adhering to the naming schema described in the definition of


 549          *     }
 550          *     final BoundMethodHandle copyWithExtendI(MethodType mt, LambdaForm lf, int narg) {
 551          *         return SPECIES_DATA.extendWith(I_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 552          *     }
 553          *     final BoundMethodHandle copyWithExtendJ(MethodType mt, LambdaForm lf, long narg) {
 554          *         return SPECIES_DATA.extendWith(J_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 555          *     }
 556          *     final BoundMethodHandle copyWithExtendF(MethodType mt, LambdaForm lf, float narg) {
 557          *         return SPECIES_DATA.extendWith(F_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 558          *     }
 559          *     public final BoundMethodHandle copyWithExtendD(MethodType mt, LambdaForm lf, double narg) {
 560          *         return SPECIES_DATA.extendWith(D_TYPE).constructor().invokeBasic(mt, lf, argL0, argL1, argI2, narg);
 561          *     }
 562          * }
 563          * </pre>
 564          *
 565          * @param types the type signature, wherein reference types are erased to 'L'
 566          * @return the generated concrete BMH class
 567          */
 568         static Class<? extends BoundMethodHandle> generateConcreteBMHClass(String types) {


 569             String shortTypes = LambdaForm.shortenSignature(types);
 570             final String className  = SPECIES_PREFIX_PATH + shortTypes;
 571             final String sourceFile = SPECIES_PREFIX_NAME + shortTypes;
 572 
 573             byte[] classFile = generateConcreteBMHClassBytes(className, sourceFile, types);
 574 
 575             // load class
 576             InvokerBytecodeGenerator.maybeDump(className, classFile);
 577             Class<? extends BoundMethodHandle> bmhClass =
 578                 //UNSAFE.defineAnonymousClass(BoundMethodHandle.class, classFile, null).asSubclass(BoundMethodHandle.class);
 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 byte[] generateConcreteBMHClassBytes(final String className, final String sourceFile, final String types) {
 587             final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 588             final int NOT_ACC_PUBLIC = 0;  // not ACC_PUBLIC
 589             cw.visit(V1_6, NOT_ACC_PUBLIC + ACC_FINAL + ACC_SUPER, className, null, BMH, null);
 590             cw.visitSource(sourceFile, null);

 591             // emit static types and SPECIES_DATA fields
 592             FieldVisitor fw = cw.visitField(NOT_ACC_PUBLIC + ACC_STATIC, "SPECIES_DATA", SPECIES_DATA_SIG, null, null);
 593             fw.visitAnnotation(STABLE_SIG, true);
 594             fw.visitEnd();

 595             // emit bound argument fields
 596             for (int i = 0; i < types.length(); ++i) {
 597                 final char t = types.charAt(i);
 598                 final String fieldName = makeFieldName(types, i);
 599                 final String fieldDesc = t == 'L' ? JLO_SIG : String.valueOf(t);
 600                 cw.visitField(ACC_FINAL, fieldName, fieldDesc, null, null).visitEnd();
 601             }

 602             MethodVisitor mv;

 603             // emit constructor
 604             mv = cw.visitMethod(ACC_PRIVATE, "<init>", makeSignature(types, true), null, null);
 605             mv.visitCode();
 606             mv.visitVarInsn(ALOAD, 0); // this
 607             mv.visitVarInsn(ALOAD, 1); // type
 608             mv.visitVarInsn(ALOAD, 2); // form

 609             mv.visitMethodInsn(INVOKESPECIAL, BMH, "<init>", makeSignature("", true), false);

 610             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
 611                 // i counts the arguments, j counts corresponding argument slots
 612                 char t = types.charAt(i);
 613                 mv.visitVarInsn(ALOAD, 0);
 614                 mv.visitVarInsn(typeLoadOp(t), j + 3); // parameters start at 3
 615                 mv.visitFieldInsn(PUTFIELD, className, makeFieldName(types, i), typeSig(t));
 616                 if (t == 'J' || t == 'D') {
 617                     ++j; // adjust argument register access
 618                 }
 619             }

 620             mv.visitInsn(RETURN);
 621             mv.visitMaxs(0, 0);
 622             mv.visitEnd();

 623             // emit implementation of speciesData()
 624             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "speciesData", MYSPECIES_DATA_SIG, null, null);
 625             mv.visitCode();
 626             mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
 627             mv.visitInsn(ARETURN);
 628             mv.visitMaxs(0, 0);
 629             mv.visitEnd();

 630             // emit implementation of fieldCount()
 631             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "fieldCount", INT_SIG, null, null);
 632             mv.visitCode();
 633             int fc = types.length();
 634             if (fc <= (ICONST_5 - ICONST_0)) {
 635                 mv.visitInsn(ICONST_0 + fc);
 636             } else {
 637                 mv.visitIntInsn(SIPUSH, fc);
 638             }
 639             mv.visitInsn(IRETURN);
 640             mv.visitMaxs(0, 0);
 641             mv.visitEnd();
 642             // emit make()  ...factory method wrapping constructor
 643             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_STATIC, "make", makeSignature(types, false), null, null);
 644             mv.visitCode();
 645             // make instance
 646             mv.visitTypeInsn(NEW, className);
 647             mv.visitInsn(DUP);
 648             // load mt, lf
 649             mv.visitVarInsn(ALOAD, 0);  // type
 650             mv.visitVarInsn(ALOAD, 1);  // form
 651             // load factory method arguments
 652             for (int i = 0, j = 0; i < types.length(); ++i, ++j) {
 653                 // i counts the arguments, j counts corresponding argument slots
 654                 char t = types.charAt(i);
 655                 mv.visitVarInsn(typeLoadOp(t), j + 2); // parameters start at 3
 656                 if (t == 'J' || t == 'D') {
 657                     ++j; // adjust argument register access
 658                 }
 659             }

 660             // finally, invoke the constructor and return
 661             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
 662             mv.visitInsn(ARETURN);
 663             mv.visitMaxs(0, 0);
 664             mv.visitEnd();

 665             // emit copyWith()
 666             mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWith", makeSignature("", false), null, null);
 667             mv.visitCode();
 668             // make instance
 669             mv.visitTypeInsn(NEW, className);
 670             mv.visitInsn(DUP);
 671             // load mt, lf
 672             mv.visitVarInsn(ALOAD, 1);
 673             mv.visitVarInsn(ALOAD, 2);
 674             // put fields on the stack
 675             emitPushFields(types, className, mv);
 676             // finally, invoke the constructor and return
 677             mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", makeSignature(types, true), false);
 678             mv.visitInsn(ARETURN);
 679             mv.visitMaxs(0, 0);
 680             mv.visitEnd();

 681             // for each type, emit copyWithExtendT()
 682             for (BasicType type : BasicType.ARG_TYPES) {
 683                 int ord = type.ordinal();
 684                 char btChar = type.basicTypeChar();
 685                 mv = cw.visitMethod(NOT_ACC_PUBLIC + ACC_FINAL, "copyWithExtend" + btChar, makeSignature(String.valueOf(btChar), false), null, E_THROWABLE);
 686                 mv.visitCode();
 687                 // return SPECIES_DATA.extendWith(t).constructor().invokeBasic(mt, lf, argL0, ..., narg)
 688                 // obtain constructor
 689                 mv.visitFieldInsn(GETSTATIC, className, "SPECIES_DATA", SPECIES_DATA_SIG);
 690                 int iconstInsn = ICONST_0 + ord;
 691                 assert(iconstInsn <= ICONST_5);
 692                 mv.visitInsn(iconstInsn);
 693                 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "extendWith", BMHSPECIES_DATA_EWI_SIG, false);
 694                 mv.visitMethodInsn(INVOKEVIRTUAL, SPECIES_DATA, "constructor", "()" + MH_SIG, false);
 695                 // load mt, lf
 696                 mv.visitVarInsn(ALOAD, 1);
 697                 mv.visitVarInsn(ALOAD, 2);
 698                 // put fields on the stack
 699                 emitPushFields(types, className, mv);
 700                 // put narg on stack
 701                 mv.visitVarInsn(typeLoadOp(btChar), 3);
 702                 // finally, invoke the constructor and return
 703                 mv.visitMethodInsn(INVOKEVIRTUAL, MH, "invokeBasic", makeSignature(types + btChar, false), false);
 704                 mv.visitInsn(ARETURN);
 705                 mv.visitMaxs(0, 0);
 706                 mv.visitEnd();
 707             }

 708             cw.visitEnd();
 709             return cw.toByteArray();










 710         }
 711 
 712         private static int typeLoadOp(char t) {
 713             switch (t) {
 714             case 'L': return ALOAD;
 715             case 'I': return ILOAD;
 716             case 'J': return LLOAD;
 717             case 'F': return FLOAD;
 718             case 'D': return DLOAD;
 719             default : throw newInternalError("unrecognized type " + t);
 720             }
 721         }
 722 
 723         private static void emitPushFields(String types, String className, MethodVisitor mv) {
 724             for (int i = 0; i < types.length(); ++i) {
 725                 char tc = types.charAt(i);
 726                 mv.visitVarInsn(ALOAD, 0);
 727                 mv.visitFieldInsn(GETFIELD, className, makeFieldName(types, i), typeSig(tc));
 728             }
 729         }


< prev index next >