1 /*
   2  * Copyright (c) 2003, 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.javac.code;
  27 
  28 import java.util.Iterator;
  29 
  30 import com.sun.tools.javac.tree.JCTree.JCLambda;
  31 import com.sun.tools.javac.util.*;
  32 
  33 /** A type annotation position.
  34 *
  35 *  <p><b>This is NOT part of any supported API.
  36 *  If you write code that depends on this, you do so at your own risk.
  37 *  This code and its internal interfaces are subject to change or
  38 *  deletion without notice.</b>
  39 */
  40 // Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position
  41 public class TypeAnnotationPosition {
  42 
  43     public enum TypePathEntryKind {
  44         ARRAY(0),
  45         INNER_TYPE(1),
  46         WILDCARD(2),
  47         TYPE_ARGUMENT(3);
  48 
  49         public final int tag;
  50 
  51         private TypePathEntryKind(int tag) {
  52             this.tag = tag;
  53         }
  54     }
  55 
  56     public static class TypePathEntry {
  57         /** The fixed number of bytes per TypePathEntry. */
  58         public static final int bytesPerEntry = 2;
  59 
  60         public final TypePathEntryKind tag;
  61         public final int arg;
  62 
  63         public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY);
  64         public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE);
  65         public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD);
  66 
  67         private TypePathEntry(TypePathEntryKind tag) {
  68             Assert.check(tag == TypePathEntryKind.ARRAY ||
  69                     tag == TypePathEntryKind.INNER_TYPE ||
  70                     tag == TypePathEntryKind.WILDCARD,
  71                     "Invalid TypePathEntryKind: " + tag);
  72             this.tag = tag;
  73             this.arg = 0;
  74         }
  75 
  76         public TypePathEntry(TypePathEntryKind tag, int arg) {
  77             Assert.check(tag == TypePathEntryKind.TYPE_ARGUMENT,
  78                     "Invalid TypePathEntryKind: " + tag);
  79             this.tag = tag;
  80             this.arg = arg;
  81         }
  82 
  83         public static TypePathEntry fromBinary(int tag, int arg) {
  84             Assert.check(arg == 0 || tag == TypePathEntryKind.TYPE_ARGUMENT.tag,
  85                     "Invalid TypePathEntry tag/arg: " + tag + "/" + arg);
  86             switch (tag) {
  87             case 0:
  88                 return ARRAY;
  89             case 1:
  90                 return INNER_TYPE;
  91             case 2:
  92                 return WILDCARD;
  93             case 3:
  94                 return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg);
  95             default:
  96                 Assert.error("Invalid TypePathEntryKind tag: " + tag);
  97                 return null;
  98             }
  99         }
 100 
 101         @Override
 102         public String toString() {
 103             return tag.toString() +
 104                     (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
 105         }
 106 
 107         @Override
 108         public boolean equals(Object other) {
 109             if (! (other instanceof TypePathEntry)) {
 110                 return false;
 111             }
 112             TypePathEntry tpe = (TypePathEntry) other;
 113             return this.tag == tpe.tag && this.arg == tpe.arg;
 114         }
 115 
 116         @Override
 117         public int hashCode() {
 118             return this.tag.hashCode() * 17 + this.arg;
 119         }
 120     }
 121 
 122     public TargetType type = TargetType.UNKNOWN;
 123 
 124     // For generic/array types.
 125     public List<TypePathEntry> location = List.nil();
 126 
 127     // Tree position.
 128     public int pos = -1;
 129 
 130     // For type casts, type tests, new, locals (as start_pc),
 131     // and method and constructor reference type arguments.
 132     public boolean isValidOffset = false;
 133     public int offset = -1;
 134 
 135     // For locals. arrays same length
 136     public int[] lvarOffset = null;
 137     public int[] lvarLength = null;
 138     public int[] lvarIndex = null;
 139 
 140     // For type parameter bound
 141     public int bound_index = Integer.MIN_VALUE;
 142 
 143     // For type parameter and method parameter
 144     public int parameter_index = Integer.MIN_VALUE;
 145 
 146     // For class extends, implements, and throws clauses
 147     public int type_index = Integer.MIN_VALUE;
 148 
 149     // For exception parameters, index into exception table.
 150     // In com.sun.tools.javac.jvm.Gen.genCatch we first set the type_index
 151     // to the catch type index - that value is only temporary.
 152     // Then in com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions
 153     // we use that value to determine the exception table index.
 154     public int exception_index = Integer.MIN_VALUE;
 155 
 156     // If this type annotation is within a lambda expression,
 157     // store a pointer to the lambda expression tree in order
 158     // to allow a later translation to the right method.
 159     public JCLambda onLambda = null;
 160 
 161     public TypeAnnotationPosition() {}
 162 
 163     @Override
 164     public String toString() {
 165         StringBuilder sb = new StringBuilder();
 166         sb.append('[');
 167         sb.append(type);
 168 
 169         switch (type) {
 170         // instanceof
 171         case INSTANCEOF:
 172         // new expression
 173         case NEW:
 174         // constructor/method reference receiver
 175         case CONSTRUCTOR_REFERENCE:
 176         case METHOD_REFERENCE:
 177             sb.append(", offset = ");
 178             sb.append(offset);
 179             break;
 180         // local variable
 181         case LOCAL_VARIABLE:
 182         // resource variable
 183         case RESOURCE_VARIABLE:
 184             if (lvarOffset == null) {
 185                 sb.append(", lvarOffset is null!");
 186                 break;
 187             }
 188             sb.append(", {");
 189             for (int i = 0; i < lvarOffset.length; ++i) {
 190                 if (i != 0) sb.append("; ");
 191                 sb.append("start_pc = ");
 192                 sb.append(lvarOffset[i]);
 193                 sb.append(", length = ");
 194                 sb.append(lvarLength[i]);
 195                 sb.append(", index = ");
 196                 sb.append(lvarIndex[i]);
 197             }
 198             sb.append("}");
 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             sb.append(", param_index = ");
 208             sb.append(parameter_index);
 209             break;
 210         // type parameter bound
 211         case CLASS_TYPE_PARAMETER_BOUND:
 212         case METHOD_TYPE_PARAMETER_BOUND:
 213             sb.append(", param_index = ");
 214             sb.append(parameter_index);
 215             sb.append(", bound_index = ");
 216             sb.append(bound_index);
 217             break;
 218         // class extends or implements clause
 219         case CLASS_EXTENDS:
 220             sb.append(", type_index = ");
 221             sb.append(type_index);
 222             break;
 223         // throws
 224         case THROWS:
 225             sb.append(", type_index = ");
 226             sb.append(type_index);
 227             break;
 228         // exception parameter
 229         case EXCEPTION_PARAMETER:
 230             sb.append(", exception_index = ");
 231             sb.append(exception_index);
 232             break;
 233         // method parameter
 234         case METHOD_FORMAL_PARAMETER:
 235             sb.append(", param_index = ");
 236             sb.append(parameter_index);
 237             break;
 238         // type cast
 239         case CAST:
 240         // method/constructor/reference type argument
 241         case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
 242         case METHOD_INVOCATION_TYPE_ARGUMENT:
 243         case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
 244         case METHOD_REFERENCE_TYPE_ARGUMENT:
 245             sb.append(", offset = ");
 246             sb.append(offset);
 247             sb.append(", type_index = ");
 248             sb.append(type_index);
 249             break;
 250         // We don't need to worry about these
 251         case METHOD_RETURN:
 252         case FIELD:
 253             break;
 254         case UNKNOWN:
 255             sb.append(", position UNKNOWN!");
 256             break;
 257         default:
 258             Assert.error("Unknown target type: " + type);
 259         }
 260 
 261         // Append location data for generics/arrays.
 262         if (!location.isEmpty()) {
 263             sb.append(", location = (");
 264             sb.append(location);
 265             sb.append(")");
 266         }
 267 
 268         sb.append(", pos = ");
 269         sb.append(pos);
 270 
 271         if (onLambda != null) {
 272             sb.append(", onLambda hash = ");
 273             sb.append(onLambda.hashCode());
 274         }
 275 
 276         sb.append(']');
 277         return sb.toString();
 278     }
 279 
 280     /**
 281      * Indicates whether the target tree of the annotation has been optimized
 282      * away from classfile or not.
 283      * @return true if the target has not been optimized away
 284      */
 285     public boolean emitToClassfile() {
 286         return !type.isLocal() || isValidOffset;
 287     }
 288 
 289 
 290     public boolean matchesPos(int pos) {
 291         return this.pos == pos;
 292     }
 293 
 294     public void updatePosOffset(int to) {
 295         offset = to;
 296         lvarOffset = new int[]{to};
 297         isValidOffset = true;
 298     }
 299 
 300     /**
 301      * Decode the binary representation for a type path and set
 302      * the {@code location} field.
 303      *
 304      * @param list The bytecode representation of the type path.
 305      */
 306     public static List<TypePathEntry> getTypePathFromBinary(java.util.List<Integer> list) {
 307         ListBuffer<TypePathEntry> loc = new ListBuffer<>();
 308         Iterator<Integer> iter = list.iterator();
 309         while (iter.hasNext()) {
 310             Integer fst = iter.next();
 311             Assert.check(iter.hasNext(), "Could not decode type path: " + list);
 312             Integer snd = iter.next();
 313             loc = loc.append(TypePathEntry.fromBinary(fst, snd));
 314         }
 315         return loc.toList();
 316     }
 317 
 318     public static List<Integer> getBinaryFromTypePath(java.util.List<TypePathEntry> locs) {
 319         ListBuffer<Integer> loc = new ListBuffer<>();
 320         for (TypePathEntry tpe : locs) {
 321             loc = loc.append(tpe.tag.tag);
 322             loc = loc.append(tpe.arg);
 323         }
 324         return loc.toList();
 325     }
 326 }