1 /* 2 * Copyright (c) 2009, 2013, 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.classfile; 27 28 import java.io.IOException; 29 import java.util.ArrayList; 30 import java.util.List; 31 32 import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry; 33 34 /** 35 * See JSR 308 specification, Section 3. 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 TypeAnnotation { 43 TypeAnnotation(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { 44 constant_pool = cr.getConstantPool(); 45 position = read_position(cr); 46 annotation = new Annotation(cr); 47 } 48 49 public TypeAnnotation(ConstantPool constant_pool, 50 Annotation annotation, Position position) { 51 this.constant_pool = constant_pool; 52 this.position = position; 53 this.annotation = annotation; 54 } 55 56 public int length() { 57 int n = annotation.length(); 58 n += position_length(position); 59 return n; 60 } 61 62 @Override 63 public String toString() { 64 try { 65 return "@" + constant_pool.getUTF8Value(annotation.type_index).toString().substring(1) + 66 " pos: " + position.toString(); 67 } catch (Exception e) { 68 e.printStackTrace(); 69 return e.toString(); 70 } 71 } 72 73 public final ConstantPool constant_pool; 74 public final Position position; 75 public final Annotation annotation; 76 77 private static Position read_position(ClassReader cr) throws IOException, Annotation.InvalidAnnotation { 78 // Copied from ClassReader 79 int tag = cr.readUnsignedByte(); // TargetType tag is a byte 80 if (!TargetType.isValidTargetTypeValue(tag)) 81 throw new Annotation.InvalidAnnotation("TypeAnnotation: Invalid type annotation target type value: " + String.format("0x%02X", tag)); 82 83 TargetType type = TargetType.fromTargetTypeValue(tag); 84 85 Position position = new Position(); 86 position.type = type; 87 88 switch (type) { 89 // instanceof 90 case INSTANCEOF: 91 // new expression 92 case NEW: 93 // constructor/method reference receiver 94 case CONSTRUCTOR_REFERENCE: 95 case METHOD_REFERENCE: 96 position.offset = cr.readUnsignedShort(); 97 break; 98 // local variable 99 case LOCAL_VARIABLE: 100 // resource variable 101 case RESOURCE_VARIABLE: 102 int table_length = cr.readUnsignedShort(); 103 position.lvarOffset = new int[table_length]; 104 position.lvarLength = new int[table_length]; 105 position.lvarIndex = new int[table_length]; 106 for (int i = 0; i < table_length; ++i) { 107 position.lvarOffset[i] = cr.readUnsignedShort(); 108 position.lvarLength[i] = cr.readUnsignedShort(); 109 position.lvarIndex[i] = cr.readUnsignedShort(); 110 } 111 break; 112 // exception parameter 113 case EXCEPTION_PARAMETER: 114 position.exception_index = cr.readUnsignedShort(); 115 break; 116 // method receiver 117 case METHOD_RECEIVER: 118 // Do nothing 119 break; 120 // type parameter 121 case CLASS_TYPE_PARAMETER: 122 case METHOD_TYPE_PARAMETER: 123 position.parameter_index = cr.readUnsignedByte(); 124 break; 125 // type parameter bound 126 case CLASS_TYPE_PARAMETER_BOUND: 127 case METHOD_TYPE_PARAMETER_BOUND: 128 position.parameter_index = cr.readUnsignedByte(); 129 position.bound_index = cr.readUnsignedByte(); 130 break; 131 // class extends or implements clause 132 case CLASS_EXTENDS: 133 int in = cr.readUnsignedShort(); 134 if (in == 0xFFFF) 135 in = -1; 136 position.type_index = in; 137 break; 138 // throws 139 case THROWS: 140 position.type_index = cr.readUnsignedShort(); 141 break; 142 // method parameter 143 case METHOD_FORMAL_PARAMETER: 144 position.parameter_index = cr.readUnsignedByte(); 145 break; 146 // type cast 147 case CAST: 148 // method/constructor/reference type argument 149 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 150 case METHOD_INVOCATION_TYPE_ARGUMENT: 151 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 152 case METHOD_REFERENCE_TYPE_ARGUMENT: 153 position.offset = cr.readUnsignedShort(); 154 position.type_index = cr.readUnsignedByte(); 155 break; 156 // We don't need to worry about these 157 case METHOD_RETURN: 158 case FIELD: 159 break; 160 case UNKNOWN: 161 throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); 162 default: 163 throw new AssertionError("TypeAnnotation: Unknown target type: " + type); 164 } 165 166 { // Write type path 167 int len = cr.readUnsignedByte(); 168 List<Integer> loc = new ArrayList<>(len); 169 for (int i = 0; i < len * TypePathEntry.bytesPerEntry; ++i) 170 loc.add(cr.readUnsignedByte()); 171 position.location = Position.getTypePathFromBinary(loc); 172 } 173 return position; 174 } 175 176 private static int position_length(Position pos) { 177 int n = 0; 178 n += 1; // TargetType tag is a byte 179 switch (pos.type) { 180 // instanceof 181 case INSTANCEOF: 182 // new expression 183 case NEW: 184 // constructor/method reference receiver 185 case CONSTRUCTOR_REFERENCE: 186 case METHOD_REFERENCE: 187 n += 2; // offset 188 break; 189 // local variable 190 case LOCAL_VARIABLE: 191 // resource variable 192 case RESOURCE_VARIABLE: 193 n += 2; // table_length; 194 int table_length = pos.lvarOffset.length; 195 n += 2 * table_length; // offset 196 n += 2 * table_length; // length 197 n += 2 * table_length; // index 198 break; 199 // exception parameter 200 case EXCEPTION_PARAMETER: 201 n += 2; // exception_index 202 break; 203 // method receiver 204 case METHOD_RECEIVER: 205 // Do nothing 206 break; 207 // type parameter 208 case CLASS_TYPE_PARAMETER: 209 case METHOD_TYPE_PARAMETER: 210 n += 1; // parameter_index 211 break; 212 // type parameter bound 213 case CLASS_TYPE_PARAMETER_BOUND: 214 case METHOD_TYPE_PARAMETER_BOUND: 215 n += 1; // parameter_index 216 n += 1; // bound_index 217 break; 218 // class extends or implements clause 219 case CLASS_EXTENDS: 220 n += 2; // type_index 221 break; 222 // throws 223 case THROWS: 224 n += 2; // type_index 225 break; 226 // method parameter 227 case METHOD_FORMAL_PARAMETER: 228 n += 1; // parameter_index 229 break; 230 // type cast 231 case CAST: 232 // method/constructor/reference type argument 233 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 234 case METHOD_INVOCATION_TYPE_ARGUMENT: 235 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 236 case METHOD_REFERENCE_TYPE_ARGUMENT: 237 n += 2; // offset 238 n += 1; // type index 239 break; 240 // We don't need to worry about these 241 case METHOD_RETURN: 242 case FIELD: 243 break; 244 case UNKNOWN: 245 throw new AssertionError("TypeAnnotation: UNKNOWN target type should never occur!"); 246 default: 247 throw new AssertionError("TypeAnnotation: Unknown target type: " + pos.type); 248 } 249 250 { 251 n += 1; // length 252 n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array 253 } 254 255 return n; 256 } 257 258 // Code duplicated from com.sun.tools.javac.code.TypeAnnotationPosition 259 public static class Position { 260 public enum TypePathEntryKind { 261 ARRAY(0), 262 INNER_TYPE(1), 263 WILDCARD(2), 264 TYPE_ARGUMENT(3); 265 266 public final int tag; 267 268 private TypePathEntryKind(int tag) { 269 this.tag = tag; 270 } 271 } 272 273 public static class TypePathEntry { 274 /** The fixed number of bytes per TypePathEntry. */ 275 public static final int bytesPerEntry = 2; 276 277 public final TypePathEntryKind tag; 278 public final int arg; 279 280 public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); 281 public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); 282 public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); 283 284 private TypePathEntry(TypePathEntryKind tag) { 285 if (!(tag == TypePathEntryKind.ARRAY || 286 tag == TypePathEntryKind.INNER_TYPE || 287 tag == TypePathEntryKind.WILDCARD)) { 288 throw new AssertionError("Invalid TypePathEntryKind: " + tag); 289 } 290 this.tag = tag; 291 this.arg = 0; 292 } 293 294 public TypePathEntry(TypePathEntryKind tag, int arg) { 295 if (tag != TypePathEntryKind.TYPE_ARGUMENT) { 296 throw new AssertionError("Invalid TypePathEntryKind: " + tag); 297 } 298 this.tag = tag; 299 this.arg = arg; 300 } 301 302 public static TypePathEntry fromBinary(int tag, int arg) { 303 if (arg != 0 && tag != TypePathEntryKind.TYPE_ARGUMENT.tag) { 304 throw new AssertionError("Invalid TypePathEntry tag/arg: " + tag + "/" + arg); 305 } 306 switch (tag) { 307 case 0: 308 return ARRAY; 309 case 1: 310 return INNER_TYPE; 311 case 2: 312 return WILDCARD; 313 case 3: 314 return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); 315 default: 316 throw new AssertionError("Invalid TypePathEntryKind tag: " + tag); 317 } 318 } 319 320 @Override 321 public String toString() { 322 return tag.toString() + 323 (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); 324 } 325 326 @Override 327 public boolean equals(Object other) { 328 if (! (other instanceof TypePathEntry)) { 329 return false; 330 } 331 TypePathEntry tpe = (TypePathEntry) other; 332 return this.tag == tpe.tag && this.arg == tpe.arg; 333 } 334 335 @Override 336 public int hashCode() { 337 return this.tag.hashCode() * 17 + this.arg; 338 } 339 } 340 341 public TargetType type = TargetType.UNKNOWN; 342 343 // For generic/array types. 344 // TODO: or should we use null? Noone will use this object. 345 public List<TypePathEntry> location = new ArrayList<>(0); 346 347 // Tree position. 348 public int pos = -1; 349 350 // For typecasts, type tests, new (and locals, as start_pc). 351 public boolean isValidOffset = false; 352 public int offset = -1; 353 354 // For locals. arrays same length 355 public int[] lvarOffset = null; 356 public int[] lvarLength = null; 357 public int[] lvarIndex = null; 358 359 // For type parameter bound 360 public int bound_index = Integer.MIN_VALUE; 361 362 // For type parameter and method parameter 363 public int parameter_index = Integer.MIN_VALUE; 364 365 // For class extends, implements, and throws clauses 366 public int type_index = Integer.MIN_VALUE; 367 368 // For exception parameters, index into exception table 369 public int exception_index = Integer.MIN_VALUE; 370 371 public Position() {} 372 373 @Override 374 public String toString() { 375 StringBuilder sb = new StringBuilder(); 376 sb.append('['); 377 sb.append(type); 378 379 switch (type) { 380 // instanceof 381 case INSTANCEOF: 382 // new expression 383 case NEW: 384 // constructor/method reference receiver 385 case CONSTRUCTOR_REFERENCE: 386 case METHOD_REFERENCE: 387 sb.append(", offset = "); 388 sb.append(offset); 389 break; 390 // local variable 391 case LOCAL_VARIABLE: 392 // resource variable 393 case RESOURCE_VARIABLE: 394 if (lvarOffset == null) { 395 sb.append(", lvarOffset is null!"); 396 break; 397 } 398 sb.append(", {"); 399 for (int i = 0; i < lvarOffset.length; ++i) { 400 if (i != 0) sb.append("; "); 401 sb.append("start_pc = "); 402 sb.append(lvarOffset[i]); 403 sb.append(", length = "); 404 sb.append(lvarLength[i]); 405 sb.append(", index = "); 406 sb.append(lvarIndex[i]); 407 } 408 sb.append("}"); 409 break; 410 // method receiver 411 case METHOD_RECEIVER: 412 // Do nothing 413 break; 414 // type parameter 415 case CLASS_TYPE_PARAMETER: 416 case METHOD_TYPE_PARAMETER: 417 sb.append(", param_index = "); 418 sb.append(parameter_index); 419 break; 420 // type parameter bound 421 case CLASS_TYPE_PARAMETER_BOUND: 422 case METHOD_TYPE_PARAMETER_BOUND: 423 sb.append(", param_index = "); 424 sb.append(parameter_index); 425 sb.append(", bound_index = "); 426 sb.append(bound_index); 427 break; 428 // class extends or implements clause 429 case CLASS_EXTENDS: 430 sb.append(", type_index = "); 431 sb.append(type_index); 432 break; 433 // throws 434 case THROWS: 435 sb.append(", type_index = "); 436 sb.append(type_index); 437 break; 438 // exception parameter 439 case EXCEPTION_PARAMETER: 440 sb.append(", exception_index = "); 441 sb.append(exception_index); 442 break; 443 // method parameter 444 case METHOD_FORMAL_PARAMETER: 445 sb.append(", param_index = "); 446 sb.append(parameter_index); 447 break; 448 // type cast 449 case CAST: 450 // method/constructor/reference type argument 451 case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: 452 case METHOD_INVOCATION_TYPE_ARGUMENT: 453 case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: 454 case METHOD_REFERENCE_TYPE_ARGUMENT: 455 sb.append(", offset = "); 456 sb.append(offset); 457 sb.append(", type_index = "); 458 sb.append(type_index); 459 break; 460 // We don't need to worry about these 461 case METHOD_RETURN: 462 case FIELD: 463 break; 464 case UNKNOWN: 465 sb.append(", position UNKNOWN!"); 466 break; 467 default: 468 throw new AssertionError("Unknown target type: " + type); 469 } 470 471 // Append location data for generics/arrays. 472 if (!location.isEmpty()) { 473 sb.append(", location = ("); 474 sb.append(location); 475 sb.append(")"); 476 } 477 478 sb.append(", pos = "); 479 sb.append(pos); 480 481 sb.append(']'); 482 return sb.toString(); 483 } 484 485 /** 486 * Indicates whether the target tree of the annotation has been optimized 487 * away from classfile or not. 488 * @return true if the target has not been optimized away 489 */ 490 public boolean emitToClassfile() { 491 return !type.isLocal() || isValidOffset; 492 } 493 494 /** 495 * Decode the binary representation for a type path and set 496 * the {@code location} field. 497 * 498 * @param list The bytecode representation of the type path. 499 */ 500 public static List<TypePathEntry> getTypePathFromBinary(List<Integer> list) { 501 List<TypePathEntry> loc = new ArrayList<>(list.size() / TypePathEntry.bytesPerEntry); 502 int idx = 0; 503 while (idx < list.size()) { 504 if (idx + 1 == list.size()) { 505 throw new AssertionError("Could not decode type path: " + list); 506 } 507 loc.add(TypePathEntry.fromBinary(list.get(idx), list.get(idx + 1))); 508 idx += 2; 509 } 510 return loc; 511 } 512 513 public static List<Integer> getBinaryFromTypePath(List<TypePathEntry> locs) { 514 List<Integer> loc = new ArrayList<>(locs.size() * TypePathEntry.bytesPerEntry); 515 for (TypePathEntry tpe : locs) { 516 loc.add(tpe.tag.tag); 517 loc.add(tpe.arg); 518 } 519 return loc; 520 } 521 } 522 523 // Code duplicated from com.sun.tools.javac.code.TargetType 524 // The IsLocal flag could be removed here. 525 public enum TargetType { 526 /** For annotations on a class type parameter declaration. */ 527 CLASS_TYPE_PARAMETER(0x00), 528 529 /** For annotations on a method type parameter declaration. */ 530 METHOD_TYPE_PARAMETER(0x01), 531 532 /** For annotations on the type of an "extends" or "implements" clause. */ 533 CLASS_EXTENDS(0x10), 534 535 /** For annotations on a bound of a type parameter of a class. */ 536 CLASS_TYPE_PARAMETER_BOUND(0x11), 537 538 /** For annotations on a bound of a type parameter of a method. */ 539 METHOD_TYPE_PARAMETER_BOUND(0x12), 540 541 /** For annotations on a field. */ 542 FIELD(0x13), 543 544 /** For annotations on a method return type. */ 545 METHOD_RETURN(0x14), 546 547 /** For annotations on the method receiver. */ 548 METHOD_RECEIVER(0x15), 549 550 /** For annotations on a method parameter. */ 551 METHOD_FORMAL_PARAMETER(0x16), 552 553 /** For annotations on a throws clause in a method declaration. */ 554 THROWS(0x17), 555 556 /** For annotations on a local variable. */ 557 LOCAL_VARIABLE(0x40, true), 558 559 /** For annotations on a resource variable. */ 560 RESOURCE_VARIABLE(0x41, true), 561 562 /** For annotations on an exception parameter. */ 563 EXCEPTION_PARAMETER(0x42, true), 564 565 /** For annotations on a type test. */ 566 INSTANCEOF(0x43, true), 567 568 /** For annotations on an object creation expression. */ 569 NEW(0x44, true), 570 571 /** For annotations on a constructor reference receiver. */ 572 CONSTRUCTOR_REFERENCE(0x45, true), 573 574 /** For annotations on a method reference receiver. */ 575 METHOD_REFERENCE(0x46, true), 576 577 /** For annotations on a typecast. */ 578 CAST(0x47, true), 579 580 /** For annotations on a type argument of an object creation expression. */ 581 CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true), 582 583 /** For annotations on a type argument of a method call. */ 584 METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true), 585 586 /** For annotations on a type argument of a constructor reference. */ 587 CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true), 588 589 /** For annotations on a type argument of a method reference. */ 590 METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true), 591 592 /** For annotations with an unknown target. */ 593 UNKNOWN(0xFF); 594 595 private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B; 596 597 private final int targetTypeValue; 598 private final boolean isLocal; 599 600 private TargetType(int targetTypeValue) { 601 this(targetTypeValue, false); 602 } 603 604 private TargetType(int targetTypeValue, boolean isLocal) { 605 if (targetTypeValue < 0 606 || targetTypeValue > 255) 607 throw new AssertionError("Attribute type value needs to be an unsigned byte: " + String.format("0x%02X", targetTypeValue)); 608 this.targetTypeValue = targetTypeValue; 609 this.isLocal = isLocal; 610 } 611 612 /** 613 * Returns whether or not this TargetType represents an annotation whose 614 * target is exclusively a tree in a method body 615 * 616 * Note: wildcard bound targets could target a local tree and a class 617 * member declaration signature tree 618 */ 619 public boolean isLocal() { 620 return isLocal; 621 } 622 623 public int targetTypeValue() { 624 return this.targetTypeValue; 625 } 626 627 private static final TargetType[] targets; 628 629 static { 630 targets = new TargetType[MAXIMUM_TARGET_TYPE_VALUE + 1]; 631 TargetType[] alltargets = values(); 632 for (TargetType target : alltargets) { 633 if (target.targetTypeValue != UNKNOWN.targetTypeValue) 634 targets[target.targetTypeValue] = target; 635 } 636 for (int i = 0; i <= MAXIMUM_TARGET_TYPE_VALUE; ++i) { 637 if (targets[i] == null) 638 targets[i] = UNKNOWN; 639 } 640 } 641 642 public static boolean isValidTargetTypeValue(int tag) { 643 if (tag == UNKNOWN.targetTypeValue) 644 return true; 645 return (tag >= 0 && tag < targets.length); 646 } 647 648 public static TargetType fromTargetTypeValue(int tag) { 649 if (tag == UNKNOWN.targetTypeValue) 650 return UNKNOWN; 651 652 if (tag < 0 || tag >= targets.length) 653 throw new AssertionError("Unknown TargetType: " + tag); 654 return targets[tag]; 655 } 656 } 657 }