Initial import
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / bytecode / JVMReturnInstruction.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.jvm.bytecode;
19
20 import gov.nasa.jpf.vm.Instruction;
21 import gov.nasa.jpf.vm.ElementInfo;
22 import gov.nasa.jpf.vm.StackFrame;
23 import gov.nasa.jpf.vm.ThreadInfo;
24 import gov.nasa.jpf.vm.bytecode.ReturnInstruction;
25
26 import java.util.Iterator;
27
28
29 /**
30  * abstraction for the various return instructions
31  */
32 public abstract class JVMReturnInstruction extends ReturnInstruction implements JVMInstruction {
33
34   // to store where we came from
35   protected StackFrame returnFrame;
36
37   abstract public int getReturnTypeSize();
38   abstract protected Object getReturnedOperandAttr(StackFrame frame);
39   
40   // note these are only callable from within the same enter - thread interleavings
41   // would cause races
42   abstract protected void getAndSaveReturnValue (StackFrame frame);
43   abstract protected void pushReturnValue (StackFrame frame);
44
45   public abstract Object getReturnValue(ThreadInfo ti);
46
47   public StackFrame getReturnFrame() {
48     return returnFrame;
49   }
50
51   public void setReturnFrame(StackFrame frame){
52     returnFrame = frame;
53   }
54
55   /**
56    * this is important since keeping the StackFrame alive would be a major
57    * memory leak
58    */
59   @Override
60   public void cleanupTransients(){
61     returnFrame = null;
62   }
63   
64   //--- attribute accessors
65   
66   // the accessors are here to save the client some effort regarding the
67   // return type (slot size).
68   // Since these are all public methods that can be called by listeners,
69   // we stick to the ThreadInfo argument
70   
71   public boolean hasReturnAttr (ThreadInfo ti){
72     StackFrame frame = ti.getTopFrame();
73     return frame.hasOperandAttr();
74   }
75   public boolean hasReturnAttr (ThreadInfo ti, Class<?> type){
76     StackFrame frame = ti.getTopFrame();
77     return frame.hasOperandAttr(type);
78   }
79   
80   /**
81    * this returns all of them - use either if you know there will be only
82    * one attribute at a time, or check/process result with ObjectList
83    * 
84    * obviously, this only makes sense from an instructionExecuted(), since
85    * the value is pushed during the enter(). Use ObjectList to access values
86    */
87   public Object getReturnAttr (ThreadInfo ti){
88     StackFrame frame = ti.getTopFrame();
89     return frame.getOperandAttr();
90   }
91
92   /**
93    * this replaces all of them - use only if you know 
94    *  - there will be only one attribute at a time
95    *  - you obtained the value you set by a previous getXAttr()
96    *  - you constructed a multi value list with ObjectList.createList()
97    * 
98    * we don't clone since pushing a return value already changed the caller frame
99    */
100   public void setReturnAttr (ThreadInfo ti, Object a){
101     StackFrame frame = ti.getModifiableTopFrame();
102     frame.setOperandAttr(a);
103   }
104   
105   public void addReturnAttr (ThreadInfo ti, Object attr){
106     StackFrame frame = ti.getModifiableTopFrame();
107     frame.addOperandAttr(attr);
108   }
109
110   /**
111    * this only returns the first attr of this type, there can be more
112    * if you don't use client private types or the provided type is too general
113    */
114   public <T> T getReturnAttr (ThreadInfo ti, Class<T> type){
115     StackFrame frame = ti.getTopFrame();
116     return frame.getOperandAttr(type);
117   }
118   public <T> T getNextReturnAttr (ThreadInfo ti, Class<T> type, Object prev){
119     StackFrame frame = ti.getTopFrame();
120     return frame.getNextOperandAttr(type, prev);
121   }
122   public Iterator<?> returnAttrIterator (ThreadInfo ti){
123     StackFrame frame = ti.getTopFrame();
124     return frame.operandAttrIterator();
125   }
126   public <T> Iterator<T> returnAttrIterator (ThreadInfo ti, Class<T> type){
127     StackFrame frame = ti.getTopFrame();
128     return frame.operandAttrIterator(type);
129   }
130   
131   // -- end attribute accessors --
132   
133   @Override
134   public Instruction execute (ThreadInfo ti) {
135     boolean didUnblock = false;
136     
137     if (!ti.isFirstStepInsn()) {
138       didUnblock = ti.leave();  // takes care of unlocking before potentially creating a CG
139     }
140     
141     if (mi.isSynchronized()) {
142       int objref = mi.isStatic() ? mi.getClassInfo().getClassObjectRef() : ti.getThis();
143       ElementInfo ei = ti.getElementInfo(objref);
144
145       if (ei.getLockCount() == 0) {
146         if (ti.getScheduler().setsLockReleaseCG(ti, ei, didUnblock)){
147           return this;
148         }
149       }
150     }
151
152     StackFrame frame = ti.getModifiableTopFrame();
153     returnFrame = frame;
154     Object attr = getReturnedOperandAttr(frame); // the return attr - get this before we pop
155     getAndSaveReturnValue(frame);
156     
157     // note that this is never the first frame, since we start all threads (incl. main)
158     // through a direct call
159     frame = ti.popAndGetModifiableTopFrame();
160
161     // remove args, push return value and continue with next insn
162     // (DirectCallStackFrames don't use this)
163     frame.removeArguments(mi);
164     pushReturnValue(frame);
165
166     if (attr != null) {
167       setReturnAttr(ti, attr);
168     }
169
170     return frame.getPC().getNext();
171   }
172   
173   @Override
174   public void accept(JVMInstructionVisitor insVisitor) {
175           insVisitor.visit(this);
176   }
177   
178   @Override
179   public String toPostExecString() {
180     return getMnemonic() + " [" + mi.getFullName() + ']';
181   }
182 }