001: //
002: // This file is part of the prose package.
003: //
004: // The contents of this file are subject to the Mozilla Public License
005: // Version 1.1 (the "License"); you may not use this file except in
006: // compliance with the License. You may obtain a copy of the License at
007: // http://www.mozilla.org/MPL/
008: //
009: // Software distributed under the License is distributed on an "AS IS" basis,
010: // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: // for the specific language governing rights and limitations under the
012: // License.
013: //
014: // The Original Code is prose.
015: //
016: // Contributor(s):
017: // $Id$
018: // =====================================================================
019: //
020: // (history at end)
021: //
022: package ch.ethz.inf.iks.jvmai.jvmdi;
023:
024: import org.apache.bcel.generic.*;
025:
026: /**
027: * A visitor that adds a JSR instruction before each `return' instruction. The
028: * jump branches to a predefined finally handle.
029: * <p>
030: * This functionality is needed to implement method exit join points.
031: *
032: * @author Angela Nicoara
033: * @author Gerald Linhopher
034: * @version $Revision$
035: */
036: public class JumpFinallyVisitor extends EmptyVisitor {
037:
038: /**
039: * Method bytecode represented as a BCEL instruction list.
040: */
041: protected InstructionList code;
042:
043: /**
044: * First instruction that will be visited.
045: */
046: protected InstructionHandle tryStart;
047:
048: /**
049: * Last instruction that will be visited.
050: */
051: protected InstructionHandle tryEnd;
052:
053: /**
054: * Branch target of JSR instruction.
055: */
056: protected InstructionHandle finallyStart;
057:
058: /**
059: * Temporary instruction handle.
060: */
061: protected InstructionHandle handle;
062:
063: /**
064: * Index of local variable where an eventual result of a return can be
065: * stored.
066: */
067: protected int localIndex;
068:
069: /**
070: * Size of local variable.
071: */
072: protected int localSize;
073:
074: /**
075: * Create a new instance of a JumpFinallyVisitor.
076: *
077: * @param code method bytecode represented as a BCEL instruction list
078: * @param tryStart first instruction that will be visited
079: * @param tryEnd last instruction that will be visited
080: * @param finallyStart branch target of JSR instruction
081: * @param localIndex index of local variable to store return result
082: */
083: public JumpFinallyVisitor(InstructionList code,
084: InstructionHandle tryStart, InstructionHandle tryEnd,
085: InstructionHandle finallyStart, int localIndex) {
086: this .code = code;
087: this .tryStart = tryStart;
088: this .tryEnd = tryEnd;
089: this .finallyStart = finallyStart;
090: this .localIndex = localIndex;
091: }
092:
093: /**
094: * Get the size of the local variable that is used to temporarily store the
095: * result.
096: *
097: * @return size of local variable
098: */
099: public int getLocalSize() {
100: return localSize;
101: }
102:
103: /**
104: * Traverse list of instructions and visit each.
105: */
106: public void go() {
107: handle = tryStart;
108: while (handle.getPrev() != tryEnd) {
109: handle.getInstruction().accept(this );
110: handle = handle.getNext();
111: }
112: }
113:
114: public void visitDRETURN(DRETURN obj) {
115: InstructionHandle ih = code.insert(handle, new DSTORE(
116: localIndex + 1));
117: code.insert(handle, new JSR(finallyStart));
118: code.insert(handle, new DLOAD(localIndex + 1));
119:
120: retarget(ih);
121: localSize = obj.getType().getSize();
122: }
123:
124: public void visitRETURN(RETURN obj) {
125: InstructionHandle ih = code.insert(handle,
126: new JSR(finallyStart));
127:
128: retarget(ih);
129: }
130:
131: public void visitLRETURN(LRETURN obj) {
132: InstructionHandle ih = code.insert(handle, new LSTORE(
133: localIndex + 1));
134: code.insert(handle, new JSR(finallyStart));
135: code.insert(handle, new LLOAD(localIndex + 1));
136:
137: retarget(ih);
138: localSize = obj.getType().getSize();
139: }
140:
141: public void visitIRETURN(IRETURN obj) {
142: InstructionHandle ih = code.insert(handle, new ISTORE(
143: localIndex + 1));
144: code.insert(handle, new JSR(finallyStart));
145: code.insert(handle, new ILOAD(localIndex + 1));
146:
147: retarget(ih);
148: localSize = obj.getType().getSize();
149: }
150:
151: public void visitARETURN(ARETURN obj) {
152: InstructionHandle ih = code.insert(handle, new ASTORE(
153: localIndex + 1));
154: code.insert(handle, new JSR(finallyStart));
155: code.insert(handle, new ALOAD(localIndex + 1));
156:
157: retarget(ih);
158: localSize = obj.getType().getSize();
159: }
160:
161: public void visitFRETURN(FRETURN obj) {
162: InstructionHandle ih = code.insert(handle, new FSTORE(
163: localIndex + 1));
164: code.insert(handle, new JSR(finallyStart));
165: code.insert(handle, new FLOAD(localIndex + 1));
166:
167: retarget(ih);
168: localSize = obj.getType().getSize();
169: }
170:
171: /**
172: * Retarget all branch instructions to `newTarget'.
173: *
174: * @param newTarget new target
175: */
176: protected void retarget(InstructionHandle newTarget) {
177: if (handle.hasTargeters()) {
178: InstructionTargeter[] its = handle.getTargeters();
179: for (int i = 0; i < its.length; i++)
180: if (its[i] instanceof BranchInstruction)
181: its[i].updateTarget(handle, newTarget);
182: }
183: }
184:
185: }
186:
187: //======================================================================
188: //
189: // $Log$
190: //
|