PALE to MONA translation

This section describes the translation procedure from PALE to MONA. The reader is assumed to be familiar with the basic ideas of the Pointer Assertion Logic, the PALE syntax and MONA syntax and semantics.

"Tc" denotes the type assigned to the construct c. All PALE identifiers are implicitly prefixed by "$" to avoid name clashes. Also, every 'v' variable used below stands for a fresh variable.


Reducing to the basic language

Before translating a PALE program into a MONA formula, the extension constructs are reduced to equivalent basic constructs by the following rules.

Assertion moving

For the code

if (condexp) {stm1} {stm2} stm3

where stm1 or stm2 (or both) contain a while, split, or procedure call and stm3 is non-empty (in which case it must begin with a while, split, or procedure call),

assert [formula] {pointerformula ...}

is inserted in both branches after stm1 and stm2, respectively. If stm3 begins with a while, formula is the loop invariant; if it begins with a split, formula is the first split formula; and if it begins with a procedure call, formula is the call invariant. The pointerformulas are those associated the formula.

If {stm2} is omitted, {} is used by default.

(The purpose of this rule is to reduce the number of required annotations.)

split statements

The code

split [formula1] {pointerformula1 ...} [formula2] {pointerformula2 ...}stm

where stm is the sequence of statements following the split statement (until the end of the innermost enclosing if branch, or the end of the current transduce) is replaced by

assert [formula1] {pointerformula1 ...}

and a new transduce is added:

transduce [formula2] {pointerformula2 ...}
stm

If [formula2] is omitted, formula1 is used in place of formula2. If [formula2] is present, a warning is generated because validity of formula2 in general cannot be verified (i.e. the rule is unsound).

while statements

The code

while [formula] {pointerformula ...} (condexp) {stm} stm'

where stm' is the sequence of statements following the while statement (until the end of the innermost enclosing if branch, or the end of the current transduce) is replaced by

assert [formula] {pointerformula ...}

and two new transduces are added:

transduce [formula & condexp] {pointerformula ...}
stm
assert [formula] {pointerformula ...}

transduce [formula & !condexp] {pointerformula ...}
stm'

proc declarations

The code

proc n(progvar1, progvar2, ...):T
logicvar1; logicvar2; ...
[formula1] {pointerformula1 ...}
{
  progvar'1; progvar'2; ...
  stm
}
[formula2] {pointerformula2 ...}

is replaced by

pointer _n__return:T;
progvar1, progvar2, ..., progvar'1; progvar'2; ...   (where each variable is renamed from v to _n_v)

transduce logicvar1; logicvar2; ... [formula1 & progvar'1=null & progvar'2=false & ...] {pointerformula1 ...}
              (assuming progvar'1 is a data or pointer and progvar'2 is a bool)
stm
assert [formula2] {pointerformula2 ...}

pred _n__pre(progvar1, progvar2, ..., logicvar1, logicvar2, ...) = formula1;

pred _n__post(logicvar1, logicvar2, ...) = formula2;

All data variables in _n__pre(...) are changed to pointer variables, and all references to the arguments and local variables in stm are replaced by their new names.

If the return type is bool instead of a type T, then "bool _n__return" is used instead of "pointer _n__return:T". If the return type is void, the variable is omitted.

If the procedure body is omitted (i.e. the declaration is a procedure prototype declaration), the transduce is not generated.

return statements and expressions

The statement

return progexp;

occuring in the procedure n is replaced by

_n__return = progexp;

The expression

return

occuring in the procedure n is replaced by

_n__return

proccall statements and expressions

The code

lprogexp = n(progexp1, progexp2, ...) [formula]; stm

where stm is the sequence of statements following the procedure call statement (until the end of the innermost enclosing if branch, or the end of the current transduce) is replaced by

assert [QUANTIFY formula & _n__pre(progexp1, progexp2, ..., logicvar1, logicvar2, ...)] {pointerformulapre ...}

where logicvar1, logicvar2, ... are the names of the logical variables of the procedure n prefixed by _n___, and a new transduce is added:

transduce [QUANTIFY formula & _n__post(logicvar1, logicvar2, ...)] {pointerformulapost ...}
lprogexp = _n__return;
stm

The pointerformulas are those from the procedure being called.

Every occurence of n.p, n.b, and n.s in formula is replaced by _n___p, etc. QUANTIFY is a list of existential quantifiers of logicvar1, logicvar2, ... (again prefixed by _n___) of the appropriate types (see EXISTSLOGICVARS below).

If "lprogexp = " is omitted, the assignment is to lprogexp is omitted.

Every "?" occuring as an actual parameter is replaced by _choice_i (where i is the number of the occurence) declared globally by "var0 _choice_i;".


Encoding the basic language in MONA

A desugared PALE program is translated into MONA formulas by 1) making the guide declaration and global variables, 2) initialising the transduction predicates, and 3) encoding each transduce as described below.

The encoding of expressions is relative to a "current" set of store predicates, indexed by z. The store predicates are those shown below under "initial transduction predicates".

Guide declaration

Declaration of the Guided Tree Automaton guide (the guide places for each data variable an instances of the its type in the infinite binary tree) and emulation of M2L-Tree:

ws2s;
guide boolss->(top_1,dummy1),
  top_1->(
Td1,top_2), ..., top_n-1->(Tdn-1,Tdn),   (for each data variable d of type Td)
  Ti->(Tdi,1,Ti_1),
..., Ti_m-1->(Tdi,m-1,Tdi,m), ...,   (for all data fields di,j in Ti and for all Ti used by a data variable)
  dummy1->(dummy1,dummy1),
  dummy2->(dummy2,dummy2);
  (used when less than 2 data variables or less than 2 data fields)
universe univ:0,dummyuniv:1;

var2 [top_1,...,top_n-1,Td1, ..., Tdn] $ where all1 p: (p in $) => ((p^ in $) | (p^=p));
allpos $;
defaultwhere2(P) = P sub $;

Global MONA variables

Pointer encoding:

pred ptr(var2 X) = X sub $ & (all1 [X] p,q: p in X & q in X => p=q);
pred null(var2 X) = empty(X);

Variables for encoding the initial store:

var2 [Tp] _ptr_p where ptr(_ptr_p);     (for each pointer variable p)
var0 _bool_b;     (for each bool variable b)
var2 [Ts] _set_s;     (for each set variable s)
var2 [Tb] _bool_T_b;     (for each bool field b in some type T)

Nondeterministic choices:

var0 _choice_i;     (for each occuring '?' (where i is its number)

Initial transduction predicates

Encoding of the initial store ("path of" is the path corresponding to the guide encoding and "p-path" is a unique path leading to a root state-space of the appropriate type):

pred bool_T_b_z(var2 v where ptr(v)) = v sub _bool_T_b;     (for each bool field b in some type T)

pred succ_T_p_z(var2 v1 where ptr(v1), var2 v2 where ptr(v2)) = v1.<path of T.p> inter $=v2;     (for each data field p in some type T)
pred null_T_p_z(var2 v where ptr(v)) = ~v.<path of T.p> sub $;     (for each data field p in some type T)

pred succ_T_p_z(var2 this where ptr(this), var2 p where ptr(p)) = [[formula]]z;     (for each pointer field p associated formula in some type T)
pred null_T_p_z(var2 this where ptr(this)) =
  ex2 [
Tp] p where ptr(p): succ_T_p_z(this,p) & null(p);     (for each pointer field p in some type T)

pred ptr_p_z(var2 v where ptr(v)) =
  (null(v)<=>root(univ).<
p-path> notin $) & (~null(v)<=>root(univ).<p-path> in v);     (for each data variable p)

pred ptr_p_z(var2 v) = _ptr_p=v;     (for each pointer variable p)

pred bool_b_z() = _bool_b;     (for each bool variable b)

pred memfailed_z() = false;

"formula" refers to the pre-condition pointer formula in the current transduce for the appropriate pointer field, or if no such formula, to the "default" pointer field formula specified in the type declaration.

(The M2L-Tree variable '$' determines the extent of the backbone; data variables are universes; boolean fields and sets are represented by second-order MONA variables; pointer variables are empty or singleton second-order variables; and boolean variables in PALE become boolean variables in MONA.)

Encoding of formula, condexp, boolexp, and lboolexp

"[[c]]z" denotes the MONA encoding of the PALE formula, condexp, boolexp, or lboolexp construct c:

[[?]]z  =  _choice_i     (where i is the number of the "?")
[[existpos p of T: formula]]z  =  ex2 [T] p where ptr(p): ~null(p) & [[formula]]z
[[allpos p of T: formula]]z  =  all2 [T] p where ptr(p): ~null(p) => [[formula]]z
[[existset s of T: formula]]z  =  ex2 [T] s: [[formula]]z
[[allset s of T: formula]]z  =  all2 [T] s: [[formula]]z
[[existptr p of T: formula]]z  =  ex2 [T] p where ptr(p): [[formula]]z
[[allptr p of T: formula]]z  =  all2 [T] p where ptr(p): [[formula]]z
[[existbool b: formula]]z  =  ex0 b: [[formula]]z
[[allbool b: formula]]z  =  all0 b: [[formula]]z
[[! formula]]z  =  ~[[formula]]z
[[formula1 & formula2]]z  =  [[formula1]]z & [[formula2]]z
[[formula1 | formula2]]z  =  [[formula1]]z | [[formula2]]z
[[formula1 => formula2]]z  =  [[formula1]]z => [[formula2]]z
[[formula1 <=> formula2]]z  =  [[formula1]]z <=> [[formula2]]z
[[ptrexp in setexp]]z  =  ex2 [Tptrexp] v1 where ptr(v1): ex2 [Tsetexp] v2: v1 sub v2 & ~null(v1) & [[ptrexp]]z(v1) & [[setexp]]z(v2)
[[setexp1 sub setexp2]]z  =  ex2 [Tsetexp1] v1: ex2 [Tsetexp2] v2: v1 sub v2 & [[setexp1]]z(v1) & [[setexp2]]z(v2)
[[setexp1 = setexp2]]z  =  ex2 [Tsetexp1] v1: ex2 [Tsetexp2] v2: v1=v2 & [[setexp1]]z(v1) & [[setexp2]]z(v2)
[[setexp1 != setexp2]]z  =  ~[[setexp1 = setexp2]]z
[[ptrexp1 = ptrexp2]]z  =  NULL(ptrexp2)   if ptrexp1 is null
                            = NULL(ptrexp1)   otherwise, if ptrexp2 is null
                            = ex2 [Tptrexp1] v1 where ptr(v1): ex2 [Tptrexp2] v2 where ptr(v2):
                             v1=v2 &
[[ptrexp1]]z(v1) & [[ptrexp2]]z(v2)   otherwise
[[ptrexp1 != ptrexp2]]z  =  ~[[ptrexp1 = ptrexp2]]z
[[boolexp1 = boolexp2]]z  =  [[boolexp1]]z <=> [[boolexp2]]z
[[boolexp1 != boolexp2]]z  =  ~[[boolexp1 = boolexp2]]z
[[empty ( setexp )]]z  =  ex2 [Tsetexp] v: empty(v) & [[setexp]]z(v)
[[ptrexp1 < routingexp > ptrexp2]]z  =  ex2 [Tptrexp1] v1 where ptr(v1): ex2 [Tptrexp2] v2,v3 where ptr(v3):
    v3 sub v2 & (null(v1) <=> null(v3)) &
[[ptrexp1]]z(v1) & [[ptrexp2]]z(v3) & [[routingexp]]z(v1,v2)
[[ptrexp < routingexp > setexp]]z  =  ex2 [Tptrexp] v1 where ptr(v1): ex2 [Tsetexp] v2:
   
[[ptrexp]]z(v1) & [[setexp]]z(v2) & [[routingexp]]z(v1,v2)
[[formula1 ? formula2 : formula3]]z = ex0 t: (t<=>[[formula1]]z) & (t=>[[formula2]]z) & (~t=>[[formula3]]z)
[[m ( ptrexp1, boolexp2, setexp3, ... )]]z  = 
    ex2 [Tptrexp1] v1 where ptr(v1): [[ptrexp1]]z(v1) &
    ex0 v2: (v2<=>
[[boolexp2]]z) &
    ex2 [
Tsetexp3] v3: [[setexp3]]z(v3) &
    ... &
    ex2 [
Tf1] f1 where ptr(f1): f1=v1 &
    ex0
f2: (f2<=>v2) &
    ex2 [
Tf3] f3: f3=v3 &
    ... &
[[body]]z   (where body is the body of m and f1, f2, f3, ... are the formal parameters of type pointer, bool, set, ..., respectively)
[[true]]z  =  true
[[false]]z  =  false
[[b]]z  =  bool_b_z()   if b refers to a global MONA declaration
       =  b         if b refers to a quantifier
[[ptrexp . b]]z  =  ex2 [Tptrexp] v where ptr(v): bool_Tv_b_z(v) & ~null(v) & [[ptrexp]]z(v)

Encoding of ptrexp, lptrexp, and setexp

"[[c]]z(v)" here denotes the MONA encoding of the PALE ptrexp, lptrexp, or setexp construct c, with its value bound to the variable v:

[[s]]z(v)  =  _set_s=v   if s refers to a global MONA declaration
         =  s=v         if s refers to a quantifier
[[p]]z(v)  =  ptr_p_z(v)   if p refers to a global MONA declaration
         =  p=v         if p refers to a quantifier
[[this]]z(v)  =  this=v   (same for pos)
[[null]]z(v)  =  null(v)
[[ptrexp . p]]z(v)  =  ex2 [Tptrexp] v' where ptr(v'): succ_Tv_p_z(v',v) & ~null(v') & [[ptrexp]]z(v')
[[ptrexp ^ T . p]]z(v)  = 
    all2 [Tv] v'' where ptr(v''): ~null(v'') =>
      (v'' sub v <=> ex2 [Tptrexp] v' where ptr(v'): ~null(v') & [[ptrexp]]z(v') & succ_T_p_z(v'',v'))
[[formula ? ptrexp1 : ptrexp2]]z(v) = ex0 t: (t<=>[[formula]]z) & (t=>[[ptrexp1]]z(v)) & (~t=>[[ptrexp2]]z(v))
[[formula ? setexp1 : setexp2]]z(v) = ex0 t: (t<=>[[formula]]z) & (t=>[[setexp1]]z(v)) & (~t=>[[setexp2]]z(v))
[[{ ptrexp1,... }]]z(v)  =  ex2 [Tptrexp1] v1 where ptr(v1): [[ptrexp1]]z(v1) & ... & v=v1 union ...
[[setexp1 union setexp2]]z(v)  =  ex2 [Tsetexp1] v1: ex2 [Tsetexp2] v2: v=v1 union v2 & [[setexp1]]z(v1) & [[setexp2]]z(v2)
[[setexp1 inter setexp2]]z(v)  =  ex2 [Tsetexp1] v1: ex2 [Tsetexp2] v2: v=v1 inter v2 & [[setexp1]]z(v1) & [[setexp2]]z(v2)
[[setexp1 minus setexp2]]z(v)  =  ex2 [Tsetexp1] v1: ex2 [Tsetexp2] v2: v=v1 \ v2 & [[setexp1]]z(v1) & [[setexp2]]z(v2)

Encoding of routingexp

"[[c]]z(v1,v2)" denotes the MONA encoding of the PALE routingexp c, with its begin and end values bound to the variables v1 and v2, respectively:

[[p]]z(v1,v2)  =  DOWN(v1,v2,p) & all2 [Tp] v: DOWN(v1,v,p) => v2 sub v
[[^ T . p]]z(v1,v2)  =  UP(v1,v2,p) & all2 [Tp] v: UP(v1,v,p) => v2 sub v
[[[ formula ]]]z(v1,v2)  =  all2 [Tv1] pos where ptr(pos): ~null(pos) => (pos sub v2 <=> pos sub v1 & [[formula]]z)
[[routingexp1 . routingexp2]]z(v1,v2)  =  ex2 [Troutingexp1] v: [[routingexp1]]z(v1,v) & [[routingexp2]]z(v,v2)
[[routingexp1 + routingexp2]]z(v1,v2)  =  ex2 [Troutingexp1] v,v': v2=v union v' & [[routingexp1]]z(v1,v) & [[routingexp2]]z(v1,v')
[[routingexp *](v1,v2)  =  STAR(routingexp,v1,v2) & ~ex2 [Troutingexp] v: STAR(routingexp,v1,v) & v sub v2 & v~=v2

DOWN(src,dst,p) =  all2 [Tsrc] v1 where ptr(v1): ~null(v1) & v1 sub src & ~null_Tsrc_p_z(v1) =>
      ex2 [
Tdst] v2 where ptr(v2): ~null(v2) & v2 sub dst & succ_Tsrc_p_z(v1,v2)
UP(src,dst,p) =  all2 [Tsrc] v1 where ptr(v1): ~null(v1) & v1 sub src =>
      all2 [
Tdst] v2 where ptr(v2): ~null(v2) & succ_Tdst_p_z(v2,v1) => v2 sub dst
STAR(routingexp,src,dst) =  src sub dst & all2 [Troutingexp] v1,v2: v1 sub dst & [[routingexp]]z(v1,v2) => v2 sub dst

Encoding of statements

Each statement is encoded as a predicate transformer by updating certain store predicates (z and z' denote the "before" and "after" store predicate indices, respectively; those predicates that are not mentioned are unchanged):

Sequence:

stm1 stm2:

If z'' denotes the store predicate index after transducing stm1 starting from z, then z' is the store predicate index after transducing stm2 starting from z''.

Assignment:

A multi-assignment (i.e. a comma-separated list of assignments) is encoded as if it was a statement sequence, except that the individual assignments all are evaluated with respect to the original store predicate index z.

p = ptrexp:

pred memfailed_z'() = memfailed_z() | NULLDEREF(ptrexp);
pred ptr_p_
z'(var2 v where ptr(v)) = [[ptrexp]]z(v);

b = condexp:

pred memfailed_z'() = memfailed_z() | NULLDEREF(condexp);
pred bool_b_
z'() = [[condexp]]z;

ptrexp1.p = ptrexp2:

pred memfailed_z'() = memfailed_z() | NULLDEREF(ptrexp1.p) | NULLDEREF(ptrexp2);
pred succ_
Tptrexp1_p_z'(var2 v1 where ptr(v1), var2 v2 where ptr(v2)) =
    IF
[[ptrexp1]]z(v1) THEN [[ptrexp2]]z(v2) ELSE succ_Tptrexp1_p_z(v1,v2);
pred null_
Tptrexp1_p_z'(var2 v where ptr(v)) =
    IF
[[ptrexp1]]z(v) THEN NULL(ptrexp2) ELSE null_Tptrexp1_p_z(v);

ptrexp.b = condexp:

pred memfailed_z'() = memfailed_z() | NULLDEREF(ptrexp.b) | NULLDEREF(condexp);
pred bool_
Tptrexp_b_z'(var2 v where ptr(v)) =
    IF
[[ptrexp]]z(v) THEN [[condexp]]z ELSE bool_Tptrexp_b_z(v);

Assertion:

assert [formula] { pointerformula ... }:

pred assertfailed_z'(DECLLOGICVARS) = assertfailed_z(LOGICVARS) | ~[[formula]]z | ~POINTERSTYPECORRECT;

The pointerformulas specify formulas which override the defaults in the type declarations. If a pointerformula is specified without a formula, that pointer field is skipped.

Conditional:

if (condexp) {stm1} {stm2}:

pred memfailed_z'() = memfailed_z() | NULLDEREF(condexp);
pred branch_
i() = [[condexp]]z;
  (where i is the number of the conditional)

Let z1 and z2 denote the store predicate indices obtained by performing predicate transformation of stm1 and stm2, respectively, starting from index z.

pred memfailed_z'() =
    IF branch_
z() THEN memfailed_z1() ELSE memfailed_z2();
pred assertfailed_z'(DECLLOGICVARS) =
    IF branch_
z() THEN assertfailed_z1(LOGICVARS) ELSE assertfailed_z2(LOGICVARS);
pred ptr_p_z'(var2 t where ptr(t)) =
    IF branch_
z() THEN ptr_p_z1(t) ELSE ptr_p_z2(t);     (for each pointer or data variable p)
pred bool_b_z'() =
    IF branch_
z() THEN bool_b_z1() ELSE bool_b_z2();     (for each bool variable b)
pred bool_T_b_z'(var2 t where ptr(t)) =
    IF branch_
z() THEN bool_T_b_z1(t) ELSE bool_T_b_z2(t);     (for each bool field b in some type T)
pred succ_T_p_z'(var2 t1 where ptr(t1), var2 t2 where ptr(t2)) =
    IF branch_
z() THEN succ_T_p_z1(t1,t2) ELSE succ_T_p_z2(t1,t2);     (for each pointer or data field d in some type T)
pred null_T_p_z'(var2 t where ptr(t)) =
    IF branch_
z() THEN null_T_p_z1(t) ELSE null_T_p_z2(t);     (for each pointer or data field p in some type T)

Abbreviations used above:

                / null(p)   if ptrexp is a quantified variable p
               /  ex2 [Tp] t where ptr(t): null(t) & ptr_p_z(t)   if ptrexp is a global pointer or data variable p
NULL(ptrexp) = <   ex2 [Tptrexp'] v where ptr(v): null_Tptrexp'_p_z(v) & [[ptrexp']]z(v)   if ptrexp is ptrexp'.p
               \  true   if ptrexp is null
                \ false   otherwise

                    / NULLDEREF(ptrexp) | NULL(ptrexp)   if exp is ptrexp.p
                   /  NULLDEREF(exp1) | NULLDEREF(exp2) & [[exp1]]z   if exp is exp1 & exp2
                  /   NULLDEREF(exp1) | NULLDEREF(exp2) & ~[[exp1]]z   if exp is exp1 | exp2
NULLDEREF(exp) = <    NULLDEREF(exp1) | NULLDEREF(exp2) & [[exp1]]z   if exp is exp1 => exp2
                  \   NULLDEREF(exp1) | NULLDEREF(exp2)   if exp is exp1 <=> exp2
                   \  NULLDEREF(exp')   if exp is !exp'
                    \ false   otherwise

IF formula1 THEN formula2 ELSE formula3 =
    ex0 t: (t<=>
formula1) & (t=>formula2) & (~t=>formula3)

Encoding of transductions

The following MONA code is generated for each occurence of

transduce logicvars [formula] stm

w is the number of the transduction, z is a unique initial store predicate index, and z' is the store predicate index obtained by performing a transduction on stm starting from z. (The initial store predicates defined above are shared for all transductions, the assertfailed predicate initialized below is defined separately for each transduction.)

pred assertfailed_z(DECLLOGICVARS) = false;

Translate the transduce formula:

pred precond_w(DECLLOGICVARS) = [[formula]]z;   (where formula is the transduce formula)

pred precondsat_w() = EXISTSLOGICVARS precond_w(LOGICVARS);

Verify that the transduce formula is satisfiable, that there can be no null pointer dereferences, that the pointer field formulas are valid, that the backbone does not contain cycles, that the data variables are disjoint and span the same cells as before execution, and that the assertions are satisfied:

verify precondsat_w();

verify precondsat_w() => ~memfailed_w();

verify precondsat_w() => nocycles1_w() & nocycles2_w();

verify precondsat_w() => datadisjoint_w();

verify precondsat_w() => datacomplete_w();

verify FORALLLOGICVARS precond_w(LOGICVARS) => ~assertfailed_w(LOGICVARS);

Abbreviations used above:

DECLLOGICVARS: for each logical variable in the transduce, a comma-separated list of:
  var2 p where ptr(p)   (for pointer variables p)
  var0 b   (for boolean variables b)
  var2 s   (for set variables s)

LOGICVARS = v1,...,vn   (for all logical variables v1,...,vn in the transduce)

FORALLLOGICVARS = for each logical variable in the transduce:
  all2 [T] p where ptr(p):   (for pointer variables p of type T)
  all0 b:   (for boolean variables b)
  all2 [T] s:   (for set variables s of type T)

EXISTSLOGICVARS = for each logical variable in the transduce:
  ex2 [T] p where ptr(p):   (for pointer variables p of type T)
  ex0 b:   (for boolean variables b)
  ex2 [T] s:   (for set variables s of type T)

The following checks well-formedness of a pointer field formula p in a type T:

verify all2 [T] this: ~null(this) =>
  (all2 [
Tp] p,p': formula_T_p_w(this,p) & formula_T_p'_w(this,p') => p=p') &
  ex2 [
Tp] p: formula_T_p_w(this,p);

formula_T_p_w(this,p) is true for a pointer field p in a type T if the associated formula is satisfied in a store z:

pred formula_T_p_w(var2 this where ptr(this), p where ptr(p)) = [[formula]]z

Type-correctness predicates

Each transduction is associated the following predicates (where w is the number of the transduction and z is the final store predicate index of the transduction).

reachable(R) is true if R is the set of heap positions which are reachable in zero or more steps from the used global data and pointer variables:

pred containreachable_w(var2 R) =
  (ex2 [
Tp] t: ptr_p_z(t) & t sub R) & ... (for every global data and pointer variable p used in the current transduction)
  (all2 [
T] t where ptr(t): ~null(t) & t sub R =>
    (~null_
T_p_z(t) => ex2 [Tp] t' where ptr(t'): ~null(t') & succ_T_p_z(t,t') & t' sub R) & ... (for every data and pointer field p in T)
  ) & ... ;  
(for every type T)

pred reachable_w(var2 R) = containreachable_w(R) & ~ex2 R': containreachable_w(R') & R' sub R & R'~=R;

datareachable(R) is true if R is the set of heap positions which are reachable in zero or more data-field steps from the global data variables:

pred containdatareachable_w(var2 R) =
  (ex2 [
Tp] t: ptr_p_z(t) & t sub R) & ... (for every global data variable p)
  (all2 [
T] t where ptr(t): ~null(t) & t sub R =>
    (~null_
T_p_z(t) => ex2 [Tp] t' where ptr(t'): ~null(t') & succ_T_p_z(t,t') & t' sub R) & ... (for every data field p in T)
  ) & ... ;  
(for every type T)

pred datareachable_w(var2 R) = containdatareachable_w(R) & ~ex2 R': containdatareachable_w(R') & R' sub R & R'~=R;

reachablefrom(t,R) is true if R is the set of heap positions which are reachable from t in one or more data-field steps:

pred containreachablefrom_w(var2 tt where ptr(tt), var2 R) =
  (all2 [
T] t where ptr(t): ~null(t) & (t=tt | t sub R) =>
    (~null_
T_p_z(t) => ex2 [Tp] t' where ptr(t'): ~null(t') & succ_T_p_z(t,t') & t' sub R) & ... (for every data field p in T)
  ) & ... ;  
(for every type T)

pred reachablefrom_w(var2 tt where ptr(tt), var2 R) =
  containreachablefrom_
w(tt,R) &
  ~ex2 R': containreachablefrom_
w(tt,R) & (containreachablefrom_w(tt,R') & (R' sub R & R'~=R;))

nocycles1() is true if there is no reachable heap position which is reachable from itself in one or more data-field steps:

pred nocycles1_w() = all2 [T1,T2,...] R: reachable_w(R) =>   (where T1,T2,... are all declared types)
  (all2 [R] t where ptr(t): ~null(t) & t sub R => all2 [R] R': reachablefrom_
w(t,R') => ~(t sub R'));

nocycles2() is true if every two data fields in the same reachable cell can reach disjoint sets of cells:

pred nocycles2_w() = all2 [T1,T2,...] R: reachable_w(R) =>   (where T1,T2,... are all declared types)
  ...

datadisjoint() is true if the used data variables refer to disjoint graph type backbones:

pred datadisjoint_w() =
  (all2 [
T1,T2,...] R: (ex2 [Tp] t: ~null(t) & ptr_p_z(t) & reachablefrom_w(t,R)) =>
    (all2 [
T1,T2,...] R': (ex2 [Tp] t: ~null(t) & ptr_p'_z(t) & reachablefrom_w(t,R')) =>
      empty(R,R'))) & ... ;  
(for every pair of distinct data variables p,p' used in the current transduction)

datacomplete() is true if the cells reachable from data variables are the same as before executing the transduction code:

pred datacomplete_w() =
  all2 [
T1,T2,...] R,S: datareachable_w(R) & S sub $ => S sub R;

POINTERSTYPECORRECT is true if all pointer field formulas are satisfied for all reachable positions:

POINTERSTYPECORRECT =
  all2 [
T1,T2,...] R: reachable_w(R) =>   (where T1,T2,... are all declared types)
  (all2 [
T] this where ptr(this): ~null(this) & this sub R =>
   (all2 [
Tp] p where ptr(p): (succ_T_p_z(this,p) & ~null_T_p_z(this) | null(p) & null_T_p_z(this)) <=> [[formula]]z) & ...
       
(for every pointer field p associated formula)
  ) & ... ;  
(for every type T)

reachable2 is as reachable above, but tied to an assert instead of a transduce:

pred containreachable2_j(var2 R) =
  (ex2 [
Tp] t: ptr_p_z(t) & t sub R) & ... (for every global data and pointer variable p used in the current transduction)
  (all2 [
T] t where ptr(t): ~null(t) & t sub R =>
    (~null_
T_p_z(t) => ex2 [Tp] t' where ptr(t'): ~null(t') & succ_T_p_z(t,t') & t' sub R) & ... (for every data and pointer field p in T)
  ) & ... ;  
(for every type T)

pred reachable2_j(var2 R) = containreachable2_j(R) & ~ex2 R': containreachable2_j(R') & R' sub R & R'~=R;


Copyright © 2000-2002 Anders Møller