Fixes default method resolution (#159)
[jpf-core.git] / src / main / gov / nasa / jpf / vm / NativeStackFrame.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.vm;
20
21 import gov.nasa.jpf.JPFException;
22 import gov.nasa.jpf.jvm.bytecode.NATIVERETURN;
23 import gov.nasa.jpf.util.HashData;
24 import gov.nasa.jpf.util.Misc;
25
26 import java.io.PrintWriter;
27 import java.io.StringWriter;
28
29 /**
30  * a stack frame for MJI methods
31  * 
32  * This is a special Stackframe to execute NativeMethodInfos, which are just a wrapper around Java reflection
33  * calls. As required by the Java reflection API, they can store argument and return values as object references
34  *
35  * NOTE: operands and locals can be, but are not automatically used during
36  * native method execution.
37  */
38 public abstract class NativeStackFrame extends StackFrame {
39
40
41   // we don't use the operand stack or locals for arguments and return value
42   // because (1) they don't have the right representation (host VM),
43   // (2) for performance reasons (no array alloc), and (3) because there is no
44   // choice point once we enter a native method, so there is no need to do
45   // copy-on-write on the ThreadInfo callstack. Native method execution is
46   // atomic (leave alone roundtrips of course)
47
48   // return value registers
49   protected Object ret;
50   protected Object retAttr;
51
52   // our argument registers
53   protected Object[] args;
54
55   public NativeStackFrame (NativeMethodInfo mi){
56     super( mi, 0, 0);
57   }
58   
59   public void setArgs (Object[] args){
60     this.args = args; 
61   }
62
63   @Override
64   public StackFrame clone () {
65     NativeStackFrame sf = (NativeStackFrame) super.clone();
66
67     if (args != null) {
68       sf.args = args.clone();
69     }
70
71     return sf;
72   }
73
74   @Override
75   public boolean isNative() {
76     return true;
77   }
78
79   @Override
80   public boolean isSynthetic() {
81     return true;
82   }
83
84   @Override
85   public boolean modifiesState() {
86     // native stackframes don't do anything with their operands or locals per se
87     // they are executed atomically, so there is no need to ever restore them
88     return false;
89   }
90
91   @Override
92   public boolean hasAnyRef() {
93     return false;
94   }
95
96   public void setReturnAttr (Object a){
97     retAttr = a;
98   }
99
100   public void setReturnValue(Object r){
101     ret = r;
102   }
103
104   public void clearReturnValue() {
105     ret = null;
106     retAttr = null;
107   }
108
109   public Object getReturnValue() {
110     return ret;
111   }
112
113   public Object getReturnAttr() {
114     return retAttr;
115   }
116
117   public Object[] getArguments() {
118     return args;
119   }
120
121   @Override
122   public void markThreadRoots (Heap heap, int tid) {
123     // what if some listener creates a CG post-EXECUTENATIVE or pre-NATIVERETURN?
124     // and the native method returned an object?
125     // on the other hand, we have to make sure we don't mark a return value from
126     // a previous transition
127
128     if (pc instanceof NATIVERETURN){
129       if (ret != null && ret instanceof Integer && mi.isReferenceReturnType()) {
130         int ref = ((Integer) ret).intValue();
131         heap.markThreadRoot(ref, tid);
132       }
133     }
134   }
135
136   @Override
137   protected void hash (HashData hd) {
138     super.hash(hd);
139
140     if (ret != null){
141       hd.add(ret);
142     }
143     if (retAttr != null){
144       hd.add(retAttr);
145     }
146
147     for (Object a : args){
148       hd.add(a);
149     }
150   }
151
152   @Override
153   public boolean equals (Object object) {
154     if (object == null || !(object instanceof NativeStackFrame)){
155       return false;
156     }
157
158     if (!super.equals(object)){
159       return false;
160     }
161
162     NativeStackFrame o = (NativeStackFrame)object;
163
164     if (ret != o.ret){
165       return false;
166     }
167     if (retAttr != o.retAttr){
168       return false;
169     }
170
171     if (args.length != o.args.length){
172       return false;
173     }
174
175     if (!Misc.compare(args.length, args, o.args)){
176       return false;
177     }
178
179     return true;
180   }
181
182   @Override
183   public String toString () {
184     StringWriter sw = new StringWriter(128);
185     PrintWriter pw = new PrintWriter(sw);
186
187     pw.print("NativeStackFrame@");
188     pw.print(Integer.toHexString(objectHashCode()));
189     pw.print("{ret=");
190     pw.print(ret);
191     if (retAttr != null){
192       pw.print('(');
193       pw.print(retAttr);
194       pw.print(')');
195     }
196     pw.print(',');
197     printContentsOn(pw);
198     pw.print('}');
199
200     return sw.toString();
201   }
202   
203   //--- NativeStackFrames aren't called directly and have special return value processing (in NATIVERETURN.execute())
204   @Override
205   public void setArgumentLocal (int idx, int value, Object attr){
206     throw new JPFException("NativeStackFrames don't support setting argument locals");
207   }
208   @Override
209   public void setLongArgumentLocal (int idx, long value, Object attr){
210     throw new JPFException("NativeStackFrames don't support setting argument locals");    
211   }
212   @Override
213   public void setReferenceArgumentLocal (int idx, int ref, Object attr){
214     throw new JPFException("NativeStackFrames don't support setting argument locals");
215   }
216   
217   //--- exception refs
218   @Override
219   public void setExceptionReference (int exRef){
220     throw new JPFException("NativeStackFrames don't support exception handlers");    
221   }
222
223   @Override
224   public int getExceptionReference (){
225     throw new JPFException("NativeStackFrames don't support exception handlers");    
226   }
227
228   @Override
229   public void setExceptionReferenceAttribute (Object attr){
230     throw new JPFException("NativeStackFrames don't support exception handlers");    
231   }
232   
233   @Override
234   public Object getExceptionReferenceAttribute (){
235     throw new JPFException("NativeStackFrames don't support exception handlers");    
236   }
237   
238   @Override
239   public int getResult(){
240     Object r = ret;
241     
242     if (r instanceof Number){
243       if (r instanceof Double){
244         throw new JPFException("result " + ret + " can't be converted into int");    
245       } else if (r instanceof Float){
246         return Float.floatToIntBits((Float)r);
247       } else {
248         return ((Number)r).intValue();
249       }
250     } else if (r instanceof Boolean){
251       return (r == Boolean.TRUE) ? 1 : 0;
252     } else {
253       throw new JPFException("result " + ret + " can't be converted into raw int value");
254     }
255   }
256   
257   @Override
258   public int getReferenceResult(){
259     if (ret instanceof Integer){
260       return (Integer)ret; // MJI requires references to be returned as 'int'
261     } else {
262       throw new JPFException("result " + ret + " can't be converted into JPF refrence value");      
263     }
264   }
265   
266   @Override
267   public long getLongResult(){
268     Object r = ret;
269     if (r instanceof Long){
270       return (Long)r;
271     } else if (r instanceof Double){
272       return Double.doubleToLongBits((Double)r);
273     } else {
274       throw new JPFException("result " + ret + " can't be converted into raw long value");      
275     }
276   }
277   
278   @Override
279   public Object getResultAttr(){
280     return retAttr;
281   }
282   @Override
283   public Object getLongResultAttr(){
284     return retAttr;    
285   }
286 }