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