1 /*
  2  * Copyright (c) 1996, 2020, 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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.asmtools.jdis;
 24 
 25 import org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData;
 26 import org.openjdk.asmtools.jasm.TypeAnnotationTypePathData;
 27 
 28 import java.io.DataInputStream;
 29 import java.io.IOException;
 30 import java.io.PrintWriter;
 31 
 32 import static org.openjdk.asmtools.jasm.TypeAnnotationTargetInfoData.*;
 33 import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*;
 34 
 35 /**
 36  * Type Annotation data is a specific kind of AnnotationData. As well as the normal data
 37  * items needed to present an annotation, Type annotations require a TargetInfo
 38  * descriptor. This descriptor is based on a TargetType, and it optionally may contain a
 39  * location descriptor (when the Type is embedded in a collection).
 40  * <p>
 41  * The TypeAnnotationData class is based on JDis's AnnotationData class, and contains the
 42  * (jasm) class for representing TargetInfo.
 43  */
 44 public class TypeAnnotationData extends AnnotationData {
 45 
 46     private static TTVis TT_Visitor = new TTVis();
 47     private TypeAnnotationTargetInfoData targetInfo;
 48     private TypeAnnotationTypePathData typePath;
 49 
 50     public TypeAnnotationData(boolean invisible, ClassData cls) {
 51         super(invisible, cls);
 52         targetInfo = null;
 53         typePath  = new TypeAnnotationTypePathData();
 54         visAnnotToken = "@T+";
 55         invAnnotToken = "@T-";
 56         dataName = "TypeAnnotationData";
 57     }
 58 
 59     @Override
 60     public void read(DataInputStream in) throws IOException {
 61 
 62         int ttype = in.readUnsignedByte();
 63         ETargetType targetType = ETargetType.getTargetType(ttype);
 64 
 65         if (targetType == null) {
 66             // Throw some kind of error for bad target type index
 67             throw new IOException("Bad target type: " + ttype + " in TypeAnnotationData");
 68         }
 69 
 70         // read the target info
 71         TT_Visitor.init(in);
 72         TT_Visitor.visitExcept(targetType);
 73         targetInfo = TT_Visitor.getTargetInfo();
 74 
 75         // read the target path info
 76         int len = in.readUnsignedByte();
 77         TraceUtils.traceln(4,"[TypeAnnotationData.read]: Reading Location (length = " + len + ").");
 78         TraceUtils.trace(4,"[TypeAnnotationData.read]: [ ");
 79         for (int i = 0; i < len; i++) {
 80             int pathType = in.readUnsignedByte();
 81             String pk = (getPathKind(pathType)).parseKey();
 82             char pathArgIndex = (char) in.readUnsignedByte();
 83             typePath.addTypePathEntry(new TypePathEntry(pathType, pathArgIndex));
 84             TraceUtils.trace(" " + pk + "(" + pathType + "," + pathArgIndex + "), ");
 85         }
 86         TraceUtils.traceln("] ");
 87         super.read(in);
 88     }
 89 
 90     @Override
 91     protected void printBody(PrintWriter out, String tab) {
 92         // For a type annotation, print out brackets,
 93         // print out the (regular) annotation name/value pairs,
 94         // then print out the target types.
 95         out.print(" {");
 96         super.printBody(out, "");
 97         targetInfo.print(out, tab);
 98         typePath.print(out, tab);
 99         out.print(tab + "}");
100     }
101 
102     /**
103      * TTVis
104      * <p>
105      * Target Type visitor, used for constructing the target-info within a type
106      * annotation. visitExcept() is the entry point. ti is the constructed target info.
107      */
108     private static class TTVis extends TypeAnnotationTargetVisitor {
109 
110         private TypeAnnotationTargetInfoData targetInfo = null;
111         private IOException IOProb = null;
112         private DataInputStream in;
113 
114         public void init(DataInputStream in) {
115             this.in = in;
116         }
117 
118         public int scanByteVal() {
119             int val = 0;
120             try {
121                 val = in.readUnsignedByte();
122             } catch (IOException e) {
123                 IOProb = e;
124             }
125             return val;
126         }
127 
128         public int scanShortVal() {
129             int val = 0;
130             try {
131                 val = in.readUnsignedShort();
132             } catch (IOException e) {
133                 IOProb = e;
134             }
135             return val;
136         }
137 
138         //This is the entry point for a visitor that tunnels exceptions
139         public void visitExcept(ETargetType tt) throws IOException {
140             IOProb = null;
141             targetInfo = null;
142 
143             TraceUtils.traceln(4,"Target Type: " + tt.parseKey());
144             visit(tt);
145 
146             if (IOProb != null) {
147                 throw IOProb;
148             }
149         }
150 
151         public TypeAnnotationTargetInfoData getTargetInfo() {
152             return targetInfo;
153         }
154 
155         private boolean error() {
156             return IOProb != null;
157         }
158 
159         @Override
160         public void visit_type_param_target(ETargetType tt) {
161             TraceUtils.trace(4,"Type Param Target: ");
162             int byteval = scanByteVal(); // param index
163             TraceUtils.traceln("{ param_index: " + byteval + "}");
164             if (!error()) {
165                 targetInfo = new type_parameter_target(tt, byteval);
166             }
167         }
168 
169         @Override
170         public void visit_supertype_target(ETargetType tt) {
171             TraceUtils.trace(4,"SuperType Target: ");
172             int shortval = scanShortVal(); // type index
173             TraceUtils.traceln("{ type_index: " + shortval + "}");
174             if (!error()) {
175                 targetInfo = new supertype_target(tt, shortval);
176             }
177         }
178 
179         @Override
180         public void visit_typeparam_bound_target(ETargetType tt) {
181             TraceUtils.trace(4,"TypeParam Bound Target: ");
182             int byteval1 = scanByteVal(); // param index
183             if (error()) {
184                 return;
185             }
186             int byteval2 = scanByteVal(); // bound index
187             if (error()) {
188                 return;
189             }
190             TraceUtils.traceln("{ param_index: " + byteval1 + " bound_index: " + byteval2 + "}");
191             targetInfo = new type_parameter_bound_target(tt, byteval1, byteval2);
192         }
193 
194         @Override
195         public void visit_empty_target(ETargetType tt) {
196             TraceUtils.traceln(4,"Empty Target: ");
197             if (!error()) {
198                 targetInfo = new empty_target(tt);
199             }
200         }
201 
202         @Override
203         public void visit_methodformalparam_target(ETargetType tt) {
204             TraceUtils.trace(4,"MethodFormalParam Target: ");
205             int byteval = scanByteVal(); // param index
206             TraceUtils.traceln("{ param_index: " + byteval + "}");
207             if (!error()) {
208                 targetInfo = new formal_parameter_target(tt, byteval);
209             }
210         }
211 
212         @Override
213         public void visit_throws_target(ETargetType tt) {
214             TraceUtils.trace(4,"Throws Target: ");
215             int shortval = scanShortVal(); // exception index
216             TraceUtils.traceln("{ exception_index: " + shortval + "}");
217             if (!error()) {
218                 targetInfo = new throws_target(tt, shortval);
219             }
220         }
221 
222         @Override
223         public void visit_localvar_target(ETargetType tt) {
224             TraceUtils.traceln(4,"LocalVar Target: ");
225             int tblsize = scanShortVal(); // table length (short)
226             if (error()) {
227                 return;
228             }
229             localvar_target locvartab = new localvar_target(tt, tblsize);
230             targetInfo = locvartab;
231 
232             for (int i = 0; i < tblsize; i++) {
233                 int shortval1 = scanShortVal(); // startPC
234                 if (error()) {
235                     return;
236                 }
237                 int shortval2 = scanShortVal(); // length
238                 if (error()) {
239                     return;
240                 }
241                 int shortval3 = scanShortVal(); // CPX
242                 TraceUtils.trace(4,"LocalVar[" + i + "]: ");
243                 TraceUtils.traceln("{ startPC: " + shortval1 + ", length: " + shortval2 + ", CPX: " + shortval3 + "}");
244                 locvartab.addEntry(shortval1, shortval2, shortval3);
245             }
246         }
247 
248         @Override
249         public void visit_catch_target(ETargetType tt) {
250             TraceUtils.trace(4,"Catch Target: ");
251             int shortval = scanShortVal(); // catch index
252             TraceUtils.traceln("{ catch_index: " + shortval + "}");
253             if (!error()) {
254                 targetInfo = new catch_target(tt, shortval);
255             }
256         }
257 
258         @Override
259         public void visit_offset_target(ETargetType tt) {
260             TraceUtils.trace(4,"Offset Target: ");
261             int shortval = scanShortVal(); // offset index
262             TraceUtils.traceln("{ offset_index: " + shortval + "}");
263             if (!error()) {
264                 targetInfo = new offset_target(tt, shortval);
265             }
266         }
267 
268         @Override
269         public void visit_typearg_target(ETargetType tt) {
270             TraceUtils.trace(4,"TypeArg Target: ");
271             int shortval = scanShortVal(); // offset
272             if (error()) {
273                 return;
274             }
275             int byteval = scanByteVal(); // type index
276             if (error()) {
277                 return;
278             }
279             TraceUtils.traceln("{ offset: " + shortval + " type_index: " + byteval + "}");
280             targetInfo = new type_argument_target(tt, shortval, byteval);
281         }
282     }
283 }