1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.classfile; 23 24 import java.io.DataInput; 25 import java.io.DataOutputStream; 26 import java.io.IOException; 27 28 import com.sun.org.apache.bcel.internal.Const; 29 30 /** 31 * This class represents a chunk of Java byte code contained in a 32 * method. It is instantiated by the 33 * <em>Attribute.readAttribute()</em> method. A <em>Code</em> 34 * attribute contains informations about operand stack, local 35 * variables, byte code and the exceptions handled within this 36 * method. 37 * 38 * This attribute has attributes itself, namely <em>LineNumberTable</em> which 39 * is used for debugging purposes and <em>LocalVariableTable</em> which 40 * contains information about the local variables. 41 * 42 * @version $Id: Code.java 1749603 2016-06-21 20:50:19Z ggregory $ 43 * @see Attribute 44 * @see CodeException 45 * @see LineNumberTable 46 * @see LocalVariableTable 47 */ 48 public final class Code extends Attribute { 49 50 private int max_stack; // Maximum size of stack used by this method // TODO this could be made final (setter is not used) 51 private int max_locals; // Number of local variables // TODO this could be made final (setter is not used) 52 private byte[] code; // Actual byte code 53 private CodeException[] exception_table; // Table of handled exceptions 54 private Attribute[] attributes; // or LocalVariable 55 56 57 /** 58 * Initialize from another object. Note that both objects use the same 59 * references (shallow copy). Use copy() for a physical copy. 60 */ 61 public Code(final Code c) { 62 this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), c.getCode(), c 63 .getExceptionTable(), c.getAttributes(), c.getConstantPool()); 64 } 65 66 67 /** 68 * @param name_index Index pointing to the name <em>Code</em> 69 * @param length Content length in bytes 70 * @param file Input stream 71 * @param constant_pool Array of constants 72 */ 73 Code(final int name_index, final int length, final DataInput file, final ConstantPool constant_pool) 74 throws IOException { 75 // Initialize with some default values which will be overwritten later 76 this(name_index, length, file.readUnsignedShort(), file.readUnsignedShort(), (byte[]) null, 77 (CodeException[]) null, (Attribute[]) null, constant_pool); 78 final int code_length = file.readInt(); 79 code = new byte[code_length]; // Read byte code 80 file.readFully(code); 81 /* Read exception table that contains all regions where an exception 82 * handler is active, i.e., a try { ... } catch() block. 83 */ 84 final int exception_table_length = file.readUnsignedShort(); 85 exception_table = new CodeException[exception_table_length]; 86 for (int i = 0; i < exception_table_length; i++) { 87 exception_table[i] = new CodeException(file); 88 } 89 /* Read all attributes, currently `LineNumberTable' and 90 * `LocalVariableTable' 91 */ 92 final int attributes_count = file.readUnsignedShort(); 93 attributes = new Attribute[attributes_count]; 94 for (int i = 0; i < attributes_count; i++) { 95 attributes[i] = Attribute.readAttribute(file, constant_pool); 96 } 97 /* Adjust length, because of setAttributes in this(), s.b. length 98 * is incorrect, because it didn't take the internal attributes 99 * into account yet! Very subtle bug, fixed in 3.1.1. 100 */ 101 super.setLength(length); 102 } 103 104 105 /** 106 * @param name_index Index pointing to the name <em>Code</em> 107 * @param length Content length in bytes 108 * @param max_stack Maximum size of stack 109 * @param max_locals Number of local variables 110 * @param code Actual byte code 111 * @param exception_table Table of handled exceptions 112 * @param attributes Attributes of code: LineNumber or LocalVariable 113 * @param constant_pool Array of constants 114 */ 115 public Code(final int name_index, final int length, final int max_stack, final int max_locals, final byte[] code, 116 final CodeException[] exception_table, final Attribute[] attributes, final ConstantPool constant_pool) { 117 super(Const.ATTR_CODE, name_index, length, constant_pool); 118 this.max_stack = max_stack; 119 this.max_locals = max_locals; 120 this.code = code != null ? code : new byte[0]; 121 this.exception_table = exception_table != null ? exception_table : new CodeException[0]; 122 this.attributes = attributes != null ? attributes : new Attribute[0]; 123 super.setLength(calculateLength()); // Adjust length 124 } 125 126 127 /** 128 * Called by objects that are traversing the nodes of the tree implicitely 129 * defined by the contents of a Java class. I.e., the hierarchy of methods, 130 * fields, attributes, etc. spawns a tree of objects. 131 * 132 * @param v Visitor object 133 */ 134 @Override 135 public void accept( final Visitor v ) { 136 v.visitCode(this); 137 } 138 139 140 /** 141 * Dump code attribute to file stream in binary format. 142 * 143 * @param file Output file stream 144 * @throws IOException 145 */ 146 @Override 147 public final void dump( final DataOutputStream file ) throws IOException { 148 super.dump(file); 149 file.writeShort(max_stack); 150 file.writeShort(max_locals); 151 file.writeInt(code.length); 152 file.write(code, 0, code.length); 153 file.writeShort(exception_table.length); 154 for (final CodeException exception : exception_table) { 155 exception.dump(file); 156 } 157 file.writeShort(attributes.length); 158 for (final Attribute attribute : attributes) { 159 attribute.dump(file); 160 } 161 } 162 163 164 /** 165 * @return Collection of code attributes. 166 * @see Attribute 167 */ 168 public final Attribute[] getAttributes() { 169 return attributes; 170 } 171 172 173 /** 174 * @return LineNumberTable of Code, if it has one 175 */ 176 public LineNumberTable getLineNumberTable() { 177 for (final Attribute attribute : attributes) { 178 if (attribute instanceof LineNumberTable) { 179 return (LineNumberTable) attribute; 180 } 181 } 182 return null; 183 } 184 185 186 /** 187 * @return LocalVariableTable of Code, if it has one 188 */ 189 public LocalVariableTable getLocalVariableTable() { 190 for (final Attribute attribute : attributes) { 191 if (attribute instanceof LocalVariableTable) { 192 return (LocalVariableTable) attribute; 193 } 194 } 195 return null; 196 } 197 198 199 /** 200 * @return Actual byte code of the method. 201 */ 202 public final byte[] getCode() { 203 return code; 204 } 205 206 207 /** 208 * @return Table of handled exceptions. 209 * @see CodeException 210 */ 211 public final CodeException[] getExceptionTable() { 212 return exception_table; 213 } 214 215 216 /** 217 * @return Number of local variables. 218 */ 219 public final int getMaxLocals() { 220 return max_locals; 221 } 222 223 224 /** 225 * @return Maximum size of stack used by this method. 226 */ 227 public final int getMaxStack() { 228 return max_stack; 229 } 230 231 232 /** 233 * @return the internal length of this code attribute (minus the first 6 bytes) 234 * and excluding all its attributes 235 */ 236 private int getInternalLength() { 237 return 2 /*max_stack*/+ 2 /*max_locals*/+ 4 /*code length*/ 238 + code.length /*byte-code*/ 239 + 2 /*exception-table length*/ 240 + 8 * (exception_table == null ? 0 : exception_table.length) /* exception table */ 241 + 2 /* attributes count */; 242 } 243 244 245 /** 246 * @return the full size of this code attribute, minus its first 6 bytes, 247 * including the size of all its contained attributes 248 */ 249 private int calculateLength() { 250 int len = 0; 251 if (attributes != null) { 252 for (final Attribute attribute : attributes) { 253 len += attribute.getLength() + 6 /*attribute header size*/; 254 } 255 } 256 return len + getInternalLength(); 257 } 258 259 260 /** 261 * @param attributes the attributes to set for this Code 262 */ 263 public final void setAttributes( final Attribute[] attributes ) { 264 this.attributes = attributes != null ? attributes : new Attribute[0]; 265 super.setLength(calculateLength()); // Adjust length 266 } 267 268 269 /** 270 * @param code byte code 271 */ 272 public final void setCode( final byte[] code ) { 273 this.code = code != null ? code : new byte[0]; 274 super.setLength(calculateLength()); // Adjust length 275 } 276 277 278 /** 279 * @param exception_table exception table 280 */ 281 public final void setExceptionTable( final CodeException[] exception_table ) { 282 this.exception_table = exception_table != null ? exception_table : new CodeException[0]; 283 super.setLength(calculateLength()); // Adjust length 284 } 285 286 287 /** 288 * @param max_locals maximum number of local variables 289 */ 290 public final void setMaxLocals( final int max_locals ) { 291 this.max_locals = max_locals; 292 } 293 294 295 /** 296 * @param max_stack maximum stack size 297 */ 298 public final void setMaxStack( final int max_stack ) { 299 this.max_stack = max_stack; 300 } 301 302 303 /** 304 * @return String representation of code chunk. 305 */ 306 public final String toString( final boolean verbose ) { 307 final StringBuilder buf = new StringBuilder(100); // CHECKSTYLE IGNORE MagicNumber 308 buf.append("Code(max_stack = ").append(max_stack).append(", max_locals = ").append( 309 max_locals).append(", code_length = ").append(code.length).append(")\n").append( 310 Utility.codeToString(code, super.getConstantPool(), 0, -1, verbose)); 311 if (exception_table.length > 0) { 312 buf.append("\nException handler(s) = \n").append("From\tTo\tHandler\tType\n"); 313 for (final CodeException exception : exception_table) { 314 buf.append(exception.toString(super.getConstantPool(), verbose)).append("\n"); 315 } 316 } 317 if (attributes.length > 0) { 318 buf.append("\nAttribute(s) = "); 319 for (final Attribute attribute : attributes) { 320 buf.append("\n").append(attribute); 321 } 322 } 323 return buf.toString(); 324 } 325 326 327 /** 328 * @return String representation of code chunk. 329 */ 330 @Override 331 public final String toString() { 332 return toString(true); 333 } 334 335 336 /** 337 * @return deep copy of this attribute 338 * 339 * @param _constant_pool the constant pool to duplicate 340 */ 341 @Override 342 public Attribute copy( final ConstantPool _constant_pool ) { 343 final Code c = (Code) clone(); 344 if (code != null) { 345 c.code = new byte[code.length]; 346 System.arraycopy(code, 0, c.code, 0, code.length); 347 } 348 c.setConstantPool(_constant_pool); 349 c.exception_table = new CodeException[exception_table.length]; 350 for (int i = 0; i < exception_table.length; i++) { 351 c.exception_table[i] = exception_table[i].copy(); 352 } 353 c.attributes = new Attribute[attributes.length]; 354 for (int i = 0; i < attributes.length; i++) { 355 c.attributes[i] = attributes[i].copy(_constant_pool); 356 } 357 return c; 358 } 359 }