ConstantWriter.java revision 2942:08092deced3f
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 26package com.sun.tools.javap; 27 28import com.sun.tools.classfile.ClassFile; 29import com.sun.tools.classfile.ConstantPool; 30import com.sun.tools.classfile.ConstantPoolException; 31 32import 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 */ 42public 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} 467