1. package com.sun.org.apache.bcel.internal.classfile;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import com.sun.org.apache.bcel.internal.Constants;
  56. import java.io.*;
  57. /**
  58. * This class represents a chunk of Java byte code contained in a
  59. * method. It is instantiated by the
  60. * <em>Attribute.readAttribute()</em> method. A <em>Code</em>
  61. * attribute contains informations about operand stack, local
  62. * variables, byte code and the exceptions handled within this
  63. * method.
  64. *
  65. * This attribute has attributes itself, namely <em>LineNumberTable</em> which
  66. * is used for debugging purposes and <em>LocalVariableTable</em> which
  67. * contains information about the local variables.
  68. *
  69. * @version $Id: Code.java,v 1.1.1.1 2001/10/29 19:59:58 jvanzyl Exp $
  70. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  71. * @see Attribute
  72. * @see CodeException
  73. * @see LineNumberTable
  74. * @see LocalVariableTable
  75. */
  76. public final class Code extends Attribute {
  77. private int max_stack; // Maximum size of stack used by this method
  78. private int max_locals; // Number of local variables
  79. private int code_length; // Length of code in bytes
  80. private byte[] code; // Actual byte code
  81. private int exception_table_length;
  82. private CodeException[] exception_table; // Table of handled exceptions
  83. private int attributes_count; // Attributes of code: LineNumber
  84. private Attribute[] attributes; // or LocalVariable
  85. /**
  86. * Initialize from another object. Note that both objects use the same
  87. * references (shallow copy). Use copy() for a physical copy.
  88. */
  89. public Code(Code c) {
  90. this(c.getNameIndex(), c.getLength(), c.getMaxStack(), c.getMaxLocals(),
  91. c.getCode(), c.getExceptionTable(), c.getAttributes(),
  92. c.getConstantPool());
  93. }
  94. /**
  95. * @param name_index Index pointing to the name <em>Code</em>
  96. * @param length Content length in bytes
  97. * @param file Input stream
  98. * @param constant_pool Array of constants
  99. */
  100. Code(int name_index, int length, DataInputStream file,
  101. ConstantPool constant_pool) throws IOException
  102. {
  103. // Initialize with some default values which will be overwritten later
  104. this(name_index, length,
  105. file.readUnsignedShort(), file.readUnsignedShort(),
  106. (byte[])null, (CodeException[])null, (Attribute[])null,
  107. constant_pool);
  108. code_length = file.readInt();
  109. code = new byte[code_length]; // Read byte code
  110. file.readFully(code);
  111. /* Read exception table that contains all regions where an exception
  112. * handler is active, i.e., a try { ... } catch() block.
  113. */
  114. exception_table_length = file.readUnsignedShort();
  115. exception_table = new CodeException[exception_table_length];
  116. for(int i=0; i < exception_table_length; i++)
  117. exception_table[i] = new CodeException(file);
  118. /* Read all attributes, currently `LineNumberTable' and
  119. * `LocalVariableTable'
  120. */
  121. attributes_count = file.readUnsignedShort();
  122. attributes = new Attribute[attributes_count];
  123. for(int i=0; i < attributes_count; i++)
  124. attributes[i] = Attribute.readAttribute(file, constant_pool);
  125. /* Adjust length, because of setAttributes in this(), s.b. length
  126. * is incorrect, because it didn't take the internal attributes
  127. * into account yet! Very subtle bug, fixed in 3.1.1.
  128. */
  129. this.length = length;
  130. }
  131. /**
  132. * @param name_index Index pointing to the name <em>Code</em>
  133. * @param length Content length in bytes
  134. * @param max_stack Maximum size of stack
  135. * @param max_locals Number of local variables
  136. * @param code Actual byte code
  137. * @param exception_table Table of handled exceptions
  138. * @param attributes Attributes of code: LineNumber or LocalVariable
  139. * @param constant_pool Array of constants
  140. */
  141. public Code(int name_index, int length,
  142. int max_stack, int max_locals,
  143. byte[] code,
  144. CodeException[] exception_table,
  145. Attribute[] attributes,
  146. ConstantPool constant_pool)
  147. {
  148. super(Constants.ATTR_CODE, name_index, length, constant_pool);
  149. this.max_stack = max_stack;
  150. this.max_locals = max_locals;
  151. setCode(code);
  152. setExceptionTable(exception_table);
  153. setAttributes(attributes); // Overwrites length!
  154. }
  155. /**
  156. * Called by objects that are traversing the nodes of the tree implicitely
  157. * defined by the contents of a Java class. I.e., the hierarchy of methods,
  158. * fields, attributes, etc. spawns a tree of objects.
  159. *
  160. * @param v Visitor object
  161. */
  162. public void accept(Visitor v) {
  163. v.visitCode(this);
  164. }
  165. /**
  166. * Dump code attribute to file stream in binary format.
  167. *
  168. * @param file Output file stream
  169. * @throw IOException
  170. */
  171. public final void dump(DataOutputStream file) throws IOException
  172. {
  173. super.dump(file);
  174. file.writeShort(max_stack);
  175. file.writeShort(max_locals);
  176. file.writeInt(code_length);
  177. file.write(code, 0, code_length);
  178. file.writeShort(exception_table_length);
  179. for(int i=0; i < exception_table_length; i++)
  180. exception_table[i].dump(file);
  181. file.writeShort(attributes_count);
  182. for(int i=0; i < attributes_count; i++)
  183. attributes[i].dump(file);
  184. }
  185. /**
  186. * @return Collection of code attributes.
  187. * @see Attribute
  188. */
  189. public final Attribute[] getAttributes() { return attributes; }
  190. /**
  191. * @return LineNumberTable of Code, if it has one
  192. */
  193. public LineNumberTable getLineNumberTable() {
  194. for(int i=0; i < attributes_count; i++)
  195. if(attributes[i] instanceof LineNumberTable)
  196. return (LineNumberTable)attributes[i];
  197. return null;
  198. }
  199. /**
  200. * @return LocalVariableTable of Code, if it has one
  201. */
  202. public LocalVariableTable getLocalVariableTable() {
  203. for(int i=0; i < attributes_count; i++)
  204. if(attributes[i] instanceof LocalVariableTable)
  205. return (LocalVariableTable)attributes[i];
  206. return null;
  207. }
  208. /**
  209. * @return Actual byte code of the method.
  210. */
  211. public final byte[] getCode() { return code; }
  212. /**
  213. * @return Table of handled exceptions.
  214. * @see CodeException
  215. */
  216. public final CodeException[] getExceptionTable() { return exception_table; }
  217. /**
  218. * @return Number of local variables.
  219. */
  220. public final int getMaxLocals() { return max_locals; }
  221. /**
  222. * @return Maximum size of stack used by this method.
  223. */
  224. public final int getMaxStack() { return max_stack; }
  225. /**
  226. * @return the internal length of this code attribute (minus the first 6 bytes)
  227. * and excluding all its attributes
  228. */
  229. private final int getInternalLength() {
  230. return 2 /*max_stack*/ + 2 /*max_locals*/ + 4 /*code length*/
  231. + code_length /*byte-code*/
  232. + 2 /*exception-table length*/
  233. + 8 * exception_table_length /* exception table */
  234. + 2 /* attributes count */;
  235. }
  236. /**
  237. * @return the full size of this code attribute, minus its first 6 bytes,
  238. * including the size of all its contained attributes
  239. */
  240. private final int calculateLength() {
  241. int len = 0;
  242. for(int i=0; i < attributes_count; i++)
  243. len += attributes[i].length + 6 /*attribute header size*/;
  244. return len + getInternalLength();
  245. }
  246. /**
  247. * @param attributes.
  248. */
  249. public final void setAttributes(Attribute[] attributes) {
  250. this.attributes = attributes;
  251. attributes_count = (attributes == null)? 0 : attributes.length;
  252. length = calculateLength(); // Adjust length
  253. }
  254. /**
  255. * @param code byte code
  256. */
  257. public final void setCode(byte[] code) {
  258. this.code = code;
  259. code_length = (code == null)? 0 : code.length;
  260. }
  261. /**
  262. * @param exception_table exception table
  263. */
  264. public final void setExceptionTable(CodeException[] exception_table) {
  265. this.exception_table = exception_table;
  266. exception_table_length = (exception_table == null)? 0 :
  267. exception_table.length;
  268. }
  269. /**
  270. * @param max_locals maximum number of local variables
  271. */
  272. public final void setMaxLocals(int max_locals) {
  273. this.max_locals = max_locals;
  274. }
  275. /**
  276. * @param max_stack maximum stack size
  277. */
  278. public final void setMaxStack(int max_stack) {
  279. this.max_stack = max_stack;
  280. }
  281. /**
  282. * @return String representation of code chunk.
  283. */
  284. public final String toString(boolean verbose) {
  285. StringBuffer buf;
  286. buf = new StringBuffer("Code(max_stack = " + max_stack +
  287. ", max_locals = " + max_locals +
  288. ", code_length = " + code_length + ")\n" +
  289. Utility.codeToString(code, constant_pool, 0, -1, verbose));
  290. if(exception_table_length > 0) {
  291. buf.append("\nException handler(s) = \n" + "From\tTo\tHandler\tType\n");
  292. for(int i=0; i < exception_table_length; i++)
  293. buf.append(exception_table[i].toString(constant_pool, verbose) + "\n");
  294. }
  295. if(attributes_count > 0) {
  296. buf.append("\nAttribute(s) = \n");
  297. for(int i=0; i < attributes_count; i++)
  298. buf.append(attributes[i].toString() + "\n");
  299. }
  300. return buf.toString();
  301. }
  302. /**
  303. * @return String representation of code chunk.
  304. */
  305. public final String toString() {
  306. return toString(true);
  307. }
  308. /**
  309. * @return deep copy of this attribute
  310. */
  311. public Attribute copy(ConstantPool constant_pool) {
  312. Code c = (Code)clone();
  313. c.code = (byte[])code.clone();
  314. c.constant_pool = constant_pool;
  315. c.exception_table = new CodeException[exception_table_length];
  316. for(int i=0; i < exception_table_length; i++)
  317. c.exception_table[i] = exception_table[i].copy();
  318. c.attributes = new Attribute[attributes_count];
  319. for(int i=0; i < attributes_count; i++)
  320. c.attributes[i] = attributes[i].copy(constant_pool);
  321. return c;
  322. }
  323. }