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