src/share/classes/com/sun/tools/classfile/TypeAnnotation.java

Sun, 17 Feb 2013 16:44:55 -0500

author
dholmes
date
Sun, 17 Feb 2013 16:44:55 -0500
changeset 1571
af8417e590f4
parent 1563
bc456436c613
child 1755
ddb4a2bfcd82
permissions
-rw-r--r--

Merge

     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  */
    26 package com.sun.tools.classfile;
    28 import java.io.IOException;
    29 import java.util.ArrayList;
    30 import java.util.List;
    32 import com.sun.tools.classfile.TypeAnnotation.Position.TypePathEntry;
    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     }
    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     }
    56     public int length() {
    57         int n = annotation.length();
    58         n += position_length(position);
    59         return n;
    60     }
    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     }
    73     public final ConstantPool constant_pool;
    74     public final Position position;
    75     public final Annotation annotation;
    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));
    83         TargetType type = TargetType.fromTargetTypeValue(tag);
    85         Position position = new Position();
    86         position.type = type;
    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.readUnsignedByte();
   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         }
   166         { // Write type path
   167             int len = cr.readUnsignedByte();
   168             List<Integer> loc = new ArrayList<Integer>(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     }
   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 += 1; // 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         }
   250         {
   251             n += 1; // length
   252             n += TypePathEntry.bytesPerEntry * pos.location.size(); // bytes for actual array
   253         }
   255         return n;
   256     }
   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);
   266             public final int tag;
   268             private TypePathEntryKind(int tag) {
   269                 this.tag = tag;
   270             }
   271         }
   273         public static class TypePathEntry {
   274             /** The fixed number of bytes per TypePathEntry. */
   275             public static final int bytesPerEntry = 2;
   277             public final TypePathEntryKind tag;
   278             public final int arg;
   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);
   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             }
   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             }
   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             }
   320             @Override
   321             public String toString() {
   322                 return tag.toString() +
   323                         (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
   324             }
   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             }
   335             @Override
   336             public int hashCode() {
   337                 return this.tag.hashCode() * 17 + this.arg;
   338             }
   339         }
   341         public TargetType type = TargetType.UNKNOWN;
   343         // For generic/array types.
   344         // TODO: or should we use null? Noone will use this object.
   345         public List<TypePathEntry> location = new ArrayList<TypePathEntry>(0);
   347         // Tree position.
   348         public int pos = -1;
   350         // For typecasts, type tests, new (and locals, as start_pc).
   351         public boolean isValidOffset = false;
   352         public int offset = -1;
   354         // For locals. arrays same length
   355         public int[] lvarOffset = null;
   356         public int[] lvarLength = null;
   357         public int[] lvarIndex = null;
   359         // For type parameter bound
   360         public int bound_index = Integer.MIN_VALUE;
   362         // For type parameter and method parameter
   363         public int parameter_index = Integer.MIN_VALUE;
   365         // For class extends, implements, and throws clauses
   366         public int type_index = Integer.MIN_VALUE;
   368         // For exception parameters, index into exception table
   369         public int exception_index = Integer.MIN_VALUE;
   371         public Position() {}
   373         @Override
   374         public String toString() {
   375             StringBuilder sb = new StringBuilder();
   376             sb.append('[');
   377             sb.append(type);
   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             }
   471             // Append location data for generics/arrays.
   472             if (!location.isEmpty()) {
   473                 sb.append(", location = (");
   474                 sb.append(location);
   475                 sb.append(")");
   476             }
   478             sb.append(", pos = ");
   479             sb.append(pos);
   481             sb.append(']');
   482             return sb.toString();
   483         }
   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         }
   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<TypePathEntry>(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         }
   513         public static List<Integer> getBinaryFromTypePath(List<TypePathEntry> locs) {
   514             List<Integer> loc = new ArrayList<Integer>(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     }
   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),
   529         /** For annotations on a method type parameter declaration. */
   530         METHOD_TYPE_PARAMETER(0x01),
   532         /** For annotations on the type of an "extends" or "implements" clause. */
   533         CLASS_EXTENDS(0x10),
   535         /** For annotations on a bound of a type parameter of a class. */
   536         CLASS_TYPE_PARAMETER_BOUND(0x11),
   538         /** For annotations on a bound of a type parameter of a method. */
   539         METHOD_TYPE_PARAMETER_BOUND(0x12),
   541         /** For annotations on a field. */
   542         FIELD(0x13),
   544         /** For annotations on a method return type. */
   545         METHOD_RETURN(0x14),
   547         /** For annotations on the method receiver. */
   548         METHOD_RECEIVER(0x15),
   550         /** For annotations on a method parameter. */
   551         METHOD_FORMAL_PARAMETER(0x16),
   553         /** For annotations on a throws clause in a method declaration. */
   554         THROWS(0x17),
   556         /** For annotations on a local variable. */
   557         LOCAL_VARIABLE(0x40, true),
   559         /** For annotations on a resource variable. */
   560         RESOURCE_VARIABLE(0x41, true),
   562         /** For annotations on an exception parameter. */
   563         EXCEPTION_PARAMETER(0x42, true),
   565         /** For annotations on a type test. */
   566         INSTANCEOF(0x43, true),
   568         /** For annotations on an object creation expression. */
   569         NEW(0x44, true),
   571         /** For annotations on a constructor reference receiver. */
   572         CONSTRUCTOR_REFERENCE(0x45, true),
   574         /** For annotations on a method reference receiver. */
   575         METHOD_REFERENCE(0x46, true),
   577         /** For annotations on a typecast. */
   578         CAST(0x47, true),
   580         /** For annotations on a type argument of an object creation expression. */
   581         CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(0x48, true),
   583         /** For annotations on a type argument of a method call. */
   584         METHOD_INVOCATION_TYPE_ARGUMENT(0x49, true),
   586         /** For annotations on a type argument of a constructor reference. */
   587         CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(0x4A, true),
   589         /** For annotations on a type argument of a method reference. */
   590         METHOD_REFERENCE_TYPE_ARGUMENT(0x4B, true),
   592         /** For annotations with an unknown target. */
   593         UNKNOWN(0xFF);
   595         private static final int MAXIMUM_TARGET_TYPE_VALUE = 0x4B;
   597         private final int targetTypeValue;
   598         private final boolean isLocal;
   600         private TargetType(int targetTypeValue) {
   601             this(targetTypeValue, false);
   602         }
   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         }
   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         }
   623         public int targetTypeValue() {
   624             return this.targetTypeValue;
   625         }
   627         private static final TargetType[] targets;
   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         }
   642         public static boolean isValidTargetTypeValue(int tag) {
   643             if (tag == UNKNOWN.targetTypeValue)
   644                 return true;
   645             return (tag >= 0 && tag < targets.length);
   646         }
   648         public static TargetType fromTargetTypeValue(int tag) {
   649             if (tag == UNKNOWN.targetTypeValue)
   650                 return UNKNOWN;
   652             if (tag < 0 || tag >= targets.length)
   653                 throw new AssertionError("Unknown TargetType: " + tag);
   654             return targets[tag];
   655         }
   656     }
   657 }

mercurial