1 /*
2  * Copyright (c) 2007, 2017, 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 {
instance(Context context)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 
ConstantWriter(Context context)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 
writeConstantPool()57     protected void writeConstantPool() {
58         ConstantPool constant_pool = classWriter.getClassFile().constant_pool;
59         writeConstantPool(constant_pool);
60     }
61 
writeConstantPool(ConstantPool constant_pool)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 visitDynamicConstant(CONSTANT_Dynamic_info info, Void p) {
108                 print("#" + info.bootstrap_method_attr_index + ":#" + info.name_and_type_index);
109                 tab();
110                 println("// " + stringValue(info));
111                 return 1;
112             }
113 
114             public Integer visitLong(CONSTANT_Long_info info, Void p) {
115                 println(stringValue(info));
116                 return 2;
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 visitModule(CONSTANT_Module_info info, Void p) {
141                 print("#" + info.name_index);
142                 tab();
143                 println("// " + stringValue(info));
144                 return 1;
145             }
146 
147             public Integer visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
148                 print("#" + info.name_index + ":#" + info.type_index);
149                 tab();
150                 println("// " + stringValue(info));
151                 return 1;
152             }
153 
154             public Integer visitPackage(CONSTANT_Package_info info, Void p) {
155                 print("#" + info.name_index);
156                 tab();
157                 println("// " + stringValue(info));
158                 return 1;
159             }
160 
161             public Integer visitString(CONSTANT_String_info info, Void p) {
162                 print("#" + info.string_index);
163                 tab();
164                 println("// " + stringValue(info));
165                 return 1;
166             }
167 
168             public Integer visitUtf8(CONSTANT_Utf8_info info, Void p) {
169                 println(stringValue(info));
170                 return 1;
171             }
172 
173         };
174         println("Constant pool:");
175         indent(+1);
176         int width = String.valueOf(constant_pool.size()).length() + 1;
177         int cpx = 1;
178         while (cpx < constant_pool.size()) {
179             print(String.format("%" + width + "s", ("#" + cpx)));
180             try {
181                 CPInfo cpInfo = constant_pool.get(cpx);
182                 print(String.format(" = %-18s ", cpTagName(cpInfo)));
183                 cpx += cpInfo.accept(v, null);
184             } catch (ConstantPool.InvalidIndex ex) {
185                 // should not happen
186             }
187         }
188         indent(-1);
189     }
190 
write(int cpx)191     protected void write(int cpx) {
192         ClassFile classFile = classWriter.getClassFile();
193         if (cpx == 0) {
194             print("#0");
195             return;
196         }
197 
198         CPInfo cpInfo;
199         try {
200             cpInfo = classFile.constant_pool.get(cpx);
201         } catch (ConstantPoolException e) {
202             print("#" + cpx);
203             return;
204         }
205 
206         int tag = cpInfo.getTag();
207         switch (tag) {
208             case CONSTANT_Methodref:
209             case CONSTANT_InterfaceMethodref:
210             case CONSTANT_Fieldref:
211                 // simplify references within this class
212                 CPRefInfo ref = (CPRefInfo) cpInfo;
213                 try {
214                     if (ref.class_index == classFile.this_class)
215                          cpInfo = classFile.constant_pool.get(ref.name_and_type_index);
216                 } catch (ConstantPool.InvalidIndex e) {
217                     // ignore, for now
218                 }
219         }
220         print(tagName(tag) + " " + stringValue(cpInfo));
221     }
222 
cpTagName(CPInfo cpInfo)223     String cpTagName(CPInfo cpInfo) {
224         String n = cpInfo.getClass().getSimpleName();
225         return n.replace("CONSTANT_", "").replace("_info", "");
226     }
227 
tagName(int tag)228     String tagName(int tag) {
229         switch (tag) {
230             case CONSTANT_Utf8:
231                 return "Utf8";
232             case CONSTANT_Integer:
233                 return "int";
234             case CONSTANT_Float:
235                 return "float";
236             case CONSTANT_Long:
237                 return "long";
238             case CONSTANT_Double:
239                 return "double";
240             case CONSTANT_Class:
241                 return "class";
242             case CONSTANT_String:
243                 return "String";
244             case CONSTANT_Fieldref:
245                 return "Field";
246             case CONSTANT_MethodHandle:
247                 return "MethodHandle";
248             case CONSTANT_MethodType:
249                 return "MethodType";
250             case CONSTANT_Methodref:
251                 return "Method";
252             case CONSTANT_InterfaceMethodref:
253                 return "InterfaceMethod";
254             case CONSTANT_InvokeDynamic:
255                 return "InvokeDynamic";
256             case CONSTANT_Dynamic:
257                 return "Dynamic";
258             case CONSTANT_NameAndType:
259                 return "NameAndType";
260             default:
261                 return "(unknown tag " + tag + ")";
262         }
263     }
264 
booleanValue(int constant_pool_index)265     String booleanValue(int constant_pool_index) {
266         ClassFile classFile = classWriter.getClassFile();
267         try {
268             CPInfo info = classFile.constant_pool.get(constant_pool_index);
269             if (info instanceof CONSTANT_Integer_info) {
270                 int value = ((CONSTANT_Integer_info) info).value;
271                switch (value) {
272                    case 0: return "false";
273                    case 1: return "true";
274                }
275             }
276             return "#" + constant_pool_index;
277         } catch (ConstantPool.InvalidIndex e) {
278             return report(e);
279         }
280     }
281 
charValue(int constant_pool_index)282     String charValue(int constant_pool_index) {
283         ClassFile classFile = classWriter.getClassFile();
284         try {
285             CPInfo info = classFile.constant_pool.get(constant_pool_index);
286             if (info instanceof CONSTANT_Integer_info) {
287                 int value = ((CONSTANT_Integer_info) info).value;
288                 return String.valueOf((char) value);
289             } else {
290                 return "#" + constant_pool_index;
291             }
292         } catch (ConstantPool.InvalidIndex e) {
293             return report(e);
294         }
295     }
296 
stringValue(int constant_pool_index)297     String stringValue(int constant_pool_index) {
298         ClassFile classFile = classWriter.getClassFile();
299         try {
300             return stringValue(classFile.constant_pool.get(constant_pool_index));
301         } catch (ConstantPool.InvalidIndex e) {
302             return report(e);
303         }
304     }
305 
stringValue(CPInfo cpInfo)306     String stringValue(CPInfo cpInfo) {
307         return stringValueVisitor.visit(cpInfo);
308     }
309 
310     StringValueVisitor stringValueVisitor = new StringValueVisitor();
311 
312     private class StringValueVisitor implements ConstantPool.Visitor<String, Void> {
visit(CPInfo info)313         public String visit(CPInfo info) {
314             return info.accept(this, null);
315         }
316 
visitClass(CONSTANT_Class_info info, Void p)317         public String visitClass(CONSTANT_Class_info info, Void p) {
318             return getCheckedName(info);
319         }
320 
getCheckedName(CONSTANT_Class_info info)321         String getCheckedName(CONSTANT_Class_info info) {
322             try {
323                 return checkName(info.getName());
324             } catch (ConstantPoolException e) {
325                 return report(e);
326             }
327         }
328 
visitDouble(CONSTANT_Double_info info, Void p)329         public String visitDouble(CONSTANT_Double_info info, Void p) {
330             return info.value + "d";
331         }
332 
visitFieldref(CONSTANT_Fieldref_info info, Void p)333         public String visitFieldref(CONSTANT_Fieldref_info info, Void p) {
334             return visitRef(info, p);
335         }
336 
visitFloat(CONSTANT_Float_info info, Void p)337         public String visitFloat(CONSTANT_Float_info info, Void p) {
338             return info.value + "f";
339         }
340 
visitInteger(CONSTANT_Integer_info info, Void p)341         public String visitInteger(CONSTANT_Integer_info info, Void p) {
342             return String.valueOf(info.value);
343         }
344 
visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p)345         public String visitInterfaceMethodref(CONSTANT_InterfaceMethodref_info info, Void p) {
346             return visitRef(info, p);
347         }
348 
visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p)349         public String visitInvokeDynamic(CONSTANT_InvokeDynamic_info info, Void p) {
350             try {
351                 String callee = stringValue(info.getNameAndTypeInfo());
352                 return "#" + info.bootstrap_method_attr_index + ":" + callee;
353             } catch (ConstantPoolException e) {
354                 return report(e);
355             }
356         }
357 
visitDynamicConstant(CONSTANT_Dynamic_info info, Void p)358         public String visitDynamicConstant(CONSTANT_Dynamic_info info, Void p) {
359             try {
360                 String callee = stringValue(info.getNameAndTypeInfo());
361                 return "#" + info.bootstrap_method_attr_index + ":" + callee;
362             } catch (ConstantPoolException e) {
363                 return report(e);
364             }
365         }
366 
visitLong(CONSTANT_Long_info info, Void p)367         public String visitLong(CONSTANT_Long_info info, Void p) {
368             return info.value + "l";
369         }
370 
visitModule(CONSTANT_Module_info info, Void p)371         public String visitModule(CONSTANT_Module_info info, Void p) {
372             try {
373                 return checkName(info.getName());
374             } catch (ConstantPoolException e) {
375                 return report(e);
376             }
377         }
378 
visitNameAndType(CONSTANT_NameAndType_info info, Void p)379         public String visitNameAndType(CONSTANT_NameAndType_info info, Void p) {
380             return getCheckedName(info) + ":" + getType(info);
381         }
382 
getCheckedName(CONSTANT_NameAndType_info info)383         String getCheckedName(CONSTANT_NameAndType_info info) {
384             try {
385                 return checkName(info.getName());
386             } catch (ConstantPoolException e) {
387                 return report(e);
388             }
389         }
390 
visitPackage(CONSTANT_Package_info info, Void p)391         public String visitPackage(CONSTANT_Package_info info, Void p) {
392             try {
393                 return checkName(info.getName());
394             } catch (ConstantPoolException e) {
395                 return report(e);
396             }
397         }
398 
getType(CONSTANT_NameAndType_info info)399         String getType(CONSTANT_NameAndType_info info) {
400             try {
401                 return info.getType();
402             } catch (ConstantPoolException e) {
403                 return report(e);
404             }
405         }
406 
visitMethodHandle(CONSTANT_MethodHandle_info info, Void p)407         public String visitMethodHandle(CONSTANT_MethodHandle_info info, Void p) {
408             try {
409                 return info.reference_kind + " " + stringValue(info.getCPRefInfo());
410             } catch (ConstantPoolException e) {
411                 return report(e);
412             }
413         }
414 
visitMethodType(CONSTANT_MethodType_info info, Void p)415         public String visitMethodType(CONSTANT_MethodType_info info, Void p) {
416             try {
417                 return info.getType();
418             } catch (ConstantPoolException e) {
419                 return report(e);
420             }
421         }
422 
visitMethodref(CONSTANT_Methodref_info info, Void p)423         public String visitMethodref(CONSTANT_Methodref_info info, Void p) {
424             return visitRef(info, p);
425         }
426 
visitString(CONSTANT_String_info info, Void p)427         public String visitString(CONSTANT_String_info info, Void p) {
428             try {
429                 ClassFile classFile = classWriter.getClassFile();
430                 int string_index = info.string_index;
431                 return stringValue(classFile.constant_pool.getUTF8Info(string_index));
432             } catch (ConstantPoolException e) {
433                 return report(e);
434             }
435         }
436 
visitUtf8(CONSTANT_Utf8_info info, Void p)437         public String visitUtf8(CONSTANT_Utf8_info info, Void p) {
438             String s = info.value;
439             StringBuilder sb = new StringBuilder();
440             for (int i = 0; i < s.length(); i++) {
441                 char c = s.charAt(i);
442                 switch (c) {
443                     case '\t':
444                         sb.append('\\').append('t');
445                         break;
446                     case '\n':
447                         sb.append('\\').append('n');
448                         break;
449                     case '\r':
450                         sb.append('\\').append('r');
451                         break;
452                     case '\b':
453                         sb.append('\\').append('b');
454                         break;
455                     case '\f':
456                         sb.append('\\').append('f');
457                         break;
458                     case '\"':
459                         sb.append('\\').append('\"');
460                         break;
461                     case '\'':
462                         sb.append('\\').append('\'');
463                         break;
464                     case '\\':
465                         sb.append('\\').append('\\');
466                         break;
467                     default:
468                         if (Character.isISOControl(c)) {
469                             sb.append(String.format("\\u%04x", (int) c));
470                             break;
471                         }
472                         sb.append(c);
473                 }
474             }
475             return sb.toString();
476         }
477 
visitRef(CPRefInfo info, Void p)478         String visitRef(CPRefInfo info, Void p) {
479             String cn = getCheckedClassName(info);
480             String nat;
481             try {
482                 nat = stringValue(info.getNameAndTypeInfo());
483             } catch (ConstantPoolException e) {
484                 nat = report(e);
485             }
486             return cn + "." + nat;
487         }
488 
getCheckedClassName(CPRefInfo info)489         String getCheckedClassName(CPRefInfo info) {
490             try {
491                 return checkName(info.getClassName());
492             } catch (ConstantPoolException e) {
493                 return report(e);
494             }
495         }
496     }
497 
498     /* If name is a valid binary name, return it; otherwise quote it. */
checkName(String name)499     private static String checkName(String name) {
500         if (name == null)
501             return "null";
502 
503         int len = name.length();
504         if (len == 0)
505             return "\"\"";
506 
507         int cc = '/';
508         int cp;
509         for (int k = 0; k < len; k += Character.charCount(cp)) {
510             cp = name.codePointAt(k);
511             if ((cc == '/' && !Character.isJavaIdentifierStart(cp))
512                     || (cp != '/' && !Character.isJavaIdentifierPart(cp))) {
513                 return "\"" + addEscapes(name) + "\"";
514             }
515             cc = cp;
516         }
517 
518         return name;
519     }
520 
521     /* If name requires escapes, put them in, so it can be a string body. */
addEscapes(String name)522     private static String addEscapes(String name) {
523         String esc = "\\\"\n\t";
524         String rep = "\\\"nt";
525         StringBuilder buf = null;
526         int nextk = 0;
527         int len = name.length();
528         for (int k = 0; k < len; k++) {
529             char cp = name.charAt(k);
530             int n = esc.indexOf(cp);
531             if (n >= 0) {
532                 if (buf == null)
533                     buf = new StringBuilder(len * 2);
534                 if (nextk < k)
535                     buf.append(name, nextk, k);
536                 buf.append('\\');
537                 buf.append(rep.charAt(n));
538                 nextk = k+1;
539             }
540         }
541         if (buf == null)
542             return name;
543         if (nextk < len)
544             buf.append(name, nextk, len);
545         return buf.toString();
546     }
547 
548     private ClassWriter classWriter;
549     private Options options;
550 }
551