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 25 import com.sun.org.apache.bcel.internal.Constants; 26 import java.io.*; 27 28 /** 29 * This class represents a chunk of Java byte code contained in a 30 * method. It is instantiated by the 31 * <em>Attribute.readAttribute()</em> method. A <em>Code</em> 32 * attribute contains informations about operand stack, local 33 * variables, byte code and the exceptions handled within this 34 * method. 35 * 36 * This attribute has attributes itself, namely <em>LineNumberTable</em> which 37 * is used for debugging purposes and <em>LocalVariableTable</em> which 38 * contains information about the local variables. 39 * 40 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 41 * @see Attribute 42 * @see CodeException 43 * @see LineNumberTable 44 * @see LocalVariableTable 45 */ 46 public final class Code extends Attribute { 47 private int max_stack; // Maximum size of stack used by this method 48 private int max_locals; // Number of local variables 49 private int code_length; // Length of code in bytes 50 private byte[] code; // Actual byte code 51 52 private int exception_table_length; 53 private CodeException[] exception_table; // Table of handled exceptions 54 private int attributes_count; // Attributes of code: LineNumber 55 private Attribute[] attributes; // or LocalVariable 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(Code c) { 62 this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(), 63 c.getCode(), c.getExceptionTable(), c.getAttributes(), 64 c.getConstantPool()); 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(int name_index, int length, DataInputStream file, 74 ConstantPool constant_pool) throws IOException 75 { 76 // Initialize with some default values which will be overwritten later 77 this(name_index, length, 78 file.readUnsignedShort(), file.readUnsignedShort(), 79 (byte[])null, (CodeException[])null, (Attribute[])null, 80 constant_pool); 81 82 code_length = file.readInt(); 83 code = new byte[code_length]; // Read byte code 84 file.readFully(code); 85 86 /* Read exception table that contains all regions where an exception 87 * handler is active, i.e., a try { ... } catch() block. 88 */ 89 exception_table_length = file.readUnsignedShort(); 90 exception_table = new CodeException[exception_table_length]; 91 92 for(int i=0; i < exception_table_length; i++) 93 exception_table[i] = new CodeException(file); 94 95 /* Read all attributes, currently `LineNumberTable' and 96 * `LocalVariableTable' 97 */ 98 attributes_count = file.readUnsignedShort(); 99 attributes = new Attribute[attributes_count]; 100 for(int i=0; i < attributes_count; i++) 101 attributes[i] = Attribute.readAttribute(file, constant_pool); 102 103 /* Adjust length, because of setAttributes in this(), s.b. length 104 * is incorrect, because it didn't take the internal attributes 105 * into account yet! Very subtle bug, fixed in 3.1.1. 106 */ 107 this.length = length; 108 } 109 110 /** 111 * @param name_index Index pointing to the name <em>Code</em> 112 * @param length Content length in bytes 113 * @param max_stack Maximum size of stack 114 * @param max_locals Number of local variables 115 * @param code Actual byte code 116 * @param exception_table Table of handled exceptions 117 * @param attributes Attributes of code: LineNumber or LocalVariable 118 * @param constant_pool Array of constants 119 */ 120 public Code(int name_index, int length, 121 int max_stack, int max_locals, 122 byte[] code, 123 CodeException[] exception_table, 124 Attribute[] attributes, 125 ConstantPool constant_pool) 126 { 127 super(Constants.ATTR_CODE, name_index, length, constant_pool); 128 129 this.max_stack = max_stack; 130 this.max_locals = max_locals; 131 132 setCode(code); 133 setExceptionTable(exception_table); 134 setAttributes(attributes); // Overwrites length! 135 } 136 137 /** 138 * Called by objects that are traversing the nodes of the tree implicitely 139 * defined by the contents of a Java class. I.e., the hierarchy of methods, 140 * fields, attributes, etc. spawns a tree of objects. 141 * 142 * @param v Visitor object 143 */ 144 public void accept(Visitor v) { 145 v.visitCode(this); 146 } 147 148 /** 149 * Dump code attribute to file stream in binary format. 150 * 151 * @param file Output file stream 152 * @throws IOException 153 */ 154 public final void dump(DataOutputStream file) throws IOException 155 { 156 super.dump(file); 157 158 file.writeShort(max_stack); 159 file.writeShort(max_locals); 160 file.writeInt(code_length); 161 file.write(code, 0, code_length); 162 163 file.writeShort(exception_table_length); 164 for(int i=0; i < exception_table_length; i++) 165 exception_table[i].dump(file); 166 167 file.writeShort(attributes_count); 168 for(int i=0; i < attributes_count; i++) 169 attributes[i].dump(file); 170 } 171 172 /** 173 * @return Collection of code attributes. 174 * @see Attribute 175 */ 176 public final Attribute[] getAttributes() { return attributes; } 177 178 /** 179 * @return LineNumberTable of Code, if it has one 180 */ 181 public LineNumberTable getLineNumberTable() { 182 for(int i=0; i < attributes_count; i++) 183 if(attributes[i] instanceof LineNumberTable) 184 return (LineNumberTable)attributes[i]; 185 186 return null; 187 } 188 189 /** 190 * @return LocalVariableTable of Code, if it has one 191 */ 192 public LocalVariableTable getLocalVariableTable() { 193 for(int i=0; i < attributes_count; i++) 194 if(attributes[i] instanceof LocalVariableTable) 195 return (LocalVariableTable)attributes[i]; 196 197 return null; 198 } 199 200 /** 201 * @return Actual byte code of the method. 202 */ 203 public final byte[] getCode() { return code; } 204 205 /** 206 * @return Table of handled exceptions. 207 * @see CodeException 208 */ 209 public final CodeException[] getExceptionTable() { return exception_table; } 210 211 /** 212 * @return Number of local variables. 213 */ 214 public final int getMaxLocals() { return max_locals; } 215 216 /** 217 * @return Maximum size of stack used by this method. 218 */ 219 220 public final int getMaxStack() { return max_stack; } 221 222 /** 223 * @return the internal length of this code attribute (minus the first 6 bytes) 224 * and excluding all its attributes 225 */ 226 private final int getInternalLength() { 227 return 2 /*max_stack*/ + 2 /*max_locals*/ + 4 /*code length*/ 228 + code_length /*byte-code*/ 229 + 2 /*exception-table length*/ 230 + 8 * exception_table_length /* exception table */ 231 + 2 /* attributes count */; 232 } 233 234 /** 235 * @return the full size of this code attribute, minus its first 6 bytes, 236 * including the size of all its contained attributes 237 */ 238 private final int calculateLength() { 239 int len = 0; 240 241 for(int i=0; i < attributes_count; i++) 242 len += attributes[i].length + 6 /*attribute header size*/; 243 244 return len + getInternalLength(); 245 } 246 247 /** 248 * @param attributes. 249 */ 250 public final void setAttributes(Attribute[] attributes) { 251 this.attributes = attributes; 252 attributes_count = (attributes == null)? 0 : attributes.length; 253 length = calculateLength(); // Adjust length 254 } 255 256 /** 257 * @param code byte code 258 */ 259 public final void setCode(byte[] code) { 260 this.code = code; 261 code_length = (code == null)? 0 : code.length; 262 } 263 264 /** 265 * @param exception_table exception table 266 */ 267 public final void setExceptionTable(CodeException[] exception_table) { 268 this.exception_table = exception_table; 269 exception_table_length = (exception_table == null)? 0 : 270 exception_table.length; 271 } 272 273 /** 274 * @param max_locals maximum number of local variables 275 */ 276 public final void setMaxLocals(int max_locals) { 277 this.max_locals = max_locals; 278 } 279 280 /** 281 * @param max_stack maximum stack size 282 */ 283 public final void setMaxStack(int max_stack) { 284 this.max_stack = max_stack; 285 } 286 287 /** 288 * @return String representation of code chunk. 289 */ 290 public final String toString(boolean verbose) { 291 StringBuffer buf; 292 293 buf = new StringBuffer("Code(max_stack = " + max_stack + 294 ", max_locals = " + max_locals + 295 ", code_length = " + code_length + ")\n" + 296 Utility.codeToString(code, constant_pool, 0, -1, verbose)); 297 298 if(exception_table_length > 0) { 299 buf.append("\nException handler(s) = \n" + "From\tTo\tHandler\tType\n"); 300 301 for(int i=0; i < exception_table_length; i++) 302 buf.append(exception_table[i].toString(constant_pool, verbose) + "\n"); 303 } 304 305 if(attributes_count > 0) { 306 buf.append("\nAttribute(s) = \n"); 307 308 for(int i=0; i < attributes_count; i++) 309 buf.append(attributes[i].toString() + "\n"); 310 } 311 312 return buf.toString(); 313 } 314 315 /** 316 * @return String representation of code chunk. 317 */ 318 public final String toString() { 319 return toString(true); 320 } 321 322 /** 323 * @return deep copy of this attribute 324 */ 325 public Attribute copy(ConstantPool constant_pool) { 326 Code c = (Code)clone(); 327 c.code = (byte[])code.clone(); 328 c.constant_pool = constant_pool; 329 330 c.exception_table = new CodeException[exception_table_length]; 331 for(int i=0; i < exception_table_length; i++) 332 c.exception_table[i] = exception_table[i].copy(); 333 334 c.attributes = new Attribute[attributes_count]; 335 for(int i=0; i < attributes_count; i++) 336 c.attributes[i] = attributes[i].copy(constant_pool); 337 338 return c; 339 } 340 }