// // Copyright (C) 2007 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.jvm.bytecode; import java.util.function.BiFunction; import cmu.conditional.Conditional; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; import gov.nasa.jpf.jvm.JVMInstruction; import gov.nasa.jpf.vm.Instruction; import gov.nasa.jpf.vm.KernelState; import gov.nasa.jpf.vm.StackFrame; import gov.nasa.jpf.vm.SystemState; import gov.nasa.jpf.vm.ThreadInfo; import gov.nasa.jpf.vm.choice.IntIntervalGenerator; /** * common root class for LOOKUPSWITCH and TABLESWITCH insns * * <2do> this is inefficient. First, we should store targets as instruction indexes * to avoid execution() looping. Second, there are no matches for a TABLESWITCH */ public abstract class SwitchInstruction extends JVMInstruction { public static final int DEFAULT = -1; protected int target; // default branch protected int[] targets; // explicit value branches protected int[] matches; // branch consts protected int lastIdx; protected SwitchInstruction (int defaultTarget, int numberOfTargets){ target = defaultTarget; targets = new int[numberOfTargets]; matches = new int[numberOfTargets]; } public int getNumberOfEntries() { return targets.length; } protected Conditional<Instruction> executeConditional(FeatureExpr ctx, ThreadInfo ti) { StackFrame frame = ti.getModifiableTopFrame(); Conditional<Integer> value = frame.pop(ctx); return value.mapf(ctx, new BiFunction<FeatureExpr, Integer, Conditional<Instruction>>() { @Override public Conditional<Instruction> apply(FeatureExpr ctx, Integer value) { lastIdx = DEFAULT; for (int i = 0, l = matches.length; i < l; i++) { if (value == matches[i]) { lastIdx = i; return new One<>(mi.getInstructionAt(targets[i])); } } return new One<>(mi.getInstructionAt(target)); } }); } public Conditional<Instruction> execute (FeatureExpr ctx, ThreadInfo ti) { // this can be overridden by subclasses, so we have to delegate the conditional execution // to avoid getting recursive in executeAllBranches() return executeConditional(ctx, ti); } /** useful for symbolic execution modes */ public Instruction executeAllBranches (SystemState ss, KernelState ks, ThreadInfo ti) { if (!ti.isFirstStepInsn()) { IntIntervalGenerator cg = new IntIntervalGenerator("switchAll", 0,matches.length); if (ss.setNextChoiceGenerator(cg)){ return this; } else { // listener did override CG, fall back to conditional execution return executeConditional(FeatureExprFactory.True(), ti).getValue(); } } else { IntIntervalGenerator cg = ss.getCurrentChoiceGenerator("switchAll", IntIntervalGenerator.class); assert (cg != null) : "no IntIntervalGenerator"; StackFrame frame = ti.getModifiableTopFrame(); int idx = frame.pop(FeatureExprFactory.True()).getValue(); // but we are not using it idx = cg.getNextChoice(); if (idx == matches.length){ // default branch lastIdx = DEFAULT; return mi.getInstructionAt(target); } else { lastIdx = idx; return mi.getInstructionAt(targets[idx]); } } } //--- a little inspection, but only post exec yet public int getLastTargetIndex () { return lastIdx; } public int getNumberOfTargets () { return matches.length; } public int getMatchConst (int idx){ return matches[idx]; } public void accept(InstructionVisitor insVisitor) { insVisitor.visit(this); } public int getTarget() { return target; } public int[] getTargets() { return targets; } public int[] getMatches() { return matches; } }