jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java
changeset 12574 92a4a887300c
parent 12573 426adeeabf00
parent 12572 47138eba5e83
child 12576 92faacdd6db2
equal deleted inserted replaced
12573:426adeeabf00 12574:92a4a887300c
     1 /*
       
     2  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
       
    26 import xmlkit.XMLKit.*;
       
    27 
       
    28 import java.util.*;
       
    29 import java.security.MessageDigest;
       
    30 import java.nio.ByteBuffer;
       
    31 import xmlkit.XMLKit.Element;
       
    32 /*
       
    33  * @author jrose
       
    34  */
       
    35 public abstract class ClassSyntax {
       
    36 
       
    37     public interface GetCPIndex {
       
    38 
       
    39         int getCPIndex(int tag, String name);  // cp finder
       
    40     }
       
    41     public static final int CONSTANT_Utf8 = 1,
       
    42             CONSTANT_Integer = 3,
       
    43             CONSTANT_Float = 4,
       
    44             CONSTANT_Long = 5,
       
    45             CONSTANT_Double = 6,
       
    46             CONSTANT_Class = 7,
       
    47             CONSTANT_String = 8,
       
    48             CONSTANT_Fieldref = 9,
       
    49             CONSTANT_Methodref = 10,
       
    50             CONSTANT_InterfaceMethodref = 11,
       
    51             CONSTANT_NameAndType = 12;
       
    52     private static final String[] cpTagName = {
       
    53         /* 0:  */null,
       
    54         /* 1:  */ "Utf8",
       
    55         /* 2:  */ null,
       
    56         /* 3:  */ "Integer",
       
    57         /* 4:  */ "Float",
       
    58         /* 5:  */ "Long",
       
    59         /* 6:  */ "Double",
       
    60         /* 7:  */ "Class",
       
    61         /* 8:  */ "String",
       
    62         /* 9:  */ "Fieldref",
       
    63         /* 10: */ "Methodref",
       
    64         /* 11: */ "InterfaceMethodref",
       
    65         /* 12: */ "NameAndType",
       
    66         null
       
    67     };
       
    68     private static final Set<String> cpTagNames;
       
    69 
       
    70     static {
       
    71         Set<String> set = new HashSet<String>(Arrays.asList(cpTagName));
       
    72         set.remove(null);
       
    73         cpTagNames = Collections.unmodifiableSet(set);
       
    74     }
       
    75     public static final int ITEM_Top = 0, // replicates by [1..4,1..4]
       
    76             ITEM_Integer = 1, // (ditto)
       
    77             ITEM_Float = 2,
       
    78             ITEM_Double = 3,
       
    79             ITEM_Long = 4,
       
    80             ITEM_Null = 5,
       
    81             ITEM_UninitializedThis = 6,
       
    82             ITEM_Object = 7,
       
    83             ITEM_Uninitialized = 8,
       
    84             ITEM_ReturnAddress = 9,
       
    85             ITEM_LIMIT = 10;
       
    86     private static final String[] itemTagName = {
       
    87         "Top",
       
    88         "Integer",
       
    89         "Float",
       
    90         "Double",
       
    91         "Long",
       
    92         "Null",
       
    93         "UninitializedThis",
       
    94         "Object",
       
    95         "Uninitialized",
       
    96         "ReturnAddress",};
       
    97     private static final Set<String> itemTagNames;
       
    98 
       
    99     static {
       
   100         Set<String> set = new HashSet<String>(Arrays.asList(itemTagName));
       
   101         set.remove(null);
       
   102         itemTagNames = Collections.unmodifiableSet(set);
       
   103     }
       
   104     protected static final HashMap<String, String> attrTypesBacking;
       
   105     protected static final Map<String, String> attrTypesInit;
       
   106 
       
   107     static {
       
   108         HashMap<String, String> at = new HashMap<String, String>();
       
   109 
       
   110         //at.put("*.Deprecated", "<deprecated=true>");
       
   111         //at.put("*.Synthetic", "<synthetic=true>");
       
   112         ////at.put("Field.ConstantValue", "<constantValue=>KQH");
       
   113         //at.put("Class.SourceFile", "<sourceFile=>RUH");
       
   114         at.put("Method.Bridge", "<Bridge>");
       
   115         at.put("Method.Varargs", "<Varargs>");
       
   116         at.put("Class.Enum", "<Enum>");
       
   117         at.put("*.Signature", "<Signature>RSH");
       
   118         //at.put("*.Deprecated", "<Deprecated>");
       
   119         //at.put("*.Synthetic", "<Synthetic>");
       
   120         at.put("Field.ConstantValue", "<ConstantValue>KQH");
       
   121         at.put("Class.SourceFile", "<SourceFile>RUH");
       
   122         at.put("Class.InnerClasses", "NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]");
       
   123         at.put("Code.LineNumberTable", "NH[<LineNumber><bci=>PH<line=>H]");
       
   124         at.put("Code.LocalVariableTable", "NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
       
   125         at.put("Code.LocalVariableTypeTable", "NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]");
       
   126         at.put("Method.Exceptions", "NH[<Exception><name=>RCH]");
       
   127         at.put("Method.Code", "<Code>...");
       
   128         at.put("Code.StackMapTable", "<Frame>...");
       
   129         //at.put("Code.StkMapX", "<FrameX>...");
       
   130         if (true) {
       
   131             at.put("Code.StackMapTable",
       
   132                     "[NH[<Frame>(1)]]"
       
   133                     + "[TB"
       
   134                     + "(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79"
       
   135                     + ",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95"
       
   136                     + ",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111"
       
   137                     + ",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127"
       
   138                     + ")[<SameLocals1StackItemFrame>(4)]"
       
   139                     + "(247)[<SameLocals1StackItemExtended>H(4)]"
       
   140                     + "(248)[<Chop3>H]"
       
   141                     + "(249)[<Chop2>H]"
       
   142                     + "(250)[<Chop1>H]"
       
   143                     + "(251)[<SameFrameExtended>H]"
       
   144                     + "(252)[<Append1>H(4)]"
       
   145                     + "(253)[<Append2>H(4)(4)]"
       
   146                     + "(254)[<Append3>H(4)(4)(4)]"
       
   147                     + "(255)[<FullFrame>H(2)(3)]"
       
   148                     + "()[<SameFrame>]]"
       
   149                     + "[NH[<Local>(4)]]"
       
   150                     + "[NH[<Stack>(4)]]"
       
   151                     + "[TB"
       
   152                     + ("(0)[<Top>]"
       
   153                     + "(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]"
       
   154                     + "(5)[<ItemNull>](6)[<ItemUninitializedThis>]"
       
   155                     + "(7)[<ItemObject><class=>RCH]"
       
   156                     + "(8)[<ItemUninitialized><bci=>PH]"
       
   157                     + "()[<ItemUnknown>]]"));
       
   158         }
       
   159 
       
   160         at.put("Class.EnclosingMethod", "<EnclosingMethod><class=>RCH<desc=>RDH");//RDNH
       
   161 
       
   162         // Layouts of metadata attrs:
       
   163         String vpf = "[<RuntimeVisibleAnnotation>";
       
   164         String ipf = "[<RuntimeInvisibleAnnotation>";
       
   165         String apf = "[<Annotation>";
       
   166         String mdanno2 = ""
       
   167                 + "<type=>RSHNH[<Member><name=>RUH(3)]]"
       
   168                 + ("[TB"
       
   169                 + "(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]"
       
   170                 + "(\\D)[<value=>KDH]"
       
   171                 + "(\\F)[<value=>KFH]"
       
   172                 + "(\\J)[<value=>KJH]"
       
   173                 + "(\\c)[<class=>RSH]"
       
   174                 + "(\\e)[<type=>RSH<name=>RUH]"
       
   175                 + "(\\s)[<String>RUH]"
       
   176                 + "(\\@)[(2)]"
       
   177                 + "(\\[)[NH[<Element>(3)]]"
       
   178                 + "()[]"
       
   179                 + "]");
       
   180         String visanno = "[NH[(2)]][(1)]" + vpf + mdanno2;
       
   181         String invanno = "[NH[(2)]][(1)]" + ipf + mdanno2;
       
   182         String vparamanno = ""
       
   183                 + "[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]"
       
   184                 + apf + mdanno2;
       
   185         String iparamanno = ""
       
   186                 + "[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]"
       
   187                 + apf + mdanno2;
       
   188         String mdannodef = "[<AnnotationDefault>(3)][(1)]" + apf + mdanno2;
       
   189         String[] mdplaces = {"Class", "Field", "Method"};
       
   190         for (String place : mdplaces) {
       
   191             at.put(place + ".RuntimeVisibleAnnotations", visanno);
       
   192             at.put(place + ".RuntimeInvisibleAnnotations", invanno);
       
   193         }
       
   194         at.put("Method.RuntimeVisibleParameterAnnotations", vparamanno);
       
   195         at.put("Method.RuntimeInvisibleParameterAnnotations", iparamanno);
       
   196         at.put("Method.AnnotationDefault", mdannodef);
       
   197 
       
   198         attrTypesBacking = at;
       
   199         attrTypesInit = Collections.unmodifiableMap(at);
       
   200     }
       
   201 
       
   202     ;
       
   203     private static final String[] jcovAttrTypes = {
       
   204         "Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]",
       
   205         "Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]",
       
   206         "Class.SourceID=<SourceID><id=>RUH",
       
   207         "Class.CompilationID=<CompilationID><id=>RUH"
       
   208     };
       
   209     protected static final String[][] modifierNames = {
       
   210         {"public"},
       
   211         {"private"},
       
   212         {"protected"},
       
   213         {"static"},
       
   214         {"final"},
       
   215         {"synchronized"},
       
   216         {null, "volatile", "bridge"},
       
   217         {null, "transient", "varargs"},
       
   218         {null, null, "native"},
       
   219         {"interface"},
       
   220         {"abstract"},
       
   221         {"strictfp"},
       
   222         {"synthetic"},
       
   223         {"annotation"},
       
   224         {"enum"},};
       
   225     protected static final String EIGHT_BIT_CHAR_ENCODING = "ISO8859_1";
       
   226     protected static final String UTF8_ENCODING = "UTF8";
       
   227     // What XML tags are used by this syntax, apart from attributes?
       
   228     protected static final Set<String> nonAttrTags;
       
   229 
       
   230     static {
       
   231         HashSet<String> tagSet = new HashSet<String>();
       
   232         Collections.addAll(tagSet, new String[]{
       
   233                     "ConstantPool",// the CP
       
   234                     "Class", // the class
       
   235                     "Interface", // implemented interfaces
       
   236                     "Method", // methods
       
   237                     "Field", // fields
       
   238                     "Handler", // exception handler pseudo-attribute
       
   239                     "Attribute", // unparsed attribute
       
   240                     "Bytes", // bytecodes
       
   241                     "Instructions" // bytecodes, parsed
       
   242                 });
       
   243         nonAttrTags = Collections.unmodifiableSet(tagSet);
       
   244     }
       
   245 
       
   246     // Accessors.
       
   247     public static Set<String> nonAttrTags() {
       
   248         return nonAttrTags;
       
   249     }
       
   250 
       
   251     public static String cpTagName(int t) {
       
   252         t &= 0xFF;
       
   253         String ts = null;
       
   254         if (t < cpTagName.length) {
       
   255             ts = cpTagName[t];
       
   256         }
       
   257         if (ts != null) {
       
   258             return ts;
       
   259         }
       
   260         return ("UnknownTag" + (int) t).intern();
       
   261     }
       
   262 
       
   263     public static int cpTagValue(String name) {
       
   264         for (int t = 0; t < cpTagName.length; t++) {
       
   265             if (name.equals(cpTagName[t])) {
       
   266                 return t;
       
   267             }
       
   268         }
       
   269         return 0;
       
   270     }
       
   271 
       
   272     public static String itemTagName(int t) {
       
   273         t &= 0xFF;
       
   274         String ts = null;
       
   275         if (t < itemTagName.length) {
       
   276             ts = itemTagName[t];
       
   277         }
       
   278         if (ts != null) {
       
   279             return ts;
       
   280         }
       
   281         return ("UnknownItem" + (int) t).intern();
       
   282     }
       
   283 
       
   284     public static int itemTagValue(String name) {
       
   285         for (int t = 0; t < itemTagName.length; t++) {
       
   286             if (name.equals(itemTagName[t])) {
       
   287                 return t;
       
   288             }
       
   289         }
       
   290         return -1;
       
   291     }
       
   292 
       
   293     public void addJcovAttrTypes() {
       
   294         addAttrTypes(jcovAttrTypes);
       
   295     }
       
   296     // Public methods for declaring attribute types.
       
   297     protected Map<String, String> attrTypes = attrTypesInit;
       
   298 
       
   299     public void addAttrType(String opt) {
       
   300         int eqpos = opt.indexOf('=');
       
   301         addAttrType(opt.substring(0, eqpos), opt.substring(eqpos + 1));
       
   302     }
       
   303 
       
   304     public void addAttrTypes(String[] opts) {
       
   305         for (String opt : opts) {
       
   306             addAttrType(opt);
       
   307         }
       
   308     }
       
   309 
       
   310     private void checkAttr(String attr) {
       
   311         if (!attr.startsWith("Class.")
       
   312                 && !attr.startsWith("Field.")
       
   313                 && !attr.startsWith("Method.")
       
   314                 && !attr.startsWith("Code.")
       
   315                 && !attr.startsWith("*.")) {
       
   316             throw new IllegalArgumentException("attr name must start with 'Class.', etc.");
       
   317         }
       
   318         String uattr = attr.substring(attr.indexOf('.') + 1);
       
   319         if (nonAttrTags.contains(uattr)) {
       
   320             throw new IllegalArgumentException("attr name must not be one of " + nonAttrTags);
       
   321         }
       
   322     }
       
   323 
       
   324     private void checkAttrs(Map<String, String> at) {
       
   325         for (String attr : at.keySet()) {
       
   326             checkAttr(attr);
       
   327         }
       
   328     }
       
   329 
       
   330     private void modAttrs() {
       
   331         if (attrTypes == attrTypesInit) {
       
   332             // Make modifiable.
       
   333             attrTypes = new HashMap<String, String>(attrTypesBacking);
       
   334         }
       
   335     }
       
   336 
       
   337     public void addAttrType(String attr, String fmt) {
       
   338         checkAttr(attr);
       
   339         modAttrs();
       
   340         attrTypes.put(attr, fmt);
       
   341     }
       
   342 
       
   343     public void addAttrTypes(Map<String, String> at) {
       
   344         checkAttrs(at);
       
   345         modAttrs();
       
   346         attrTypes.putAll(at);
       
   347     }
       
   348 
       
   349     public Map<String, String> getAttrTypes() {
       
   350         if (attrTypes == attrTypesInit) {
       
   351             return attrTypes;
       
   352         }
       
   353         return Collections.unmodifiableMap(attrTypes);
       
   354     }
       
   355 
       
   356     public void setAttrTypes(Map<String, String> at) {
       
   357         checkAttrs(at);
       
   358         modAttrs();
       
   359         attrTypes.keySet().retainAll(at.keySet());
       
   360         attrTypes.putAll(at);
       
   361     }
       
   362 
       
   363     // attr format helpers
       
   364     protected static boolean matchTag(int tagValue, String caseStr) {
       
   365         //System.out.println("matchTag "+tagValue+" in "+caseStr);
       
   366         for (int pos = 0, max = caseStr.length(), comma;
       
   367                 pos < max;
       
   368                 pos = comma + 1) {
       
   369             int caseValue;
       
   370             if (caseStr.charAt(pos) == '\\') {
       
   371                 caseValue = caseStr.charAt(pos + 1);
       
   372                 comma = pos + 2;
       
   373                 assert (comma == max || caseStr.charAt(comma) == ',');
       
   374             } else {
       
   375                 comma = caseStr.indexOf(',', pos);
       
   376                 if (comma < 0) {
       
   377                     comma = max;
       
   378                 }
       
   379                 caseValue = Integer.parseInt(caseStr.substring(pos, comma));
       
   380             }
       
   381             if (tagValue == caseValue) {
       
   382                 return true;
       
   383             }
       
   384         }
       
   385         return false;
       
   386     }
       
   387 
       
   388     protected static String[] getBodies(String type) {
       
   389         ArrayList<String> bodies = new ArrayList<String>();
       
   390         for (int i = 0; i < type.length();) {
       
   391             String body = getBody(type, i);
       
   392             bodies.add(body);
       
   393             i += body.length() + 2;  // skip body and brackets
       
   394         }
       
   395         return bodies.toArray(new String[bodies.size()]);
       
   396     }
       
   397 
       
   398     protected static String getBody(String type, int i) {
       
   399         assert (type.charAt(i) == '[');
       
   400         int next = ++i;  // skip bracket
       
   401         for (int depth = 1; depth > 0; next++) {
       
   402             switch (type.charAt(next)) {
       
   403                 case '[':
       
   404                     depth++;
       
   405                     break;
       
   406                 case ']':
       
   407                     depth--;
       
   408                     break;
       
   409                 case '(':
       
   410                     next = type.indexOf(')', next);
       
   411                     break;
       
   412                 case '<':
       
   413                     next = type.indexOf('>', next);
       
   414                     break;
       
   415             }
       
   416             assert (next > 0);
       
   417         }
       
   418         --next;  // get before bracket
       
   419         assert (type.charAt(next) == ']');
       
   420         return type.substring(i, next);
       
   421     }
       
   422 
       
   423     public Element makeCPDigest(int length) {
       
   424         MessageDigest md;
       
   425         try {
       
   426             md = MessageDigest.getInstance("MD5");
       
   427         } catch (java.security.NoSuchAlgorithmException ee) {
       
   428             throw new Error(ee);
       
   429         }
       
   430         int items = 0;
       
   431         for (Element e : cpool.elements()) {
       
   432             if (items == length) {
       
   433                 break;
       
   434             }
       
   435             if (cpTagNames.contains(e.getName())) {
       
   436                 items += 1;
       
   437                 md.update((byte) cpTagValue(e.getName()));
       
   438                 try {
       
   439                     md.update(e.getText().toString().getBytes(UTF8_ENCODING));
       
   440                 } catch (java.io.UnsupportedEncodingException ee) {
       
   441                     throw new Error(ee);
       
   442                 }
       
   443             }
       
   444         }
       
   445         ByteBuffer bb = ByteBuffer.wrap(md.digest());
       
   446         String l0 = Long.toHexString(bb.getLong(0));
       
   447         String l1 = Long.toHexString(bb.getLong(8));
       
   448         while (l0.length() < 16) {
       
   449             l0 = "0" + l0;
       
   450         }
       
   451         while (l1.length() < 16) {
       
   452             l1 = "0" + l1;
       
   453         }
       
   454         return new Element("Digest",
       
   455                 "length", "" + items,
       
   456                 "bytes", l0 + l1);
       
   457     }
       
   458 
       
   459     public Element getCPDigest(int length) {
       
   460         if (length == -1) {
       
   461             length = cpool.countAll(XMLKit.elementFilter(cpTagNames));
       
   462         }
       
   463         for (Element md : cpool.findAllElements("Digest").elements()) {
       
   464             if (md.getAttrLong("length") == length) {
       
   465                 return md;
       
   466             }
       
   467         }
       
   468         Element md = makeCPDigest(length);
       
   469         cpool.add(md);
       
   470         return md;
       
   471     }
       
   472 
       
   473     public Element getCPDigest() {
       
   474         return getCPDigest(-1);
       
   475     }
       
   476 
       
   477     public boolean checkCPDigest(Element md) {
       
   478         return md.equals(getCPDigest((int) md.getAttrLong("length")));
       
   479     }
       
   480 
       
   481     public static int computeInterfaceNum(String intMethRef) {
       
   482         intMethRef = intMethRef.substring(1 + intMethRef.lastIndexOf(' '));
       
   483         if (!intMethRef.startsWith("(")) {
       
   484             return -1;
       
   485         }
       
   486         int signum = 1;  // start with one for "this"
       
   487         scanSig:
       
   488         for (int i = 1; i < intMethRef.length(); i++) {
       
   489             char ch = intMethRef.charAt(i);
       
   490             signum++;
       
   491             switch (ch) {
       
   492                 case ')':
       
   493                     --signum;
       
   494                     break scanSig;
       
   495                 case 'L':
       
   496                     i = intMethRef.indexOf(';', i);
       
   497                     break;
       
   498                 case '[':
       
   499                     while (ch == '[') {
       
   500                         ch = intMethRef.charAt(++i);
       
   501                     }
       
   502                     if (ch == 'L') {
       
   503                         i = intMethRef.indexOf(';', i);
       
   504                     }
       
   505                     break;
       
   506             }
       
   507         }
       
   508         int num = (signum << 8) | 0;
       
   509         //System.out.println("computeInterfaceNum "+intMethRef+" => "+num);
       
   510         return num;
       
   511     }
       
   512     // Protected state for representing the class file.
       
   513     protected Element cfile;          // <ClassFile ...>
       
   514     protected Element cpool;          // <ConstantPool ...>
       
   515     protected Element klass;          // <Class ...>
       
   516     protected Element currentMember;  // varies during scans
       
   517     protected Element currentCode;    // varies during scans
       
   518 }