Initial import
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / bytecode / NATIVERETURN.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
19 package gov.nasa.jpf.jvm.bytecode;
20
21 import gov.nasa.jpf.vm.Instruction;
22 import gov.nasa.jpf.vm.NativeStackFrame;
23 import gov.nasa.jpf.vm.StackFrame;
24 import gov.nasa.jpf.vm.ThreadInfo;
25 import gov.nasa.jpf.vm.Types;
26
27 /**
28  * synthetic return instruction for native method invocations, so that
29  * we don't have to do special provisions to copy the caller args in case
30  * a post exec listener wants them.
31  */
32 public class NATIVERETURN extends JVMReturnInstruction {
33
34   Object ret;
35   Object retAttr;
36   Byte retType;
37
38   // this is more simple than a normal JVMReturnInstruction because NativeMethodInfos
39   // are not synchronized, and NativeStackFrames are never the first frame in a thread
40   @Override
41   public Instruction execute (ThreadInfo ti) {
42     if (!ti.isFirstStepInsn()) {
43       ti.leave();  // takes care of unlocking before potentially creating a CG
44       // NativeMethodInfo is never synchronized, so no thread CG here
45     }
46
47     StackFrame frame = ti.getModifiableTopFrame();    
48     getAndSaveReturnValue(frame);
49
50     // NativeStackFrame can never can be the first stack frame, so no thread CG
51
52     frame = ti.popAndGetModifiableTopFrame();
53
54     // remove args, push return value and continue with next insn
55     frame.removeArguments(mi);
56     pushReturnValue(frame);
57
58     if (retAttr != null) {
59       setReturnAttr(ti, retAttr);
60     }
61
62     if (mi.isClinit()) {
63       // this is in the clinit RETURN insn for non-MJIs so we have to duplicate here
64       // Duplication could be avoided in DIRECTCALLRETURN, but there is no reliable
65       // way to check if the direct call did return from a clinit since the corresponding
66       // synthetic method could do anything
67       mi.getClassInfo().setInitialized();
68     }
69
70     return frame.getPC().getNext();
71   }
72
73   @Override
74   public void cleanupTransients(){
75     ret = null;
76     retAttr = null;
77     returnFrame = null;
78   }
79   
80   @Override
81   public boolean isExtendedInstruction() {
82     return true;
83   }
84
85   public static final int OPCODE = 260;
86
87   @Override
88   public int getByteCode () {
89     return OPCODE;
90   }
91
92   @Override
93   public void accept(JVMInstructionVisitor insVisitor) {
94           insVisitor.visit(this);
95   }
96
97   @Override
98   protected void getAndSaveReturnValue (StackFrame frame) {
99     // it's got to be a NativeStackFrame since this insn is created by JPF
100     NativeStackFrame nativeFrame = (NativeStackFrame)frame;
101
102     returnFrame = nativeFrame;
103
104     ret = nativeFrame.getReturnValue();
105     retAttr = nativeFrame.getReturnAttr();
106     retType = nativeFrame.getMethodInfo().getReturnTypeCode();
107   }
108
109   @Override
110   public int getReturnTypeSize() {
111     switch (retType) {
112     case Types.T_BOOLEAN:
113     case Types.T_BYTE:
114     case Types.T_CHAR:
115     case Types.T_SHORT:
116     case Types.T_INT:
117     case Types.T_FLOAT:
118       return 1;
119       
120     case Types.T_LONG:
121     case Types.T_DOUBLE:
122       return 2;
123
124     default:
125       return 1;
126     }
127   }
128
129   // this is only called internally right before we return
130   @Override
131   protected Object getReturnedOperandAttr (StackFrame frame) {
132     return retAttr;
133   }
134
135   // <2do> this should use the getResult..() methods of NativeStackFrame
136   
137   @Override
138   protected void pushReturnValue (StackFrame fr) {
139     int  ival;
140     long lval;
141     int  retSize = 1;
142
143     // in case of a return type mismatch, we get a ClassCastException, which
144     // is handled in executeMethod() and reported as a InvocationTargetException
145     // (not completely accurate, but we rather go with safety)
146     if (ret != null) {
147       switch (retType) {
148       case Types.T_BOOLEAN:
149         ival = Types.booleanToInt(((Boolean) ret).booleanValue());
150         fr.push(ival);
151         break;
152
153       case Types.T_BYTE:
154         fr.push(((Byte) ret).byteValue());
155         break;
156
157       case Types.T_CHAR:
158         fr.push(((Character) ret).charValue());
159         break;
160
161       case Types.T_SHORT:
162         fr.push(((Short) ret).shortValue());
163         break;
164
165       case Types.T_INT:
166         fr.push(((Integer) ret).intValue());
167         break;
168
169       case Types.T_LONG:
170         fr.pushLong(((Long)ret).longValue());
171         retSize=2;
172         break;
173
174       case Types.T_FLOAT:
175         ival = Types.floatToInt(((Float) ret).floatValue());
176         fr.push(ival);
177         break;
178
179       case Types.T_DOUBLE:
180         lval = Types.doubleToLong(((Double) ret).doubleValue());
181         fr.pushLong(lval);
182         retSize=2;
183         break;
184
185       default:
186         // everything else is supposed to be a reference
187         fr.push(((Integer) ret).intValue(), true);
188       }
189
190       if (retAttr != null) {
191         if (retSize == 1) {
192           fr.setOperandAttr(retAttr);
193         } else {
194           fr.setLongOperandAttr(retAttr);
195         }
196       }
197     }
198   }
199
200   @Override
201   public Object getReturnAttr (ThreadInfo ti) {
202     if (isCompleted(ti)){
203       return retAttr;
204     } else {
205       NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame();
206       return nativeFrame.getReturnAttr();
207     }
208   }
209
210
211   @Override
212   public Object getReturnValue(ThreadInfo ti) {
213     if (isCompleted(ti)){
214       return ret;
215     } else {
216       NativeStackFrame nativeFrame = (NativeStackFrame) ti.getTopFrame();
217       return nativeFrame.getReturnValue();
218     }
219   }
220
221   @Override
222   public String toString(){
223     StringBuilder sb = new StringBuilder();
224     sb.append("nativereturn ");
225     sb.append(mi.getFullName());
226
227     return sb.toString();
228   }
229
230 }