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 }