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 
TypePathEntryKind(int tag)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 
TypePathEntry(TypePathEntryKind tag)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 
TypePathEntry(TypePathEntryKind tag, int arg)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 
fromBinary(int tag, int arg)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
toString()102         public String toString() {
103             return tag.toString() +
104                     (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : "");
105         }
106 
107         @Override
equals(Object other)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
hashCode()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 
TypeAnnotationPosition()161     public TypeAnnotationPosition() {}
162 
163     @Override
toString()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      */
emitToClassfile()285     public boolean emitToClassfile() {
286         return !type.isLocal() || isValidOffset;
287     }
288 
289 
matchesPos(int pos)290     public boolean matchesPos(int pos) {
291         return this.pos == pos;
292     }
293 
updatePosOffset(int to)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      */
getTypePathFromBinary(java.util.List<Integer> list)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 
getBinaryFromTypePath(java.util.List<TypePathEntry> locs)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 }
327