2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
18 package gov.nasa.jpf.search;
20 import gov.nasa.jpf.Config;
21 import gov.nasa.jpf.ConfigChangeListener;
22 import gov.nasa.jpf.Error;
23 import gov.nasa.jpf.JPF;
24 import gov.nasa.jpf.JPFException;
25 import gov.nasa.jpf.JPFListenerException;
26 import gov.nasa.jpf.Property;
27 import gov.nasa.jpf.State;
28 import gov.nasa.jpf.report.Reporter;
29 import gov.nasa.jpf.util.IntVector;
30 import gov.nasa.jpf.util.JPFLogger;
31 import gov.nasa.jpf.util.Misc;
32 import gov.nasa.jpf.vm.VM;
33 import gov.nasa.jpf.vm.Path;
34 import gov.nasa.jpf.vm.ThreadList;
35 import gov.nasa.jpf.vm.Transition;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.concurrent.atomic.AtomicBoolean;
42 * The {@code Search} abstract class is at the heart of all search classes. Even when it is not extended by child classes, it will
43 * be embedded in the logic as an input for some of the methods.
45 * <p>The main purpose of the {@code Search} class is to track general search information such as depth, configured properties,
46 * errors, etc. as well as to define how the search algorithm functions. In its simplest form, a search algorithm can be defined
47 * using the abstract method {@code search} with a series of {@code forward} and {@code backtrack}. More complex search
48 * algorithms can also make use of the state storing functionality of the {@code Search} class, as well as ignoring states and
49 * removing states from the search tree.
51 * <p>Another very important aspect of the {@code Search} class is not only to implement search algorithms, but also to define
52 * the information that describes the current search loop. This is crucial in order to enable the {@code SearchListener} and
53 * {@code SearchListenerAdapter} classes responsible for extracting crucial data from the search loop during its verification
56 public abstract class Search {
58 /** The {@code JPFLogger} object assigned to the {@code gov.nasa.jpf.search} subsystem
59 * @see gov.nasa.jpf.util.JPFLogger
61 protected static JPFLogger log = JPF.getLogger("gov.nasa.jpf.search");
63 /** The value of {@code currentError} will either be the error encountered during last
64 * transition or null if no error was encountered */
65 protected Error currentError = null;
67 /** A running list of all errors encountered during verification. The list will always
68 * contain the current and past values of {@code currentError}. Errors are set added
69 * during verification in the {@code error}
72 * <p>{@code errors} will only hold one error before verification stops unless {@code getAllErrors}
75 * @see #error(Property, Path, ThreadList)
78 protected ArrayList<Error> errors = new ArrayList<Error>();
80 /** {@code depth} represents the current depth of the search tree. */
81 protected int depth = 0;
82 /** {@code vm} represents the virtual machine that the search algorithm will be traversing*/
85 /** A list of properties provided from the search configuration at the start of verification. Every property has a {@code check}
86 * method that will be used during verification to tell if any of the properties have been violated.*/
87 protected ArrayList<Property> properties;
89 /** A property set by the user before verification. If {@code matchDepth} is true it will change the behavior of
90 * {@code isNewState()}.
91 * @see #isNewState() */
92 protected boolean matchDepth;
93 /** A property set by the user to define what the minimum memory required to keep verifying is. The reason this is a non-zero
94 * value is to ensure some memory is left over to output a legible message before ending execution instead of simply throwing
95 * an {@code OutOfMemoryError}.
97 * <p> The default value for {@code minFreeMemory} is 1024 << 10 bytes. */
98 protected long minFreeMemory;
99 /** A property set by the user to define what the maximum depth allowed during verification is.
101 * <p>By default the value is set to {@code Integer.MAX_VALUE}*/
102 protected int depthLimit;
104 /** A property set by the user to define whether to halt execution after encountering the first error during verification.
105 * If {@code getAllErrors} is set to true, verification will not stop after the first error, and every possible error
106 * during verification will be logged as a result. */
107 protected boolean getAllErrors;
109 /** A {@code String} set to contain details on what the constraint that caused verification to halt was. Will generally be
110 * used by the {@code searchContraintHit} methods in {@code SearchListeners}.
112 * @see gov.nasa.jpf.search.SearchListener#searchConstraintHit(Search) */
113 protected String lastSearchConstraint;
115 /** {@code done} is a flag set during verification to notify the search loop when verification has finished. */
116 protected boolean done = false;
117 /** {@code doBacktrack} is a flag set during verification in order to request that the search loop backtracks
119 protected boolean doBacktrack = false;
121 /** {@code notifyProbeListeners} is a flag set during verification stating whether or not a probe has been
122 * requested. When a probe is requested, relevant {@code SearchListeners} will be notified via {@code checkAndResetProbeRequest}*/
123 protected AtomicBoolean notifyProbeListeners = new AtomicBoolean(false);
125 /** {@code listeners} is an array used to hold {@code SearchListener} objects. We keep them in a simple array to avoid
126 creating objects on each notification */
127 protected SearchListener[] listeners = new SearchListener[0];
129 /** {@code reporter} is a special listener that is always notified last in order to ensure all other listeners have been notified
130 * beforehand. {@code reporter} is used to report information about the search loop to whichever output method the user has
133 * <p>By default, the output method is to console.*/
134 protected Reporter reporter;
136 /** {@code config} is an object passed in during instantiation of the {@code Search} object and it specifies the properties and
137 * configurations the search loop should run under. The value behind {@code config} is only ever used once and stored within this
139 protected final Config config;
142 * {@code ConfigListener} is an implementation of the interface {@code ConfigChangeListener} and is used to subscribe to changes
143 * that occur to the configuration of JPF in order to update the {@code config} object. While highly useful, one should always
144 * remember to unregister the {@code config} object from each {@code ConfigListener} once it is no longer needed. Failure to
145 * do this will cause massive memory leaks to begin piling up as a result of the same {@code Config} object being used across
146 * several JPF executions.
149 class ConfigListener implements ConfigChangeListener {
152 public void propertyChanged(Config config, String key, String oldValue, String newValue) {
153 // Different Config instance
154 if (!config.equals(Search.this.config)) {
158 // Check if Search configuration changed
159 if (key.startsWith("search.")){
160 String k = key.substring(7);
161 if ("match_depth".equals(k) ||
162 "min_free".equals(k) ||
163 "multiple_errors".equals(k)){
170 public void jpfRunTerminated (Config config){
171 config.removeChangeListener(this);
175 /** {@code stateDepth} is an int vector storage system (akin to a map) that is responsible for associating states with their
176 * corresponding depths.
178 * <p>{@code stateDepth} maps the state id of every state to the corresponding depth, in a one to one mapping.*/
179 protected final IntVector stateDepth = new IntVector();
182 * Constructs a {@code Search} object using the configuration specified by the user in {@code config} and a virtual machine
183 * that will be used for verification.
185 * @param config The configuration and properties that the search loop will be required to commence verification under
186 * @param vm The virtual machine that the search loop will traverse and verify states from
188 protected Search (Config config, VM vm) {
190 this.config = config;
194 properties = getProperties(config);
195 if (properties.isEmpty()) {
196 log.severe("no property");
199 config.addChangeListener( new ConfigListener());
203 * Initializes the properties that the search loop will need to run under in order to make sure that each iteration of the search
204 * loop is in compliance with the properties set by JPF and the user.
206 * @param conf The configuration object ({@code config}) that contains the necessary information to initialize the property values
208 protected void initialize( Config conf){
209 depthLimit = conf.getInt("search.depth_limit", Integer.MAX_VALUE);
210 matchDepth = conf.getBoolean("search.match_depth");
211 minFreeMemory = conf.getMemorySize("search.min_free", 1024<<10);
212 getAllErrors = conf.getBoolean("search.multiple_errors");
216 * Called after the JPF run is finished. Should not be public, but is called by JPF
218 public void cleanUp(){
219 // nothing here, the ConfigListener removes itself
223 * Returns the {@code config} object that is used by the {@code Search} class.
225 * @return The configuration object that is used for verification
227 public Config getConfig() {
232 * One of the most important methods in the {@code Search} class. {@code search} is used to specify what the algorithm and behavior
233 * for verification are. When the term "search loop" is brought up in other documentation, it generally means the loop that is used
234 * running in the {@code search} method.
236 public abstract void search ();
239 * Sets the {@code reporter} object used during verification to the specified {@code reporter}.
241 * @param reporter The reporter used to replace the current reporter object in the {@code Search} class
243 public void setReporter(Reporter reporter){
244 this.reporter = reporter;
248 * Appends a {@code SearchListener} object to the {@code listener} array. In addition to appending the search listener, the action is also logged
249 * to the JPFLog {@code log} used in the {@code Search} class.
251 * @param newListener A new {@code SearchListener} to append to the {@code listener} array
253 public void addListener (SearchListener newListener) {
254 log.info("SearchListener added: ", newListener);
255 listeners = Misc.appendElement(listeners, newListener);
259 * Checks whether a listener of the same type as {@code listenerCls} exists in {@code listeners} already.
261 * @param listenerCls The object type to check {@code listeners} against
262 * @return true if an element of the same type as the input parameter exists in {@code listeners}. False otherwise
264 public boolean hasListenerOfType (Class<?> listenerCls) {
265 return Misc.hasElementOfType(listeners, listenerCls);
269 * Returns the next element in {@code listeners} after the element matching {@code prev} that is of the same type as {@code type}.
271 * @param type The type of element to search for and return
272 * @param prev The previous element to begin the search from
273 * @return An element of the same class as {@code type} and coming after {@code prev} in the {@code listeners} array
275 public <T> T getNextListenerOfType(Class<T> type, T prev){
276 return Misc.getNextElementOfType(listeners, type, prev);
280 * Remove the specified {@code SearchListener} from the {@code listeners} array.
282 * @param removeListener The element to remove from the {@code listeners} array
284 public void removeListener (SearchListener removeListener) {
285 listeners = Misc.removeElement(listeners, removeListener);
289 * Add a new property to {@code properties}
291 * @param newProperty The property to add to {@code properties}
293 public void addProperty (Property newProperty) {
294 properties.add(newProperty);
298 * Remove the specified property from {@code properties}
300 * @param oldProperty The property to remove from {@code properties}
302 public void removeProperty (Property oldProperty) {
303 properties.remove(oldProperty);
307 * Returns the list of configured properties.
309 * <p>Note there is a name clash here - JPF 'properties' have nothing to do with Java properties (java.util.Properties)
311 * @param config The config object to retrieve the properties list from
312 * @return The list of configured properties
314 protected ArrayList<Property> getProperties (Config config) {
315 Class<?>[] argTypes = { Config.class, Search.class };
316 Object[] args = { config, this };
318 ArrayList<Property> list = config.getInstances("search.properties", Property.class,
325 * Check for property violations and return true if a property is violated and the search loop has finished running (i.e. {@code done}
326 * is set to true). Returns false otherwise.
328 * @return true if an a property has been violated (i.e. {@code currentError} is not null) and {@code done} is true
330 protected boolean hasPropertyTermination () {
331 if (currentError != null){
334 } else { // we search for multiple errors, so we ignore and go on
343 * Iterates through {@code properties} and checks for property violations. {@code checkPropertyViolation} should only be
344 * called once per transition to avoid it adding the same error every time it is called.
346 * @return true if a property violation is found, false otherwise
348 protected boolean checkPropertyViolation () {
349 for (Property p : properties) {
350 if (!p.check(this, vm)) {
351 error(p, vm.getClonedPath(), vm.getThreadList());
360 * Returns the list of errors encountered during verification
362 * @return The list of errors encountered during verification
364 public List<Error> getErrors () {
369 * Returns the number of errors encountered during verification. Will always return 1 if {@code getAllErrors} is false
371 * @return The number of errors encountered during verification
373 public int getNumberOfErrors(){
374 return errors.size();
378 * Returns the search constraint that was most recently encountered
380 * @return A String detailing the search constraint most recently hit or null if none was encountered
382 public String getLastSearchConstraint() {
383 return lastSearchConstraint;
389 * <p>This does not perform the actual listener notification, it only stores
390 * the request, which is then processed from within JPFs inner execution loop.
391 * As a consequence, {@code probeSearch} can be called asynchronously, and {@code searchProbed} listeners
392 * don't have to bother with synchronization or inconsistent JPF states (notification
393 * happens from within JPFs main thread after a completed Instruction execution)
395 public void probeSearch(){
396 notifyProbeListeners.set(true);
400 * Performs the actual notification and resets the request, hence this call should only happen from within JPFs main thread
402 public void checkAndResetProbeRequest(){
403 if (notifyProbeListeners.compareAndSet(true, false)){
404 notifySearchProbed();
409 * Returns the most recent error encountered during the last transition
411 * @return The error encountered during the last transition or null if none was encountered
413 public Error getCurrentError(){
418 * Returns the most recent error encountered in the past
420 * @return The most recent error encountered in the past or none if no error has been encountered during verification
422 public Error getLastError() {
423 int i=errors.size()-1;
425 return errors.get(i);
432 * Returns whether or not the search loop has encountered an error yet
434 * @return true if an error has been encountered, false otherwise
436 public boolean hasErrors(){
437 return !errors.isEmpty();
441 * Returns the {@code vm} object used by the search loop
443 * @return the {@code vm} object used by {@code Search}
450 * Returns true if the search loop has transitioned into an end state in the virtual machine
452 * @return true if the current state of the {@code vm} is an end state
454 public boolean isEndState () {
455 return vm.isEndState();
459 * Returns if an error has been encountered during the transition into the current state
461 * @return true if an error has been encountered during the most recent transition, false otherwise
463 public boolean isErrorState(){
464 return (currentError != null);
468 * Returns whether of not the current state is an end state in the virtual machine
470 * @return true if this is not an end state of the {@code vm}, false otherwise
472 public boolean hasNextState () {
473 return !isEndState();
477 * Returns whether a transition has occurred from the previous state or not
479 * @return true if a transition has occurred, false otherwise
481 public boolean transitionOccurred(){
482 return vm.transitionOccurred();
486 * Returns whether the current state in the search loop is a new state and false otherwise.
488 * <p>However, if {@code matchDepth} is set to true,
489 * then it will true if the state is new or if the states depth is less than the previously recorded depth. If the state is new, the states
490 * depth will also be recorded for future use.
492 * @return true if the current state is a new state and false otherwise (behaviour changes if {@code matchDepth} is true
494 public boolean isNewState () {
495 boolean isNew = vm.isNewState();
498 int id = vm.getStateId();
501 setStateDepth(id, depth);
503 return depth < getStateDepth(id);
511 * Returns whether the current state has been visited yet. The opposite of {@code isNewState}
513 * @return true if the state has been visited, false otherwise (behavior changes if {@code matchDepth} is true)
516 public boolean isVisitedState () {
517 return !isNewState();
521 * Returns whether the current state is an ignored state in the virtual machine
523 * @return true if the current state is an ignored state, false otherwise
525 public boolean isIgnoredState(){
526 return vm.isIgnoredState();
530 * Returns whether the current state has been fully explored by the search loop.
532 * @return true if the current state has been fully explored and processed, false otherwise
534 public boolean isProcessedState(){
535 return vm.getChoiceGenerator().isProcessed();
539 * Return whether the search loop has finished verification
541 * @return true if the search loop has finished verification, false otherwise
543 public boolean isDone(){
548 * Return the current depth of the search loop
550 * @return The current depth inside the search tree.
552 public int getDepth () {
557 * Returns the most recent search constraint that was encountered
559 * @return A String detailing the most recent search constraint that was encountered
561 public String getSearchConstraint () {
562 return lastSearchConstraint;
566 * Returns the most recent transition that has occurred
568 * @return The last transition that occurred during verification, or null if none has occurred
570 public Transition getTransition () {
571 return vm.getLastTransition();
575 * Returns the state id of the current state
577 * @return The state id of the current state
579 public int getStateId () {
580 return vm.getStateId();
584 * Returns the purged states id
586 * <p>Note that while it should return the purged states id, it currently only returns -1 as a
587 * result of many searches not utilizing this functionality. If it is required, {@code getPurgedStateId}
588 * should be overridden and changed in subsequent child classes.
590 * @return The purged states id (currently only returns -1)
592 public int getPurgedStateId () {
593 return -1; // a lot of Searches don't purge any states
598 * Requests that the search loop backtracks one step
600 * <p>This is somewhat redundant to {@code SystemState.setIgnored}, but we don't
601 * want to mix the case of overriding state matching with backtracking when
602 * searching for multiple errors.
604 * @return The value of {@code doBacktrack} after is has been set to true (i.e. always true)
606 public boolean requestBacktrack () {
607 return doBacktrack = true;
611 * Returns the value of {@code doBacktrack} as well as resetting {@code doBacktrack} to false
613 * @return the value of {@code doBackTrack}
615 protected boolean checkAndResetBacktrackRequest() {
625 * Returns whether the search algorithm supports backtracking or not
627 * @return true if the search algorithm supports backtracking, false otherwise (by default the return
628 * is true unless overridden)
630 public boolean supportsBacktrack () {
635 * Returns whether the search algorithm supports restoring states that have been stored (a useful method in
636 * BreadthFirstSearch)
638 * @return true if the search algorithm supports restoring states, false otherwise (by default the return
639 * is false as the function is unsupported)
641 public boolean supportsRestoreState () {
642 // not supported by default
647 * Returns the depth limit set at the beginning of verification
649 * @return The {@code depthLimit} property
651 public int getDepthLimit () {
656 * Sets a new value for the {@code depthLimit} property
658 * @param limit The new limit to set {@code depthLimit} to
660 public void setDepthLimit(int limit){
665 * Returns a {@code SearchState} object with information describing the current state in the search loop
667 * @return A {@code SearchState} object with information about the current state
669 protected SearchState getSearchState () {
670 return new SearchState(this);
674 * Creates a new error with the corresponding {@code Property} that causes the error. Does not provide a {@code Path} or {@code ThreadList}, and
675 * can therefore be used by {@code SearchListeners} to create path-less errors to ensure liveness.
677 * @param property the property that caused the error
678 * @see #error(Property, Path, ThreadList)
680 public void error (Property property) {
681 error(property, null, null);
685 * Creates an error with the corresponding {@code Property} that causes the error, alongside the {@code Path}, and {@code ThreadList}.
687 * <p>Will set {@code done} to true and halt the search loop if {@code getAllErrors} is false. If {@code getAllErrors} is true, it will
688 * clone the {@code Property}, {@code Path}, and {@code ThreadList} objects that were passed in (as not cloning them may cause subsequent
689 * operations to overwrite information still in use) and add them to the {@code errors} list
690 * and continue verification.
692 * <p>The property that caused the error is not reset here as the listeners attached to the search should be notified of the error first.
693 * This becomes especially problematic if one of the listeners caused the property violation, as which point it would get confused
694 * if the {@code propertyViolated()} notification happens after the property is reset.
696 * @param property The property that causes the error
697 * @param path The path corresponding to the error
698 * @param threadList The list of thread information corresponding to the error
700 public void error (Property property, Path path, ThreadList threadList) {
703 // otherwise we are going to overwrite it if we go on
705 property = property.clone();
707 threadList = (ThreadList) threadList.clone(); // this makes it a snapshot (deep) clone
708 } catch (CloneNotSupportedException cnsx){
709 throw new JPFException("failed to clone error information: " + cnsx);
717 currentError = new Error(errors.size()+1, property, path, threadList);
719 errors.add(currentError);
724 * Resets all properties, returning violated properties to their default states.
726 public void resetProperties(){
727 for (Property p : properties) {
733 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has advanced states.
735 protected void notifyStateAdvanced () {
737 for (int i = 0; i < listeners.length; i++) {
738 listeners[i].stateAdvanced(this);
740 if (reporter != null){
741 // reporter always comes last to ensure all listeners have been notified
742 reporter.stateAdvanced(this);
744 } catch (Throwable t) {
745 throw new JPFListenerException("exception during stateAdvanced() notification", t);
750 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has finished processing
753 protected void notifyStateProcessed() {
755 for (int i = 0; i < listeners.length; i++) {
756 listeners[i].stateProcessed(this);
758 if (reporter != null){
759 reporter.stateProcessed(this);
761 } catch (Throwable t) {
762 throw new JPFListenerException("exception during stateProcessed() notification", t);
767 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has stored the current state.
769 protected void notifyStateStored() {
771 for (int i = 0; i < listeners.length; i++) {
772 listeners[i].stateStored(this);
774 if (reporter != null){
775 reporter.stateStored(this);
777 } catch (Throwable t) {
778 throw new JPFListenerException("exception during stateStored() notification", t);
783 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has restored a currently
786 protected void notifyStateRestored() {
788 for (int i = 0; i < listeners.length; i++) {
789 listeners[i].stateRestored(this);
791 if (reporter != null){
792 reporter.stateRestored(this);
794 } catch (Throwable t) {
795 throw new JPFListenerException("exception during stateRestored() notification", t);
800 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has backtracked to a
803 protected void notifyStateBacktracked() {
805 for (int i = 0; i < listeners.length; i++) {
806 listeners[i].stateBacktracked(this);
808 if (reporter != null){
809 reporter.stateBacktracked(this);
811 } catch (Throwable t) {
812 throw new JPFListenerException("exception during stateBacktracked() notification", t);
817 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has purged the current state.
819 protected void notifyStatePurged() {
821 for (int i = 0; i < listeners.length; i++) {
822 listeners[i].statePurged(this);
824 if (reporter != null){
825 reporter.statePurged(this);
827 } catch (Throwable t) {
828 throw new JPFListenerException("exception during statePurged() notification", t);
833 * Notifies the {@code SearchListener} objects in the {@code listeners} list that a probe request has been triggered during
836 public void notifySearchProbed() {
838 for (int i = 0; i < listeners.length; i++) {
839 listeners[i].searchProbed(this);
841 if (reporter != null){
842 reporter.searchProbed(this);
844 } catch (Throwable t) {
845 throw new JPFListenerException("exception during searchProbed() notification", t);
851 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has encountered a property
854 protected void notifyPropertyViolated() {
856 for (int i = 0; i < listeners.length; i++) {
857 listeners[i].propertyViolated(this);
859 if (reporter != null){
860 reporter.propertyViolated(this);
862 } catch (Throwable t) {
863 throw new JPFListenerException("exception during propertyViolated() notification", t);
866 // reset properties if getAllErrors is set
873 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has begun verification.
875 protected void notifySearchStarted() {
877 for (int i = 0; i < listeners.length; i++) {
878 listeners[i].searchStarted(this);
880 if (reporter != null){
881 reporter.searchStarted(this);
883 } catch (Throwable t) {
884 throw new JPFListenerException("exception during searchStarted() notification", t);
889 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has encountered a
890 * search constraint. The {@code details} String outlines the search constraint that was hit as well as any other
891 * relevant information.
893 * @param details Information regarding the recent search constraint that was encountered.
895 public void notifySearchConstraintHit(String details) {
897 lastSearchConstraint = details;
898 for (int i = 0; i < listeners.length; i++) {
899 listeners[i].searchConstraintHit(this);
901 if (reporter != null){
902 reporter.searchConstraintHit(this);
904 } catch (Throwable t) {
905 throw new JPFListenerException("exception during searchConstraintHit() notification", t);
910 * Notifies the {@code SearchListener} objects in the {@code listeners} list that the search loop has finished verification.
912 protected void notifySearchFinished() {
914 for (int i = 0; i < listeners.length; i++) {
915 listeners[i].searchFinished(this);
917 if (reporter != null){
918 reporter.searchFinished(this);
920 } catch (Throwable t) {
921 throw new JPFListenerException("exception during searchFinished() notification", t);
926 * Requests that the virtual machine move to the next unvisited state below the current one in the search tree.
927 * {@code forward} along with {@code backtrack} constitute the two methods that are generally used to advance
928 * the search algorithm during verification.
930 * @return true if a state exists and the virtual machine can move to it, false if the state does not exist
931 * or if it was previously explored.
934 protected boolean forward () {
937 boolean ret = vm.forward();
939 checkPropertyViolation();
944 * Requests that the virtual machine move to the previous state in the search tree. {@code backtrack} along
945 * with {@code forward} constitute the two methods that are generally used to advance the search algorithm
946 * during verification.
948 * @return true if the backtrack to the previous state was successful, false otherwise
950 protected boolean backtrack () {
951 return vm.backtrack();
955 * Requests that the virtual machine sets whether the current state should be ignored in all future iterations
956 * of the search loop. This should not be used without cause as it causes the search tree to be pruned whenever
957 * it is called, which is expensive, especially in larger trees.
959 * @param cond Whether or not the current state should be ignored
961 public void setIgnoredState (boolean cond) {
962 vm.ignoreState(cond);
966 * Restores a previously stored virtual machine state.
968 * <p>By default this method is not supported, and therefore requires implementation logic in child classes.
970 * @param state The stored state to be restored
972 protected void restoreState (State state) {
973 // not supported by default
977 * Sets {@code done} to true in order to terminate the search loop.
979 * <p>Can be used by listeners to terminate the search.
982 public void terminate () {
987 * Sets the depth of the specified state given its state id.
989 * <p>When the depth of the state is set, it is set as depth + 1. This is to differentiate between
990 * states that have had their depths set, and states that have not (in which case their default depth
993 * @param stateId The state in question
994 * @param depth The new depth to set for the state
996 protected void setStateDepth (int stateId, int depth) {
997 stateDepth.set(stateId, depth + 1);
1002 * Returns the saved depth of the specified state given its state id.
1004 * <p>If the state in question has not had its state depth set previously, then it will by default have
1005 * a depth that is less than or equal to 0. Otherwise if the state has been visited, the depth will be
1008 * @param stateId The state to return the depth of
1009 * @return The depth of the specified state
1010 * @throws JPFException If the state has not been visited in the past
1012 public int getStateDepth (int stateId) {
1013 int depthPlusOne = stateDepth.get(stateId);
1014 if (depthPlusOne <= 0) {
1015 throw new JPFException("Asked for depth of unvisited state");
1017 return depthPlusOne - 1;
1022 * Check if there is the minimum amount of free memory left or more. If not, we would rather stop in time
1023 * (with a threshold amount left) in order to report something useful, and not just end verification silently
1024 * with a OutOfMemoryError (which is not handled too gracefully by most VMs)
1026 * <p>If the minimum amount of memory has been reached, the method will first try to activate garbage collection
1027 * and then check again if that made a difference. If the amount of memory available is still less than the
1028 * minimum amount of memory, then we return false.
1030 * @return true if we have more memory than the minimum free memory, false otherwise.
1032 public boolean checkStateSpaceLimit () {
1033 Runtime rt = Runtime.getRuntime();
1035 long avail = rt.freeMemory();
1037 // we could also just check for a max number of states, but what really
1038 // limits us is the memory required to store states
1040 if (avail < minFreeMemory) {
1041 // try to collect first
1043 avail = rt.freeMemory();
1045 if (avail < minFreeMemory) {
1046 // Ok, we give up, threshold reached