diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/gov/nasa/jpf/vm/serialize/DynamicAbstractionSerializer.java	Fri Jan 23 10:14:01 2015 -0800
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2014, United States Government, as represented by the
+ * Administrator of the National Aeronautics and Space Administration.
+ * All rights reserved.
+ *
+ * The Java Pathfinder core (jpf-core) platform is licensed under the
+ * Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ * 
+ *        http://www.apache.org/licenses/LICENSE-2.0. 
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+package gov.nasa.jpf.vm.serialize;
+
+import gov.nasa.jpf.Config;
+import gov.nasa.jpf.JPF;
+import gov.nasa.jpf.ListenerAdapter;
+import gov.nasa.jpf.util.FieldSpec;
+import gov.nasa.jpf.util.FinalBitSet;
+import gov.nasa.jpf.util.JPFLogger;
+import gov.nasa.jpf.util.StringSetMatcher;
+import gov.nasa.jpf.vm.ArrayFields;
+import gov.nasa.jpf.vm.ClassInfo;
+import gov.nasa.jpf.vm.ClassLoaderInfo;
+import gov.nasa.jpf.vm.ElementInfo;
+import gov.nasa.jpf.vm.FieldInfo;
+import gov.nasa.jpf.vm.Fields;
+import gov.nasa.jpf.vm.MJIEnv;
+import gov.nasa.jpf.vm.VM;
+import gov.nasa.jpf.vm.MethodInfo;
+import gov.nasa.jpf.vm.ReferenceArrayFields;
+import gov.nasa.jpf.vm.StackFrame;
+import gov.nasa.jpf.vm.StaticElementInfo;
+import gov.nasa.jpf.vm.Statics;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * a serializer that uses Abstraction objects stored as field attributes to
+ * obtain the values to hash. 
+ */
+public class DynamicAbstractionSerializer extends FilteringSerializer {
+
+  static JPFLogger logger = JPF.getLogger("gov.nasa.jpf.vm.serialize.DynamicAbstractionSerializer");
+
+  static class FieldAbstraction {
+    FieldSpec fspec;
+    Abstraction abstraction;
+
+    FieldAbstraction(FieldSpec f, Abstraction a) {
+      fspec = f;
+      abstraction = a;
+    }
+  }
+
+  public class Attributor extends ListenerAdapter {
+
+    @Override
+    public void classLoaded(VM vm, ClassInfo loadedClass) {
+
+      if (!loadedClass.isArray() && !loadedClass.isPrimitive()) {
+
+        if (!fieldAbstractions.isEmpty()) {
+          for (FieldInfo fi : loadedClass.getDeclaredInstanceFields()) {
+            for (FieldAbstraction fabs : fieldAbstractions) {
+              if (fabs.fspec.matches(fi)) {
+                logger.info("setting instance field abstraction ", fabs.abstraction.getClass().getName(),
+                        " for field ", fi.getFullName());
+                fi.addAttr(fabs.abstraction);
+              }
+            }
+          }
+
+          for (FieldInfo fi : loadedClass.getDeclaredStaticFields()) {
+            for (FieldAbstraction fabs : fieldAbstractions) {
+              if (fabs.fspec.matches(fi)) {
+                logger.info("setting static field abstraction ", fabs.abstraction.getClass().getName(),
+                        " for field ", fi.getFullName());
+                fi.addAttr(fabs.abstraction);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  protected StringSetMatcher includeClasses = null; //  means all
+  protected StringSetMatcher excludeClasses = null; //  means none
+  protected StringSetMatcher includeMethods = null;
+  protected StringSetMatcher excludeMethods = null;
+
+  List<FieldAbstraction> fieldAbstractions;
+
+  protected boolean processAllObjects;
+  protected boolean declaredFieldsOnly;
+
+  
+  public DynamicAbstractionSerializer(Config conf) {
+    processAllObjects = conf.getBoolean("das.all_objects", true);
+    declaredFieldsOnly = conf.getBoolean("das.declared_fields", false);
+
+    includeClasses = StringSetMatcher.getNonEmpty(conf.getStringArray("das.classes.include"));
+    excludeClasses = StringSetMatcher.getNonEmpty(conf.getStringArray("das.classes.exclude"));
+
+    includeMethods = StringSetMatcher.getNonEmpty(conf.getStringArray("das.methods.include"));
+    excludeMethods = StringSetMatcher.getNonEmpty(conf.getStringArray("das.methods.exclude"));
+
+    fieldAbstractions = getFieldAbstractions(conf);
+  }
+
+  
+  protected List<FieldAbstraction> getFieldAbstractions(Config conf){
+    List<FieldAbstraction> list = null;
+    
+    String[] fids = conf.getCompactTrimmedStringArray("das.fields");
+    for (String id : fids) {
+      String keyPrefix = "das." + id;
+      String fs = conf.getString(keyPrefix + ".field");
+      if (fs != null) {
+        FieldSpec fspec = FieldSpec.createFieldSpec(fs);
+        if (fspec != null) {
+          String aKey = keyPrefix + ".abstraction";
+          Abstraction abstraction = conf.getInstance(aKey, Abstraction.class);
+
+          logger.info("found field abstraction for ", fspec, " = ", abstraction.getClass().getName());
+          
+          if (list == null){
+            list = new LinkedList<FieldAbstraction>();
+          }
+          
+          list.add(new FieldAbstraction(fspec, abstraction));
+        }
+      } else {
+        logger.warning("no field spec for id: " + id);
+      }
+    }
+    
+    return list;
+  }
+  
+  @Override
+  public void attach (VM vm){
+    super.attach(vm);
+    
+    if (fieldAbstractions != null){
+      Attributor attributor = new Attributor();
+      vm.addListener(attributor);
+    }
+  }
+  
+  
+  // note that we don't add the reference value here
+  @Override
+  public void processReference(int objref) {
+    if (objref != MJIEnv.NULL) {
+      ElementInfo ei = heap.get(objref);
+      if (!ei.isMarked()) { // only add objects once
+        ei.setMarked();
+        refQueue.add(ei);
+      }
+    }
+    
+    // we DON'T add the reference value to the buffer here
+  }
+
+  protected void processField(Fields fields, int[] slotValues, FieldInfo fi, FinalBitSet filtered) {
+    int off = fi.getStorageOffset();
+    if (!filtered.get(off)) {
+      Abstraction a = fi.getAttr(Abstraction.class);
+      if (a != null) {
+        if (fi.is1SlotField()) {
+          if (fi.isReference()) {
+            int ref = fields.getReferenceValue(off);
+            buf.add(a.getAbstractObject(ref));
+
+            if (a.traverseObject(ref)) {
+              processReference(ref);
+            }
+
+          } else if (fi.isFloatField()) {
+            buf.add(a.getAbstractValue(fields.getFloatValue(off)));
+          } else {
+            buf.add(a.getAbstractValue(fields.getIntValue(off)));
+          }
+        } else { // double or long
+          if (fi.isLongField()) {
+            buf.add(a.getAbstractValue(fields.getLongValue(off)));
+          } else { // got to be double
+            buf.add(a.getAbstractValue(fields.getDoubleValue(off)));
+          }
+        }
+
+      } else { // no abstraction, fall back to concrete values
+        if (fi.is1SlotField()) {
+          if (fi.isReference()) {
+            int ref = slotValues[off];
+            buf.add(ref);
+            processReference(ref);
+
+          } else {
+            buf.add(slotValues[off]);
+          }
+
+        } else { // double or long
+          buf.add(slotValues[off]);
+          buf.add(slotValues[off + 1]);
+        }
+      }
+    }
+  }
+
+  // non-ignored class
+  @Override
+  protected void processArrayFields(ArrayFields fields) {
+    buf.add(fields.arrayLength());
+
+    if (fields.isReferenceArray()) {
+      int[] values = fields.asReferenceArray();
+      for (int i = 0; i < values.length; i++) {
+        processReference(values[i]);
+        buf.add(values[i]);
+      }
+    } else {
+      fields.appendTo(buf);
+    }
+  }
+
+  // for ignored class, to get all live objects
+  protected void processNamedInstanceReferenceFields(ClassInfo ci, Fields fields) {
+    FinalBitSet filtered = getInstanceFilterMask(ci);
+    FinalBitSet refs = getInstanceRefMask(ci);
+    int[] slotValues = fields.asFieldSlots(); // for non-attributed fields
+
+    for (int i = 0; i < slotValues.length; i++) {
+      if (!filtered.get(i)) {
+        if (refs.get(i)) {
+          processReference(slotValues[i]);
+        }
+      }
+    }
+  }
+
+  // for ignored class, to get all live objects
+  protected void processNamedStaticReferenceFields(ClassInfo ci, Fields fields) {
+    FinalBitSet filtered = getStaticFilterMask(ci);
+    FinalBitSet refs = getStaticRefMask(ci);
+    int[] slotValues = fields.asFieldSlots(); // for non-attributed fields
+
+    for (int i = 0; i < slotValues.length; i++) {
+      if (!filtered.get(i)) {
+        if (refs.get(i)) {
+          processReference(slotValues[i]);
+        }
+      }
+    }
+  }
+
+  // for ignored class, to get all live objects
+  protected void processReferenceArray(ReferenceArrayFields fields) {
+    int[] slotValues = fields.asReferenceArray();
+    for (int i = 0; i < slotValues.length; i++) {
+      processReference(slotValues[i]);
+    }
+  }
+
+  // non-ignored class
+  @Override
+  protected void processNamedFields(ClassInfo ci, Fields fields) {
+    FinalBitSet filtered = getInstanceFilterMask(ci);
+    int nFields = ci.getNumberOfInstanceFields();
+    int[] slotValues = fields.asFieldSlots(); // for non-attributed fields
+
+    for (int i = 0; i < nFields; i++) {
+      FieldInfo fi = ci.getInstanceField(i);
+
+      if (declaredFieldsOnly && fi.getClassInfo() != ci) {
+        continue;
+      }
+
+      processField(fields, slotValues, fi, filtered);
+    }
+  }
+
+  // <2do> this should also allow abstraction of whole objects, so that
+  // we can hash combinations/relations of field values
+  @Override
+  public void process (ElementInfo ei) {
+    Fields fields = ei.getFields();
+    ClassInfo ci = ei.getClassInfo();
+
+    if (StringSetMatcher.isMatch(ci.getName(), includeClasses, excludeClasses)) {
+      buf.add(ci.getUniqueId());
+
+      if (fields instanceof ArrayFields) { // not filtered
+        processArrayFields((ArrayFields) fields);
+      } else { // named fields, potentially filtered & abstracted via attributes
+        processNamedFields(ci, fields);
+      }
+
+    } else { // ignored class
+      // we check for live non-ignored objects along all stack frames, so we should do the same for all objects
+      if (fields instanceof ArrayFields) {
+        if (fields instanceof ReferenceArrayFields) {
+          processReferenceArray((ReferenceArrayFields) fields);
+        }
+      } else {
+        processNamedInstanceReferenceFields(ci, fields);
+      }
+    }
+  }
+
+  @Override
+  protected void serializeFrame (StackFrame frame) {
+    MethodInfo mi = frame.getMethodInfo();
+    
+    if (StringSetMatcher.isMatch(mi.getFullName(), includeMethods, excludeMethods)){
+      // <2do> should do frame abstraction here
+      super.serializeFrame(frame);
+
+    } else {
+      if (processAllObjects) {
+        frame.visitReferenceSlots(this);
+      }
+    }
+  }
+
+  @Override
+  protected void serializeClass (StaticElementInfo sei) {
+    ClassInfo ci = sei.getClassInfo();
+    Fields fields = sei.getFields();
+
+    if (StringSetMatcher.isMatch(ci.getName(), includeClasses, excludeClasses)) {
+      buf.add(sei.getStatus());
+
+      FinalBitSet filtered = getStaticFilterMask(ci);
+      int[] slotValues = fields.asFieldSlots();
+
+      for (FieldInfo fi : ci.getDeclaredStaticFields()) {
+        processField(fields, slotValues, fi, filtered);
+      }
+
+    } else {
+      // ignored class, but still process references to extract live objects
+      processNamedStaticReferenceFields(ci, fields);
+    }
+  }
+
+  @Override
+  protected void serializeClassLoaders(){
+    // we don't care about the number of classloaders
+    
+    for (ClassLoaderInfo cl : ks.classLoaders) {
+      if(cl.isAlive()) {
+        serializeStatics( cl.getStatics());
+      }
+    }
+  }
+
+  @Override
+  protected void serializeStatics(Statics statics){
+    // we don't care about the number of statics entries
+
+    for (StaticElementInfo sei : statics.liveStatics()) {
+      serializeClass(sei);
+    }
+  }
+}