Initial import
[jpf-core.git] / src / main / gov / nasa / jpf / jvm / bytecode / INVOKECLINIT.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.ClassInfo;
21 import gov.nasa.jpf.vm.ElementInfo;
22 import gov.nasa.jpf.vm.Instruction;
23 import gov.nasa.jpf.vm.MethodInfo;
24 import gov.nasa.jpf.vm.ThreadInfo;
25
26 /**
27  * this is an artificial bytecode that we use to deal with the particularities of 
28  * <clinit> calls, which are never in the loaded bytecode but always directly called by
29  * the VM. The most obvious difference is that <clinit> execution does not trigger
30  * class initialization.
31  * A more subtle difference is that we save a wait() - if a class
32  * is concurrently initialized, both enter INVOKECLINIT (i.e. compete and sync for/on
33  * the class object lock), but once the second thread gets resumed and detects that the
34  * class is now initialized (by the first thread), it skips the method execution and
35  * returns right away (after deregistering as a lock contender). That's kind of hackish,
36  * but we have no method to do the wait in, unless we significantly complicate the
37  * direct call stubs, which would obfuscate observability (debugging dynamically
38  * generated code isn't very appealing). 
39  */
40 public class INVOKECLINIT extends INVOKESTATIC {
41
42   public INVOKECLINIT (ClassInfo ci){
43     super(ci.getSignature(), "<clinit>", "()V");
44   }
45
46   @Override
47   public Instruction execute (ThreadInfo ti) {    
48     MethodInfo callee = getInvokedMethod(ti);
49     ClassInfo ciClsObj = callee.getClassInfo();
50     ElementInfo ei = ciClsObj.getClassObject();
51
52     if (ciClsObj.isInitialized()) { // somebody might have already done it if this is re-executed
53       if (ei.isRegisteredLockContender(ti)){
54         ei = ei.getModifiableInstance();
55         ei.unregisterLockContender(ti);
56       }
57       return getNext();
58     }
59
60     // not much use to update sharedness, clinits are automatically synchronized
61     if (reschedulesLockAcquisition(ti, ei)){     // this blocks or registers as lock contender
62       return this;
63     }
64     
65     // if we get here we still have to execute the clinit method
66     setupCallee( ti, callee); // this creates, initializes & pushes the callee StackFrame, then acquires the lock
67     ciClsObj.setInitializing(ti);
68
69     return ti.getPC(); // we can't just return the first callee insn if a listener throws an exception
70   }
71
72   @Override
73   public boolean isExtendedInstruction() {
74     return true;
75   }
76
77   public static final int OPCODE = 256;
78
79   @Override
80   public int getByteCode () {
81     return OPCODE;
82   }
83   
84   @Override
85   public void accept(JVMInstructionVisitor insVisitor) {
86           insVisitor.visit(this);
87   }
88 }