Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }