< prev index next >

src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java

Print this page

   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.reflect;
  27 



  28 import jdk.internal.org.objectweb.asm.ClassWriter;
  29 import jdk.internal.org.objectweb.asm.Label;
  30 import jdk.internal.org.objectweb.asm.MethodVisitor;
  31 import jdk.internal.org.objectweb.asm.Opcodes;
  32 import jdk.internal.org.objectweb.asm.Type;
  33 import sun.invoke.util.Wrapper;
  34 import sun.security.action.GetBooleanAction;
  35 
  36 import java.io.IOException;
  37 import java.lang.invoke.MethodType;
  38 import java.nio.file.Files;
  39 import java.nio.file.Path;
  40 import java.util.ArrayList;
  41 import java.util.Arrays;

  42 import java.util.LinkedHashMap;
  43 import java.util.List;
  44 import java.util.ListIterator;
  45 import java.util.Map;

  46 
  47 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  48 
  49 /**
  50  * ProxyGenerator contains the code to generate a dynamic proxy class
  51  * for the java.lang.reflect.Proxy API.
  52  * <p>
  53  * The external interface to ProxyGenerator is the static
  54  * "generateProxyClass" method.
  55  */
  56 final class ProxyGenerator extends ClassWriter {
  57     private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major();
  58     private static final String JL_CLASS = "java/lang/Class";
  59     private static final String JL_OBJECT = "java/lang/Object";
  60     private static final String JL_THROWABLE = "java/lang/Throwable";
  61     private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
  62     private static final String JL_ILLEGAL_ACCESS_EX = "java/lang/IllegalAccessException";
  63 
  64     private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
  65     private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";

 438             }
 439         }
 440     }
 441 
 442     /**
 443      * Returns the {@link ClassLoader} to be used by the default implementation of {@link
 444      * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
 445      * default.
 446      *
 447      * @return ClassLoader
 448      */
 449     protected ClassLoader getClassLoader() {
 450         return loader;
 451     }
 452 
 453     /**
 454      * Generate a class file for the proxy class.  This method drives the
 455      * class file generation process.
 456      */
 457     private byte[] generateClassFile() {
 458         visit(CLASSFILE_VERSION, accessFlags, dotToSlash(className), null,

 459                 JLR_PROXY, typeNames(interfaces));
 460 
 461         /*
 462          * Add proxy methods for the hashCode, equals,
 463          * and toString methods of java.lang.Object.  This is done before
 464          * the methods from the proxy interfaces so that the methods from
 465          * java.lang.Object take precedence over duplicate methods in the
 466          * proxy interfaces.
 467          */
 468         addProxyMethod(hashCodeMethod);
 469         addProxyMethod(equalsMethod);
 470         addProxyMethod(toStringMethod);
 471 
 472         /*
 473          * Accumulate all of the methods from the proxy interfaces.
 474          */
 475         for (Class<?> intf : interfaces) {
 476             for (Method m : intf.getMethods()) {
 477                 if (!Modifier.isStatic(m.getModifiers())) {
 478                     addProxyMethod(m, intf);
 479                 }
 480             }
 481         }
 482 
 483         /*
 484          * For each set of proxy methods with the same signature,
 485          * verify that the methods' return types are compatible.


 486          */

 487         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 488             checkReturnTypes(sigmethods);



 489         }
 490 
 491         generateConstructor();
 492 
 493         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 494             for (ProxyMethod pm : sigmethods) {
 495                 // add static field for the Method object
 496                 visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
 497                         LJLR_METHOD, null, null);
 498 
 499                 // Generate code for proxy method
 500                 pm.generateMethod(this, className);
 501             }
 502         }



 503 
 504         generateStaticInitializer();
 505         generateLookupAccessor();
 506         return toByteArray();
 507     }
 508 
 509     /**
 510      * Add another method to be proxied, either by creating a new
 511      * ProxyMethod object or augmenting an old one for a duplicate
 512      * method.
 513      *
 514      * "fromClass" indicates the proxy interface that the method was
 515      * found through, which may be different from (a subinterface of)
 516      * the method's "declaring class".  Note that the first Method
 517      * object passed for a given name and descriptor identifies the
 518      * Method object (and thus the declaring class) that will be
 519      * passed to the invocation handler's "invoke" method for a given
 520      * set of duplicate methods.
 521      */
 522     private void addProxyMethod(Method m, Class<?> fromClass) {

 664         mv.visitJumpInsn(IFEQ, L_illegalAccess);
 665         mv.visitMethodInsn(INVOKESTATIC, JLI_METHODHANDLES, "lookup",
 666                 "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
 667         mv.visitInsn(ARETURN);
 668 
 669         mv.visitLabel(L_illegalAccess);
 670         mv.visitTypeInsn(Opcodes.NEW, JL_ILLEGAL_ACCESS_EX);
 671         mv.visitInsn(DUP);
 672         mv.visitVarInsn(ALOAD, 0);
 673         mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "toString",
 674                 "()Ljava/lang/String;", false);
 675         mv.visitMethodInsn(INVOKESPECIAL, JL_ILLEGAL_ACCESS_EX,
 676                 "<init>", "(Ljava/lang/String;)V", false);
 677         mv.visitInsn(ATHROW);
 678 
 679         // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
 680         mv.visitMaxs(-1, -1);
 681         mv.visitEnd();
 682     }
 683 


















 684     /**
 685      * A ProxyMethod object represents a proxy method in the proxy class
 686      * being generated: a method whose implementation will encode and
 687      * dispatch invocations to the proxy instance's invocation handler.
 688      */
 689     private static class ProxyMethod {
 690 
 691         private final Method method;
 692         private final String shortSignature;
 693         private final Class<?> fromClass;
 694         private final Class<?>[] parameterTypes;
 695         private final Class<?> returnType;
 696         private final String methodFieldName;
 697         private Class<?>[] exceptionTypes;
 698 
 699         private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
 700                             Class<?> returnType, Class<?>[] exceptionTypes,
 701                             Class<?> fromClass, String methodFieldName) {
 702             this.method = method;
 703             this.shortSignature = sig;

 793 
 794             mv.visitLabel(L_endBlock);
 795 
 796             // Generate exception handler
 797             mv.visitLabel(L_RuntimeHandler);
 798             mv.visitInsn(ATHROW);   // just rethrow the exception
 799 
 800             mv.visitLabel(L_ThrowableHandler);
 801             mv.visitVarInsn(ASTORE, 1);
 802             mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
 803             mv.visitInsn(DUP);
 804             mv.visitVarInsn(ALOAD, 1);
 805             mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
 806                     "<init>", "(Ljava/lang/Throwable;)V", false);
 807             mv.visitInsn(ATHROW);
 808             // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
 809             mv.visitMaxs(-1, -1);
 810             mv.visitEnd();
 811         }
 812 





















 813         /**
 814          * Generate code for wrapping an argument of the given type
 815          * whose value can be found at the specified local variable
 816          * index, in order for it to be passed (as an Object) to the
 817          * invocation handler's "invoke" method.
 818          */
 819         private void codeWrapArgument(MethodVisitor mv, Class<?> type, int slot) {
 820             if (type.isPrimitive()) {
 821                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
 822 
 823                 mv.visitVarInsn(prim.loadOpcode, slot);
 824                 mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
 825                         prim.wrapperValueOfDesc, false);
 826             } else {
 827                 mv.visitVarInsn(ALOAD, slot);
 828             }
 829         }
 830 
 831         /**
 832          * Generate code for unwrapping a return value of the given

 879                 mv.visitInsn(Opcodes.AASTORE);
 880             }
 881             // lookup the method
 882             mv.visitMethodInsn(INVOKEVIRTUAL,
 883                     JL_CLASS,
 884                     "getMethod",
 885                     "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
 886                     false);
 887 
 888             mv.visitFieldInsn(PUTSTATIC,
 889                     dotToSlash(className),
 890                     methodFieldName, LJLR_METHOD);
 891         }
 892 
 893         /*
 894          * =============== Code Generation Utility Methods ===============
 895          */
 896 
 897         /**
 898          * Generate code to invoke the Class.forName with the name of the given
 899          * class to get its Class object at runtime.  The code is written to
 900          * the supplied stream.  Note that the code generated by this method
 901          * may cause the checked ClassNotFoundException to be thrown. A class
 902          * loader is anticipated at local variable index 0.


 903          */
 904         private void codeClassForName(MethodVisitor mv, Class<?> cl) {
 905             mv.visitLdcInsn(cl.getName());
 906             mv.visitInsn(ICONST_0); // false
 907             mv.visitVarInsn(ALOAD, 0); // classLoader
 908             mv.visitMethodInsn(INVOKESTATIC,
 909                     JL_CLASS,
 910                     "forName",
 911                     "(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
 912                     false);
 913         }
 914 
 915         /**
 916          * Visit a bytecode for a constant.
 917          *
 918          * @param mv  The MethodVisitor
 919          * @param cst The constant value
 920          */
 921         private void emitIconstInsn(MethodVisitor mv, final int cst) {
 922             if (cst >= -1 && cst <= 5) {

   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.reflect;
  27 
  28 import jdk.internal.misc.PreviewFeatures;
  29 import jdk.internal.org.objectweb.asm.Attribute;
  30 import jdk.internal.org.objectweb.asm.ByteVector;
  31 import jdk.internal.org.objectweb.asm.ClassWriter;
  32 import jdk.internal.org.objectweb.asm.Label;
  33 import jdk.internal.org.objectweb.asm.MethodVisitor;
  34 import jdk.internal.org.objectweb.asm.Opcodes;
  35 import jdk.internal.org.objectweb.asm.Type;
  36 import sun.invoke.util.Wrapper;
  37 import sun.security.action.GetBooleanAction;
  38 
  39 import java.io.IOException;
  40 import java.lang.invoke.MethodType;
  41 import java.nio.file.Files;
  42 import java.nio.file.Path;
  43 import java.util.ArrayList;
  44 import java.util.Arrays;
  45 import java.util.HashSet;
  46 import java.util.LinkedHashMap;
  47 import java.util.List;
  48 import java.util.ListIterator;
  49 import java.util.Map;
  50 import java.util.Set;
  51 
  52 import static jdk.internal.org.objectweb.asm.Opcodes.*;
  53 
  54 /**
  55  * ProxyGenerator contains the code to generate a dynamic proxy class
  56  * for the java.lang.reflect.Proxy API.
  57  * <p>
  58  * The external interface to ProxyGenerator is the static
  59  * "generateProxyClass" method.
  60  */
  61 final class ProxyGenerator extends ClassWriter {
  62     private static final int CLASSFILE_VERSION = ClassFileFormatVersion.latest().major();
  63     private static final String JL_CLASS = "java/lang/Class";
  64     private static final String JL_OBJECT = "java/lang/Object";
  65     private static final String JL_THROWABLE = "java/lang/Throwable";
  66     private static final String JL_CLASS_NOT_FOUND_EX = "java/lang/ClassNotFoundException";
  67     private static final String JL_ILLEGAL_ACCESS_EX = "java/lang/IllegalAccessException";
  68 
  69     private static final String JL_NO_CLASS_DEF_FOUND_ERROR = "java/lang/NoClassDefFoundError";
  70     private static final String JL_NO_SUCH_METHOD_EX = "java/lang/NoSuchMethodException";

 443             }
 444         }
 445     }
 446 
 447     /**
 448      * Returns the {@link ClassLoader} to be used by the default implementation of {@link
 449      * #getCommonSuperClass(String, String)}, that of this {@link ClassWriter}'s runtime type by
 450      * default.
 451      *
 452      * @return ClassLoader
 453      */
 454     protected ClassLoader getClassLoader() {
 455         return loader;
 456     }
 457 
 458     /**
 459      * Generate a class file for the proxy class.  This method drives the
 460      * class file generation process.
 461      */
 462     private byte[] generateClassFile() {
 463         int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
 464         visit(version, accessFlags, dotToSlash(className), null,
 465                 JLR_PROXY, typeNames(interfaces));
 466 
 467         /*
 468          * Add proxy methods for the hashCode, equals,
 469          * and toString methods of java.lang.Object.  This is done before
 470          * the methods from the proxy interfaces so that the methods from
 471          * java.lang.Object take precedence over duplicate methods in the
 472          * proxy interfaces.
 473          */
 474         addProxyMethod(hashCodeMethod);
 475         addProxyMethod(equalsMethod);
 476         addProxyMethod(toStringMethod);
 477 
 478         /*
 479          * Accumulate all of the methods from the proxy interfaces.
 480          */
 481         for (Class<?> intf : interfaces) {
 482             for (Method m : intf.getMethods()) {
 483                 if (!Modifier.isStatic(m.getModifiers())) {
 484                     addProxyMethod(m, intf);
 485                 }
 486             }
 487         }
 488 
 489         /*
 490          * For each set of proxy methods with the same signature,
 491          * verify that the methods' return types are compatible.
 492          *
 493          * Determine if any value classes to be preloaded.
 494          */
 495         Set<Class<?>> preloadClasses = new HashSet<>();
 496         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 497             checkReturnTypes(sigmethods);
 498             for (ProxyMethod pm : sigmethods) {
 499                 preloadClasses.addAll(pm.preloadClasses());
 500             }
 501         }
 502 
 503         generateConstructor();
 504 
 505         for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
 506             for (ProxyMethod pm : sigmethods) {
 507                 // add static field for the Method object
 508                 visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, pm.methodFieldName,
 509                         LJLR_METHOD, null, null);
 510 
 511                 // Generate code for proxy method
 512                 pm.generateMethod(this, className);
 513             }
 514         }
 515         if (preloadClasses.size() > 0) {
 516             generatePreloadAttribute(preloadClasses);
 517         }
 518 
 519         generateStaticInitializer();
 520         generateLookupAccessor();
 521         return toByteArray();
 522     }
 523 
 524     /**
 525      * Add another method to be proxied, either by creating a new
 526      * ProxyMethod object or augmenting an old one for a duplicate
 527      * method.
 528      *
 529      * "fromClass" indicates the proxy interface that the method was
 530      * found through, which may be different from (a subinterface of)
 531      * the method's "declaring class".  Note that the first Method
 532      * object passed for a given name and descriptor identifies the
 533      * Method object (and thus the declaring class) that will be
 534      * passed to the invocation handler's "invoke" method for a given
 535      * set of duplicate methods.
 536      */
 537     private void addProxyMethod(Method m, Class<?> fromClass) {

 679         mv.visitJumpInsn(IFEQ, L_illegalAccess);
 680         mv.visitMethodInsn(INVOKESTATIC, JLI_METHODHANDLES, "lookup",
 681                 "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
 682         mv.visitInsn(ARETURN);
 683 
 684         mv.visitLabel(L_illegalAccess);
 685         mv.visitTypeInsn(Opcodes.NEW, JL_ILLEGAL_ACCESS_EX);
 686         mv.visitInsn(DUP);
 687         mv.visitVarInsn(ALOAD, 0);
 688         mv.visitMethodInsn(INVOKEVIRTUAL, JLI_LOOKUP, "toString",
 689                 "()Ljava/lang/String;", false);
 690         mv.visitMethodInsn(INVOKESPECIAL, JL_ILLEGAL_ACCESS_EX,
 691                 "<init>", "(Ljava/lang/String;)V", false);
 692         mv.visitInsn(ATHROW);
 693 
 694         // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
 695         mv.visitMaxs(-1, -1);
 696         mv.visitEnd();
 697     }
 698 
 699     private void generatePreloadAttribute(Set<Class<?>> preloadClasses) {
 700         Attribute attr = new Attribute("Preload") {
 701             @Override
 702             protected ByteVector write(ClassWriter cw,
 703                                        byte[] code,
 704                                        int len,
 705                                        int maxStack,
 706                                        int maxLocals) {
 707                 ByteVector attr = new ByteVector();
 708                 attr.putShort(preloadClasses.size());
 709                 for (Class<?> c : preloadClasses) {
 710                     attr.putShort(cw.newClass(Type.getInternalName(c)));
 711                 }
 712                 return attr;
 713             }
 714         };
 715         visitAttribute(attr);
 716     }
 717     /**
 718      * A ProxyMethod object represents a proxy method in the proxy class
 719      * being generated: a method whose implementation will encode and
 720      * dispatch invocations to the proxy instance's invocation handler.
 721      */
 722     private static class ProxyMethod {
 723 
 724         private final Method method;
 725         private final String shortSignature;
 726         private final Class<?> fromClass;
 727         private final Class<?>[] parameterTypes;
 728         private final Class<?> returnType;
 729         private final String methodFieldName;
 730         private Class<?>[] exceptionTypes;
 731 
 732         private ProxyMethod(Method method, String sig, Class<?>[] parameterTypes,
 733                             Class<?> returnType, Class<?>[] exceptionTypes,
 734                             Class<?> fromClass, String methodFieldName) {
 735             this.method = method;
 736             this.shortSignature = sig;

 826 
 827             mv.visitLabel(L_endBlock);
 828 
 829             // Generate exception handler
 830             mv.visitLabel(L_RuntimeHandler);
 831             mv.visitInsn(ATHROW);   // just rethrow the exception
 832 
 833             mv.visitLabel(L_ThrowableHandler);
 834             mv.visitVarInsn(ASTORE, 1);
 835             mv.visitTypeInsn(Opcodes.NEW, JLR_UNDECLARED_THROWABLE_EX);
 836             mv.visitInsn(DUP);
 837             mv.visitVarInsn(ALOAD, 1);
 838             mv.visitMethodInsn(INVOKESPECIAL, JLR_UNDECLARED_THROWABLE_EX,
 839                     "<init>", "(Ljava/lang/Throwable;)V", false);
 840             mv.visitInsn(ATHROW);
 841             // Maxs computed by ClassWriter.COMPUTE_FRAMES, these arguments ignored
 842             mv.visitMaxs(-1, -1);
 843             mv.visitEnd();
 844         }
 845 
 846         Set<Class<?>> preloadClasses() {
 847             Set<Class<?>> preloadClasses = new HashSet<>();
 848             for (Class<?> type : parameterTypes) {
 849                 if (requiresPreload(type)) {
 850                     preloadClasses.add(type);
 851                 }
 852             }
 853             if (requiresPreload(returnType)) {
 854                 preloadClasses.add(returnType);
 855             }
 856             return preloadClasses;
 857         }
 858 
 859         boolean requiresPreload(Class<?> cls) {
 860             Class<?> c = cls;
 861             while (c.isArray()) {
 862                 c = c.getComponentType();
 863             }
 864             return c.isValue();
 865         }
 866 
 867         /**
 868          * Generate code for wrapping an argument of the given type
 869          * whose value can be found at the specified local variable
 870          * index, in order for it to be passed (as an Object) to the
 871          * invocation handler's "invoke" method.
 872          */
 873         private void codeWrapArgument(MethodVisitor mv, Class<?> type, int slot) {
 874             if (type.isPrimitive()) {
 875                 PrimitiveTypeInfo prim = PrimitiveTypeInfo.get(type);
 876 
 877                 mv.visitVarInsn(prim.loadOpcode, slot);
 878                 mv.visitMethodInsn(INVOKESTATIC, prim.wrapperClassName, "valueOf",
 879                         prim.wrapperValueOfDesc, false);
 880             } else {
 881                 mv.visitVarInsn(ALOAD, slot);
 882             }
 883         }
 884 
 885         /**
 886          * Generate code for unwrapping a return value of the given

 933                 mv.visitInsn(Opcodes.AASTORE);
 934             }
 935             // lookup the method
 936             mv.visitMethodInsn(INVOKEVIRTUAL,
 937                     JL_CLASS,
 938                     "getMethod",
 939                     "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;",
 940                     false);
 941 
 942             mv.visitFieldInsn(PUTSTATIC,
 943                     dotToSlash(className),
 944                     methodFieldName, LJLR_METHOD);
 945         }
 946 
 947         /*
 948          * =============== Code Generation Utility Methods ===============
 949          */
 950 
 951         /**
 952          * Generate code to invoke the Class.forName with the name of the given
 953          * class to get its Class object at runtime.  And also generate code
 954          * to invoke Class::asValueType if the class is a primitive value type.
 955          *
 956          * The code is written to the supplied stream.  Note that the code generated
 957          * by this method may caused the checked ClassNotFoundException to be thrown.
 958          * A class loader is anticipated at local variable index 0.
 959          */
 960         private void codeClassForName(MethodVisitor mv, Class<?> cl) {
 961             mv.visitLdcInsn(cl.getName());
 962             mv.visitInsn(ICONST_0); // false
 963             mv.visitVarInsn(ALOAD, 0); // classLoader
 964             mv.visitMethodInsn(INVOKESTATIC,
 965                     JL_CLASS,
 966                     "forName",
 967                     "(Ljava/lang/String;Z" + LJL_CLASSLOADER + ")Ljava/lang/Class;",
 968                     false);
 969         }
 970 
 971         /**
 972          * Visit a bytecode for a constant.
 973          *
 974          * @param mv  The MethodVisitor
 975          * @param cst The constant value
 976          */
 977         private void emitIconstInsn(MethodVisitor mv, final int cst) {
 978             if (cst >= -1 && cst <= 5) {
< prev index next >