Source code: edu/ucsb/ccs/jcontractor/transformation/ReplaceReturnInstructionsTransformation.java
1 package edu.ucsb.ccs.jcontractor.transformation;
2
3 import org.apache.bcel.generic.*;
4 import edu.ucsb.ccs.jcontractor.jContractor;
5 import edu.ucsb.ccs.jaqual.Logical;
6
7 /**
8 * A transformation to replace all the return statements in a
9 * non-contract methods with a jump to the end of the method, so that
10 * exit condition checking code may be appended to the instruction
11 * list. The transformation is only neccessary when an exit condition
12 * needs to be checked, so it only modifies methods for which either
13 * the postcondition or the exit invariant is checkable.
14 *
15 * <p>The transformation also saves the method's return value to a
16 * local variable, and makes the index of this variable available to
17 * subsequent transformations (AppendReturnTransformation, in
18 * particular, needs it). The index is saved in the shared data table
19 * as an Integer, under the key <code>SHARED_INFO_RESULT_INDEX_KEY +
20 * methodName + methodSignature</code>. Nothing is stored if the
21 * return type is void.
22 *
23 * <p>Here's an example of some bytecode processed by this
24 * transformation:
25 *
26 * <pre>
27 * Before: After:
28 * ----------- --------------
29 * 0: iload_0 0: iload_0
30 * 1: ifeq #4 1: ifeq #4
31 * 2: iconst_0 2: iconst_0
32 * 3: return 3: goto #6
33 * 4: iconst_1 4: iconst_1
34 * 5: return 5: goto #6
35 * 6: nop
36 * </pre>
37 *
38 * @see AppendReturnTransformation
39 *
40 * @author Parker Abercrombie
41 * @version $Id: ReplaceReturnInstructionsTransformation.java,v 1.8 2002/07/14 07:58:03 parkera Exp $
42 */
43
44 public class ReplaceReturnInstructionsTransformation
45 extends ContractTransformation {
46
47 /**
48 * Constant for the key with which the result index is saved in the
49 * shared data.
50 */
51 public static final String SHARED_INFO_RESULT_INDEX_KEY
52 = "ReplaceReturnInstructionsTransformation_result_index";
53
54 /**
55 * Determine if the current class should be processed. All classes
56 * in which contracts are checkable are processed.
57 *
58 * @return true if contracts are checkable in
59 * the current class.
60 */
61 public boolean acceptClass () {
62 return contractsCheckable(transformer.getCurrentClass());
63 }
64
65 /**
66 * Replace all the return statements in the method with code a jump
67 * the end of the method. Only methods with exit conditions need to
68 * be transformed, so only methods for which either the
69 * postcondition or exit invariant is checkable are processed.
70 *
71 * @param mg the method to transform.
72 */
73 public void transformMethod (MethodGen mg) {
74 if (canCheckPostcondition(mg) || canCheckExitInvariant(mg)) {
75 InstructionList il = mg.getInstructionList();
76 replaceReturnInstructions(il);
77 mg.setInstructionList(il);
78
79 saveResult(mg);
80 }
81 }
82
83 /**
84 * Save the result of the method to a local variable named
85 * "$result", and save the index of this new variable in the shared
86 * info table. The index is saved as an Integer, under the key
87 * <code>SHARED_INFO_RESULT_INDEX_KEY + mg.getName() +
88 * mg.getSignature()</code>. No value will be stored if the mehod's
89 * return type is void.
90 *
91 * @param mg the method whose result is to be saved.
92 */
93 protected void saveResult (MethodGen mg) {
94 Type methodReturnType;
95 int resultIndex;
96
97 // If the return type is not void, save the return value (on top
98 // of the stack) to a local variable so it may be retrieved
99 // later.
100 // TODO: optimize -- save only if referenced in PostCond
101 methodReturnType = mg.getReturnType();
102 if (!Type.VOID.equals(methodReturnType)) {
103 resultIndex = mg.addLocalVariable("$result",
104 methodReturnType,
105 null, null).getIndex();
106
107 // Save result with the appropriate 'store' variant depending on
108 // type.
109 mg.getInstructionList()
110 .append(InstructionFactory.createStore(methodReturnType, resultIndex));
111
112 // Save the result index in the shared data. If the return type
113 // is void, remove the info.
114 transformer.getSharedInfo().put(SHARED_INFO_RESULT_INDEX_KEY
115 + mg.getName()
116 + mg.getSignature(),
117 new Integer(resultIndex));
118 }
119 }
120
121 protected boolean saveResult_Postcondition (MethodGen mg, Void RESULT) {
122 return Logical.implies(!Type.VOID.equals(mg.getReturnType()),
123 transformer.getSharedInfo()
124 .get(SHARED_INFO_RESULT_INDEX_KEY
125 + mg.getName()
126 + mg.getSignature()) != null)
127 && Logical.implies(Type.VOID.equals(mg.getReturnType()),
128 transformer.getSharedInfo()
129 .get(SHARED_INFO_RESULT_INDEX_KEY
130 + mg.getName()
131 + mg.getSignature()) == null);
132 }
133
134 /**
135 * Does nothing. This transformation operates only on methods.
136 */
137 public void transformClass () { }
138 }