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