Initial import
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / bytecode / INVOKESTATIC.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
21 import gov.nasa.jpf.vm.ClassInfo;
22 import gov.nasa.jpf.vm.ClassLoaderInfo;
23 import gov.nasa.jpf.vm.ElementInfo;
24 import gov.nasa.jpf.vm.Instruction;
25 import gov.nasa.jpf.vm.LoadOnJPFRequired;
26 import gov.nasa.jpf.vm.MethodInfo;
27 import gov.nasa.jpf.vm.StaticElementInfo;
28 import gov.nasa.jpf.vm.ThreadInfo;
29 import gov.nasa.jpf.vm.Types;
30
31
32 /**
33  * Invoke a class (static) method
34  * ..., [arg1, [arg2 ...]]  => ...
35  */
36 public class INVOKESTATIC extends JVMInvokeInstruction {
37   ClassInfo ci;
38   
39   protected INVOKESTATIC (String clsDescriptor, String methodName, String signature){
40     super(clsDescriptor, methodName, signature);
41   }
42
43   protected ClassInfo getClassInfo () {
44     if (ci == null) {
45       ci = ClassLoaderInfo.getCurrentResolvedClassInfo(cname);
46     }
47     return ci;
48   }
49   
50   @Override
51   public int getByteCode () {
52     return 0xB8;
53   }
54
55   @Override
56   public String toPostExecString(){
57     StringBuilder sb = new StringBuilder();
58     sb.append(getMnemonic());
59     sb.append(' ');
60     sb.append( invokedMethod.getFullName());
61
62     if (invokedMethod.isMJI()){
63       sb.append(" [native]");
64     }
65     
66     return sb.toString();
67
68   }
69   
70   public StaticElementInfo getStaticElementInfo (){
71     return getClassInfo().getStaticElementInfo();
72   }
73
74   public int getClassObjectRef(){
75     return getClassInfo().getStaticElementInfo().getClassObjectRef();
76   }
77
78   @Override
79   public Instruction execute (ThreadInfo ti) {
80     MethodInfo callee;
81     
82     try {
83       callee = getInvokedMethod(ti);
84     } catch (LoadOnJPFRequired lre) {
85       return ti.getPC();
86     }
87         
88     if (callee == null) {
89       return ti.createAndThrowException("java.lang.NoSuchMethodException", cname + '.' + mname);
90     }
91
92     // this can be actually different than (can be a base)
93     ClassInfo ciCallee = callee.getClassInfo();
94     
95     if (ciCallee.initializeClass(ti)) {
96       // do class initialization before continuing
97       // note - this returns the next insn in the topmost clinit that just got pushed
98       return ti.getPC();
99     }
100
101     if (callee.isSynchronized()) {
102       ElementInfo ei = ciCallee.getClassObject();
103       ei = ti.getScheduler().updateObjectSharedness(ti, ei, null); // locks most likely belong to shared objects
104       
105       if (reschedulesLockAcquisition(ti, ei)){
106         return this;
107       }
108     }
109         
110     setupCallee( ti, callee); // this creates, initializes and pushes the callee StackFrame
111
112     return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception
113   }
114
115   @Override
116   public MethodInfo getInvokedMethod(){
117     if (invokedMethod != null){
118       return invokedMethod;
119     } else {
120       // Hmm, this would be pre-exec, but if the current thread is not the one executing the insn 
121       // this might result in false sharedness of the class object
122       return getInvokedMethod( ThreadInfo.getCurrentThread());
123     }
124   }
125   
126   @Override
127   public MethodInfo getInvokedMethod (ThreadInfo ti){
128     if (invokedMethod == null) {
129       ClassInfo clsInfo = getClassInfo();
130       if (clsInfo != null){
131         MethodInfo callee = clsInfo.getMethod(mname, true);
132         if (callee != null){
133           ClassInfo ciCallee = callee.getClassInfo(); // might be a superclass of ci, i.e. not what is referenced in the insn
134
135           if (!ciCallee.isRegistered()){
136             // if it wasn't registered yet, classLoaded listeners didn't have a chance yet to modify it..
137             ciCallee.registerClass(ti);
138             // .. and might replace/remove MethodInfos
139             callee = clsInfo.getMethod(mname, true);
140           }
141           invokedMethod = callee;
142         }
143       }    
144     }
145     return invokedMethod;
146   }
147   
148   // can be different thatn the ci - method can be in a superclass
149   public ClassInfo getInvokedClassInfo(){
150     return getInvokedMethod().getClassInfo();
151   }
152
153   public String getInvokedClassName(){
154     return getInvokedClassInfo().getName();
155   }
156
157   @Override
158   public int getArgSize () {
159     if (argSize < 0) {
160       argSize = Types.getArgumentsSize(signature);
161     }
162
163     return argSize;
164   }
165
166   
167   @Override
168   public String toString() {
169     // methodInfo not set outside real call context (requires target object)
170     return "invokestatic " + cname + '.' + mname;
171   }
172
173   @Override
174   public Object getFieldValue (String id, ThreadInfo ti) {
175     return getClassInfo().getStaticFieldValueObject(id);
176   }
177   
178   @Override
179   public void accept(JVMInstructionVisitor insVisitor) {
180           insVisitor.visit(this);
181   }
182
183   @Override
184   public Instruction typeSafeClone(MethodInfo mi) {
185     INVOKESTATIC clone = null;
186
187     try {
188       clone = (INVOKESTATIC) super.clone();
189
190       // reset the method that this insn belongs to
191       clone.mi = mi;
192
193       clone.invokedMethod = null;
194       clone.lastObj = Integer.MIN_VALUE;
195       clone.ci = null;
196     } catch (CloneNotSupportedException e) {
197       e.printStackTrace();
198     }
199
200     return clone;
201   }
202 }
203