I’ve enhanced the parser of the Thread Checker to the point where it can correctly check the structure of compound predicate annotations and build a data structure that contains all the relevant information, including default values. This is a strange kind of parser, though: It parses Java class files, which are already represented in a kind of AST, and creates another AST that’s more suitable for my needs, one that omits a lot of irrelevant information, but collects pertinent data from all over the program in one place.
For now, I have decided that predicate annotations that represent the combination of other predicate annotations have to be marked with the meta-annotation
@Combine. As parameter to this meta-annotation, you can specify the Boolean operation, or mode, that will be used to combine the member predicate annotations. Possible modes are
@Combine(Combine.Mode.NOT); if no mode is specified, then “or” is assumed.
The behavior of
@Combine(Combine.Mode.NOT) may be a bit peculiar: The Boolean operation “not” is really intended to be applied to only one operand. However, I decided not to limit the number of member predicate annotations to one when “not” is selected as mode. Instead, I decided that the result of each member predicate annotation will be inverted, and then the inverses will be combined using “and”.
The rationale for this is that the default mode of combination is “or”:
a OR b OR c. De Morgan’s law tells us that
NOT (a OR b OR c) is
(NOT a) AND (NOT b) AND (NOT c). Therefore, if more than one predicate annotation is combined using “not”, it makes sense to combined the inverses using “and”.
For simplicity’s sake, I have also decided that the two meta-annotations that designate an annotation as Thread Checker annotation, namely
@Combine, are mutually exclusive. You can either define a new predicate annotation that uses a predicate method, or you can combine existing predicate annotations into compound annotations, but you cannot do both at the same time.
A result of this simplification is that I disallowed annotations and arrays of annotations in
@PredicateLink-type annotations, while
@Combine-type annotations may only contain other ThreadChecker annotations or arrays of ThreadChecker annotations as members.
To help me debug the parser, I have again enhanced the instrumentor that generates XML output. Thread Checker annotations that combine other annotations use a
<combine> tag instead of a
<predicate> tag, but the remainder of the output is identical.
To make sure that I correctly read in all the required data, including default values, I can optionally output the entire set of values in a
<values> tag nested beneath the
<predicate> tags. I still don’t think these values belong in the XML file, but right now they are helpful for debugging.
I still haven’t written any code that inserts bytecode into methods to actually call the predicate methods and log violations. That will be one of the more difficult tasks I’ve faced with the thread checker. One obstacle, for example, is that I have to add all the constant pool items that are used in the annotation to the constant pool of the class where the annotation is being used; if default values are present, then some constant pool items may not be present yet.
Another thing I have to consider is how I will actually deal with compound predicate annotations. The regualr kind of predicate annotation that actually has a link to a predicate method will be relatively easy to deal with: I set up the parameters, I make the call, I check the return value. But for compound predicate annotations, there is no single predicate method, there are several. And in the most complicated case, a compound predicate annotation may be comprised of predicate annotations that are compounds themselves, so it’s not even guaranteed that the member predicate annotations have associated predicate methods.
Right now, I think that I may automatically generate these predicate methods. That way, even when a compound is comprised of other compounds, the members have an auto-generated predicate method, and I can treat them the same as regular predicate annotations that have a user-written predicate method. But where do I put these auto-generated predicate methods? What name do I give them, and how do I find them?
I think I’ll sleep over those questions.