Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/listener/ChoiceSelector.java @ 0:61d41facf527
initial v8 import (history reset)
author | Peter Mehlitz <Peter.C.Mehlitz@nasa.gov> |
---|---|
date | Fri, 23 Jan 2015 10:14:01 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (C) 2014, United States Government, as represented by the * Administrator of the National Aeronautics and Space Administration. * All rights reserved. * * The Java Pathfinder core (jpf-core) platform is licensed under the * Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package gov.nasa.jpf.listener; import gov.nasa.jpf.Config; import gov.nasa.jpf.JPF; import gov.nasa.jpf.ListenerAdapter; import gov.nasa.jpf.annotation.JPFOption; import gov.nasa.jpf.annotation.JPFOptions; import gov.nasa.jpf.jvm.bytecode.JVMInvokeInstruction; import gov.nasa.jpf.search.Search; import gov.nasa.jpf.util.StringSetMatcher; import gov.nasa.jpf.vm.ChoiceGenerator; import gov.nasa.jpf.vm.ChoicePoint; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.VM; import gov.nasa.jpf.vm.ThreadInfo; import java.util.Random; /** * this is a listener that only executes single choices until it detects * that it should start to search. If nothing is specified, this is pretty * much a simulator that randomly picks choices. Otherwise the user can * give it any combination of * - a set of thread names * - a set of method names * - a start search depth * to turn on the search. If more than one condition is given, all have to be * satisfied */ @JPFOptions({ @JPFOption(type = "Int", key = "choice.seed", defaultValue= "42", comment = ""), @JPFOption(type = "StringArray", key = "choice.threads", defaultValue = "", comment="start search, when all threads in the set are active"), @JPFOption(type = "StringArray", key = "choice.calls", defaultValue = "", comment = "start search, when any of the methods is called"), @JPFOption(type = "Int", key = "choice.depth", defaultValue = "-1", comment = "start search, when reaching this depth"), @JPFOption(type = "String", key = "choice.use_trace", defaultValue ="", comment = ""), @JPFOption(type = "Boolean", key = "choice.search_after_trace", defaultValue = "true", comment="start search, when reaching the end of the stored trace") }) public class ChoiceSelector extends ListenerAdapter { Random random; boolean singleChoice = true; // those are our singleChoice end conditions (i.e. where we start the search) StringSetMatcher threadSet; // we start when all threads in the set are active boolean threadsAlive = true;; StringSetMatcher calls; // .. when any of the methods is called boolean callSeen = true; int startDepth; // .. when reaching this depth boolean depthReached = true; // set if we replay a trace ChoicePoint trace; // start the search when reaching the end of the stored trace. If not set, // the listener will just randomly select single choices once the trace // got processed boolean searchAfterTrace; public ChoiceSelector (Config config, JPF jpf) { random = new Random( config.getInt("choice.seed", 42)); threadSet = StringSetMatcher.getNonEmpty(config.getStringArray("choice.threads")); if (threadSet != null) { threadsAlive = false; } calls = StringSetMatcher.getNonEmpty(config.getStringArray("choice.calls")); callSeen = false; startDepth = config.getInt("choice.depth", -1); if (startDepth != -1) { depthReached = false; } // if nothing was specified, we just do single choice (simulation) if ((threadSet == null) && (calls == null) && (startDepth == -1)) { threadsAlive = false; callSeen = false; depthReached = false; } VM vm = jpf.getVM(); trace = ChoicePoint.readTrace(config.getString("choice.use_trace"), vm.getSUTName()); searchAfterTrace = config.getBoolean("choice.search_after_trace", true); vm.setTraceReplay(trace != null); } void checkSingleChoiceCond() { singleChoice = !(depthReached && callSeen && threadsAlive); } @Override public void choiceGeneratorAdvanced (VM vm, ChoiceGenerator<?> currentCG) { int n = currentCG.getTotalNumberOfChoices(); if (trace != null) { // this is a replay // <2do> maybe that should just be a warning, and then a single choice assert currentCG.getClass().getName().equals(trace.getCgClassName()) : "wrong choice generator class, expecting: " + trace.getCgClassName() + ", read: " + currentCG.getClass().getName(); int choiceIndex = trace.getChoiceIndex(); currentCG.select(choiceIndex); } else { if (singleChoice) { if (n > 1) { int r = random.nextInt(n); currentCG.select(r); // sets it done, so we never backtrack into it } } } } @Override public void threadStarted(VM vm, ThreadInfo ti) { if (singleChoice && (threadSet != null)) { String tname = ti.getName(); if (threadSet.matchesAny( tname)){ threadsAlive = true; checkSingleChoiceCond(); } } } @Override public void executeInstruction(VM vm, ThreadInfo ti, Instruction insnToExecute) { if (singleChoice && !callSeen && (calls != null)) { if (insnToExecute instanceof JVMInvokeInstruction) { String mthName = ((JVMInvokeInstruction)insnToExecute).getInvokedMethod(ti).getBaseName(); if (calls.matchesAny(mthName)){ callSeen = true; checkSingleChoiceCond(); } } } } @Override public void stateAdvanced(Search search) { if (trace != null) { // there is no backtracking or restoring as long as we replay trace = trace.getNext(); if (trace == null){ search.getVM().setTraceReplay(false); if (searchAfterTrace){ singleChoice = false; } } } else { if (singleChoice && !depthReached && (startDepth >= 0)) { if (search.getDepth() == startDepth) { depthReached = true; checkSingleChoiceCond(); } } } } }