Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.bytecode;
     17 
     18 import java.io.DataInputStream;
     19 import java.io.IOException;
     20 import java.util.Map;
     21 import java.util.ArrayList;
     22 import javassist.CtClass;
     23 
     24 /**
     25  * <code>Signature_attribute</code>.
     26  */
     27 public class SignatureAttribute extends AttributeInfo {
     28     /**
     29      * The name of this attribute <code>"Signature"</code>.
     30      */
     31     public static final String tag = "Signature";
     32 
     33     SignatureAttribute(ConstPool cp, int n, DataInputStream in)
     34         throws IOException
     35     {
     36         super(cp, n, in);
     37     }
     38 
     39     /**
     40      * Constructs a Signature attribute.
     41      *
     42      * @param cp                a constant pool table.
     43      * @param signature         the signature represented by this attribute.
     44      */
     45     public SignatureAttribute(ConstPool cp, String signature) {
     46         super(cp, tag);
     47         int index = cp.addUtf8Info(signature);
     48         byte[] bvalue = new byte[2];
     49         bvalue[0] = (byte)(index >>> 8);
     50         bvalue[1] = (byte)index;
     51         set(bvalue);
     52     }
     53 
     54     /**
     55      * Returns the signature indicated by <code>signature_index</code>.
     56      *
     57      * @see #toClassSignature(String)
     58      * @see #toMethodSignature(String)
     59      */
     60     public String getSignature() {
     61         return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0));
     62     }
     63 
     64     /**
     65      * Sets <code>signature_index</code> to the index of the given signature,
     66      * which is added to a constant pool.
     67      *
     68      * @param sig       new signature.
     69      * @since 3.11
     70      */
     71     public void setSignature(String sig) {
     72         int index = getConstPool().addUtf8Info(sig);
     73         ByteArray.write16bit(index, info, 0);
     74     }
     75 
     76     /**
     77      * Makes a copy.  Class names are replaced according to the
     78      * given <code>Map</code> object.
     79      *
     80      * @param newCp     the constant pool table used by the new copy.
     81      * @param classnames        pairs of replaced and substituted
     82      *                          class names.
     83      */
     84     public AttributeInfo copy(ConstPool newCp, Map classnames) {
     85         return new SignatureAttribute(newCp, getSignature());
     86     }
     87 
     88     void renameClass(String oldname, String newname) {
     89         String sig = renameClass(getSignature(), oldname, newname);
     90         setSignature(sig);
     91     }
     92 
     93     void renameClass(Map classnames) {
     94         String sig = renameClass(getSignature(), classnames);
     95         setSignature(sig);
     96     }
     97 
     98     static String renameClass(String desc, String oldname, String newname) {
     99         Map map = new java.util.HashMap();
    100         map.put(oldname, newname);
    101         return renameClass(desc, map);
    102     }
    103 
    104     static String renameClass(String desc, Map map) {
    105         if (map == null)
    106             return desc;
    107 
    108         StringBuilder newdesc = new StringBuilder();
    109         int head = 0;
    110         int i = 0;
    111         for (;;) {
    112             int j = desc.indexOf('L', i);
    113             if (j < 0)
    114                 break;
    115 
    116             StringBuilder nameBuf = new StringBuilder();
    117             int k = j;
    118             char c;
    119             try {
    120                 while ((c = desc.charAt(++k)) != ';') {
    121                     nameBuf.append(c);
    122                     if (c == '<') {
    123                         while ((c = desc.charAt(++k)) != '>')
    124                             nameBuf.append(c);
    125 
    126                         nameBuf.append(c);
    127                     }
    128                 }
    129             }
    130             catch (IndexOutOfBoundsException e) { break; }
    131             i = k + 1;
    132             String name = nameBuf.toString();
    133             String name2 = (String)map.get(name);
    134             if (name2 != null) {
    135                 newdesc.append(desc.substring(head, j));
    136                 newdesc.append('L');
    137                 newdesc.append(name2);
    138                 newdesc.append(c);
    139                 head = i;
    140             }
    141         }
    142 
    143         if (head == 0)
    144             return desc;
    145         else {
    146             int len = desc.length();
    147             if (head < len)
    148                 newdesc.append(desc.substring(head, len));
    149 
    150             return newdesc.toString();
    151         }
    152     }
    153 
    154     private static boolean isNamePart(int c) {
    155         return c != ';' && c != '<';
    156     }
    157 
    158     static private class Cursor {
    159         int position = 0;
    160 
    161         int indexOf(String s, int ch) throws BadBytecode {
    162             int i = s.indexOf(ch, position);
    163             if (i < 0)
    164                 throw error(s);
    165             else {
    166                 position = i + 1;
    167                 return i;
    168             }
    169         }
    170     }
    171 
    172     /**
    173      * Class signature.
    174      */
    175     public static class ClassSignature {
    176         TypeParameter[] params;
    177         ClassType superClass;
    178         ClassType[] interfaces;
    179         ClassSignature(TypeParameter[] p, ClassType s, ClassType[] i) {
    180             params = p;
    181             superClass = s;
    182             interfaces = i;
    183         }
    184 
    185         /**
    186          * Returns the type parameters.
    187          *
    188          * @return a zero-length array if the type parameters are not specified.
    189          */
    190         public TypeParameter[] getParameters() {
    191             return params;
    192         }
    193 
    194         /**
    195          * Returns the super class.
    196          */
    197         public ClassType getSuperClass() { return superClass; }
    198 
    199         /**
    200          * Returns the super interfaces.
    201          *
    202          * @return a zero-length array if the super interfaces are not specified.
    203          */
    204         public ClassType[] getInterfaces() { return interfaces; }
    205 
    206         /**
    207          * Returns the string representation.
    208          */
    209         public String toString() {
    210             StringBuffer sbuf = new StringBuffer();
    211 
    212             TypeParameter.toString(sbuf, params);
    213             sbuf.append(" extends ").append(superClass);
    214             if (interfaces.length > 0) {
    215                 sbuf.append(" implements ");
    216                 Type.toString(sbuf, interfaces);
    217             }
    218 
    219             return sbuf.toString();
    220         }
    221     }
    222 
    223     /**
    224      * Method type signature.
    225      */
    226     public static class MethodSignature {
    227         TypeParameter[] typeParams;
    228         Type[] params;
    229         Type retType;
    230         ObjectType[] exceptions;
    231 
    232         MethodSignature(TypeParameter[] tp, Type[] p, Type ret, ObjectType[] ex) {
    233             typeParams = tp;
    234             params = p;
    235             retType = ret;
    236             exceptions = ex;
    237         }
    238 
    239         /**
    240          * Returns the formal type parameters.
    241          *
    242          * @return a zero-length array if the type parameters are not specified.
    243          */
    244         public TypeParameter[] getTypeParameters() { return typeParams; }
    245 
    246         /**
    247          * Returns the types of the formal parameters.
    248          *
    249          * @return a zero-length array if no formal parameter is taken.
    250          */
    251         public Type[] getParameterTypes() { return params; }
    252 
    253         /**
    254          * Returns the type of the returned value.
    255          */
    256         public Type getReturnType() { return retType; }
    257 
    258         /**
    259          * Returns the types of the exceptions that may be thrown.
    260          *
    261          * @return a zero-length array if exceptions are never thrown or
    262          * the exception types are not parameterized types or type variables.
    263          */
    264         public ObjectType[] getExceptionTypes() { return exceptions; }
    265 
    266         /**
    267          * Returns the string representation.
    268          */
    269         public String toString() {
    270             StringBuffer sbuf = new StringBuffer();
    271 
    272             TypeParameter.toString(sbuf, typeParams);
    273             sbuf.append(" (");
    274             Type.toString(sbuf, params);
    275             sbuf.append(") ");
    276             sbuf.append(retType);
    277             if (exceptions.length > 0) {
    278                 sbuf.append(" throws ");
    279                 Type.toString(sbuf, exceptions);
    280             }
    281 
    282             return sbuf.toString();
    283         }
    284     }
    285 
    286     /**
    287      * Formal type parameters.
    288      */
    289     public static class TypeParameter {
    290         String name;
    291         ObjectType superClass;
    292         ObjectType[] superInterfaces;
    293 
    294         TypeParameter(String sig, int nb, int ne, ObjectType sc, ObjectType[] si) {
    295             name = sig.substring(nb, ne);
    296             superClass = sc;
    297             superInterfaces = si;
    298         }
    299 
    300         /**
    301          * Returns the name of the type parameter.
    302          */
    303         public String getName() {
    304             return name;
    305         }
    306 
    307         /**
    308          * Returns the class bound of this parameter.
    309          *
    310          * @return null if the class bound is not specified.
    311          */
    312         public ObjectType getClassBound() { return superClass; }
    313 
    314         /**
    315          * Returns the interface bound of this parameter.
    316          *
    317          * @return a zero-length array if the interface bound is not specified.
    318          */
    319         public ObjectType[] getInterfaceBound() { return superInterfaces; }
    320 
    321         /**
    322          * Returns the string representation.
    323          */
    324         public String toString() {
    325             StringBuffer sbuf = new StringBuffer(getName());
    326             if (superClass != null)
    327                 sbuf.append(" extends ").append(superClass.toString());
    328 
    329             int len = superInterfaces.length;
    330             if (len > 0) {
    331                 for (int i = 0; i < len; i++) {
    332                     if (i > 0 || superClass != null)
    333                         sbuf.append(" & ");
    334                     else
    335                         sbuf.append(" extends ");
    336 
    337                     sbuf.append(superInterfaces[i].toString());
    338                 }
    339             }
    340 
    341             return sbuf.toString();
    342         }
    343 
    344         static void toString(StringBuffer sbuf, TypeParameter[] tp) {
    345             sbuf.append('<');
    346             for (int i = 0; i < tp.length; i++) {
    347                 if (i > 0)
    348                     sbuf.append(", ");
    349 
    350                 sbuf.append(tp[i]);
    351             }
    352 
    353             sbuf.append('>');
    354         }
    355     }
    356 
    357     /**
    358      * Type argument.
    359      */
    360     public static class TypeArgument {
    361         ObjectType arg;
    362         char wildcard;
    363 
    364         TypeArgument(ObjectType a, char w) {
    365             arg = a;
    366             wildcard = w;
    367         }
    368 
    369         /**
    370          * Returns the kind of this type argument.
    371          *
    372          * @return <code>' '</code> (not-wildcard), <code>'*'</code> (wildcard), <code>'+'</code> (wildcard with
    373          * upper bound), or <code>'-'</code> (wildcard with lower bound).
    374          */
    375         public char getKind() { return wildcard; }
    376 
    377         /**
    378          * Returns true if this type argument is a wildcard type
    379          * such as <code>?</code>, <code>? extends String</code>, or <code>? super Integer</code>.
    380          */
    381         public boolean isWildcard() { return wildcard != ' '; }
    382 
    383         /**
    384          * Returns the type represented by this argument
    385          * if the argument is not a wildcard type.  Otherwise, this method
    386          * returns the upper bound (if the kind is '+'),
    387          * the lower bound (if the kind is '-'), or null (if the upper or lower
    388          * bound is not specified).
    389          */
    390         public ObjectType getType() { return arg; }
    391 
    392         /**
    393          * Returns the string representation.
    394          */
    395         public String toString() {
    396             if (wildcard == '*')
    397                 return "?";
    398 
    399             String type = arg.toString();
    400             if (wildcard == ' ')
    401                 return type;
    402             else if (wildcard == '+')
    403                 return "? extends " + type;
    404             else
    405                 return "? super " + type;
    406         }
    407     }
    408 
    409     /**
    410      * Primitive types and object types.
    411      */
    412     public static abstract class Type {
    413         static void toString(StringBuffer sbuf, Type[] ts) {
    414             for (int i = 0; i < ts.length; i++) {
    415                 if (i > 0)
    416                     sbuf.append(", ");
    417 
    418                 sbuf.append(ts[i]);
    419             }
    420         }
    421     }
    422 
    423     /**
    424      * Primitive types.
    425      */
    426     public static class BaseType extends Type {
    427         char descriptor;
    428         BaseType(char c) { descriptor = c; }
    429 
    430         /**
    431          * Returns the descriptor representing this primitive type.
    432          *
    433          * @see javassist.bytecode.Descriptor
    434          */
    435         public char getDescriptor() { return descriptor; }
    436 
    437         /**
    438          * Returns the <code>CtClass</code> representing this
    439          * primitive type.
    440          */
    441         public CtClass getCtlass() {
    442             return Descriptor.toPrimitiveClass(descriptor);
    443         }
    444 
    445         /**
    446          * Returns the string representation.
    447          */
    448         public String toString() {
    449             return Descriptor.toClassName(Character.toString(descriptor));
    450         }
    451     }
    452 
    453     /**
    454      * Class types, array types, and type variables.
    455      */
    456     public static abstract class ObjectType extends Type {}
    457 
    458     /**
    459      * Class types.
    460      */
    461     public static class ClassType extends ObjectType {
    462         String name;
    463         TypeArgument[] arguments;
    464 
    465         static ClassType make(String s, int b, int e,
    466                               TypeArgument[] targs, ClassType parent) {
    467             if (parent == null)
    468                 return new ClassType(s, b, e, targs);
    469             else
    470                 return new NestedClassType(s, b, e, targs, parent);
    471         }
    472 
    473         ClassType(String signature, int begin, int end, TypeArgument[] targs) {
    474             name = signature.substring(begin, end).replace('/', '.');
    475             arguments = targs;
    476         }
    477 
    478         /**
    479          * Returns the class name.
    480          */
    481         public String getName() {
    482             return name;
    483         }
    484 
    485         /**
    486          * Returns the type arguments.
    487          *
    488          * @return null if no type arguments are given to this class.
    489          */
    490         public TypeArgument[] getTypeArguments() { return arguments; }
    491 
    492         /**
    493          * If this class is a member of another class, returns the
    494          * class in which this class is declared.
    495          *
    496          * @return null if this class is not a member of another class.
    497          */
    498         public ClassType getDeclaringClass() { return null; }
    499 
    500         /**
    501          * Returns the string representation.
    502          */
    503         public String toString() {
    504             StringBuffer sbuf = new StringBuffer();
    505             ClassType parent = getDeclaringClass();
    506             if (parent != null)
    507                 sbuf.append(parent.toString()).append('.');
    508 
    509             sbuf.append(name);
    510             if (arguments != null) {
    511                 sbuf.append('<');
    512                 int n = arguments.length;
    513                 for (int i = 0; i < n; i++) {
    514                     if (i > 0)
    515                         sbuf.append(", ");
    516 
    517                     sbuf.append(arguments[i].toString());
    518                 }
    519 
    520                 sbuf.append('>');
    521             }
    522 
    523             return sbuf.toString();
    524         }
    525     }
    526 
    527     /**
    528      * Nested class types.
    529      */
    530     public static class NestedClassType extends ClassType {
    531         ClassType parent;
    532         NestedClassType(String s, int b, int e,
    533                         TypeArgument[] targs, ClassType p) {
    534             super(s, b, e, targs);
    535             parent = p;
    536         }
    537 
    538         /**
    539          * Returns the class that declares this nested class.
    540          * This nested class is a member of that declaring class.
    541          */
    542         public ClassType getDeclaringClass() { return parent; }
    543     }
    544 
    545     /**
    546      * Array types.
    547      */
    548     public static class ArrayType extends ObjectType {
    549         int dim;
    550         Type componentType;
    551 
    552         public ArrayType(int d, Type comp) {
    553             dim = d;
    554             componentType = comp;
    555         }
    556 
    557         /**
    558          * Returns the dimension of the array.
    559          */
    560         public int getDimension() { return dim; }
    561 
    562         /**
    563          * Returns the component type.
    564          */
    565         public Type getComponentType() {
    566             return componentType;
    567         }
    568 
    569         /**
    570          * Returns the string representation.
    571          */
    572         public String toString() {
    573             StringBuffer sbuf = new StringBuffer(componentType.toString());
    574             for (int i = 0; i < dim; i++)
    575                 sbuf.append("[]");
    576 
    577             return sbuf.toString();
    578         }
    579     }
    580 
    581     /**
    582      * Type variables.
    583      */
    584     public static class TypeVariable extends ObjectType {
    585         String name;
    586 
    587         TypeVariable(String sig, int begin, int end) {
    588             name = sig.substring(begin, end);
    589         }
    590 
    591         /**
    592          * Returns the variable name.
    593          */
    594         public String getName() {
    595             return name;
    596         }
    597 
    598         /**
    599          * Returns the string representation.
    600          */
    601         public String toString() {
    602             return name;
    603         }
    604     }
    605 
    606     /**
    607      * Parses the given signature string as a class signature.
    608      *
    609      * @param  sig                  the signature.
    610      * @throws BadBytecode          thrown when a syntactical error is found.
    611      * @since 3.5
    612      */
    613     public static ClassSignature toClassSignature(String sig) throws BadBytecode {
    614         try {
    615             return parseSig(sig);
    616         }
    617         catch (IndexOutOfBoundsException e) {
    618             throw error(sig);
    619         }
    620     }
    621 
    622     /**
    623      * Parses the given signature string as a method type signature.
    624      *
    625      * @param  sig                  the signature.
    626      * @throws BadBytecode          thrown when a syntactical error is found.
    627      * @since 3.5
    628      */
    629     public static MethodSignature toMethodSignature(String sig) throws BadBytecode {
    630         try {
    631             return parseMethodSig(sig);
    632         }
    633         catch (IndexOutOfBoundsException e) {
    634             throw error(sig);
    635         }
    636     }
    637 
    638     /**
    639      * Parses the given signature string as a field type signature.
    640      *
    641      * @param  sig                  the signature string.
    642      * @return the field type signature.
    643      * @throws BadBytecode          thrown when a syntactical error is found.
    644      * @since 3.5
    645      */
    646     public static ObjectType toFieldSignature(String sig) throws BadBytecode {
    647         try {
    648             return parseObjectType(sig, new Cursor(), false);
    649         }
    650         catch (IndexOutOfBoundsException e) {
    651             throw error(sig);
    652         }
    653     }
    654 
    655     private static ClassSignature parseSig(String sig)
    656         throws BadBytecode, IndexOutOfBoundsException
    657     {
    658         Cursor cur = new Cursor();
    659         TypeParameter[] tp = parseTypeParams(sig, cur);
    660         ClassType superClass = parseClassType(sig, cur);
    661         int sigLen = sig.length();
    662         ArrayList ifArray = new ArrayList();
    663         while (cur.position < sigLen && sig.charAt(cur.position) == 'L')
    664             ifArray.add(parseClassType(sig, cur));
    665 
    666         ClassType[] ifs
    667             = (ClassType[])ifArray.toArray(new ClassType[ifArray.size()]);
    668         return new ClassSignature(tp, superClass, ifs);
    669     }
    670 
    671     private static MethodSignature parseMethodSig(String sig)
    672         throws BadBytecode
    673     {
    674         Cursor cur = new Cursor();
    675         TypeParameter[] tp = parseTypeParams(sig, cur);
    676         if (sig.charAt(cur.position++) != '(')
    677             throw error(sig);
    678 
    679         ArrayList params = new ArrayList();
    680         while (sig.charAt(cur.position) != ')') {
    681             Type t = parseType(sig, cur);
    682             params.add(t);
    683         }
    684 
    685         cur.position++;
    686         Type ret = parseType(sig, cur);
    687         int sigLen = sig.length();
    688         ArrayList exceptions = new ArrayList();
    689         while (cur.position < sigLen && sig.charAt(cur.position) == '^') {
    690             cur.position++;
    691             ObjectType t = parseObjectType(sig, cur, false);
    692             if (t instanceof ArrayType)
    693                 throw error(sig);
    694 
    695             exceptions.add(t);
    696         }
    697 
    698         Type[] p = (Type[])params.toArray(new Type[params.size()]);
    699         ObjectType[] ex = (ObjectType[])exceptions.toArray(new ObjectType[exceptions.size()]);
    700         return new MethodSignature(tp, p, ret, ex);
    701     }
    702 
    703     private static TypeParameter[] parseTypeParams(String sig, Cursor cur)
    704         throws BadBytecode
    705     {
    706         ArrayList typeParam = new ArrayList();
    707         if (sig.charAt(cur.position) == '<') {
    708             cur.position++;
    709             while (sig.charAt(cur.position) != '>') {
    710                 int nameBegin = cur.position;
    711                 int nameEnd = cur.indexOf(sig, ':');
    712                 ObjectType classBound = parseObjectType(sig, cur, true);
    713                 ArrayList ifBound = new ArrayList();
    714                 while (sig.charAt(cur.position) == ':') {
    715                     cur.position++;
    716                     ObjectType t = parseObjectType(sig, cur, false);
    717                     ifBound.add(t);
    718                 }
    719 
    720                 TypeParameter p = new TypeParameter(sig, nameBegin, nameEnd,
    721                         classBound, (ObjectType[])ifBound.toArray(new ObjectType[ifBound.size()]));
    722                 typeParam.add(p);
    723             }
    724 
    725             cur.position++;
    726         }
    727 
    728         return (TypeParameter[])typeParam.toArray(new TypeParameter[typeParam.size()]);
    729     }
    730 
    731     private static ObjectType parseObjectType(String sig, Cursor c, boolean dontThrow)
    732         throws BadBytecode
    733     {
    734         int i;
    735         int begin = c.position;
    736         switch (sig.charAt(begin)) {
    737         case 'L' :
    738             return parseClassType2(sig, c, null);
    739         case 'T' :
    740             i = c.indexOf(sig, ';');
    741             return new TypeVariable(sig, begin + 1, i);
    742         case '[' :
    743             return parseArray(sig, c);
    744         default :
    745             if (dontThrow)
    746                 return null;
    747             else
    748                 throw error(sig);
    749         }
    750     }
    751 
    752     private static ClassType parseClassType(String sig, Cursor c)
    753         throws BadBytecode
    754     {
    755         if (sig.charAt(c.position) == 'L')
    756             return parseClassType2(sig, c, null);
    757         else
    758             throw error(sig);
    759     }
    760 
    761     private static ClassType parseClassType2(String sig, Cursor c, ClassType parent)
    762         throws BadBytecode
    763     {
    764         int start = ++c.position;
    765         char t;
    766         do {
    767             t = sig.charAt(c.position++);
    768         } while (t != '$' && t != '<' && t != ';');
    769         int end = c.position - 1;
    770         TypeArgument[] targs;
    771         if (t == '<') {
    772             targs = parseTypeArgs(sig, c);
    773             t = sig.charAt(c.position++);
    774         }
    775         else
    776             targs = null;
    777 
    778         ClassType thisClass = ClassType.make(sig, start, end, targs, parent);
    779         if (t == '$') {
    780             c.position--;
    781             return parseClassType2(sig, c, thisClass);
    782         }
    783         else
    784             return thisClass;
    785     }
    786 
    787     private static TypeArgument[] parseTypeArgs(String sig, Cursor c) throws BadBytecode {
    788         ArrayList args = new ArrayList();
    789         char t;
    790         while ((t = sig.charAt(c.position++)) != '>') {
    791             TypeArgument ta;
    792             if (t == '*' )
    793                 ta = new TypeArgument(null, '*');
    794             else {
    795                 if (t != '+' && t != '-') {
    796                     t = ' ';
    797                     c.position--;
    798                 }
    799 
    800                 ta = new TypeArgument(parseObjectType(sig, c, false), t);
    801             }
    802 
    803             args.add(ta);
    804         }
    805 
    806         return (TypeArgument[])args.toArray(new TypeArgument[args.size()]);
    807     }
    808 
    809     private static ObjectType parseArray(String sig, Cursor c) throws BadBytecode {
    810         int dim = 1;
    811         while (sig.charAt(++c.position) == '[')
    812             dim++;
    813 
    814         return new ArrayType(dim, parseType(sig, c));
    815     }
    816 
    817     private static Type parseType(String sig, Cursor c) throws BadBytecode {
    818         Type t = parseObjectType(sig, c, true);
    819         if (t == null)
    820             t = new BaseType(sig.charAt(c.position++));
    821 
    822         return t;
    823     }
    824 
    825     private static BadBytecode error(String sig) {
    826         return new BadBytecode("bad signature: " + sig);
    827     }
    828 }
    829