// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.util.Iterator; import java.util.Stack; import gov.nasa.jpf.Config; /** * This class represents the SUT program state (statics, heap and threads) */ public class KernelState implements Restorable<KernelState> { /** The area containing the heap */ public Heap heap; /** The list of the threads */ public ThreadList threads; /** the list of the class loaders */ public ClassLoaderList classLoaders; /** * current listeners waiting for notification of next change. */ private Stack<ChangeListener> listeners = new Stack<ChangeListener>(); static class KsMemento implements Memento<KernelState> { // note - order does matter: threads need to be restored before the heap Memento<ThreadList> threadsMemento; Memento<ClassLoaderList> cloadersMemento; Memento<Heap> heapMemento; KsMemento (KernelState ks){ threadsMemento = ks.threads.getMemento(); cloadersMemento = ks.classLoaders.getMemento(); heapMemento = ks.heap.getMemento(); } public KernelState restore (KernelState ks) { // those are all in-situ objects, no need to set them in ks threadsMemento.restore(ks.threads); cloadersMemento.restore(ks.classLoaders); heapMemento.restore(ks.heap); return ks; } } /** * Creates a new kernel state object. */ public KernelState (Config config) { Class<?>[] argTypes = { Config.class, KernelState.class }; Object[] args = { config, this }; classLoaders = new ClassLoaderList(); heap = config.getEssentialInstance("vm.heap.class", Heap.class, argTypes, args); threads = config.getEssentialInstance("vm.threadlist.class", ThreadList.class, argTypes, args); } public Memento<KernelState> getMemento(MementoFactory factory) { return factory.getMemento(this); } public Memento<KernelState> getMemento(){ return new KsMemento(this); } /** * Adds the given loader to the list of existing class loaders. */ public void addClassLoader(ClassLoaderInfo cl) { classLoaders.add(cl); } /** * Returns the ClassLoader with the given globalId */ protected ClassLoaderInfo getClassLoader(int gid) { Iterator<ClassLoaderInfo> it = classLoaders.iterator(); while(it.hasNext()) { ClassLoaderInfo cl = it.next(); if(cl.getId() == gid) { return cl; } } return null; } public Heap getHeap() { return heap; } public ThreadList getThreadList() { return threads; } public ClassLoaderList getClassLoaderList() { return classLoaders; } /** * interface for getting notified of changes to KernelState and everything * "below" it. */ public interface ChangeListener { void kernelStateChanged(KernelState ks); } /** * called by internals to indicate a change in KernelState. list of listeners * is emptied. */ public void changed() { while (!listeners.empty()) { listeners.pop().kernelStateChanged(this); } } /** * push a listener for notification of the next change. further notification * requires re-pushing. */ public void pushChangeListener(ChangeListener cl) { if (cl instanceof IncrementalChangeTracker && listeners.size() > 0) { for (ChangeListener l : listeners) { if (l instanceof IncrementalChangeTracker) { throw new IllegalStateException("Only one IncrementalChangeTracker allowed!"); } } } listeners.push(cl); } public int getThreadCount () { return threads.length(); } public void gc () { heap.gc(); // we might have stored stale references in live objects // (outside of reference fields) // <2do> get rid of this by storing objects instead of ref/id values that are reused heap.cleanUpDanglingReferences(); cleanUpDanglingStaticReferences(); } private void cleanUpDanglingStaticReferences() { for(ClassLoaderInfo cl: classLoaders) { Statics sa = cl.getStatics(); sa.cleanUpDanglingReferences(heap); } } }