001: /* CodeVertex.java */
002: package org.quilt.cl;
003:
004: import org.quilt.graph.*;
005: import org.apache.bcel.generic.GotoInstruction;
006: import org.apache.bcel.generic.Instruction;
007: import org.apache.bcel.generic.InstructionHandle;
008: import org.apache.bcel.generic.InstructionList;
009:
010: /**
011: * A Vertex extended to carry the initial bytecode offset, line
012: * number, and an instruction list.
013: *
014: * @author <a href="mailto:jddixon@users.sourceforge.net">Jim Dixon</a>
015: */
016: public class CodeVertex extends Vertex {
017: /** initial offset of first instruction in bytecode */
018: protected int pos = -1;
019:
020: /** the bytecode iteself */
021: protected InstructionList ilist = new InstructionList();
022:
023: /**
024: * Line number in source code corresponding to first instruction,
025: * or if there is no such instruction, of the connecting instruction.
026: */
027: protected int startLine_ = -1;
028:
029: /**
030: * Line number in source code corresponding to the connecting
031: * instruction, or if there is no such instruction, to the last
032: * instruction in the block
033: */
034: protected int endLine_ = -1;
035:
036: /** Instruction connecting this vertex to other(s). */
037: protected Instruction connInst_ = null;
038:
039: /**
040: * Create a code vertex with default bytecode offset, line number,
041: * empty instruction list, and no label.
042: *
043: * @param g Graph which the vertex belongs to.
044: */
045: public CodeVertex(ControlFlowGraph g) {
046: super (g);
047: }
048:
049: /** Create a code vertex, specifying a non-negative bytecode offset.
050: *
051: * @param g Graph which the vertex belongs to.
052: * @param position Offset of the first instruction in the bytecode.
053: */
054: public CodeVertex(ControlFlowGraph g, int position) {
055: super (g);
056: if (position < 0) {
057: throw new IllegalArgumentException(
058: "position cannot be negative");
059: }
060: pos = position;
061: }
062:
063: /**
064: * Create a code vertex, specifying a label
065: *
066: * @param g Graph which the vertex belongs to.
067: * @param l The String label applied to the vertex.
068: */
069: public CodeVertex(ControlFlowGraph g, String l) {
070: super (g);
071: pos = -1;
072: label_ = l;
073: }
074:
075: // GET/SET METHODS //////////////////////////////////////////////
076: /** Get connecting instruction. */
077: public Instruction getConnInst() {
078: return connInst_;
079: }
080:
081: /** Set the connecting instruction for this vertex. */
082: public void setConnInst(Instruction i) {
083: if (i == null) {
084: throw new IllegalArgumentException("null instruction");
085: }
086: connInst_ = i;
087: }
088:
089: // /** Set the connecting instruction to null. */
090: // public void clearConnInst () {
091: // connInst_ = null;
092: // }
093: /**
094: * Get a reference to the InstructionList carried by the vertex.
095: * This is a doubly indirect reference to the first instruction
096: * in the list.
097: *
098: * @return Instruction list.
099: */
100: public InstructionList getInstructionList() {
101: return ilist;
102: }
103:
104: /**
105: * Get the source code line number of the first instruction in a
106: * code vertex.
107: *
108: * @return Non-negative integer or -1, meaning no line number assigned.
109: */
110: public int getStartLine() {
111: return startLine_;
112: }
113:
114: /**
115: * Set the source code line number.
116: * @param n Source code line number.
117: */
118: public void setStartLine(int n) {
119: startLine_ = n;
120: }
121:
122: /**
123: * Get the line number in source code corresponding to the
124: * connecting instruction or last instruction in the block.
125: */
126: public int getEndLine() {
127: return endLine_;
128: }
129:
130: /**
131: * Set the source line number of the connecting instruction, or of
132: * the last line number in the block if there is no connecting
133: * instruction.
134: *
135: * @param n Source code end line number.
136: */
137: public void setEndLine(int n) {
138: endLine_ = n;
139: }
140:
141: /**
142: * Get the bytecode offset of the first instruction.
143: *
144: * @return The initial bytecode offset of the first instruction
145: * carried by the vertex (excluding any connection instruction.
146: */
147: public int getPosition() {
148: return pos;
149: }
150:
151: /**
152: * Set the bytecode offset for the first instruction.
153: *
154: * XXX Should rename this to <code>setPosition</code> to match the
155: * <code>get</code> method.
156: *
157: * @param position A non-negative integer representing the bytecode
158: * position of the first instruction.
159: */
160: public void setPos(int position) {
161: if (position < 0) {
162: throw new IllegalArgumentException(
163: "position cannot be negative");
164: }
165: pos = position;
166: }
167:
168: // OTHER METHODS ////////////////////////////////////////////////
169: /**
170: * Move this code vertex's Goto to another code vertex. The
171: * second vertex will be the target on the otherEdge from this
172: * vertex. This vertex has a BinaryConnector. The second vertex
173: * has a UnaryConnector.
174: *
175: * The goto instruction does NOT point to the target. The target
176: * is some sort of instrumentation being inserted into the graph.
177: */
178: public void moveGoto(final CodeVertex target) {
179: if (target == null) {
180: throw new IllegalArgumentException("null target vertex");
181: }
182: // this vertex's binary connector
183: BinaryConnector biConnector = (BinaryConnector) getConnector();
184: Edge flowEdge = biConnector.getEdge();
185: Edge otherEdge = biConnector.getOtherEdge(); // used by goto
186:
187: if (otherEdge.getTarget() != target) {
188: throw new IllegalArgumentException(
189: "not target of otherEdge");
190: }
191: if (!(connInst_ instanceof GotoInstruction)) {
192: throw new IllegalArgumentException(
193: "connecting instruction not goto");
194: }
195: // the target vertex's unary connector
196: UnaryConnector uConnector = (UnaryConnector) target
197: .getConnector();
198: Edge uEdge = uConnector.getEdge();
199: Vertex tgtTarget = uEdge.getTarget();
200:
201: // // DEBUG
202: // System.out.println("CodeVertex.moveGoto:"
203: // + "\n source: " + toString()
204: // + "\n edge: " + flowEdge
205: // + "\n other edge: " + otherEdge
206: // + "\n target: " + target
207: // + "\n edge: " + uEdge
208: // );
209: // // END
210:
211: // change the unary connector and move it to this vertex
212: uEdge.setSource(this );
213: uEdge.setTarget(target);
214: setConnector(uConnector);
215:
216: // change the binary connector and attach it to the target
217: flowEdge.setSource(target);
218: // flow target is unchanged
219: otherEdge.setSource(target);
220: otherEdge.setTarget(tgtTarget);
221: target.setConnector(biConnector);
222:
223: // move the connecting instruction, a goto
224: target.setConnInst(connInst_); // move it to the target
225: connInst_ = null; // erase from this vertex
226:
227: // // DEBUG
228: // System.out.println("CodeVertex.moveGoto:"
229: // + "\n source: " + toString()
230: // + "\n edge " + getEdge()
231: // + "\n target: " + target
232: // + "\n edge " + flowEdge
233: // + "\n other edge " + otherEdge );
234: // // END
235: }
236:
237: /**
238: * Less verbose <code>toString.</code>
239: *
240: * @return Graph index and Vertex index in a neatly formatted String,
241: * *not* newline-terminated.
242: */
243: public String toString() {
244: StringBuffer sb = new StringBuffer().append("Code ").append(
245: super .toString()).append(" pos ").append(pos);
246:
247: // may look a bit strange if there is an end line but no start line
248: if (startLine_ > -1) {
249: sb.append(" line ").append(startLine_);
250: }
251: if (endLine_ > -1) {
252: sb.append("/").append(endLine_);
253: }
254: return sb.toString();
255: }
256:
257: /**
258: * Optionally more verbose method.
259: *
260: * @param b If true, add label (if any) and instruction list.
261: * @return A neatly formatted String.
262: */
263: public String toString(boolean b) {
264:
265: StringBuffer sb = new StringBuffer().append(toString());
266: if (b) {
267: if (label_ != null) {
268: sb.append("\n label ").append(label_);
269: }
270: sb.append("\n ilist: ");
271: InstructionHandle ih = ilist.getStart();
272: while (ih != null) {
273: sb.append(ih.getInstruction());
274: }
275: }
276: return sb.toString();
277: }
278: }
|