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: // The Initial Developer of the Original Code is Angela Nicoara. Portions
017: // created by Angela Nicoara are Copyright (C) 2002 Angela Nicoara.
018: // All Rights Reserved.
019: //
020: // Contributor(s):
021: // $Id$
022: // =====================================================================
023: //
024: // (history at end)
025: //
026:
027: package ch.ethz.prose.jvmai.jikesrvm.advice_weaver;
028:
029: import org.apache.bcel.generic.*;
030:
031: /**
032: * A visitor that adds a JSR instruction before each `return' instruction. The
033: * jump branches to a predefined finally handle.
034: * <p>
035: * This functionality is needed to implement method exit join points.
036: *
037: * @version $Revision$
038: * @author Johann Gyger
039: * @author Angela Nicoara
040: */
041: public class JumpFinallyVisitor extends EmptyVisitor {
042:
043: /**
044: * Method bytecode represented as a BCEL instruction list.
045: */
046: protected InstructionList code;
047:
048: /**
049: * First instruction that will be visited.
050: */
051: protected InstructionHandle tryStart;
052:
053: /**
054: * Last instruction that will be visited.
055: */
056: protected InstructionHandle tryEnd;
057:
058: /**
059: * Branch target of JSR instruction.
060: */
061: protected InstructionHandle finallyStart;
062:
063: /**
064: * Temporary instruction handle.
065: */
066: protected InstructionHandle handle;
067:
068: /**
069: * Index of local variable where an eventual result of a return can be
070: * stored.
071: */
072: protected int localIndex;
073:
074: /**
075: * Size of local variable.
076: */
077: protected int localSize;
078:
079: /**
080: * Create a new instance of a JumpFinallyVisitor.
081: *
082: * @param code method bytecode represented as a BCEL instruction list
083: * @param tryStart first instruction that will be visited
084: * @param tryEnd last instruction that will be visited
085: * @param finallyStart branch target of JSR instruction
086: * @param localIndex index of local variable to store return result
087: */
088: public JumpFinallyVisitor(InstructionList code,
089: InstructionHandle tryStart, InstructionHandle tryEnd,
090: InstructionHandle finallyStart, int localIndex) {
091: this .code = code;
092: this .tryStart = tryStart;
093: this .tryEnd = tryEnd;
094: this .finallyStart = finallyStart;
095: this .localIndex = localIndex;
096: }
097:
098: /**
099: * Get the size of the local variable that is used to temporarily store the
100: * result.
101: *
102: * @return size of local variable
103: */
104: public int getLocalSize() {
105: return localSize;
106: }
107:
108: /**
109: * Traverse list of instructions and visit each.
110: */
111: public void go() {
112: handle = tryStart;
113: while (handle.getPrev() != tryEnd) {
114: handle.getInstruction().accept(this );
115: handle = handle.getNext();
116: }
117: }
118:
119: public void visitDRETURN(DRETURN obj) {
120: InstructionHandle ih = code.insert(handle, new DSTORE(
121: localIndex + 1));
122: code.insert(handle, new JSR(finallyStart));
123: code.insert(handle, new DLOAD(localIndex + 1));
124:
125: retarget(ih);
126: localSize = obj.getType().getSize();
127: }
128:
129: public void visitRETURN(RETURN obj) {
130: InstructionHandle ih = code.insert(handle,
131: new JSR(finallyStart));
132:
133: retarget(ih);
134: }
135:
136: public void visitLRETURN(LRETURN obj) {
137: InstructionHandle ih = code.insert(handle, new LSTORE(
138: localIndex + 1));
139: code.insert(handle, new JSR(finallyStart));
140: code.insert(handle, new LLOAD(localIndex + 1));
141:
142: retarget(ih);
143: localSize = obj.getType().getSize();
144: }
145:
146: public void visitIRETURN(IRETURN obj) {
147: InstructionHandle ih = code.insert(handle, new ISTORE(
148: localIndex + 1));
149: code.insert(handle, new JSR(finallyStart));
150: code.insert(handle, new ILOAD(localIndex + 1));
151:
152: retarget(ih);
153: localSize = obj.getType().getSize();
154: }
155:
156: public void visitARETURN(ARETURN obj) {
157: InstructionHandle ih = code.insert(handle, new ASTORE(
158: localIndex + 1));
159: code.insert(handle, new JSR(finallyStart));
160: code.insert(handle, new ALOAD(localIndex + 1));
161:
162: retarget(ih);
163: localSize = obj.getType().getSize();
164: }
165:
166: public void visitFRETURN(FRETURN obj) {
167: InstructionHandle ih = code.insert(handle, new FSTORE(
168: localIndex + 1));
169: code.insert(handle, new JSR(finallyStart));
170: code.insert(handle, new FLOAD(localIndex + 1));
171:
172: retarget(ih);
173: localSize = obj.getType().getSize();
174: }
175:
176: /**
177: * Retarget all branch instructions to `newTarget'.
178: *
179: * @param newTarget new target
180: */
181: protected void retarget(InstructionHandle newTarget) {
182: if (handle.hasTargeters()) {
183: InstructionTargeter[] its = handle.getTargeters();
184: for (int i = 0; i < its.length; i++)
185: if (its[i] instanceof BranchInstruction)
186: its[i].updateTarget(handle, newTarget);
187: }
188: }
189:
190: }
191:
192: //======================================================================
193: //
194: // $Log$
195: //
|