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.
19 package gov.nasa.jpf.perturb;
21 import java.util.Random;
22 import java.util.Vector;
23 import gov.nasa.jpf.Config;
24 import gov.nasa.jpf.vm.ChoiceGenerator;
25 import gov.nasa.jpf.vm.IntChoiceGenerator;
26 import gov.nasa.jpf.vm.MethodInfo;
27 import gov.nasa.jpf.vm.StackFrame;
28 import gov.nasa.jpf.vm.Types;
29 import gov.nasa.jpf.vm.choice.IntChoiceFromSet;
32 * This file implements a generic data abstraction module that can be used
33 * with the Perturbator to execute a method with a choice of values for the
36 * This module handles all basic types and selects values for them as follows:
37 * int, short: random negative integer | 0 | random positive integer
38 * float: random negative floating point | 0 | random positive floating point
39 * char: two random values in [0, 255] and an explicit 0
40 * boolean: true | false
42 * An instance of this class is expected to be specialized for each method that we
43 * want perturbed. The cstor creates a vector of valuations for the parameters
44 * using all choices for each basic type such that each vector can be written
45 * directly into the method stack frame for parameters
49 public class GenericDataAbstractor implements OperandPerturbator {
51 // A valuations helper class
52 public class Valuation {
53 protected int valuation[] = null;
55 public Valuation(int size) {
56 valuation = new int[size];
58 // create an object from an existing valuation
59 public Valuation(Valuation seedValuation) {
60 valuation = seedValuation.valuation.clone();
62 public Valuation(Valuation val, int size) {
63 valuation = new int[size];
64 int[] valuationArray = val.getValuation();
65 for (int i = 0; i < valuationArray.length; i++)
66 valuation[i] = valuationArray[i];
68 public int[] getValuation() {
71 public void add(int index, int element) {
72 valuation[index] = element;
78 protected MethodInfo mi;
79 protected StackFrame stackFrame;
80 protected int nParams;
81 protected byte[] paramTypes = null;
82 protected String[] paramTypeNames = null;
83 protected String[] paramNames = null;
84 protected Vector<Valuation> valuations = new Vector<Valuation>();
85 protected int choices;
86 protected int operandSize;
87 protected Valuation valuation = null;
88 protected boolean isStatic;
89 protected Random randomizer = new Random(seed);
91 public GenericDataAbstractor (Config conf, String keyPrefix){
92 // this will expand to read parameters from the configuration
93 // to specialize the behavior of the abstractor
98 // At the time of instance creation we don't have the MethodInfo object
99 // for the method that needs its parameters perturbed. Therefore, we
100 // should set MethodInfo using a call to the following method before
101 // we can use this instance to perturb a method invocation
102 public void setMethodInfo(MethodInfo m, StackFrame frame) {
108 // Need to figure out the right number of parameters.
109 paramTypes = mi.getArgumentTypes();
110 paramTypeNames = mi.getArgumentTypeNames();
111 nParams = paramTypes.length;
112 isStatic = mi.isStatic();
114 // now compute the operand size in 32-bit words
116 for (byte type : paramTypes) {
117 if (type == Types.T_LONG || type == Types.T_DOUBLE)
123 // useful when we call the various populate methods that populate
124 // choice vectors. The parameter name can be used to specialize
125 // population to parameter names
126 paramNames = new String[nParams];
128 String[] localVars = mi.getLocalVariableNames();
129 for (int i = 0; i < nParams; i++) {
130 paramNames[i] = isStatic? localVars[i] : localVars[i + 1];
134 // We build an array of choices, with each choice being an index into
135 // an array of integers representing the operand stack values.
136 // We then use an IntChoiceGenerator to give us an index that is then
137 // used to access the values we want to replace for the operands on the
140 valuation = new Valuation(operandSize);
141 valuations.add(valuation);
142 populateValuations(frame, 0, 0);
144 // we now know how many choices there are and hence set choices
145 choices = valuations.size() - 1;
148 // Method to populate boolean values
149 public int[] populateBoolean(MethodInfo mi, String name) {
150 int[] bVec = {0 /* false */, 1 /* true */};
155 // Method to populate character values
156 public int[] populateChar(MethodInfo mi, String name) {
157 int[] iVec = {Math.abs(randomizer.nextInt() % 255), 0, Math.abs(randomizer.nextInt() % 255)};
162 // Method to populate byte values
163 public int[] populateByte(MethodInfo mi, String name) {
164 int[] iVec = {Math.abs(randomizer.nextInt() % 128), 0, -1 * Math.abs(randomizer.nextInt() % 127)};
169 // Method to populate integer values
170 public int[] populateInt(MethodInfo mi, String name) {
171 int[] iVec = {Math.abs(randomizer.nextInt() % 100), 0, -1 * Math.abs(randomizer.nextInt() % 100)};
176 // Method to populate integer values
177 public int[] populateShort(MethodInfo mi, String name) {
178 return populateInt(mi, name);
181 // Method to populate long values
182 public int[] populateLong(MethodInfo mi, String name) {
183 long[] lVec = {Math.abs(randomizer.nextLong() % 100), 0, -1 * Math.abs(randomizer.nextLong() % 100)};
184 int[] iVec = new int[lVec.length * 2];
187 for (long l : lVec) {
188 iVec[i++] = Types.hiLong(l);
189 iVec[i++] = Types.loLong(l);
194 // Method to populate integer values
195 public int[] populateFloat(MethodInfo mi, String name) {
196 int[] fVec = {Float.floatToIntBits(randomizer.nextFloat()), 0,
197 -1 * Float.floatToIntBits(randomizer.nextFloat())};
202 // Method to populate long values
203 public int[] populateDouble(MethodInfo mi, String name) {
204 double[] dVec = {-1.414, 0.0, 3.141};
205 int[] iVec = new int[dVec.length * 2];
208 for (double d : dVec) {
209 iVec[i++] = Types.hiDouble(d);
210 iVec[i++] = Types.loDouble(d);
215 public void populateValuations(StackFrame frame, int paramIndex, int dataIndex) {
216 if (paramIndex == nParams) {
217 // copy the contents of the previous vector as a
218 // suffix of it will be over-written, retaining
219 // the valuations for all parameters ahead of the
221 valuation = new Valuation(valuation);
222 valuations.add(valuation);
224 switch (paramTypes[paramIndex]) {
226 populateValuations(frame, paramIndex + 1, dataIndex + 1);
228 case Types.T_BOOLEAN:
229 int[] bVec = populateBoolean(mi, paramNames[paramIndex]);
230 for (int i = 0; i < bVec.length; i++) {
231 valuation.add(dataIndex, bVec[i]);
232 populateValuations(frame, paramIndex + 1, dataIndex + 1);
236 int[] fVec = populateFloat(mi, paramNames[paramIndex]);
237 for (int i = 0; i < fVec.length; i++) {
238 valuation.add(dataIndex, fVec[i]);
239 populateValuations(frame, paramIndex + 1, dataIndex + 1);
243 int[] iVec = populateChar(mi, paramNames[paramIndex]);
244 for (int i = 0; i < iVec.length; i++) {
245 valuation.add(dataIndex, iVec[i]);
246 populateValuations(frame, paramIndex + 1, dataIndex + 1);
250 iVec = populateByte(mi, paramNames[paramIndex]);
251 for (int i = 0; i < iVec.length; i++) {
252 valuation.add(dataIndex, iVec[i]);
253 populateValuations(frame, paramIndex + 1, dataIndex + 1);
257 iVec = populateInt(mi, paramNames[paramIndex]);
258 for (int i = 0; i < iVec.length; i++) {
259 valuation.add(dataIndex, iVec[i]);
260 populateValuations(frame, paramIndex + 1, dataIndex + 1);
264 iVec = populateShort(mi, paramNames[paramIndex]);
265 for (int i = 0; i < iVec.length; i++) {
266 valuation.add(dataIndex, iVec[i]);
267 populateValuations(frame, paramIndex + 1, dataIndex + 1);
271 int[] lVec = populateLong(mi, paramNames[paramIndex]);
273 while (i < lVec.length) {
274 valuation.add(dataIndex, lVec[i++]);
275 valuation.add(dataIndex + 1, lVec[i++]);
276 populateValuations(frame, paramIndex + 1, dataIndex + 2);
280 int[] dVec = populateDouble(mi, paramNames[paramIndex]);
282 while (i < dVec.length) {
283 valuation.add(dataIndex, dVec[i++]);
284 valuation.add(dataIndex + 1, dVec[i++]);
285 populateValuations(frame, paramIndex + 1, dataIndex + 2);
293 public ChoiceGenerator<?> createChoiceGenerator (String id, StackFrame frame, Object refObject) {
294 // We expect that the refObject in this case will be a MethodInfo object
295 // Set it so that we can create valuation vectors
296 assert refObject instanceof MethodInfo : "wrong refObject type for GenericDataAbstractor: " +
297 refObject.getClass().getName();
299 setMethodInfo((MethodInfo)refObject, frame);
302 // now create a choices vector which will be used to iterate over the number of
303 // parameter valuations we want to use. We set each element of the vector simply
304 // to an index into the valuations vector
305 int[] indices = new int[choices];
306 for (int i = 0; i < choices; i++) {
309 return new IntChoiceFromSet(id, indices);
315 public boolean perturb(ChoiceGenerator<?>cg, StackFrame frame) {
316 assert cg instanceof IntChoiceGenerator : "wrong choice generator type for GenericDataAbstractor: " + cg.getClass().getName();
318 int choice = ((IntChoiceGenerator)cg).getNextChoice();
319 Valuation valuation = valuations.get(choice);
321 // iterate over the number of operands and set the operand array to the values
322 // we have in the valuation vector
325 int top = frame.getTopPos();
326 int stackIdx = frame.getLocalVariableCount() + ((isStatic)? 0 : 1);
327 int argSize = paramTypes.length;
329 for (int j = 0; j < argSize; j++) { // j ranges over actual arguments
330 if (!frame.isOperandRef(top - stackIdx)) {
331 frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false);
332 if (paramTypes[j] == Types.T_LONG || paramTypes[j] == Types.T_DOUBLE) {
333 frame.setOperand(top - stackIdx++, valuation.getValuation()[val++], false);
338 return cg.hasMoreChoices();
342 public Class<? extends ChoiceGenerator<?>> getChoiceGeneratorType(){
343 return IntChoiceFromSet.class;