Mercurial > hg > Members > kono > jpf-core
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 } |