001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package EDU.purdue.cs.bloat.cfg;
022:
023: import java.io.*;
024: import java.util.*;
025:
026: import EDU.purdue.cs.bloat.editor.*;
027: import EDU.purdue.cs.bloat.tree.*;
028:
029: /**
030: * Subroutine represents a subroutine (target of a <i>jsr</i> instruction) in
031: * java bytecode. Subroutines are used to implement the finally part of a
032: * try-catch-finally block.
033: * <p>
034: * Each Subroutine belongs in a control flow graph, has an entry and exit block,
035: * and has a local variable that contains its return address. Additionally, it
036: * maintains a list of paths from blocks in which the subroutine is called to
037: * block that is executed after the subroutine returns.
038: * <p>
039: * Note that it is assumed that each subroutine ends with a <i>ret</i>. While
040: * this is true for bytecode generated by javac, it is not required.
041: *
042: * @see AddressStoreStmt
043: * @see Block
044: */
045:
046: // Important: I assume there is a ret statement for each jsr.
047: // This is true for javac code, but not in general.
048: public class Subroutine {
049: FlowGraph graph; // CFG containing this Subroutine
050:
051: Block entry; // Basic Block at beginning of code
052:
053: Block exit; // Basic Block ending code
054:
055: ArrayList paths;
056:
057: LocalVariable returnAddress; // This Subroutine's return address
058:
059: /**
060: * Constructor.
061: *
062: * @param graph
063: * The CFG containing the block.
064: */
065: public Subroutine(final FlowGraph graph) {
066: this .graph = graph;
067: this .entry = null;
068: this .exit = null;
069: this .paths = new ArrayList();
070: this .returnAddress = null;
071: }
072:
073: /**
074: * Returns the local variable containing the return address of this
075: * subroutine.
076: */
077: public LocalVariable returnAddress() {
078: return returnAddress;
079: }
080:
081: /**
082: * Sets the address (stored in a LocalVariable) to which this subroutine
083: * will return once it is finished.
084: *
085: * @param returnAddress
086: * Local variable that stores the address to which the subroutine
087: * returns when it is completed.
088: *
089: * @see Tree#visit_astore
090: */
091: public void setReturnAddress(final LocalVariable returnAddress) {
092: this .returnAddress = returnAddress;
093: }
094:
095: /**
096: * Returns the number of places that this subroutine is called.
097: */
098: public int numPaths() {
099: return paths.size();
100: }
101:
102: /**
103: * Returns the paths (a Collection of two-element arrays of Blocks) that
104: * represent the Blocks that end in a call to this subroutine and the block
105: * that begin with the return address from this subroutine.
106: */
107: public Collection paths() {
108: return paths;
109: }
110:
111: /**
112: * Returns the CFG that contains this subroutine.
113: */
114: public FlowGraph graph() {
115: return graph;
116: }
117:
118: /**
119: * Removes all paths involving block regardless of whether it is a calling
120: * (source) block or a returning (target) block.
121: */
122: public void removePathsContaining(final Block block) {
123: for (int i = paths.size() - 1; i >= 0; i--) {
124: final Block[] path = (Block[]) paths.get(i);
125: if ((path[0] == block) || (path[1] == block)) {
126: if (FlowGraph.DEBUG) {
127: System.out.println("removing path " + path[0]
128: + " -> " + path[1]);
129: }
130: paths.remove(i);
131: }
132: }
133: }
134:
135: /**
136: * Removes a path between a caller Block and a return Block.
137: */
138: public void removePath(final Block callerBlock,
139: final Block returnBlock) {
140: for (int i = 0; i < paths.size(); i++) {
141: final Block[] path = (Block[]) paths.get(i);
142: if ((path[0] == callerBlock) && (path[1] == returnBlock)) {
143: if (FlowGraph.DEBUG) {
144: System.out.println("removing path " + path[0]
145: + " -> " + path[1]);
146: }
147: paths.remove(i);
148: return;
149: }
150: }
151: }
152:
153: /**
154: * Removes all caller-return paths.
155: */
156: public void removeAllPaths() {
157: paths = new ArrayList();
158: }
159:
160: /**
161: * Adds a path from the block before a Subroutine is called to a block after
162: * the subroutine is called. If the callerBlock is already associated with a
163: * returnBlock, the old returnBlock is replaced.
164: *
165: * @param callerBlock
166: * The block in which the subroutine is called. This Block ends
167: * with a <i>jsr</i> to this subroutine.
168: * @param returnBlock
169: * The block to which the subroutine returns. This Block begins
170: * at the return address of this subroutine.
171: */
172: public void addPath(final Block callerBlock, final Block returnBlock) {
173: for (int i = 0; i < paths.size(); i++) {
174: final Block[] path = (Block[]) paths.get(i);
175: if (path[0] == callerBlock) {
176: path[1] = returnBlock;
177: return;
178: }
179: }
180:
181: paths.add(new Block[] { callerBlock, returnBlock });
182: }
183:
184: /**
185: * Returns the "return block" for a given "caller block".
186: */
187: public Block pathTarget(final Block block) {
188: for (int i = 0; i < paths.size(); i++) {
189: final Block[] path = (Block[]) paths.get(i);
190: if (path[0] == block) {
191: return path[1];
192: }
193: }
194:
195: return null;
196: }
197:
198: /**
199: * Returns the "caller block" for a given "return block".
200: */
201: public Block pathSource(final Block block) {
202: for (int i = 0; i < paths.size(); i++) {
203: final Block[] path = (Block[]) paths.get(i);
204: if (path[1] == block) {
205: return path[0];
206: }
207: }
208:
209: return null;
210: }
211:
212: /**
213: * Sets the entry Block for this Subroutine.
214: */
215: public void setEntry(final Block entry) {
216: this .entry = entry;
217: }
218:
219: /**
220: * Sets the exit Block for this Subroutine.
221: */
222: public void setExit(final Block exit) {
223: this .exit = exit;
224: }
225:
226: /**
227: * Returns the first Block in the subroutine.
228: */
229: public Block entry() {
230: return entry;
231: }
232:
233: /**
234: * Returns the last Block in the subroutine.
235: */
236: public Block exit() {
237: return exit;
238: }
239:
240: /**
241: * Prints a textual representation of this Subroutine.
242: *
243: * @param out
244: * The PrintStream to which to print.
245: */
246: public void print(final PrintStream out) {
247: out.println(" " + entry);
248:
249: final Iterator e = paths().iterator();
250:
251: while (e.hasNext()) {
252: final Block[] path = (Block[]) e.next();
253: out.println(" path: " + path[0] + " -> " + path[1]);
254: }
255: }
256:
257: public String toString() {
258: return "sub " + entry;
259: }
260: }
|