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