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.Modifiers;
26
27 import java.io.DataInputStream;
28 import java.io.IOException;
29 import java.util.ArrayList;
30
31 import static org.openjdk.asmtools.jasm.JasmTokens.Token;
32 import static org.openjdk.asmtools.jasm.Tables.AttrTag;
33 import static org.openjdk.asmtools.jasm.Tables.CF_Context;
34
35 /**
36 * Method data for method members in a class of the Java Disassembler
37 */
38 public class MethodData extends MemberData {
39
40 /**
41 * CP index to the method name
42 */
43 protected int name_cpx;
44
45 /**
46 * CP index to the method type
47 */
48 protected int sig_cpx;
49 protected String lP; // labelPrefix
50 /**
51 * The parameter names for this method
52 */
53 protected ArrayList<ParamNameData> paramNames;
54 /**
55 * The visible parameter annotations for this method
56 */
57 protected ParameterAnnotationData visibleParameterAnnotations;
58 /**
59 * The invisible parameter annotations for this method
60 */
61 protected ParameterAnnotationData invisibleParameterAnnotations;
62 /**
63 * The invisible parameter annotations for this method
64 */
65 protected AnnotationElement.AnnotValue defaultAnnotation;
66 /**
67 * The code data for this method. May be null
68 */
69 private CodeData code;
70 /**
71 * The exception table (thrown exceptions) for this method. May be null
72 */
73 private int[] exc_table = null;
74
75 public MethodData(ClassData cls) {
76 super(cls);
77 memberType = "MethodData";
78 lP = (options.contains(Options.PR.LABS)) ? "L" : "";
79 paramNames = null;
80 }
81
82 /*========================================================*/
83 /* Read Methods */
84 @Override
85 protected boolean handleAttributes(DataInputStream in, AttrTag attrtag, int attrlen) throws IOException {
86 // Read the Attributes
87 boolean handled = true;
88 switch (attrtag) {
89 case ATT_Code:
90 code = new CodeData(this);
91 code.read(in, attrlen);
92 break;
93 case ATT_Exceptions:
94 readExceptions(in);
95 break;
96 case ATT_MethodParameters:
97 readMethodParameters(in);
98 break;
99 case ATT_RuntimeVisibleParameterAnnotations:
100 case ATT_RuntimeInvisibleParameterAnnotations:
101 boolean invisible = (attrtag == AttrTag.ATT_RuntimeInvisibleParameterAnnotations);
102 ParameterAnnotationData pannots = new ParameterAnnotationData(cls, invisible);
103 pannots.read(in);
104 if (invisible) {
105 invisibleParameterAnnotations = pannots;
106 } else {
107 visibleParameterAnnotations = pannots;
108 }
109 break;
110 case ATT_AnnotationDefault:
111 defaultAnnotation = AnnotationElement.readValue(in, cls, false);
112 break;
113 default:
114 handled = false;
115 break;
116 }
117 return handled;
118 }
119
120 /**
121 * read
122 * read and resolve the method data called from ClassData.
123 * Precondition: NumFields has already been read from the stream.
124 */
125 public void read(DataInputStream in) throws IOException {
126 // read the Methods CP indexes
127 access = in.readUnsignedShort(); // & MM_METHOD; // Q
128 name_cpx = in.readUnsignedShort();
129 sig_cpx = in.readUnsignedShort();
130 TraceUtils.traceln(2,"MethodData: {modifiers}: " + Modifiers.toString(access, CF_Context.CTX_METHOD),
131 " MethodData: name[" + name_cpx + "]=" + cls.pool.getString(name_cpx) + " sig[" + sig_cpx + "]=" + cls.pool.getString(sig_cpx));
132 // Read the attributes
133 readAttributes(in);
134 }
135
136 private void readExceptions(DataInputStream in) throws IOException {
137 // this is not really a CodeAttr attribute, it's part of the CodeAttr
138 int exc_table_len = in.readUnsignedShort();
139 TraceUtils.traceln(3,"ExceptionsAttr[" + exc_table_len + "]");
140 exc_table = new int[exc_table_len];
141 for (int l = 0; l < exc_table_len; l++) {
142 int exc = in.readShort();
143 TraceUtils.traceln(4,"throws:#" + exc);
144 exc_table[l] = exc;
145 }
146 }
147
148 private void readMethodParameters(DataInputStream in) throws IOException {
149 // this is not really a CodeAttr attribute, it's part of the CodeAttr
150 int num_params = in.readUnsignedByte();
151 TraceUtils.traceln(3,"MethodParametersAttr[" + num_params + "]");
152 paramNames = new ArrayList<>(num_params);
153 for (int l = 0; l < num_params; l++) {
154 short pname_cpx = (short) in.readUnsignedShort();
155 int paccess = in.readUnsignedShort();
156 TraceUtils.traceln(4,"P[" + l + "] ={ name[" + pname_cpx + "]: " + cls.pool.getString(pname_cpx)
157 + " modifiers [" + paccess + "]: " + Modifiers.toString(paccess, CF_Context.CTX_METHOD) + "}");
158 paramNames.add(l, new ParamNameData(pname_cpx, paccess));
159 }
160 }
161
162 /**
163 * printPAnnotations
164 * <p>
165 * prints the parameter annotations for this method. called from CodeAttr (since JASM
166 * code integrates the PAnnotation Syntax inside the method body).
167 */
168 // This is called from the CodeAttr
169 public void printPAnnotations() throws IOException {
170 int visSize = 0;
171 int invisSize = 0;
172 int pNumSize = 0;
173
174 if (visibleParameterAnnotations != null) {
175 visSize = visibleParameterAnnotations.numParams();
176 }
177 if (invisibleParameterAnnotations != null) {
178 invisSize = invisibleParameterAnnotations.numParams();
179 }
180 if (paramNames != null) {
181 pNumSize = paramNames.size();
182 }
183
184 int maxParams;
185 maxParams = (pNumSize > invisSize) ? pNumSize : invisSize;
186 maxParams = (visSize > maxParams) ? visSize : maxParams;
187
188 for (int paramNum = 0; paramNum < maxParams; paramNum++) {
189 ArrayList<AnnotationData> visAnnots = null;
190 if (visibleParameterAnnotations != null && paramNum < visSize) {
191 visAnnots = visibleParameterAnnotations.get(paramNum);
192 }
193 ArrayList<AnnotationData> invisAnnots = null;
194 if (invisibleParameterAnnotations != null && paramNum < invisSize) {
195 invisAnnots = invisibleParameterAnnotations.get(paramNum);
196 }
197 ParamNameData pname = (paramNames == null) ? null : paramNames.get(paramNum);
198
199 boolean nullAnnots = ((visAnnots == null) && (invisAnnots == null));
200 if (pname != null && pname.name_cpx == 0) {
201 pname = null;
202 }
203
204 // Print the Param number (header)
205 if ((pname != null) || !nullAnnots) {
206 out.print("\t" + paramNum + ": ");
207 } else {
208 continue;
209 }
210
211 boolean firstTime = true;
212
213 // Print the Parameter name
214 if (pname != null) {
215 out.print(Token.PARAM_NAME.parseKey());
216 out.print(Token.LBRACE.parseKey());
217 out.print(cls.pool.getString(pname.name_cpx));
218 out.print(" ");
219 out.print(Modifiers.toString(pname.access, CF_Context.CTX_METHOD));
220 out.print(Token.RBRACE.parseKey());
221 out.print(" ");
222 }
223
224 // Print any visible param annotations
225 if (visAnnots != null) {
226 for (AnnotationData annot : visAnnots) {
227 if (!firstTime) {
228 out.print("\t ");
229 }
230 annot.print(out, getIndentString());
231 // out.println();
232 firstTime = false;
233 }
234 }
235
236 // Print any invisible param annotations
237 if (invisAnnots != null) {
238 for (AnnotationData annot : invisAnnots) {
239 if (!firstTime) {
240 out.print("\t ");
241 }
242 annot.print(out, getIndentString());
243 // out.println();
244 firstTime = false;
245 }
246 }
247
248 // Reset the line, if there were parameters
249 if ((pname != null) || !nullAnnots) {
250 out.println();
251 }
252
253 }
254
255 }
256
257 /**
258 * Prints the method data to the current output stream. called from ClassData.
259 */
260 @Override
261 public void print() throws IOException {
262
263 printAnnotations(getIndentString());
264
265 out.print(getIndentString() + Modifiers.accessString(access, CF_Context.CTX_METHOD));
266
267 if (isSynthetic) {
268 out.print(Token.SYNTHETIC.parseKey() + " ");
269 }
270 if (isDeprecated) {
271 out.print(Token.DEPRECATED.parseKey() + " ");
272 }
273 out.print(Token.METHODREF.parseKey() + " ");
274
275 if (pr_cpx) {
276 // print the CPX method descriptor
277 out.print("#" + name_cpx + ":#" + sig_cpx +
278 ((code == null && exc_table == null && defaultAnnotation == null) ? ";" : "") +
279 "\t // " + cls.pool.getName(name_cpx) + ":" + cls.pool.getName(sig_cpx));
280 } else {
281 out.print(cls.pool.getName(name_cpx) + ":" + cls.pool.getName(sig_cpx) +
282 ((code == null && exc_table == null && defaultAnnotation == null) ? ";" : ""));
283 }
284 // followed by default annotation
285 if (defaultAnnotation != null) {
286 out.print(" default { ");
287 defaultAnnotation.print(out, getIndentString());
288 out.print(" }" + ((code == null && exc_table == null) ? ";" : " "));
289 }
290 // followed by exception table
291 printExceptionTable();
292
293 if (code != null) {
294 code.print();
295 } else {
296 if( exc_table != null ) {
297 out.print(';');
298 }
299 out.println();
300 }
301 }
302
303 private void printExceptionTable() {
304 if (exc_table != null) {
305 out.print("\n\tthrows ");
306 int len = exc_table.length;
307 for (int exceptNum = 0; exceptNum < len; exceptNum++) {
308 out.print(cls.pool.getClassName(exc_table[exceptNum]));
309 if (exceptNum < len - 1) {
310 out.print(", ");
311 }
312 }
313 }
314 }
315
316 /**
317 * MethodParamData
318 */
319 class ParamNameData {
320
321 public int access;
322 public int name_cpx;
323
324 public ParamNameData(int name, int access) {
325 this.access = access;
326 this.name_cpx = name;
327 }
328 }
329 } // end MethodData