Fixing a few bugs in the statistics printout.
[jpf-core.git] / src / main / gov / nasa / jpf / vm / KernelState.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.vm;
19
20 import gov.nasa.jpf.Config;
21 import java.util.Iterator;
22 import java.util.Stack;
23
24
25 /**
26  * This class represents the SUT program state (statics, heap and threads)
27  */
28 public class KernelState implements Restorable<KernelState> {
29
30   /** The area containing the heap */
31   public Heap heap;
32
33   /** The list of the threads */
34   public ThreadList threads;
35
36   /** the list of the class loaders */
37   public ClassLoaderList classLoaders;
38
39   /**
40    * current listeners waiting for notification of next change.
41    */
42   private Stack<ChangeListener> listeners = new Stack<ChangeListener>();
43
44
45   static class KsMemento implements Memento<KernelState> {
46     // note - order does matter: threads need to be restored before the heap
47     Memento<ThreadList> threadsMemento;
48     Memento<ClassLoaderList> cloadersMemento;
49     Memento<Heap> heapMemento;
50
51     KsMemento (KernelState ks){
52       threadsMemento = ks.threads.getMemento();
53       cloadersMemento = ks.classLoaders.getMemento();
54       heapMemento = ks.heap.getMemento();
55     }
56
57     @Override
58         public KernelState restore (KernelState ks) {
59       // those are all in-situ objects, no need to set them in ks
60       threadsMemento.restore(ks.threads);
61       cloadersMemento.restore(ks.classLoaders);
62       heapMemento.restore(ks.heap);
63
64       return ks;
65     }
66   }
67
68   /**
69    * Creates a new kernel state object.
70    */
71   public KernelState (Config config) {
72     Class<?>[] argTypes = { Config.class, KernelState.class };
73     Object[] args = { config, this };
74
75     classLoaders = new ClassLoaderList();  
76     heap = config.getEssentialInstance("vm.heap.class", Heap.class, argTypes, args);
77     threads = config.getEssentialInstance("vm.threadlist.class", ThreadList.class, argTypes, args);
78   }
79
80   @Override
81   public Memento<KernelState> getMemento(MementoFactory factory) {
82     return factory.getMemento(this);
83   }
84
85   public Memento<KernelState> getMemento(){
86     return new KsMemento(this);
87   }
88
89   /**
90    * Adds the given loader to the list of existing class loaders. 
91    */
92   public void addClassLoader(ClassLoaderInfo cl) {
93     classLoaders.add(cl);
94   }
95
96   /**
97    * Returns the ClassLoader with the given globalId
98    */
99   protected ClassLoaderInfo getClassLoader(int gid) {
100     Iterator<ClassLoaderInfo> it = classLoaders.iterator();
101
102     while(it.hasNext()) {
103       ClassLoaderInfo cl = it.next();
104       if(cl.getId() == gid) {
105         return cl;
106       }
107     }
108
109     return null;
110   }
111
112   public Heap getHeap() {
113     return heap;
114   }
115
116   public ThreadList getThreadList() {
117     return threads;
118   }
119
120   public ClassLoaderList getClassLoaderList() {
121     return classLoaders;
122   }
123   
124   /**
125    * interface for getting notified of changes to KernelState and everything
126    * "below" it.
127    */
128   public interface ChangeListener {
129     void kernelStateChanged(KernelState ks);
130   }
131
132   /**
133    * called by internals to indicate a change in KernelState.  list of listeners
134    * is emptied.
135    */
136   public void changed() {
137     while (!listeners.empty()) {
138       listeners.pop().kernelStateChanged(this);
139     }
140   }
141
142   /**
143    * push a listener for notification of the next change.  further notification
144    * requires re-pushing.
145    */
146   public void pushChangeListener(ChangeListener cl) {
147     if (cl instanceof IncrementalChangeTracker && listeners.size() > 0) {
148       for (ChangeListener l : listeners) {
149         if (l instanceof IncrementalChangeTracker) {
150           throw new IllegalStateException("Only one IncrementalChangeTracker allowed!");
151         }
152       }
153     }
154     listeners.push(cl);
155   }
156
157   public int getThreadCount () {
158     return threads.length();
159   }
160
161   public void gc () {
162         
163     heap.gc();
164
165     // we might have stored stale references in live objects
166     // (ElementInfos on the heap have already been cleaned up in the gc)
167     cleanUpDanglingStaticReferences();
168   }
169
170   
171   
172   private void cleanUpDanglingStaticReferences() {
173     for(ClassLoaderInfo cl: classLoaders) {
174       Statics sa = cl.getStatics();
175       sa.cleanUpDanglingReferences(heap);
176     }
177   }
178 }