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