Mercurial > hg > Members > kono > jpf-core
view src/main/gov/nasa/jpf/listener/CGRemover.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.jvm.bytecode.JVMInvokeInstruction; import gov.nasa.jpf.util.JPFLogger; import gov.nasa.jpf.util.LocationSpec; import gov.nasa.jpf.util.MethodSpec; import gov.nasa.jpf.vm.ChoiceGenerator; import gov.nasa.jpf.vm.ClassInfo; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.ThreadInfo; import gov.nasa.jpf.vm.VM; import gov.nasa.jpf.vm.MethodInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * listener that removes CGs for specified locations, method calls or method bodies * * This is an application specific state space optimizer that should be used * carefully since it has to be aware of which CGs can be removed, and which * ones can't (e.g. blocking sync or wait). You also have to be aware of the * order of listener registration, since subsequently registered listeners can * still add new CGs after they got removed here. THIS IS ONLY AN OPTIMIZATION * TOOL THAT SHOULD BE USED IN A WELL KNOWN APPLICATION CONTEXT. * * cgrm.thread.cg_class = gov.nasa.jpf.vm.ThreadChoiceGenerator * cgrm.thread.locations = Foobar.java:42 // either a LocationSpec * cgrm.thread.method_bodies = a.SomeClass.someMethod() // ..or a MethodSpec for a body * cgrm.thread.method_calls = b.A.foo(int) // ..or a MethodSpec for a call * * NOTE: in its current implementation, this listener has to be registered * before targeted classes are loaded */ public class CGRemover extends ListenerAdapter { static JPFLogger log = JPF.getLogger("gov.nasa.jpf.CGRemover"); static class Category { String id; Class<?> cgClass; ArrayList<LocationSpec> locations = new ArrayList<LocationSpec>(); ArrayList<MethodSpec> methodBodies = new ArrayList<MethodSpec>(); ArrayList<MethodSpec> methodCalls = new ArrayList<MethodSpec>(); Category (String id){ this.id = id; } boolean checkSpecification() { return cgClass != null && (!locations.isEmpty() || !methodBodies.isEmpty() || !methodCalls.isEmpty()); } } List<Category> categories; HashMap<MethodInfo,Category> methodBodies; HashMap<MethodInfo,Category> methodCalls; HashMap<Instruction,Category> locations; public CGRemover (Config conf){ categories = parseCategories(conf); } protected List<Category> parseCategories (Config conf){ ArrayList<Category> list = new ArrayList<Category>(); Category category = null; for (String key : conf.getKeysStartingWith("cgrm.")){ String[] kc = conf.getKeyComponents(key); if (kc.length == 3){ String k = kc[1]; if (category != null){ if (!category.id.equals(k)){ addCategory(list, category); category = new Category(k); } } else { category = new Category(k); } k = kc[2]; if ("cg_class".equals(k)){ category.cgClass = conf.getClass(key); } else if ("locations".equals(k)){ parseLocationSpecs(category.locations, conf.getStringArray(key)); } else if ("method_bodies".equals(k)){ parseMethodSpecs(category.methodBodies, conf.getStringArray(key)); } else if ("method_calls".equals(k)){ parseMethodSpecs(category.methodCalls, conf.getStringArray(key)); } else { // we might have more options in the future log.warning("illegal CGRemover option: ", key); } } else { log.warning("illegal CGRemover key: ", key); } } addCategory(list, category); return list; } protected void addCategory (List<Category> list, Category cat){ if (cat != null) { if (cat.checkSpecification()) { list.add(cat); log.info("added category: ", cat.id); } else { log.warning("incomplete CGRemover category: ", cat.id); } } } protected void parseLocationSpecs (List<LocationSpec> list, String[] specs){ for (String spec : specs) { LocationSpec locSpec = LocationSpec.createLocationSpec(spec); if (locSpec != null) { if (locSpec.isAnyLine()){ log.warning("whole file location specs not supported by CGRemover (use cgrm...method_bodies)"); } else { list.add(locSpec); } } else { log.warning("location spec did not parse: ", spec); } } } protected void parseMethodSpecs (List<MethodSpec> list, String[] specs){ for (String spec : specs) { MethodSpec mthSpec = MethodSpec.createMethodSpec(spec); if (mthSpec != null) { list.add(mthSpec); } else { log.warning("methos spec did not parse: ", spec); } } } protected void processClass (ClassInfo ci, Category cat){ String fname = ci.getSourceFileName(); for (LocationSpec loc : cat.locations){ if (loc.matchesFile(fname)){ // Ok, we have to dig out the corresponding insns (if any) Instruction[] insns = ci.getMatchingInstructions(loc); if (insns != null){ if (locations == null){ locations = new HashMap<Instruction,Category>(); } for (Instruction insn : insns){ locations.put(insn, cat); } } else { log.warning("no insns for location: ", loc, " in class: ", ci.getName()); } } } for (MethodSpec ms : cat.methodBodies){ List<MethodInfo> list = ci.getMatchingMethodInfos(ms); if (list != null){ for (MethodInfo mi : list){ if (methodBodies == null){ methodBodies = new HashMap<MethodInfo,Category>(); } methodBodies.put(mi, cat); } } } for (MethodSpec ms : cat.methodCalls){ List<MethodInfo> list = ci.getMatchingMethodInfos(ms); if (list != null){ for (MethodInfo mi : list){ if (methodCalls == null){ methodCalls = new HashMap<MethodInfo,Category>(); } methodCalls.put(mi, cat); } } } } protected boolean removeCG (VM vm, Category cat, ChoiceGenerator<?> cg){ if (cat != null){ if (cat.cgClass.isAssignableFrom(cg.getClass())){ vm.getSystemState().removeNextChoiceGenerator(); log.info("removed CG: ", cg); return true; } } return false; } //--- VMListener interface // this is where we turn Categories into MethodInfos and Instructions to watch out for @Override public void classLoaded (VM vm, ClassInfo loadedClass){ for (Category cat : categories){ processClass(loadedClass, cat); } } // this is our main purpose in life @Override public void choiceGeneratorRegistered (VM vm, ChoiceGenerator<?> nextCG, ThreadInfo ti, Instruction executedInsn){ ChoiceGenerator<?> cg = vm.getNextChoiceGenerator(); Instruction insn = cg.getInsn(); if (locations != null){ if ( removeCG(vm, locations.get(insn), cg)){ return; } } if (insn instanceof JVMInvokeInstruction){ MethodInfo invokedMi = ((JVMInvokeInstruction)insn).getInvokedMethod(); if (methodCalls != null) { if (removeCG(vm, methodCalls.get(invokedMi), cg)) { return; } } } if (methodBodies != null){ if (removeCG(vm, methodBodies.get(insn.getMethodInfo()), cg)) { return; } } } }