Posts for the month of June 2011

Support for multiple attributes

support for multiple attributes was finally added for

  • ChoiceGenerators
  • objects (ElementInfo/Fields)
  • fields (ElementInfo/Fields)
  • operands (ThreadInfo/StackFrame)
  • locals (ThreadInfo/StackFrame)

The API is a compromise though, trying to balance runtime/memory costs, not changing existing clients, and providing new capabilities. The underlying implementation is using gov.nasa.jpf.util.ObjectList, which provides a static API to transparently handle lists that can either be a single Object value (i.e. no list, just a single element), or a linked list that uses a private type which does not conflict with potential element values. See ObjectList for restrictions and invariants (such as no null values etc.).

The assumed usage pattern is that listeners/peers use their own, private types for attributes, and retrieve attributes using such private types to make sure there are no other clients interfering with the same attribute types.

The general interface in the above classes looks like this

  • hasAttr()
  • hasAttr(Class<?>type)
  • getAttr() - returns all attributes (i.e. either the single value or the list head), so use only if you just want to copy all, or process elements by means of ObjectList (since it returns either an Object attr value, or a private ObjectList node instance)
  • getAttr(Class<T> type) - get the first attribute value of this type
  • getNextAttr(Class<T> type, Object prevValue) - iterate over the remaining attribute values of this type
  • attrIterator() - LIFO iterate over all attribute values (it's actually returning an Iterable, i.e. can be directly used in foreach loops)
  • attrIterator(Class<T> type) - LIFO iterate over all values of the specified type
  • setAttr(Object attr) - this sets all attributes, i.e. potentially overwrites the list head. Use only if you want to copy all that was obtained by a previous getAttr(), you want to make sure there is only a single attribute set, or what you set was created with ObjectList.createList(Object... a)
  • addAttr(Object attr) - this adds a new value as the first list element (which implies enumeration is LIFO)
  • removeAttr(Object attr) - uses equals() comparison to identify the attribute value to remove (if only one attribute remains, representation changes back to Object)
  • replaceAttr(Object oldAttr, Object newAttr) - if the order of attribute enumeration should not be changed

The danger is of course that some listeners/peers don't play nicely with others and just indiscriminately use get/setAttr(), overwriting everything. This in turn can cause funny force fights between multiple pre-exec listeners, post-exec listeners and peers. However, enforcing attribute containers and renaming the API would have ended in a lot of @Deprecated methods, which people just tend to ignore anyways. Since we still anticipate this is mostly used in a single attribute value context, adding containers would also also have imposed significant runtime overhead (attributes are state stored).

Bottom line is to be a nice citizen that (a) uses its own attribute types and (b) is aware of that there might be other attributes.

The jpf-core itself will not make use of attributes for internal purposes.