Mercurial > hg > Members > kono > jpf-core
comparison src/main/gov/nasa/jpf/vm/serialize/DynamicAbstractionSerializer.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 package gov.nasa.jpf.vm.serialize; | |
19 | |
20 import gov.nasa.jpf.Config; | |
21 import gov.nasa.jpf.JPF; | |
22 import gov.nasa.jpf.ListenerAdapter; | |
23 import gov.nasa.jpf.util.FieldSpec; | |
24 import gov.nasa.jpf.util.FinalBitSet; | |
25 import gov.nasa.jpf.util.JPFLogger; | |
26 import gov.nasa.jpf.util.StringSetMatcher; | |
27 import gov.nasa.jpf.vm.ArrayFields; | |
28 import gov.nasa.jpf.vm.ClassInfo; | |
29 import gov.nasa.jpf.vm.ClassLoaderInfo; | |
30 import gov.nasa.jpf.vm.ElementInfo; | |
31 import gov.nasa.jpf.vm.FieldInfo; | |
32 import gov.nasa.jpf.vm.Fields; | |
33 import gov.nasa.jpf.vm.MJIEnv; | |
34 import gov.nasa.jpf.vm.VM; | |
35 import gov.nasa.jpf.vm.MethodInfo; | |
36 import gov.nasa.jpf.vm.ReferenceArrayFields; | |
37 import gov.nasa.jpf.vm.StackFrame; | |
38 import gov.nasa.jpf.vm.StaticElementInfo; | |
39 import gov.nasa.jpf.vm.Statics; | |
40 | |
41 import java.util.LinkedList; | |
42 import java.util.List; | |
43 | |
44 /** | |
45 * a serializer that uses Abstraction objects stored as field attributes to | |
46 * obtain the values to hash. | |
47 */ | |
48 public class DynamicAbstractionSerializer extends FilteringSerializer { | |
49 | |
50 static JPFLogger logger = JPF.getLogger("gov.nasa.jpf.vm.serialize.DynamicAbstractionSerializer"); | |
51 | |
52 static class FieldAbstraction { | |
53 FieldSpec fspec; | |
54 Abstraction abstraction; | |
55 | |
56 FieldAbstraction(FieldSpec f, Abstraction a) { | |
57 fspec = f; | |
58 abstraction = a; | |
59 } | |
60 } | |
61 | |
62 public class Attributor extends ListenerAdapter { | |
63 | |
64 @Override | |
65 public void classLoaded(VM vm, ClassInfo loadedClass) { | |
66 | |
67 if (!loadedClass.isArray() && !loadedClass.isPrimitive()) { | |
68 | |
69 if (!fieldAbstractions.isEmpty()) { | |
70 for (FieldInfo fi : loadedClass.getDeclaredInstanceFields()) { | |
71 for (FieldAbstraction fabs : fieldAbstractions) { | |
72 if (fabs.fspec.matches(fi)) { | |
73 logger.info("setting instance field abstraction ", fabs.abstraction.getClass().getName(), | |
74 " for field ", fi.getFullName()); | |
75 fi.addAttr(fabs.abstraction); | |
76 } | |
77 } | |
78 } | |
79 | |
80 for (FieldInfo fi : loadedClass.getDeclaredStaticFields()) { | |
81 for (FieldAbstraction fabs : fieldAbstractions) { | |
82 if (fabs.fspec.matches(fi)) { | |
83 logger.info("setting static field abstraction ", fabs.abstraction.getClass().getName(), | |
84 " for field ", fi.getFullName()); | |
85 fi.addAttr(fabs.abstraction); | |
86 } | |
87 } | |
88 } | |
89 } | |
90 } | |
91 } | |
92 } | |
93 | |
94 protected StringSetMatcher includeClasses = null; // means all | |
95 protected StringSetMatcher excludeClasses = null; // means none | |
96 protected StringSetMatcher includeMethods = null; | |
97 protected StringSetMatcher excludeMethods = null; | |
98 | |
99 List<FieldAbstraction> fieldAbstractions; | |
100 | |
101 protected boolean processAllObjects; | |
102 protected boolean declaredFieldsOnly; | |
103 | |
104 | |
105 public DynamicAbstractionSerializer(Config conf) { | |
106 processAllObjects = conf.getBoolean("das.all_objects", true); | |
107 declaredFieldsOnly = conf.getBoolean("das.declared_fields", false); | |
108 | |
109 includeClasses = StringSetMatcher.getNonEmpty(conf.getStringArray("das.classes.include")); | |
110 excludeClasses = StringSetMatcher.getNonEmpty(conf.getStringArray("das.classes.exclude")); | |
111 | |
112 includeMethods = StringSetMatcher.getNonEmpty(conf.getStringArray("das.methods.include")); | |
113 excludeMethods = StringSetMatcher.getNonEmpty(conf.getStringArray("das.methods.exclude")); | |
114 | |
115 fieldAbstractions = getFieldAbstractions(conf); | |
116 } | |
117 | |
118 | |
119 protected List<FieldAbstraction> getFieldAbstractions(Config conf){ | |
120 List<FieldAbstraction> list = null; | |
121 | |
122 String[] fids = conf.getCompactTrimmedStringArray("das.fields"); | |
123 for (String id : fids) { | |
124 String keyPrefix = "das." + id; | |
125 String fs = conf.getString(keyPrefix + ".field"); | |
126 if (fs != null) { | |
127 FieldSpec fspec = FieldSpec.createFieldSpec(fs); | |
128 if (fspec != null) { | |
129 String aKey = keyPrefix + ".abstraction"; | |
130 Abstraction abstraction = conf.getInstance(aKey, Abstraction.class); | |
131 | |
132 logger.info("found field abstraction for ", fspec, " = ", abstraction.getClass().getName()); | |
133 | |
134 if (list == null){ | |
135 list = new LinkedList<FieldAbstraction>(); | |
136 } | |
137 | |
138 list.add(new FieldAbstraction(fspec, abstraction)); | |
139 } | |
140 } else { | |
141 logger.warning("no field spec for id: " + id); | |
142 } | |
143 } | |
144 | |
145 return list; | |
146 } | |
147 | |
148 @Override | |
149 public void attach (VM vm){ | |
150 super.attach(vm); | |
151 | |
152 if (fieldAbstractions != null){ | |
153 Attributor attributor = new Attributor(); | |
154 vm.addListener(attributor); | |
155 } | |
156 } | |
157 | |
158 | |
159 // note that we don't add the reference value here | |
160 @Override | |
161 public void processReference(int objref) { | |
162 if (objref != MJIEnv.NULL) { | |
163 ElementInfo ei = heap.get(objref); | |
164 if (!ei.isMarked()) { // only add objects once | |
165 ei.setMarked(); | |
166 refQueue.add(ei); | |
167 } | |
168 } | |
169 | |
170 // we DON'T add the reference value to the buffer here | |
171 } | |
172 | |
173 protected void processField(Fields fields, int[] slotValues, FieldInfo fi, FinalBitSet filtered) { | |
174 int off = fi.getStorageOffset(); | |
175 if (!filtered.get(off)) { | |
176 Abstraction a = fi.getAttr(Abstraction.class); | |
177 if (a != null) { | |
178 if (fi.is1SlotField()) { | |
179 if (fi.isReference()) { | |
180 int ref = fields.getReferenceValue(off); | |
181 buf.add(a.getAbstractObject(ref)); | |
182 | |
183 if (a.traverseObject(ref)) { | |
184 processReference(ref); | |
185 } | |
186 | |
187 } else if (fi.isFloatField()) { | |
188 buf.add(a.getAbstractValue(fields.getFloatValue(off))); | |
189 } else { | |
190 buf.add(a.getAbstractValue(fields.getIntValue(off))); | |
191 } | |
192 } else { // double or long | |
193 if (fi.isLongField()) { | |
194 buf.add(a.getAbstractValue(fields.getLongValue(off))); | |
195 } else { // got to be double | |
196 buf.add(a.getAbstractValue(fields.getDoubleValue(off))); | |
197 } | |
198 } | |
199 | |
200 } else { // no abstraction, fall back to concrete values | |
201 if (fi.is1SlotField()) { | |
202 if (fi.isReference()) { | |
203 int ref = slotValues[off]; | |
204 buf.add(ref); | |
205 processReference(ref); | |
206 | |
207 } else { | |
208 buf.add(slotValues[off]); | |
209 } | |
210 | |
211 } else { // double or long | |
212 buf.add(slotValues[off]); | |
213 buf.add(slotValues[off + 1]); | |
214 } | |
215 } | |
216 } | |
217 } | |
218 | |
219 // non-ignored class | |
220 @Override | |
221 protected void processArrayFields(ArrayFields fields) { | |
222 buf.add(fields.arrayLength()); | |
223 | |
224 if (fields.isReferenceArray()) { | |
225 int[] values = fields.asReferenceArray(); | |
226 for (int i = 0; i < values.length; i++) { | |
227 processReference(values[i]); | |
228 buf.add(values[i]); | |
229 } | |
230 } else { | |
231 fields.appendTo(buf); | |
232 } | |
233 } | |
234 | |
235 // for ignored class, to get all live objects | |
236 protected void processNamedInstanceReferenceFields(ClassInfo ci, Fields fields) { | |
237 FinalBitSet filtered = getInstanceFilterMask(ci); | |
238 FinalBitSet refs = getInstanceRefMask(ci); | |
239 int[] slotValues = fields.asFieldSlots(); // for non-attributed fields | |
240 | |
241 for (int i = 0; i < slotValues.length; i++) { | |
242 if (!filtered.get(i)) { | |
243 if (refs.get(i)) { | |
244 processReference(slotValues[i]); | |
245 } | |
246 } | |
247 } | |
248 } | |
249 | |
250 // for ignored class, to get all live objects | |
251 protected void processNamedStaticReferenceFields(ClassInfo ci, Fields fields) { | |
252 FinalBitSet filtered = getStaticFilterMask(ci); | |
253 FinalBitSet refs = getStaticRefMask(ci); | |
254 int[] slotValues = fields.asFieldSlots(); // for non-attributed fields | |
255 | |
256 for (int i = 0; i < slotValues.length; i++) { | |
257 if (!filtered.get(i)) { | |
258 if (refs.get(i)) { | |
259 processReference(slotValues[i]); | |
260 } | |
261 } | |
262 } | |
263 } | |
264 | |
265 // for ignored class, to get all live objects | |
266 protected void processReferenceArray(ReferenceArrayFields fields) { | |
267 int[] slotValues = fields.asReferenceArray(); | |
268 for (int i = 0; i < slotValues.length; i++) { | |
269 processReference(slotValues[i]); | |
270 } | |
271 } | |
272 | |
273 // non-ignored class | |
274 @Override | |
275 protected void processNamedFields(ClassInfo ci, Fields fields) { | |
276 FinalBitSet filtered = getInstanceFilterMask(ci); | |
277 int nFields = ci.getNumberOfInstanceFields(); | |
278 int[] slotValues = fields.asFieldSlots(); // for non-attributed fields | |
279 | |
280 for (int i = 0; i < nFields; i++) { | |
281 FieldInfo fi = ci.getInstanceField(i); | |
282 | |
283 if (declaredFieldsOnly && fi.getClassInfo() != ci) { | |
284 continue; | |
285 } | |
286 | |
287 processField(fields, slotValues, fi, filtered); | |
288 } | |
289 } | |
290 | |
291 // <2do> this should also allow abstraction of whole objects, so that | |
292 // we can hash combinations/relations of field values | |
293 @Override | |
294 public void process (ElementInfo ei) { | |
295 Fields fields = ei.getFields(); | |
296 ClassInfo ci = ei.getClassInfo(); | |
297 | |
298 if (StringSetMatcher.isMatch(ci.getName(), includeClasses, excludeClasses)) { | |
299 buf.add(ci.getUniqueId()); | |
300 | |
301 if (fields instanceof ArrayFields) { // not filtered | |
302 processArrayFields((ArrayFields) fields); | |
303 } else { // named fields, potentially filtered & abstracted via attributes | |
304 processNamedFields(ci, fields); | |
305 } | |
306 | |
307 } else { // ignored class | |
308 // we check for live non-ignored objects along all stack frames, so we should do the same for all objects | |
309 if (fields instanceof ArrayFields) { | |
310 if (fields instanceof ReferenceArrayFields) { | |
311 processReferenceArray((ReferenceArrayFields) fields); | |
312 } | |
313 } else { | |
314 processNamedInstanceReferenceFields(ci, fields); | |
315 } | |
316 } | |
317 } | |
318 | |
319 @Override | |
320 protected void serializeFrame (StackFrame frame) { | |
321 MethodInfo mi = frame.getMethodInfo(); | |
322 | |
323 if (StringSetMatcher.isMatch(mi.getFullName(), includeMethods, excludeMethods)){ | |
324 // <2do> should do frame abstraction here | |
325 super.serializeFrame(frame); | |
326 | |
327 } else { | |
328 if (processAllObjects) { | |
329 frame.visitReferenceSlots(this); | |
330 } | |
331 } | |
332 } | |
333 | |
334 @Override | |
335 protected void serializeClass (StaticElementInfo sei) { | |
336 ClassInfo ci = sei.getClassInfo(); | |
337 Fields fields = sei.getFields(); | |
338 | |
339 if (StringSetMatcher.isMatch(ci.getName(), includeClasses, excludeClasses)) { | |
340 buf.add(sei.getStatus()); | |
341 | |
342 FinalBitSet filtered = getStaticFilterMask(ci); | |
343 int[] slotValues = fields.asFieldSlots(); | |
344 | |
345 for (FieldInfo fi : ci.getDeclaredStaticFields()) { | |
346 processField(fields, slotValues, fi, filtered); | |
347 } | |
348 | |
349 } else { | |
350 // ignored class, but still process references to extract live objects | |
351 processNamedStaticReferenceFields(ci, fields); | |
352 } | |
353 } | |
354 | |
355 @Override | |
356 protected void serializeClassLoaders(){ | |
357 // we don't care about the number of classloaders | |
358 | |
359 for (ClassLoaderInfo cl : ks.classLoaders) { | |
360 if(cl.isAlive()) { | |
361 serializeStatics( cl.getStatics()); | |
362 } | |
363 } | |
364 } | |
365 | |
366 @Override | |
367 protected void serializeStatics(Statics statics){ | |
368 // we don't care about the number of statics entries | |
369 | |
370 for (StaticElementInfo sei : statics.liveStatics()) { | |
371 serializeClass(sei); | |
372 } | |
373 } | |
374 } |