langtools/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java
changeset 30846 2b3f379840f0
parent 26390 1d0902fe3ca0
child 39104 61c5b5f8fd8c
equal deleted inserted replaced
30845:43ddd58a5a56 30846:2b3f379840f0
       
     1 /*
       
     2  * Copyright (c) 2007, 2014, 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 
       
    26 package com.sun.tools.javap;
       
    27 
       
    28 import com.sun.tools.classfile.ClassFile;
       
    29 import com.sun.tools.classfile.ConstantPool;
       
    30 import com.sun.tools.classfile.ConstantPoolException;
       
    31 
       
    32 import static com.sun.tools.classfile.ConstantPool.*;
       
    33 
       
    34 /*
       
    35  *  Write a constant pool entry.
       
    36  *
       
    37  *  <p><b>This is NOT part of any supported API.
       
    38  *  If you write code that depends on this, you do so at your own risk.
       
    39  *  This code and its internal interfaces are subject to change or
       
    40  *  deletion without notice.</b>
       
    41  */
       
    42 public class ConstantWriter extends BasicWriter {
       
    43     public static ConstantWriter instance(Context context) {
       
    44         ConstantWriter instance = context.get(ConstantWriter.class);
       
    45         if (instance == null)
       
    46             instance = new ConstantWriter(context);
       
    47         return instance;
       
    48     }
       
    49 
       
    50     protected ConstantWriter(Context context) {
       
    51         super(context);
       
    52         context.put(ConstantWriter.class, this);
       
    53         classWriter = ClassWriter.instance(context);
       
    54         options = Options.instance(context);
       
    55     }
       
    56 
       
    57     protected void writeConstantPool() {
       
    58         ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
       
    59         writeConstantPool(constant_pool);
       
    60     }
       
    61 
       
    62     protected void writeConstantPool(ConstantPool constant_pool) {
       
    63         ConstantPool.Visitor<Integer, Void> v = new ConstantPool.Visitor<Integer,Void>() {
       
    64             public Integer visitClass(CONSTANT_Class_info info, Void p) {
       
    65                 print("#" + info.name_index);
       
    66                 tab();
       
    67                 println("// " + stringValue(info));
       
    68                 return 1;
       
    69             }
       
    70 
       
    71             public Integer visitDouble(CONSTANT_Double_info info, Void p) {
       
    72                 println(stringValue(info));
       
    73                 return 2;
       
    74             }
       
    75 
       
    76             public Integer visitFieldref(CONSTANT_Fieldref_info info, Void p) {
       
    77                 print("#" + info.class_index + ".#" + info.name_and_type_index);
       
    78                 tab();
       
    79                 println("// " + stringValue(info));
       
    80                 return 1;
       
    81             }
       
    82 
       
    83             public Integer visitFloat(CONSTANT_Float_info info, Void p) {
       
    84                 println(stringValue(info));
       
    85                 return 1;
       
    86             }
       
    87 
       
    88             public Integer visitInteger(CONSTANT_Integer_info info, Void p) {
       
    89                 println(stringValue(info));
       
    90                 return 1;
       
    91             }
       
    92 
       
    93             public Integer visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
       
    94                 print("#" + info.class_index + ".#" + info.name_and_type_index);
       
    95                 tab();
       
    96                 println("// " + stringValue(info));
       
    97                 return 1;
       
    98             }
       
    99 
       
   100             public Integer visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
       
   101                 print("#" + info.bootstrap_method_attr_index + ":#" + info.name_and_type_index);
       
   102                 tab();
       
   103                 println("// " + stringValue(info));
       
   104                 return 1;
       
   105             }
       
   106 
       
   107             public Integer visitLong(CONSTANT_Long_info info, Void p) {
       
   108                 println(stringValue(info));
       
   109                 return 2;
       
   110             }
       
   111 
       
   112             public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
       
   113                 print("#" + info.name_index + ":#" + info.type_index);
       
   114                 tab();
       
   115                 println("// " + stringValue(info));
       
   116                 return 1;
       
   117             }
       
   118 
       
   119             public Integer visitMethodref(CONSTANT_Methodref_info info, Void p) {
       
   120                 print("#" + info.class_index + ".#" + info.name_and_type_index);
       
   121                 tab();
       
   122                 println("// " + stringValue(info));
       
   123                 return 1;
       
   124             }
       
   125 
       
   126             public Integer visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
       
   127                 print("#" + info.reference_kind.tag + ":#" + info.reference_index);
       
   128                 tab();
       
   129                 println("// " + stringValue(info));
       
   130                 return 1;
       
   131             }
       
   132 
       
   133             public Integer visitMethodType(CONSTANT_MethodType_info info, Void p) {
       
   134                 print("#" + info.descriptor_index);
       
   135                 tab();
       
   136                 println("//  " + stringValue(info));
       
   137                 return 1;
       
   138             }
       
   139 
       
   140             public Integer visitString(CONSTANT_String_info info, Void p) {
       
   141                 print("#" + info.string_index);
       
   142                 tab();
       
   143                 println("// " + stringValue(info));
       
   144                 return 1;
       
   145             }
       
   146 
       
   147             public Integer visitUtf8(CONSTANT_Utf8_info info, Void p) {
       
   148                 println(stringValue(info));
       
   149                 return 1;
       
   150             }
       
   151 
       
   152         };
       
   153         println("Constant pool:");
       
   154         indent(+1);
       
   155         int width = String.valueOf(constant_pool.size()).length() + 1;
       
   156         int cpx = 1;
       
   157         while (cpx < constant_pool.size()) {
       
   158             print(String.format("%" + width + "s", ("#" + cpx)));
       
   159             try {
       
   160                 CPInfo cpInfo = constant_pool.get(cpx);
       
   161                 print(String.format(" = %-18s ", cpTagName(cpInfo)));
       
   162                 cpx += cpInfo.accept(v, null);
       
   163             } catch (ConstantPool.InvalidIndex ex) {
       
   164                 // should not happen
       
   165             }
       
   166         }
       
   167         indent(-1);
       
   168     }
       
   169 
       
   170     protected void write(int cpx) {
       
   171         ClassFile classFile = classWriter.getClassFile();
       
   172         if (cpx == 0) {
       
   173             print("#0");
       
   174             return;
       
   175         }
       
   176 
       
   177         CPInfo cpInfo;
       
   178         try {
       
   179             cpInfo = classFile.constant_pool.get(cpx);
       
   180         } catch (ConstantPoolException e) {
       
   181             print("#" + cpx);
       
   182             return;
       
   183         }
       
   184 
       
   185         int tag = cpInfo.getTag();
       
   186         switch (tag) {
       
   187             case CONSTANT_Methodref:
       
   188             case CONSTANT_InterfaceMethodref:
       
   189             case CONSTANT_Fieldref:
       
   190                 // simplify references within this class
       
   191                 CPRefInfo ref = (CPRefInfo) cpInfo;
       
   192                 try {
       
   193                     if (ref.class_index == classFile.this_class)
       
   194                          cpInfo = classFile.constant_pool.get(ref.name_and_type_index);
       
   195                 } catch (ConstantPool.InvalidIndex e) {
       
   196                     // ignore, for now
       
   197                 }
       
   198         }
       
   199         print(tagName(tag) + " " + stringValue(cpInfo));
       
   200     }
       
   201 
       
   202     String cpTagName(CPInfo cpInfo) {
       
   203         String n = cpInfo.getClass().getSimpleName();
       
   204         return n.replace("CONSTANT_", "").replace("_info", "");
       
   205     }
       
   206 
       
   207     String tagName(int tag) {
       
   208         switch (tag) {
       
   209             case CONSTANT_Utf8:
       
   210                 return "Utf8";
       
   211             case CONSTANT_Integer:
       
   212                 return "int";
       
   213             case CONSTANT_Float:
       
   214                 return "float";
       
   215             case CONSTANT_Long:
       
   216                 return "long";
       
   217             case CONSTANT_Double:
       
   218                 return "double";
       
   219             case CONSTANT_Class:
       
   220                 return "class";
       
   221             case CONSTANT_String:
       
   222                 return "String";
       
   223             case CONSTANT_Fieldref:
       
   224                 return "Field";
       
   225             case CONSTANT_MethodHandle:
       
   226                 return "MethodHandle";
       
   227             case CONSTANT_MethodType:
       
   228                 return "MethodType";
       
   229             case CONSTANT_Methodref:
       
   230                 return "Method";
       
   231             case CONSTANT_InterfaceMethodref:
       
   232                 return "InterfaceMethod";
       
   233             case CONSTANT_InvokeDynamic:
       
   234                 return "InvokeDynamic";
       
   235             case CONSTANT_NameAndType:
       
   236                 return "NameAndType";
       
   237             default:
       
   238                 return "(unknown tag " + tag + ")";
       
   239         }
       
   240     }
       
   241 
       
   242     String stringValue(int constant_pool_index) {
       
   243         ClassFile classFile = classWriter.getClassFile();
       
   244         try {
       
   245             return stringValue(classFile.constant_pool.get(constant_pool_index));
       
   246         } catch (ConstantPool.InvalidIndex e) {
       
   247             return report(e);
       
   248         }
       
   249     }
       
   250 
       
   251     String stringValue(CPInfo cpInfo) {
       
   252         return stringValueVisitor.visit(cpInfo);
       
   253     }
       
   254 
       
   255     StringValueVisitor stringValueVisitor = new StringValueVisitor();
       
   256 
       
   257     private class StringValueVisitor implements ConstantPool.Visitor<String, Void> {
       
   258         public String visit(CPInfo info) {
       
   259             return info.accept(this, null);
       
   260         }
       
   261 
       
   262         public String visitClass(CONSTANT_Class_info info, Void p) {
       
   263             return getCheckedName(info);
       
   264         }
       
   265 
       
   266         String getCheckedName(CONSTANT_Class_info info) {
       
   267             try {
       
   268                 return checkName(info.getName());
       
   269             } catch (ConstantPoolException e) {
       
   270                 return report(e);
       
   271             }
       
   272         }
       
   273 
       
   274         public String visitDouble(CONSTANT_Double_info info, Void p) {
       
   275             return info.value + "d";
       
   276         }
       
   277 
       
   278         public String visitFieldref(CONSTANT_Fieldref_info info, Void p) {
       
   279             return visitRef(info, p);
       
   280         }
       
   281 
       
   282         public String visitFloat(CONSTANT_Float_info info, Void p) {
       
   283             return info.value + "f";
       
   284         }
       
   285 
       
   286         public String visitInteger(CONSTANT_Integer_info info, Void p) {
       
   287             return String.valueOf(info.value);
       
   288         }
       
   289 
       
   290         public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
       
   291             return visitRef(info, p);
       
   292         }
       
   293 
       
   294         public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
       
   295             try {
       
   296                 String callee = stringValue(info.getNameAndTypeInfo());
       
   297                 return "#" + info.bootstrap_method_attr_index + ":" + callee;
       
   298             } catch (ConstantPoolException e) {
       
   299                 return report(e);
       
   300             }
       
   301         }
       
   302 
       
   303         public String visitLong(CONSTANT_Long_info info, Void p) {
       
   304             return info.value + "l";
       
   305         }
       
   306 
       
   307         public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
       
   308             return getCheckedName(info) + ":" + getType(info);
       
   309         }
       
   310 
       
   311         String getCheckedName(CONSTANT_NameAndType_info info) {
       
   312             try {
       
   313                 return checkName(info.getName());
       
   314             } catch (ConstantPoolException e) {
       
   315                 return report(e);
       
   316             }
       
   317         }
       
   318 
       
   319         String getType(CONSTANT_NameAndType_info info) {
       
   320             try {
       
   321                 return info.getType();
       
   322             } catch (ConstantPoolException e) {
       
   323                 return report(e);
       
   324             }
       
   325         }
       
   326 
       
   327         public String visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
       
   328             try {
       
   329                 return info.reference_kind.name + " " + stringValue(info.getCPRefInfo());
       
   330             } catch (ConstantPoolException e) {
       
   331                 return report(e);
       
   332             }
       
   333         }
       
   334 
       
   335         public String visitMethodType(CONSTANT_MethodType_info info, Void p) {
       
   336             try {
       
   337                 return info.getType();
       
   338             } catch (ConstantPoolException e) {
       
   339                 return report(e);
       
   340             }
       
   341         }
       
   342 
       
   343         public String visitMethodref(CONSTANT_Methodref_info info, Void p) {
       
   344             return visitRef(info, p);
       
   345         }
       
   346 
       
   347         public String visitString(CONSTANT_String_info info, Void p) {
       
   348             try {
       
   349                 ClassFile classFile = classWriter.getClassFile();
       
   350                 int string_index = info.string_index;
       
   351                 return stringValue(classFile.constant_pool.getUTF8Info(string_index));
       
   352             } catch (ConstantPoolException e) {
       
   353                 return report(e);
       
   354             }
       
   355         }
       
   356 
       
   357         public String visitUtf8(CONSTANT_Utf8_info info, Void p) {
       
   358             String s = info.value;
       
   359             StringBuilder sb = new StringBuilder();
       
   360             for (int i = 0; i < s.length(); i++) {
       
   361                 char c = s.charAt(i);
       
   362                 switch (c) {
       
   363                     case '\t':
       
   364                         sb.append('\\').append('t');
       
   365                         break;
       
   366                     case '\n':
       
   367                         sb.append('\\').append('n');
       
   368                         break;
       
   369                     case '\r':
       
   370                         sb.append('\\').append('r');
       
   371                         break;
       
   372                     case '\b':
       
   373                         sb.append('\\').append('b');
       
   374                         break;
       
   375                     case '\f':
       
   376                         sb.append('\\').append('f');
       
   377                         break;
       
   378                     case '\"':
       
   379                         sb.append('\\').append('\"');
       
   380                         break;
       
   381                     case '\'':
       
   382                         sb.append('\\').append('\'');
       
   383                         break;
       
   384                     case '\\':
       
   385                         sb.append('\\').append('\\');
       
   386                         break;
       
   387                     default:
       
   388                         sb.append(c);
       
   389                 }
       
   390             }
       
   391             return sb.toString();
       
   392         }
       
   393 
       
   394         String visitRef(CPRefInfo info, Void p) {
       
   395             String cn = getCheckedClassName(info);
       
   396             String nat;
       
   397             try {
       
   398                 nat = stringValue(info.getNameAndTypeInfo());
       
   399             } catch (ConstantPoolException e) {
       
   400                 nat = report(e);
       
   401             }
       
   402             return cn + "." + nat;
       
   403         }
       
   404 
       
   405         String getCheckedClassName(CPRefInfo info) {
       
   406             try {
       
   407                 return checkName(info.getClassName());
       
   408             } catch (ConstantPoolException e) {
       
   409                 return report(e);
       
   410             }
       
   411         }
       
   412     }
       
   413 
       
   414     /* If name is a valid binary name, return it; otherwise quote it. */
       
   415     private static String checkName(String name) {
       
   416         if (name == null)
       
   417             return "null";
       
   418 
       
   419         int len = name.length();
       
   420         if (len == 0)
       
   421             return "\"\"";
       
   422 
       
   423         int cc = '/';
       
   424         int cp;
       
   425         for (int k = 0; k < len; k += Character.charCount(cp)) {
       
   426             cp = name.codePointAt(k);
       
   427             if ((cc == '/' && !Character.isJavaIdentifierStart(cp))
       
   428                     || (cp != '/' && !Character.isJavaIdentifierPart(cp))) {
       
   429                 return "\"" + addEscapes(name) + "\"";
       
   430             }
       
   431             cc = cp;
       
   432         }
       
   433 
       
   434         return name;
       
   435     }
       
   436 
       
   437     /* If name requires escapes, put them in, so it can be a string body. */
       
   438     private static String addEscapes(String name) {
       
   439         String esc = "\\\"\n\t";
       
   440         String rep = "\\\"nt";
       
   441         StringBuilder buf = null;
       
   442         int nextk = 0;
       
   443         int len = name.length();
       
   444         for (int k = 0; k < len; k++) {
       
   445             char cp = name.charAt(k);
       
   446             int n = esc.indexOf(cp);
       
   447             if (n >= 0) {
       
   448                 if (buf == null)
       
   449                     buf = new StringBuilder(len * 2);
       
   450                 if (nextk < k)
       
   451                     buf.append(name, nextk, k);
       
   452                 buf.append('\\');
       
   453                 buf.append(rep.charAt(n));
       
   454                 nextk = k+1;
       
   455             }
       
   456         }
       
   457         if (buf == null)
       
   458             return name;
       
   459         if (nextk < len)
       
   460             buf.append(name, nextk, len);
       
   461         return buf.toString();
       
   462     }
       
   463 
       
   464     private ClassWriter classWriter;
       
   465     private Options options;
       
   466 }