1. package com.sun.org.apache.bcel.internal.generic;
  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 com.sun.org.apache.bcel.internal.classfile.*;
  57. import java.util.*;
  58. /**
  59. * Template class for building up a method. This is done by defining exception
  60. * handlers, adding thrown exceptions, local variables and attributes, whereas
  61. * the `LocalVariableTable' and `LineNumberTable' attributes will be set
  62. * automatically for the code. Use stripAttributes() if you don't like this.
  63. *
  64. * While generating code it may be necessary to insert NOP operations. You can
  65. * use the `removeNOPs' method to get rid off them.
  66. * The resulting method object can be obtained via the `getMethod()' method.
  67. *
  68. * @version $Id: MethodGen.java,v 1.1.1.1 2001/10/29 20:00:24 jvanzyl Exp $
  69. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  70. * @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
  71. * @see InstructionList
  72. * @see Method
  73. */
  74. public class MethodGen extends FieldGenOrMethodGen {
  75. private String class_name;
  76. private Type[] arg_types;
  77. private String[] arg_names;
  78. private int max_locals;
  79. private int max_stack;
  80. private InstructionList il;
  81. private boolean strip_attributes;
  82. private ArrayList variable_vec = new ArrayList();
  83. private ArrayList line_number_vec = new ArrayList();
  84. private ArrayList exception_vec = new ArrayList();
  85. private ArrayList throws_vec = new ArrayList();
  86. private ArrayList code_attrs_vec = new ArrayList();
  87. /**
  88. * Declare method. If the method is non-static the constructor
  89. * automatically declares a local variable `$this' in slot 0. The
  90. * actual code is contained in the `il' parameter, which may further
  91. * manipulated by the user. But he must take care not to remove any
  92. * instruction (handles) that are still referenced from this object.
  93. *
  94. * For example one may not add a local variable and later remove the
  95. * instructions it refers to without causing havoc. It is safe
  96. * however if you remove that local variable, too.
  97. *
  98. * @param access_flags access qualifiers
  99. * @param return_type method type
  100. * @param arg_types argument types
  101. * @param arg_names argument names (if this is null, default names will be provided
  102. * for them)
  103. * @param method_name name of method
  104. * @param class_name class name containing this method (may be null, if you don't care)
  105. * @param il instruction list associated with this method, may be null only for
  106. * abstract or native methods
  107. * @param cp constant pool
  108. */
  109. public MethodGen(int access_flags, Type return_type, Type[] arg_types,
  110. String[] arg_names, String method_name, String class_name,
  111. InstructionList il, ConstantPoolGen cp) {
  112. setAccessFlags(access_flags);
  113. setType(return_type);
  114. setArgumentTypes(arg_types);
  115. setArgumentNames(arg_names);
  116. setName(method_name);
  117. setClassName(class_name);
  118. setInstructionList(il);
  119. setConstantPool(cp);
  120. if((access_flags & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0) {
  121. InstructionHandle start = il.getStart();
  122. InstructionHandle end = il.getEnd();
  123. /* Add local variables, namely the implicit `this' and the arguments
  124. */
  125. if(!isStatic() && (class_name != null)) // Instance method -> `this' is local var 0
  126. addLocalVariable("this", new ObjectType(class_name), start, end);
  127. if(arg_types != null) {
  128. int size = arg_types.length;
  129. if(arg_names != null) { // Names for variables provided?
  130. if(size != arg_names.length)
  131. throw new ClassGenException("Mismatch in argument array lengths: " +
  132. size + " vs. " + arg_names.length);
  133. } else { // Give them dummy names
  134. arg_names = new String[size];
  135. for(int i=0; i < size; i++)
  136. arg_names[i] = "arg" + i;
  137. setArgumentNames(arg_names);
  138. }
  139. for(int i=0; i < size; i++)
  140. addLocalVariable(arg_names[i], arg_types[i], start, end);
  141. }
  142. }
  143. }
  144. /**
  145. * Instantiate from existing method.
  146. *
  147. * @param m method
  148. * @param class_name class name containing this method
  149. * @param cp constant pool
  150. */
  151. public MethodGen(Method m, String class_name, ConstantPoolGen cp) {
  152. this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
  153. Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
  154. m.getName(), class_name,
  155. ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
  156. new InstructionList(m.getCode().getCode()) : null,
  157. cp);
  158. Attribute[] attributes = m.getAttributes();
  159. for(int i=0; i < attributes.length; i++) {
  160. Attribute a = attributes[i];
  161. if(a instanceof Code) {
  162. Code c = (Code)a;
  163. setMaxStack(c.getMaxStack());
  164. setMaxLocals(c.getMaxLocals());
  165. CodeException[] ces = c.getExceptionTable();
  166. if(ces != null) {
  167. for(int j=0; j < ces.length; j++) {
  168. CodeException ce = ces[j];
  169. int type = ce.getCatchType();
  170. ObjectType c_type = null;
  171. if(type > 0) {
  172. String cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
  173. c_type = new ObjectType(cen);
  174. }
  175. int end_pc = ce.getEndPC();
  176. int length = m.getCode().getCode().length;
  177. InstructionHandle end;
  178. if(length == end_pc) { // May happen, because end_pc is exclusive
  179. end = il.getEnd();
  180. } else {
  181. end = il.findHandle(end_pc);
  182. end = end.getPrev(); // Make it inclusive
  183. }
  184. addExceptionHandler(il.findHandle(ce.getStartPC()), end,
  185. il.findHandle(ce.getHandlerPC()), c_type);
  186. }
  187. }
  188. Attribute[] c_attributes = c.getAttributes();
  189. for(int j=0; j < c_attributes.length; j++) {
  190. a = c_attributes[j];
  191. if(a instanceof LineNumberTable) {
  192. LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
  193. for(int k=0; k < ln.length; k++) {
  194. LineNumber l = ln[k];
  195. addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
  196. }
  197. } else if(a instanceof LocalVariableTable) {
  198. LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
  199. for(int k=0; k < lv.length; k++) {
  200. LocalVariable l = lv[k];
  201. InstructionHandle start = il.findHandle(l.getStartPC());
  202. InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
  203. // Repair malformed handles
  204. if(start == null)
  205. start = il.getStart();
  206. if(end == null)
  207. end = il.getEnd();
  208. addLocalVariable(l.getName(), Type.getType(l.getSignature()),
  209. l.getIndex(), start, end);
  210. }
  211. } else
  212. addCodeAttribute(a);
  213. }
  214. } else if(a instanceof ExceptionTable) {
  215. String[] names = ((ExceptionTable)a).getExceptionNames();
  216. for(int j=0; j < names.length; j++)
  217. addException(names[j]);
  218. } else
  219. addAttribute(a);
  220. }
  221. }
  222. /**
  223. * Adds a local variable to this method.
  224. *
  225. * @param name variable name
  226. * @param type variable type
  227. * @param slot the index of the local variable, if type is long or double, the next available
  228. * index is slot+2
  229. * @param start from where the variable is valid
  230. * @param end until where the variable is valid
  231. * @return new local variable object
  232. * @see LocalVariable
  233. */
  234. public LocalVariableGen addLocalVariable(String name, Type type, int slot,
  235. InstructionHandle start,
  236. InstructionHandle end) {
  237. byte t = type.getType();
  238. int add = type.getSize();
  239. if(slot + add > max_locals)
  240. max_locals = slot + add;
  241. LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
  242. int i;
  243. if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
  244. variable_vec.set(i, l);
  245. else
  246. variable_vec.add(l);
  247. return l;
  248. }
  249. /**
  250. * Adds a local variable to this method and assigns an index automatically.
  251. *
  252. * @param name variable name
  253. * @param type variable type
  254. * @param start from where the variable is valid, if this is null,
  255. * it is valid from the start
  256. * @param end until where the variable is valid, if this is null,
  257. * it is valid to the end
  258. * @return new local variable object
  259. * @see LocalVariable
  260. */
  261. public LocalVariableGen addLocalVariable(String name, Type type,
  262. InstructionHandle start,
  263. InstructionHandle end) {
  264. return addLocalVariable(name, type, max_locals, start, end);
  265. }
  266. /**
  267. * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable
  268. * with an explicit index argument.
  269. */
  270. public void removeLocalVariable(LocalVariableGen l) {
  271. variable_vec.remove(l);
  272. }
  273. /**
  274. * Remove all local variables.
  275. */
  276. public void removeLocalVariables() {
  277. variable_vec.clear();
  278. }
  279. /**
  280. * Sort local variables by index
  281. */
  282. private static final void sort(LocalVariableGen[] vars, int l, int r) {
  283. int i = l, j = r;
  284. int m = vars[(l + r) / 2].getIndex();
  285. LocalVariableGen h;
  286. do {
  287. while(vars[i].getIndex() < m) i++;
  288. while(m < vars[j].getIndex()) j--;
  289. if(i <= j) {
  290. h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
  291. i++; j--;
  292. }
  293. } while(i <= j);
  294. if(l < j) sort(vars, l, j);
  295. if(i < r) sort(vars, i, r);
  296. }
  297. /*
  298. * If the range of the variable has not been set yet, it will be set to be valid from
  299. * the start to the end of the instruction list.
  300. *
  301. * @return array of declared local variables sorted by index
  302. */
  303. public LocalVariableGen[] getLocalVariables() {
  304. int size = variable_vec.size();
  305. LocalVariableGen[] lg = new LocalVariableGen[size];
  306. variable_vec.toArray(lg);
  307. for(int i=0; i < size; i++) {
  308. if(lg[i].getStart() == null)
  309. lg[i].setStart(il.getStart());
  310. if(lg[i].getEnd() == null)
  311. lg[i].setEnd(il.getEnd());
  312. }
  313. if(size > 1)
  314. sort(lg, 0, size - 1);
  315. return lg;
  316. }
  317. /**
  318. * @return `LocalVariableTable' attribute of all the local variables of this method.
  319. */
  320. public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
  321. LocalVariableGen[] lg = getLocalVariables();
  322. int size = lg.length;
  323. LocalVariable[] lv = new LocalVariable[size];
  324. for(int i=0; i < size; i++)
  325. lv[i] = lg[i].getLocalVariable(cp);
  326. return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
  327. 2 + lv.length * 10, lv, cp.getConstantPool());
  328. }
  329. /**
  330. * Give an instruction a line number corresponding to the source code line.
  331. *
  332. * @param ih instruction to tag
  333. * @return new line number object
  334. * @see LineNumber
  335. */
  336. public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
  337. LineNumberGen l = new LineNumberGen(ih, src_line);
  338. line_number_vec.add(l);
  339. return l;
  340. }
  341. /**
  342. * Remove a line number.
  343. */
  344. public void removeLineNumber(LineNumberGen l) {
  345. line_number_vec.remove(l);
  346. }
  347. /**
  348. * Remove all line numbers.
  349. */
  350. public void removeLineNumbers() {
  351. line_number_vec.clear();
  352. }
  353. /*
  354. * @return array of line numbers
  355. */
  356. public LineNumberGen[] getLineNumbers() {
  357. LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
  358. line_number_vec.toArray(lg);
  359. return lg;
  360. }
  361. /**
  362. * @return `LineNumberTable' attribute of all the local variables of this method.
  363. */
  364. public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
  365. int size = line_number_vec.size();
  366. LineNumber[] ln = new LineNumber[size];
  367. try {
  368. for(int i=0; i < size; i++)
  369. ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber();
  370. } catch(ArrayIndexOutOfBoundsException e) {} // Never occurs
  371. return new LineNumberTable(cp.addUtf8("LineNumberTable"),
  372. 2 + ln.length * 4, ln, cp.getConstantPool());
  373. }
  374. /**
  375. * Add an exception handler, i.e., specify region where a handler is active and an
  376. * instruction where the actual handling is done.
  377. *
  378. * @param start_pc Start of region (inclusive)
  379. * @param end_pc End of region (inclusive)
  380. * @param handler_pc Where handling is done
  381. * @param catch_type fully qualified class name of handled exception or null if any
  382. * exception is handled
  383. * @return new exception handler object
  384. */
  385. public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
  386. InstructionHandle end_pc,
  387. InstructionHandle handler_pc,
  388. ObjectType catch_type) {
  389. if((start_pc == null) || (end_pc == null) || (handler_pc == null))
  390. throw new ClassGenException("Exception handler target is null instruction");
  391. CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
  392. handler_pc, catch_type);
  393. exception_vec.add(c);
  394. return c;
  395. }
  396. /**
  397. * Remove an exception handler.
  398. */
  399. public void removeExceptionHandler(CodeExceptionGen c) {
  400. exception_vec.remove(c);
  401. }
  402. /**
  403. * Remove all line numbers.
  404. */
  405. public void removeExceptionHandlers() {
  406. exception_vec.clear();
  407. }
  408. /*
  409. * @return array of declared exception handlers
  410. */
  411. public CodeExceptionGen[] getExceptionHandlers() {
  412. CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()];
  413. exception_vec.toArray(cg);
  414. return cg;
  415. }
  416. /**
  417. * @return code exceptions for `Code' attribute
  418. */
  419. private CodeException[] getCodeExceptions() {
  420. int size = exception_vec.size();
  421. CodeException[] c_exc = new CodeException[size];
  422. try {
  423. for(int i=0; i < size; i++) {
  424. CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i);
  425. c_exc[i] = c.getCodeException(cp);
  426. }
  427. } catch(ArrayIndexOutOfBoundsException e) {}
  428. return c_exc;
  429. }
  430. /**
  431. * Add an exception possibly thrown by this method.
  432. *
  433. * @param class_name (fully qualified) name of exception
  434. */
  435. public void addException(String class_name) {
  436. throws_vec.add(class_name);
  437. }
  438. /**
  439. * Remove an exception.
  440. */
  441. public void removeException(String c) {
  442. throws_vec.remove(c);
  443. }
  444. /**
  445. * Remove all exceptions.
  446. */
  447. public void removeExceptions() {
  448. throws_vec.clear();
  449. }
  450. /*
  451. * @return array of thrown exceptions
  452. */
  453. public String[] getExceptions() {
  454. String[] e = new String[throws_vec.size()];
  455. throws_vec.toArray(e);
  456. return e;
  457. }
  458. /**
  459. * @return `Exceptions' attribute of all the exceptions thrown by this method.
  460. */
  461. private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
  462. int size = throws_vec.size();
  463. int[] ex = new int[size];
  464. try {
  465. for(int i=0; i < size; i++)
  466. ex[i] = cp.addClass((String)throws_vec.get(i));
  467. } catch(ArrayIndexOutOfBoundsException e) {}
  468. return new ExceptionTable(cp.addUtf8("Exceptions"),
  469. 2 + 2 * size, ex, cp.getConstantPool());
  470. }
  471. /**
  472. * Add an attribute to the code. Currently, the JVM knows about the
  473. * LineNumberTable, LocalVariableTable and StackMap attributes,
  474. * where the former two will be generated automatically and the
  475. * latter is used for the MIDP only. Other attributes will be
  476. * ignored by the JVM but do no harm.
  477. *
  478. * @param a attribute to be added
  479. */
  480. public void addCodeAttribute(Attribute a) { code_attrs_vec.add(a); }
  481. /**
  482. * Remove a code attribute.
  483. */
  484. public void removeCodeAttribute(Attribute a) { code_attrs_vec.remove(a); }
  485. /**
  486. * Remove all code attributes.
  487. */
  488. public void removeCodeAttributes() {
  489. code_attrs_vec.clear();
  490. }
  491. /**
  492. * @return all attributes of this method.
  493. */
  494. public Attribute[] getCodeAttributes() {
  495. Attribute[] attributes = new Attribute[code_attrs_vec.size()];
  496. code_attrs_vec.toArray(attributes);
  497. return attributes;
  498. }
  499. /**
  500. * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively,
  501. * before calling this method (the same applies for max locals).
  502. *
  503. * @return method object
  504. */
  505. public Method getMethod() {
  506. String signature = getSignature();
  507. int name_index = cp.addUtf8(name);
  508. int signature_index = cp.addUtf8(signature);
  509. /* Also updates positions of instructions, i.e., their indices
  510. */
  511. byte[] byte_code = null;
  512. if(il != null)
  513. byte_code = il.getByteCode();
  514. LineNumberTable lnt = null;
  515. LocalVariableTable lvt = null;
  516. /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
  517. */
  518. if((variable_vec.size() > 0) && !strip_attributes)
  519. addCodeAttribute(lvt = getLocalVariableTable(cp));
  520. if((line_number_vec.size() > 0) && !strip_attributes)
  521. addCodeAttribute(lnt = getLineNumberTable(cp));
  522. Attribute[] code_attrs = getCodeAttributes();
  523. /* Each attribute causes 6 additional header bytes
  524. */
  525. int attrs_len = 0;
  526. for(int i=0; i < code_attrs.length; i++)
  527. attrs_len += (code_attrs[i].getLength() + 6);
  528. CodeException[] c_exc = getCodeExceptions();
  529. int exc_len = c_exc.length * 8; // Every entry takes 8 bytes
  530. Code code = null;
  531. if((il != null) && !isAbstract()) {
  532. code = new Code(cp.addUtf8("Code"),
  533. 8 + byte_code.length + // prologue byte code
  534. 2 + exc_len + // exceptions
  535. 2 + attrs_len, // attributes
  536. max_stack, max_locals,
  537. byte_code, c_exc,
  538. code_attrs,
  539. cp.getConstantPool());
  540. addAttribute(code);
  541. }
  542. ExceptionTable et = null;
  543. if(throws_vec.size() > 0)
  544. addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses
  545. Method m = new Method(access_flags, name_index, signature_index,
  546. getAttributes(), cp.getConstantPool());
  547. // Undo effects of adding attributes
  548. if(lvt != null) removeCodeAttribute(lvt);
  549. if(lnt != null) removeCodeAttribute(lnt);
  550. if(code != null) removeAttribute(code);
  551. if(et != null) removeAttribute(et);
  552. return m;
  553. }
  554. /**
  555. * Remove all NOPs from the instruction list (if possible) and update every
  556. * object refering to them, i.e., branch instructions, local variables and
  557. * exception handlers.
  558. */
  559. public void removeNOPs() {
  560. if(il != null) {
  561. InstructionHandle next;
  562. /* Check branch instructions.
  563. */
  564. for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
  565. next = ih.next;
  566. if((next != null) && (ih.getInstruction() instanceof NOP)) {
  567. try {
  568. il.delete(ih);
  569. } catch(TargetLostException e) {
  570. InstructionHandle[] targets = e.getTargets();
  571. for(int i=0; i < targets.length; i++) {
  572. InstructionTargeter[] targeters = targets[i].getTargeters();
  573. for(int j=0; j < targeters.length; j++)
  574. targeters[j].updateTarget(targets[i], next);
  575. }
  576. }
  577. }
  578. }
  579. }
  580. }
  581. /**
  582. * Set maximum number of local variables.
  583. */
  584. public void setMaxLocals(int m) { max_locals = m; }
  585. public int getMaxLocals() { return max_locals; }
  586. /**
  587. * Set maximum stack size for this method.
  588. */
  589. public void setMaxStack(int m) { max_stack = m; }
  590. public int getMaxStack() { return max_stack; }
  591. /** @return class that contains this method
  592. */
  593. public String getClassName() { return class_name; }
  594. public void setClassName(String class_name) { this.class_name = class_name; }
  595. public void setReturnType(Type return_type) { setType(return_type); }
  596. public Type getReturnType() { return getType(); }
  597. public void setArgumentTypes(Type[] arg_types) { this.arg_types = arg_types; }
  598. public Type[] getArgumentTypes() { return (Type[])arg_types.clone(); }
  599. public void setArgumentType(int i, Type type) { arg_types[i] = type; }
  600. public Type getArgumentType(int i) { return arg_types[i]; }
  601. public void setArgumentNames(String[] arg_names) { this.arg_names = arg_names; }
  602. public String[] getArgumentNames() { return (String[])arg_names.clone(); }
  603. public void setArgumentName(int i, String name) { arg_names[i] = name; }
  604. public String getArgumentName(int i) { return arg_names[i]; }
  605. public InstructionList getInstructionList() { return il; }
  606. public void setInstructionList(InstructionList il) { this.il = il; }
  607. public String getSignature() {
  608. return Type.getMethodSignature(type, arg_types);
  609. }
  610. /**
  611. * Computes max. stack size by performing control flow analysis.
  612. * @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
  613. */
  614. public void setMaxStack() {
  615. if(il != null)
  616. max_stack = getMaxStack(cp, il, getExceptionHandlers());
  617. else
  618. max_stack = 0;
  619. }
  620. /**
  621. * Compute maximum number of local variables.
  622. */
  623. public void setMaxLocals() {
  624. if(il != null) {
  625. int max = isStatic()? 0 : 1;
  626. if(arg_types != null)
  627. for(int i=0; i < arg_types.length; i++)
  628. max += arg_types[i].getSize();
  629. for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
  630. Instruction ins = ih.getInstruction();
  631. if((ins instanceof LocalVariableInstruction) ||
  632. (ins instanceof RET) || (ins instanceof IINC))
  633. {
  634. int index = ((IndexedInstruction)ins).getIndex() +
  635. ((TypedInstruction)ins).getType(cp).getSize();
  636. if(index > max)
  637. max = index;
  638. }
  639. }
  640. max_locals = max;
  641. } else
  642. max_locals = 0;
  643. }
  644. /** Do not/Do produce attributes code attributesLineNumberTable and
  645. * LocalVariableTable, like javac -O
  646. */
  647. public void stripAttributes(boolean flag) { strip_attributes = flag; }
  648. static final class BranchTarget {
  649. InstructionHandle target;
  650. int stackDepth;
  651. BranchTarget(InstructionHandle target, int stackDepth) {
  652. this.target = target;
  653. this.stackDepth = stackDepth;
  654. }
  655. }
  656. static final class BranchStack {
  657. Stack branchTargets = new Stack();
  658. Hashtable visitedTargets = new Hashtable();
  659. public void push(InstructionHandle target, int stackDepth) {
  660. if(visited(target))
  661. return;
  662. branchTargets.push(visit(target, stackDepth));
  663. }
  664. public BranchTarget pop() {
  665. if(!branchTargets.empty()) {
  666. BranchTarget bt = (BranchTarget) branchTargets.pop();
  667. return bt;
  668. }
  669. return null;
  670. }
  671. private final BranchTarget visit(InstructionHandle target, int stackDepth) {
  672. BranchTarget bt = new BranchTarget(target, stackDepth);
  673. visitedTargets.put(target, bt);
  674. return bt;
  675. }
  676. private final boolean visited(InstructionHandle target) {
  677. return (visitedTargets.get(target) != null);
  678. }
  679. }
  680. /**
  681. * Computes stack usage of an instruction list by performing control flow analysis.
  682. *
  683. * @return maximum stack depth used by method
  684. */
  685. public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
  686. BranchStack branchTargets = new BranchStack();
  687. /* Initially, populate the branch stack with the exception
  688. * handlers, because these aren't (necessarily) branched to
  689. * explicitly. in each case, the stack will have depth 1,
  690. * containing the exception object.
  691. */
  692. for (int i = 0; i < et.length; i++) {
  693. InstructionHandle handler_pc = et[i].getHandlerPC();
  694. if (handler_pc != null)
  695. branchTargets.push(handler_pc, 1);
  696. }
  697. int stackDepth = 0, maxStackDepth = 0;
  698. InstructionHandle ih = il.getStart();
  699. while(ih != null) {
  700. Instruction instruction = ih.getInstruction();
  701. short opcode = instruction.getOpcode();
  702. int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
  703. stackDepth += delta;
  704. if(stackDepth > maxStackDepth)
  705. maxStackDepth = stackDepth;
  706. // choose the next instruction based on whether current is a branch.
  707. if(instruction instanceof BranchInstruction) {
  708. BranchInstruction branch = (BranchInstruction) instruction;
  709. if(instruction instanceof Select) {
  710. // explore all of the select's targets. the default target is handled below.
  711. Select select = (Select) branch;
  712. InstructionHandle[] targets = select.getTargets();
  713. for (int i = 0; i < targets.length; i++)
  714. branchTargets.push(targets[i], stackDepth);
  715. // nothing to fall through to.
  716. ih = null;
  717. } else if(!(branch instanceof IfInstruction)) {
  718. // if an instruction that comes back to following PC,
  719. // push next instruction, with stack depth reduced by 1.
  720. if(opcode == Constants.JSR || opcode == Constants.JSR_W)
  721. branchTargets.push(ih.getNext(), stackDepth - 1);
  722. ih = null;
  723. }
  724. // for all branches, the target of the branch is pushed on the branch stack.
  725. // conditional branches have a fall through case, selects don't, and
  726. // jsr/jsr_w return to the next instruction.
  727. branchTargets.push(branch.getTarget(), stackDepth);
  728. } else {
  729. // check for instructions that terminate the method.
  730. if(opcode == Constants.ATHROW || opcode == Constants.RET ||
  731. (opcode >= Constants.IRETURN && opcode <= Constants.RETURN))
  732. ih = null;
  733. }
  734. // normal case, go to the next instruction.
  735. if(ih != null)
  736. ih = ih.getNext();
  737. // if we have no more instructions, see if there are any deferred branches to explore.
  738. if(ih == null) {
  739. BranchTarget bt = branchTargets.pop();
  740. if (bt != null) {
  741. ih = bt.target;
  742. stackDepth = bt.stackDepth;
  743. }
  744. }
  745. }
  746. return maxStackDepth;
  747. }
  748. private ArrayList observers;
  749. /** Add observer for this object.
  750. */
  751. public void addObserver(MethodObserver o) {
  752. if(observers == null)
  753. observers = new ArrayList();
  754. observers.add(o);
  755. }
  756. /** Remove observer for this object.
  757. */
  758. public void removeObserver(MethodObserver o) {
  759. if(observers != null)
  760. observers.remove(o);
  761. }
  762. /** Call notify() method on all observers. This method is not called
  763. * automatically whenever the state has changed, but has to be
  764. * called by the user after he has finished editing the object.
  765. */
  766. public void update() {
  767. if(observers != null)
  768. for(Iterator e = observers.iterator(); e.hasNext(); )
  769. ((MethodObserver)e.next()).notify(this);
  770. }
  771. /**
  772. * Return string representation close to declaration format,
  773. * `public static void main(String[]) throws IOException', e.g.
  774. *
  775. * @return String representation of the method.
  776. */
  777. public final String toString() {
  778. String access = Utility.accessToString(access_flags);
  779. String signature = Type.getMethodSignature(type, arg_types);
  780. signature = Utility.methodSignatureToString(signature, name, access,
  781. true, getLocalVariableTable(cp));
  782. StringBuffer buf = new StringBuffer(signature);
  783. if(throws_vec.size() > 0) {
  784. for(Iterator e = throws_vec.iterator(); e.hasNext(); )
  785. buf.append("\n\t\tthrows " + e.next());
  786. }
  787. return buf.toString();
  788. }
  789. /** @return deep copy of this method
  790. */
  791. public MethodGen copy(String class_name, ConstantPoolGen cp) {
  792. Method m = ((MethodGen)clone()).getMethod();
  793. MethodGen mg = new MethodGen(m, class_name, this.cp);
  794. if(this.cp != cp) {
  795. mg.setConstantPool(cp);
  796. mg.getInstructionList().replaceConstantPool(this.cp, cp);
  797. }
  798. return mg;
  799. }
  800. }