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