/* * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.javac.code; import java.util.Iterator; import com.sun.tools.javac.tree.JCTree.JCLambda; import com.sun.tools.javac.util.*; /** A type annotation position. * * <p><b>This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice.</b> */ // Code duplicated in com.sun.tools.classfile.TypeAnnotation.Position public class TypeAnnotationPosition { public enum TypePathEntryKind { ARRAY(0), INNER_TYPE(1), WILDCARD(2), TYPE_ARGUMENT(3); public final int tag; private TypePathEntryKind(int tag) { this.tag = tag; } } public static class TypePathEntry { /** The fixed number of bytes per TypePathEntry. */ public static final int bytesPerEntry = 2; public final TypePathEntryKind tag; public final int arg; public static final TypePathEntry ARRAY = new TypePathEntry(TypePathEntryKind.ARRAY); public static final TypePathEntry INNER_TYPE = new TypePathEntry(TypePathEntryKind.INNER_TYPE); public static final TypePathEntry WILDCARD = new TypePathEntry(TypePathEntryKind.WILDCARD); private TypePathEntry(TypePathEntryKind tag) { Assert.check(tag == TypePathEntryKind.ARRAY || tag == TypePathEntryKind.INNER_TYPE || tag == TypePathEntryKind.WILDCARD, "Invalid TypePathEntryKind: " + tag); this.tag = tag; this.arg = 0; } public TypePathEntry(TypePathEntryKind tag, int arg) { Assert.check(tag == TypePathEntryKind.TYPE_ARGUMENT, "Invalid TypePathEntryKind: " + tag); this.tag = tag; this.arg = arg; } public static TypePathEntry fromBinary(int tag, int arg) { Assert.check(arg == 0 || tag == TypePathEntryKind.TYPE_ARGUMENT.tag, "Invalid TypePathEntry tag/arg: " + tag + "/" + arg); switch (tag) { case 0: return ARRAY; case 1: return INNER_TYPE; case 2: return WILDCARD; case 3: return new TypePathEntry(TypePathEntryKind.TYPE_ARGUMENT, arg); default: Assert.error("Invalid TypePathEntryKind tag: " + tag); return null; } } @Override public String toString() { return tag.toString() + (tag == TypePathEntryKind.TYPE_ARGUMENT ? ("(" + arg + ")") : ""); } @Override public boolean equals(Object other) { if (! (other instanceof TypePathEntry)) { return false; } TypePathEntry tpe = (TypePathEntry) other; return this.tag == tpe.tag && this.arg == tpe.arg; } @Override public int hashCode() { return this.tag.hashCode() * 17 + this.arg; } } public TargetType type = TargetType.UNKNOWN; // For generic/array types. public List<TypePathEntry> location = List.nil(); // Tree position. public int pos = -1; // For type casts, type tests, new, locals (as start_pc), // and method and constructor reference type arguments. public boolean isValidOffset = false; public int offset = -1; // For locals. arrays same length public int[] lvarOffset = null; public int[] lvarLength = null; public int[] lvarIndex = null; // For type parameter bound public int bound_index = Integer.MIN_VALUE; // For type parameter and method parameter public int parameter_index = Integer.MIN_VALUE; // For class extends, implements, and throws clauses public int type_index = Integer.MIN_VALUE; // For exception parameters, index into exception table. // In com.sun.tools.javac.jvm.Gen.genCatch we first set the type_index // to the catch type index - that value is only temporary. // Then in com.sun.tools.javac.jvm.Code.fillExceptionParameterPositions // we use that value to determine the exception table index. public int exception_index = Integer.MIN_VALUE; // If this type annotation is within a lambda expression, // store a pointer to the lambda expression tree in order // to allow a later translation to the right method. public JCLambda onLambda = null; public TypeAnnotationPosition() {} @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append('['); sb.append(type); switch (type) { // instanceof case INSTANCEOF: // new expression case NEW: // constructor/method reference receiver case CONSTRUCTOR_REFERENCE: case METHOD_REFERENCE: sb.append(", offset = "); sb.append(offset); break; // local variable case LOCAL_VARIABLE: // resource variable case RESOURCE_VARIABLE: if (lvarOffset == null) { sb.append(", lvarOffset is null!"); break; } sb.append(", {"); for (int i = 0; i < lvarOffset.length; ++i) { if (i != 0) sb.append("; "); sb.append("start_pc = "); sb.append(lvarOffset[i]); sb.append(", length = "); sb.append(lvarLength[i]); sb.append(", index = "); sb.append(lvarIndex[i]); } sb.append("}"); break; // method receiver case METHOD_RECEIVER: // Do nothing break; // type parameter case CLASS_TYPE_PARAMETER: case METHOD_TYPE_PARAMETER: sb.append(", param_index = "); sb.append(parameter_index); break; // type parameter bound case CLASS_TYPE_PARAMETER_BOUND: case METHOD_TYPE_PARAMETER_BOUND: sb.append(", param_index = "); sb.append(parameter_index); sb.append(", bound_index = "); sb.append(bound_index); break; // class extends or implements clause case CLASS_EXTENDS: sb.append(", type_index = "); sb.append(type_index); break; // throws case THROWS: sb.append(", type_index = "); sb.append(type_index); break; // exception parameter case EXCEPTION_PARAMETER: sb.append(", exception_index = "); sb.append(exception_index); break; // method parameter case METHOD_FORMAL_PARAMETER: sb.append(", param_index = "); sb.append(parameter_index); break; // type cast case CAST: // method/constructor/reference type argument case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT: case METHOD_INVOCATION_TYPE_ARGUMENT: case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT: case METHOD_REFERENCE_TYPE_ARGUMENT: sb.append(", offset = "); sb.append(offset); sb.append(", type_index = "); sb.append(type_index); break; // We don't need to worry about these case METHOD_RETURN: case FIELD: break; case UNKNOWN: sb.append(", position UNKNOWN!"); break; default: Assert.error("Unknown target type: " + type); } // Append location data for generics/arrays. if (!location.isEmpty()) { sb.append(", location = ("); sb.append(location); sb.append(")"); } sb.append(", pos = "); sb.append(pos); if (onLambda != null) { sb.append(", onLambda hash = "); sb.append(onLambda.hashCode()); } sb.append(']'); return sb.toString(); } /** * Indicates whether the target tree of the annotation has been optimized * away from classfile or not. * @return true if the target has not been optimized away */ public boolean emitToClassfile() { return !type.isLocal() || isValidOffset; } public boolean matchesPos(int pos) { return this.pos == pos; } public void updatePosOffset(int to) { offset = to; lvarOffset = new int[]{to}; isValidOffset = true; } /** * Decode the binary representation for a type path and set * the {@code location} field. * * @param list The bytecode representation of the type path. */ public static List<TypePathEntry> getTypePathFromBinary(java.util.List<Integer> list) { ListBuffer<TypePathEntry> loc = new ListBuffer<>(); Iterator<Integer> iter = list.iterator(); while (iter.hasNext()) { Integer fst = iter.next(); Assert.check(iter.hasNext(), "Could not decode type path: " + list); Integer snd = iter.next(); loc = loc.append(TypePathEntry.fromBinary(fst, snd)); } return loc.toList(); } public static List<Integer> getBinaryFromTypePath(java.util.List<TypePathEntry> locs) { ListBuffer<Integer> loc = new ListBuffer<>(); for (TypePathEntry tpe : locs) { loc = loc.append(tpe.tag.tag); loc = loc.append(tpe.arg); } return loc.toList(); } }