comparison src/main/gov/nasa/jpf/perturb/GenericDataAbstractor.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
comparison
equal deleted inserted replaced
-1:000000000000 0:61d41facf527
1 /*
2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
4 * All rights reserved.
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0.
11 *
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.
17 */
18
19 package gov.nasa.jpf.perturb;
20
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;
30
31 /**
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
34 * method parameters.
35 *
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
41 *
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
46 *
47 */
48
49 public class GenericDataAbstractor implements OperandPerturbator {
50
51 // A valuations helper class
52 public class Valuation {
53 protected int valuation[] = null;
54
55 public Valuation(int size) {
56 valuation = new int[size];
57 }
58 // create an object from an existing valuation
59 public Valuation(Valuation seedValuation) {
60 valuation = seedValuation.valuation.clone();
61 }
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];
67 }
68 public int[] getValuation() {
69 return valuation;
70 }
71 public void add(int index, int element) {
72 valuation[index] = element;
73 }
74 }
75
76 static long seed = 5;
77
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);
90
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
94 mi = null;
95 choices = 0;
96 }
97
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) {
103 if (mi != null)
104 return;
105
106 mi = m;
107 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();
113
114 // now compute the operand size in 32-bit words
115 operandSize = 0;
116 for (byte type : paramTypes) {
117 if (type == Types.T_LONG || type == Types.T_DOUBLE)
118 operandSize += 2;
119 else
120 operandSize++;
121 }
122
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];
127 if (nParams != 0) {
128 String[] localVars = mi.getLocalVariableNames();
129 for (int i = 0; i < nParams; i++) {
130 paramNames[i] = isStatic? localVars[i] : localVars[i + 1];
131 }
132 }
133
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
138 // stack
139
140 valuation = new Valuation(operandSize);
141 valuations.add(valuation);
142 populateValuations(frame, 0, 0);
143
144 // we now know how many choices there are and hence set choices
145 choices = valuations.size() - 1;
146 }
147
148 // Method to populate boolean values
149 public int[] populateBoolean(MethodInfo mi, String name) {
150 int[] bVec = {0 /* false */, 1 /* true */};
151
152 return bVec;
153 }
154
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)};
158
159 return iVec;
160 }
161
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)};
165
166 return iVec;
167 }
168
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)};
172
173 return iVec;
174 }
175
176 // Method to populate integer values
177 public int[] populateShort(MethodInfo mi, String name) {
178 return populateInt(mi, name);
179 }
180
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];
185
186 int i = 0;
187 for (long l : lVec) {
188 iVec[i++] = Types.hiLong(l);
189 iVec[i++] = Types.loLong(l);
190 }
191 return iVec;
192 }
193
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())};
198
199 return fVec;
200 }
201
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];
206
207 int i = 0;
208 for (double d : dVec) {
209 iVec[i++] = Types.hiDouble(d);
210 iVec[i++] = Types.loDouble(d);
211 }
212 return iVec;
213 }
214
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
220 // suffix
221 valuation = new Valuation(valuation);
222 valuations.add(valuation);
223 } else {
224 switch (paramTypes[paramIndex]) {
225 case Types.T_ARRAY:
226 populateValuations(frame, paramIndex + 1, dataIndex + 1);
227 break;
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);
233 }
234 break;
235 case Types.T_FLOAT:
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);
240 }
241 break;
242 case Types.T_CHAR:
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);
247 }
248 break;
249 case Types.T_BYTE:
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);
254 }
255 break;
256 case Types.T_INT:
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);
261 }
262 break;
263 case Types.T_SHORT:
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);
268 }
269 break;
270 case Types.T_LONG:
271 int[] lVec = populateLong(mi, paramNames[paramIndex]);
272 int i = 0;
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);
277 }
278 break;
279 case Types.T_DOUBLE:
280 int[] dVec = populateDouble(mi, paramNames[paramIndex]);
281 i = 0;
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);
286 }
287 break;
288 }
289 }
290 }
291
292 @Override
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();
298
299 setMethodInfo((MethodInfo)refObject, frame);
300
301 if (choices > 0) {
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++) {
307 indices[i] = i;
308 }
309 return new IntChoiceFromSet(id, indices);
310 } else
311 return null;
312 }
313
314 @Override
315 public boolean perturb(ChoiceGenerator<?>cg, StackFrame frame) {
316 assert cg instanceof IntChoiceGenerator : "wrong choice generator type for GenericDataAbstractor: " + cg.getClass().getName();
317
318 int choice = ((IntChoiceGenerator)cg).getNextChoice();
319 Valuation valuation = valuations.get(choice);
320
321 // iterate over the number of operands and set the operand array to the values
322 // we have in the valuation vector
323 int val = 0;
324
325 int top = frame.getTopPos();
326 int stackIdx = frame.getLocalVariableCount() + ((isStatic)? 0 : 1);
327 int argSize = paramTypes.length;
328
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);
334 }
335 }
336 }
337
338 return cg.hasMoreChoices();
339 }
340
341 @Override
342 public Class<? extends ChoiceGenerator<?>> getChoiceGeneratorType(){
343 return IntChoiceFromSet.class;
344 }
345 }