jdk/test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java
changeset 12576 92faacdd6db2
parent 12575 b03bb9688c69
parent 12574 92a4a887300c
child 12578 cf47ce2b7787
equal deleted inserted replaced
12575:b03bb9688c69 12576:92faacdd6db2
     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 
       
    27 import xmlkit.XMLKit.Element;
       
    28 import java.util.HashMap;
       
    29 import java.util.Map;
       
    30 /*
       
    31  * @author jrose
       
    32  */
       
    33 public abstract class InstructionSyntax {
       
    34 
       
    35     InstructionSyntax() {
       
    36     }
       
    37     static final String[] bcNames;
       
    38     static final String[] bcFormats;
       
    39     static final String[] bcWideFormats;
       
    40     static final HashMap<String, Integer> bcCodes;
       
    41     static final HashMap<String, Element> abbrevs;
       
    42     static final HashMap<Element, String> rabbrevs;
       
    43 
       
    44     static {
       
    45         TokenList tl = new TokenList(
       
    46                 " nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3"
       
    47                 + " iconst_4 iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2"
       
    48                 + " dconst_0 dconst_1 bipush/s sipush/ss ldc/k ldc_w/kk ldc2_w/kk"
       
    49                 + " iload/wl lload/wl fload/wl dload/wl aload/wl iload_0 iload_1"
       
    50                 + " iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1"
       
    51                 + " fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1"
       
    52                 + " aload_2 aload_3 iaload laload faload daload aaload baload caload"
       
    53                 + " saload istore/wl lstore/wl fstore/wl dstore/wl astore/wl"
       
    54                 + " istore_0 istore_1 istore_2 istore_3 lstore_0 lstore_1 lstore_2"
       
    55                 + " lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 dstore_1"
       
    56                 + " dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore"
       
    57                 + " lastore fastore dastore aastore bastore castore sastore pop pop2"
       
    58                 + " dup dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd"
       
    59                 + " isub lsub fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem"
       
    60                 + " lrem frem drem ineg lneg fneg dneg ishl lshl ishr lshr iushr"
       
    61                 + " lushr iand land ior lor ixor lxor iinc/wls i2l i2f i2d l2i l2f"
       
    62                 + " l2d f2i f2l f2d d2i d2l d2f i2b i2c i2s lcmp fcmpl fcmpg dcmpl"
       
    63                 + " dcmpg ifeq/oo ifne/oo iflt/oo ifge/oo ifgt/oo ifle/oo"
       
    64                 + " if_icmpeq/oo if_icmpne/oo if_icmplt/oo if_icmpge/oo if_icmpgt/oo"
       
    65                 + " if_icmple/oo if_acmpeq/oo if_acmpne/oo goto/oo jsr/oo ret/wl"
       
    66                 + " tableswitch/oooot lookupswitch/oooot ireturn lreturn freturn dreturn areturn"
       
    67                 + " return getstatic/kf putstatic/kf getfield/kf putfield/kf"
       
    68                 + " invokevirtual/km invokespecial/km invokestatic/km"
       
    69                 + " invokeinterface/knxx xxxunusedxxx new/kc newarray/x anewarray/kc"
       
    70                 + " arraylength athrow checkcast/kc instanceof/kc monitorenter"
       
    71                 + " monitorexit wide multianewarray/kcx ifnull/oo ifnonnull/oo"
       
    72                 + " goto_w/oooo jsr_w/oooo");
       
    73         assert (tl.size() == 202);  // this many instructions!
       
    74         HashMap<String, Integer> map = new HashMap<String, Integer>(tl.size());
       
    75         String[] names = tl.toArray(new String[tl.size()]);
       
    76         String[] formats = new String[names.length];
       
    77         String[] wideFormats = new String[names.length];
       
    78         StringBuilder sbuf = new StringBuilder();
       
    79         sbuf.append('i');  // all op formats begin with "i"
       
    80         int i = 0;
       
    81         for (String ins : names) {
       
    82             assert (ins == ins.trim());  // no whitespace
       
    83             int sfx = ins.indexOf('/');
       
    84             String format = "i";
       
    85             String wideFormat = null;
       
    86             if (sfx >= 0) {
       
    87                 format = ins.substring(sfx + 1);
       
    88                 ins = ins.substring(0, sfx);
       
    89                 if (format.charAt(0) == 'w') {
       
    90                     format = format.substring(1);
       
    91                     sbuf.setLength(1);
       
    92                     for (int j = 0; j < format.length(); j++) {
       
    93                         // double everything except the initial 'i'
       
    94                         sbuf.append(format.charAt(j));
       
    95                         sbuf.append(format.charAt(j));
       
    96                     }
       
    97                     wideFormat = sbuf.toString().intern();
       
    98                 }
       
    99                 sbuf.setLength(1);
       
   100                 sbuf.append(format);
       
   101                 format = sbuf.toString().intern();
       
   102             }
       
   103             ins = ins.intern();
       
   104             names[i] = ins;
       
   105             formats[i] = format;
       
   106             wideFormats[i] = (wideFormat != null) ? wideFormat : format;
       
   107             //System.out.println(ins+" "+format+" "+wideFormat);
       
   108             map.put(ins, i++);
       
   109         }
       
   110         //map = Collections.unmodifiableMap(map);
       
   111 
       
   112         HashMap<String, Element> abb = new HashMap<String, Element>(tl.size() / 2);
       
   113         abb.put("iconst_m1", new Element("bipush", "num", "-1"));
       
   114         for (String ins : names) {
       
   115             int sfx = ins.indexOf('_');
       
   116             if (sfx >= 0 && Character.isDigit(ins.charAt(sfx + 1))) {
       
   117                 String pfx = ins.substring(0, sfx).intern();
       
   118                 String num = ins.substring(sfx + 1);
       
   119                 String att = pfx.endsWith("const") ? "num" : "loc";
       
   120                 Element exp = new Element(pfx, att, num).deepFreeze();
       
   121                 abb.put(ins, exp);
       
   122             }
       
   123         }
       
   124         //abb = Collections.unmodifiableMap(abb);
       
   125         HashMap<Element, String> rabb = new HashMap<Element, String>(tl.size() / 2);
       
   126         for (Map.Entry<String, Element> e : abb.entrySet()) {
       
   127             rabb.put(e.getValue(), e.getKey());
       
   128         }
       
   129         //rabb = Collections.unmodifiableMap(rabb);
       
   130 
       
   131 
       
   132         bcNames = names;
       
   133         bcFormats = formats;
       
   134         bcWideFormats = wideFormats;
       
   135         bcCodes = map;
       
   136         abbrevs = abb;
       
   137         rabbrevs = rabb;
       
   138     }
       
   139 
       
   140     public static String opName(int op) {
       
   141         if (op >= 0 && op < bcNames.length) {
       
   142             return bcNames[op];
       
   143         }
       
   144         return "unknown#" + op;
       
   145     }
       
   146 
       
   147     public static String opFormat(int op) {
       
   148         return opFormat(op, false);
       
   149     }
       
   150 
       
   151     public static String opFormat(int op, boolean isWide) {
       
   152         if (op >= 0 && op < bcFormats.length) {
       
   153             return (isWide ? bcWideFormats[op] : bcFormats[op]);
       
   154         }
       
   155         return "?";
       
   156     }
       
   157 
       
   158     public static int opCode(String opName) {
       
   159         Integer op = (Integer) bcCodes.get(opName);
       
   160         if (op != null) {
       
   161             return op.intValue();
       
   162         }
       
   163         return -1;
       
   164     }
       
   165 
       
   166     public static Element expandAbbrev(String opName) {
       
   167         return abbrevs.get(opName);
       
   168     }
       
   169 
       
   170     public static String findAbbrev(Element op) {
       
   171         return rabbrevs.get(op);
       
   172     }
       
   173 
       
   174     public static int invertBranchOp(int op) {
       
   175         assert (opFormat(op).indexOf('o') >= 0);
       
   176         final int IFMIN = 0x99;
       
   177         final int IFMAX = 0xa6;
       
   178         final int IFMIN2 = 0xc6;
       
   179         final int IFMAX2 = 0xc7;
       
   180         assert (bcNames[IFMIN] == "ifeq");
       
   181         assert (bcNames[IFMAX] == "if_acmpne");
       
   182         assert (bcNames[IFMIN2] == "ifnonnull");
       
   183         assert (bcNames[IFMAX2] == "ifnull");
       
   184         int rop;
       
   185         if (op >= IFMIN && op <= IFMAX) {
       
   186             rop = IFMIN + ((op - IFMIN) ^ 1);
       
   187         } else if (op >= IFMIN2 && op <= IFMAX2) {
       
   188             rop = IFMIN2 + ((op - IFMIN2) ^ 1);
       
   189         } else {
       
   190             assert (false);
       
   191             rop = op;
       
   192         }
       
   193         assert (opFormat(rop).indexOf('o') >= 0);
       
   194         return rop;
       
   195     }
       
   196 
       
   197     public static Element parse(String bytes) {
       
   198         Element e = new Element("Instructions", bytes.length());
       
   199         boolean willBeWide;
       
   200         boolean isWide = false;
       
   201         Element[] tempMap = new Element[bytes.length()];
       
   202         for (int pc = 0, nextpc; pc < bytes.length(); pc = nextpc) {
       
   203             int op = bytes.charAt(pc);
       
   204             Element i = new Element(opName(op));
       
   205 
       
   206             nextpc = pc + 1;
       
   207             int locarg = 0;
       
   208             int cparg = 0;
       
   209             int intarg = 0;
       
   210             int labelarg = 0;
       
   211 
       
   212             willBeWide = false;
       
   213             switch (op) {
       
   214                 case 0xc4: //wide
       
   215                     willBeWide = true;
       
   216                     break;
       
   217                 case 0x10: //bipush
       
   218                     intarg = nextpc++;
       
   219                     intarg *= -1;  //mark signed
       
   220                     break;
       
   221                 case 0x11: //sipush
       
   222                     intarg = nextpc;
       
   223                     nextpc += 2;
       
   224                     intarg *= -1;  //mark signed
       
   225                     break;
       
   226                 case 0x12: //ldc
       
   227                     cparg = nextpc++;
       
   228                     break;
       
   229                 case 0x13: //ldc_w
       
   230                 case 0x14: //ldc2_w
       
   231                 case 0xb2: //getstatic
       
   232                 case 0xb3: //putstatic
       
   233                 case 0xb4: //getfield
       
   234                 case 0xb5: //putfield
       
   235                 case 0xb6: //invokevirtual
       
   236                 case 0xb7: //invokespecial
       
   237                 case 0xb8: //invokestatic
       
   238                 case 0xbb: //new
       
   239                 case 0xbd: //anewarray
       
   240                 case 0xc0: //checkcast
       
   241                 case 0xc1: //instanceof
       
   242                     cparg = nextpc;
       
   243                     nextpc += 2;
       
   244                     break;
       
   245                 case 0xb9: //invokeinterface
       
   246                     cparg = nextpc;
       
   247                     nextpc += 2;
       
   248                     intarg = nextpc;
       
   249                     nextpc += 2;
       
   250                     break;
       
   251                 case 0xc5: //multianewarray
       
   252                     cparg = nextpc;
       
   253                     nextpc += 2;
       
   254                     intarg = nextpc++;
       
   255                     break;
       
   256                 case 0x15: //iload
       
   257                 case 0x16: //lload
       
   258                 case 0x17: //fload
       
   259                 case 0x18: //dload
       
   260                 case 0x19: //aload
       
   261                 case 0x36: //istore
       
   262                 case 0x37: //lstore
       
   263                 case 0x38: //fstore
       
   264                 case 0x39: //dstore
       
   265                 case 0x3a: //astore
       
   266                 case 0xa9: //ret
       
   267                     locarg = nextpc++;
       
   268                     if (isWide) {
       
   269                         nextpc++;
       
   270                     }
       
   271                     break;
       
   272                 case 0x84: //iinc
       
   273                     locarg = nextpc++;
       
   274                     if (isWide) {
       
   275                         nextpc++;
       
   276                     }
       
   277                     intarg = nextpc++;
       
   278                     if (isWide) {
       
   279                         nextpc++;
       
   280                     }
       
   281                     intarg *= -1;  //mark signed
       
   282                     break;
       
   283                 case 0x99: //ifeq
       
   284                 case 0x9a: //ifne
       
   285                 case 0x9b: //iflt
       
   286                 case 0x9c: //ifge
       
   287                 case 0x9d: //ifgt
       
   288                 case 0x9e: //ifle
       
   289                 case 0x9f: //if_icmpeq
       
   290                 case 0xa0: //if_icmpne
       
   291                 case 0xa1: //if_icmplt
       
   292                 case 0xa2: //if_icmpge
       
   293                 case 0xa3: //if_icmpgt
       
   294                 case 0xa4: //if_icmple
       
   295                 case 0xa5: //if_acmpeq
       
   296                 case 0xa6: //if_acmpne
       
   297                 case 0xa7: //goto
       
   298                 case 0xa8: //jsr
       
   299                     labelarg = nextpc;
       
   300                     nextpc += 2;
       
   301                     break;
       
   302                 case 0xbc: //newarray
       
   303                     intarg = nextpc++;
       
   304                     break;
       
   305                 case 0xc6: //ifnull
       
   306                 case 0xc7: //ifnonnull
       
   307                     labelarg = nextpc;
       
   308                     nextpc += 2;
       
   309                     break;
       
   310                 case 0xc8: //goto_w
       
   311                 case 0xc9: //jsr_w
       
   312                     labelarg = nextpc;
       
   313                     nextpc += 4;
       
   314                     break;
       
   315 
       
   316                 // save the best for last:
       
   317                 case 0xaa: //tableswitch
       
   318                     nextpc = parseSwitch(bytes, pc, true, i);
       
   319                     break;
       
   320                 case 0xab: //lookupswitch
       
   321                     nextpc = parseSwitch(bytes, pc, false, i);
       
   322                     break;
       
   323             }
       
   324 
       
   325             String format = null;
       
   326             assert ((format = opFormat(op, isWide)) != null);
       
   327             //System.out.println("pc="+pc+" len="+(nextpc - pc)+" w="+isWide+" op="+op+" name="+opName(op)+" format="+format);
       
   328             assert ((nextpc - pc) == format.length() || format.indexOf('t') >= 0);
       
   329 
       
   330             // Parse out instruction fields.
       
   331             if (locarg != 0) {
       
   332                 int len = nextpc - locarg;
       
   333                 if (intarg != 0) {
       
   334                     len /= 2;  // split
       
   335                 }
       
   336                 i.setAttr("loc", "" + getInt(bytes, locarg, len));
       
   337                 assert ('l' == format.charAt(locarg - pc + 0));
       
   338                 assert ('l' == format.charAt(locarg - pc + len - 1));
       
   339             }
       
   340             if (cparg != 0) {
       
   341                 int len = nextpc - cparg;
       
   342                 if (len > 2) {
       
   343                     len = 2;
       
   344                 }
       
   345                 i.setAttr("ref", "" + getInt(bytes, cparg, len));
       
   346                 assert ('k' == format.charAt(cparg - pc + 0));
       
   347             }
       
   348             if (intarg != 0) {
       
   349                 boolean isSigned = (intarg < 0);
       
   350                 if (isSigned) {
       
   351                     intarg *= -1;
       
   352                 }
       
   353                 int len = nextpc - intarg;
       
   354                 i.setAttr("num", "" + getInt(bytes, intarg, isSigned ? -len : len));
       
   355                 assert ((isSigned ? 's' : 'x') == format.charAt(intarg - pc + 0));
       
   356                 assert ((isSigned ? 's' : 'x') == format.charAt(intarg - pc + len - 1));
       
   357             }
       
   358             if (labelarg != 0) {
       
   359                 int len = nextpc - labelarg;
       
   360                 int offset = getInt(bytes, labelarg, -len);
       
   361                 int target = pc + offset;
       
   362                 i.setAttr("lab", "" + target);
       
   363                 assert ('o' == format.charAt(labelarg - pc + 0));
       
   364                 assert ('o' == format.charAt(labelarg - pc + len - 1));
       
   365             }
       
   366 
       
   367             e.add(i);
       
   368             tempMap[pc] = i;
       
   369             isWide = willBeWide;
       
   370         }
       
   371 
       
   372         // Mark targets of branches.
       
   373         for (Element i : e.elements()) {
       
   374             for (int j = -1; j < i.size(); j++) {
       
   375                 Element c = (j < 0) ? i : (Element) i.get(j);
       
   376                 Number targetNum = c.getAttrNumber("lab");
       
   377                 if (targetNum != null) {
       
   378                     int target = targetNum.intValue();
       
   379                     Element ti = null;
       
   380                     if (target >= 0 && target < tempMap.length) {
       
   381                         ti = tempMap[target];
       
   382                     }
       
   383                     if (ti != null) {
       
   384                         ti.setAttr("pc", "" + target);
       
   385                     } else {
       
   386                         c.setAttr("lab.error", "");
       
   387                     }
       
   388                 }
       
   389             }
       
   390         }
       
   391 
       
   392         // Shrink to fit:
       
   393         for (Element i : e.elements()) {
       
   394             i.trimToSize();
       
   395         }
       
   396         e.trimToSize();
       
   397 
       
   398         /*
       
   399         String assem = assemble(e);
       
   400         if (!assem.equals(bytes)) {
       
   401         System.out.println("Bytes: "+bytes);
       
   402         System.out.println("Insns: "+e);
       
   403         System.out.println("Assem: "+parse(assem));
       
   404         }
       
   405          */
       
   406 
       
   407         return e;
       
   408     }
       
   409 
       
   410     static int switchBase(int pc) {
       
   411         int apc = pc + 1;
       
   412         apc += (-apc) & 3;
       
   413         return apc;
       
   414     }
       
   415 
       
   416     static int parseSwitch(String s, int pc, boolean isTable, Element i) {
       
   417         int apc = switchBase(pc);
       
   418         int defLabel = pc + getInt(s, apc + 4 * 0, 4);
       
   419         i.setAttr("lab", "" + defLabel);
       
   420         if (isTable) {
       
   421             int lowCase = getInt(s, apc + 4 * 1, 4);
       
   422             int highCase = getInt(s, apc + 4 * 2, 4);
       
   423             int caseCount = highCase - lowCase + 1;
       
   424             for (int n = 0; n < caseCount; n++) {
       
   425                 Element c = new Element("Case", 4);
       
   426                 int caseVal = lowCase + n;
       
   427                 int caseLab = getInt(s, apc + 4 * (3 + n), 4) + pc;
       
   428                 c.setAttr("num", "" + caseVal);
       
   429                 c.setAttr("lab", "" + caseLab);
       
   430                 assert (c.getExtraCapacity() == 0);
       
   431                 i.add(c);
       
   432             }
       
   433             return apc + 4 * (3 + caseCount);
       
   434         } else {
       
   435             int caseCount = getInt(s, apc + 4 * 1, 4);
       
   436             for (int n = 0; n < caseCount; n++) {
       
   437                 Element c = new Element("Case", 4);
       
   438                 int caseVal = getInt(s, apc + 4 * (2 + (2 * n) + 0), 4);
       
   439                 int caseLab = getInt(s, apc + 4 * (2 + (2 * n) + 1), 4) + pc;
       
   440                 c.setAttr("num", "" + caseVal);
       
   441                 c.setAttr("lab", "" + caseLab);
       
   442                 assert (c.getExtraCapacity() == 0);
       
   443                 i.add(c);
       
   444             }
       
   445             return apc + 4 * (2 + 2 * caseCount);
       
   446         }
       
   447     }
       
   448 
       
   449     static int getInt(String s, int pc, int len) {
       
   450         //System.out.println("getInt s["+s.length()+"] pc="+pc+" len="+len);
       
   451         int result = s.charAt(pc);
       
   452         if (len < 0) {
       
   453             len = -len;
       
   454             result = (byte) result;
       
   455         }
       
   456         if (!(len == 1 || len == 2 || len == 4)) {
       
   457             System.out.println("len=" + len);
       
   458         }
       
   459         assert (len == 1 || len == 2 || len == 4);
       
   460         for (int i = 1; i < len; i++) {
       
   461             result <<= 8;
       
   462             result += s.charAt(pc + i) & 0xFF;
       
   463         }
       
   464         return result;
       
   465     }
       
   466 
       
   467     public static String assemble(Element instructions) {
       
   468         return InstructionAssembler.assemble(instructions, null, null);
       
   469     }
       
   470 
       
   471     public static String assemble(Element instructions, String pcAttrName) {
       
   472         return InstructionAssembler.assemble(instructions, pcAttrName, null);
       
   473     }
       
   474 
       
   475     public static String assemble(Element instructions, ClassSyntax.GetCPIndex getCPI) {
       
   476         return InstructionAssembler.assemble(instructions, null, getCPI);
       
   477     }
       
   478 
       
   479     public static String assemble(Element instructions, String pcAttrName,
       
   480             ClassSyntax.GetCPIndex getCPI) {
       
   481         return InstructionAssembler.assemble(instructions, pcAttrName, getCPI);
       
   482     }
       
   483 }