Theory of partial functions.
module partial_function(f,d,r) = {
axiom ~f(X:d,Y:r) | ~f(X:d,Z:r) | Y:r = Z:r
relation dom[f](X:d)
axiom ~f(X:d,Y:r) | dom[f](X:d)
schema img[f](x) = ~dom[f](x) | f(x,f[x])
update dom[f] from f
params v:d,w:r in v.f := w ->
ensures ((~old dom[f](X:d) | dom[f](X:d)) & dom[f](v))
params v:d in v.f := null ->
ensures (~old dom[f](X:d) | X:d = v | dom[f](X:d))
params v:d,w:d in v.f := w.f ->
ensures (old dom[f](Y:d) & Y:d ~= v | old dom[f](w) & Y:d = v) ->
dom[f](Y:d)
}
type object
type addr
module hack(f,x,d) = {
individual f[x] : d
}
instantiate hack(m0,ae1,addr)
relation (X:addr < Y:addr)
relation (X:addr <= Y:addr)
axiom ~(X < X)
axiom (X < Y & Y < Z) -> (X < Z)
axiom X <= Y <-> (X < Y | X = Y)
axiom X < Y | X = Y | Y < X
individual flo:addr,fhi:addr,tlo:addr,thi:addr
derived faddr(X:addr) = flo <= X & X < fhi
derived taddr(X:addr) = tlo <= X & X < thi
axiom ~(faddr(X) & taddr(X))
axiom taddr(tlo)
individual temp_addr:addr # TODO: this should be in macro below
macro incr_addr(x) = {
temp_addr := x;
x := *;
assume temp_addr < x;
assume ~(temp_addr < X & X < x);
temp_addr := *
}
relation repr(X:object,Y:addr)
instantiate partial_function(repr,object,addr)
individual hroot:object #root of the abstract heap
relation h0(X:object,Y:object)
instantiate partial_function(h0,object,object)
the machine memory
individual mroot:addr #address of root in machine memory
relation m0(X:addr,Y:addr)
instantiate partial_function(m0,addr,addr)
copied map
relation copied_to(A1:addr,A2:addr)
macro rep_inv = forall [O1,O2,A1,A2] ( repr(hroot,mroot) & (repr(O1,A1) & h0(O1,O2) -> domm0) & (repr(O1,A1) & h0(O1,O2) & m0(A1,A2) -> repr(O2,A2)) & (repr(O1,A1) & h1(O1,O2) -> domm1) & (repr(O1,A1) & h1(O1,O2) & m1(A1,A2) -> repr(O2,A2)))
init
repr(hroot,mroot)
& (repr(O1,A1) & h0(O1,O2) -> dom[m0](A1))
& (repr(O1,A1) & h0(O1,O2) & m0(A1,A2) -> repr(O2,A2))
& (repr(O1,A1) & repr(O2,A1) -> O1 = O2)
& (repr(O1,A1) & m0(A1,A2) -> dom[h0](O1))
& ((repr(O1,A1) & repr(O2, A2)) -> (m0(A1,A2) <-> h0(O1,O2)))
& (repr(O1,A1) -> faddr(A1))
& faddr(mroot) # root is in "from" region
& ~(m0(A1,A2) & faddr(A1) & ~faddr(A2))
& ~copied_to(A1,A2)
algorithm state variables
individual tnext:addr,talloc:addr
individual oe1:object,oe2:object,ae1:addr,ae2:addr,a:addr,obj:object,a2:addr
macro copy_obj(fr,to) = {
to.m0 := fr.m0;
fr.copied_to := to;
obj := *;
assume repr(obj,fr);
obj.repr := to;
instantiate incr_addr(to)
}
macro sweep(field) = {
a := *; # TODO: should be a := tnext.field
a2 := *;
if (dom[field](tnext)) {
assume field(tnext,a);
if * {
assume ~copied_to(a,X);
tnext.field := talloc;
assume talloc < thi;
instantiate copy_obj(a,talloc)
} else {
assume copied_to(a,a2);
tnext.field := a2
}
}
}
action initialize = {
talloc := tlo; # allocation pointer
tnext := tlo; # next object to sweep
instantiate copy_obj(mroot,talloc);
mroot := tlo
}
action step = {
assume tnext < talloc & talloc < thi;
instantiate sweep(m0);
instantiate incr_addr(tnext)
}
action error = {
assume tnext = talloc;
instantiate img[m0](ae1);
assume ~(
repr(hroot,mroot)
& taddr(mroot)
& (repr(oe1,ae1) & h0(oe1,oe2) & taddr(ae1) -> dom[m0](ae1))
& (repr(oe1,ae1) & h0(oe1,oe2) & taddr(ae1) & m0(ae1,ae2) -> repr(oe2,ae2) & taddr(ae2))
& (repr(oe1,ae1) & repr(oe2,ae1) -> oe1 = oe2)
)
}
concept spaces from interpolants
concept itp_a = ~domrepr concept itp_b = ~repr(hroot, mroot) concept itp_d = ~taddr(mroot) concept itp_c = (tnext = talloc) concept itp_e = (talloc = fhi * tnext = fhi * ~repr(hroot, mroot)) concept itp_f = (tnext = talloc * ~repr(hroot, mroot)) concept itp_g = (thi = temp_addr) concept itp_h = (~taddr(talloc) * talloc < thi) concept itp_i = (tnext = talloc * ~taddr(talloc)) concept itp_j = (~taddr(tnext)) concept itp_k(V0) = (~domm1 * h1(hroot, V0)) concept itp_l(V1) = (tnext = talloc * h1(hroot, V1)) concept itp_m(V0, V1, V2) = (~repr(V1, V0) * h1(V2, V1) * m1(V0, V0) * repr(V2, V0) * taddr(V0)) concept itp_n(V0, V1) = (talloc = fhi * tnext = fhi * ~repr(hroot, V0) * h1(V1, hroot) * m1(V0, V0) * repr(V1, V0) * taddr(V0)) concept itp_o(V0, V1) = (~domm0 * tnext < V0 * h0(V1, V1) * repr(V1, V0)) concept itp_p(V1) = (~domm0 * h0(V1, V1) * repr(V1, talloc)) concept itp_q = (tnext < mroot) concept itp_r = (tnext = mroot) concept itp_s(V2) = (talloc < flo * h0(V2, obj) * m0(talloc, talloc) * repr(V2, talloc)) concept itp_t(V3) = (talloc < thi * h0(V3, obj) * m0(thi, talloc) * repr(V3, thi)) concept itp_u(V3) = (talloc < thi * h0(V3, hroot) * m0(thi, talloc) * repr(V3, thi)) concept itp_v(V0, V2) = (thi = flo * V0 < flo * h0(V2, hroot) * m0(V0, V0) * repr(V2, V0)) concept itp_w(V2) = (talloc < flo * h0(V2, hroot) * m0(talloc, talloc) * repr(V2, talloc)) concept itp_x(V3) = (talloc < thi * h0(V3, hroot) * m0(talloc, talloc) * repr(V3, talloc)) concept itp_y(V1, V4, V2) = (V2 < thi * tnext < V2 * h0(V4, hroot) * m0(V1, V2) * repr(V4, V1)) concept itp_z(V2, V0) = (tnext = talloc * h0(V2, hroot) * m0(V0, talloc) * repr(V2, V0)) concept itp_a0 = (tnext < temp_addr) concept itp_b0(V0, V1) = (~domm1 * tnext < V0 * h1(V1, V1) * repr(V1, V0)) concept itp_c0(V0) = (V0 < tnext * taddr(V0)) concept itp_e0(V0, V1, V2) = (V0 < tnext * h0(V1, V2) * repr(V1, V0) * ~domm0) concept itp_e1(V0, V1, V2) = (V0 < tnext * h1(V1, V2) * repr(V1, V0) * ~domm1)
conjecture repr(hroot, mroot)
conjecture taddr(mroot)
conjecture tlo <= tnext & tnext <= talloc
conjecture tnext < thi
conjecture tlo <= talloc & talloc <= thi
conjecture mroot = tlo
conjecture repr(O1, A) & repr(O2, A) -> O1 = O2
conjecture repr(O, A) -> ((faddr(A) & ~copied_to(A, X)) | (tlo <= A & A < talloc))
conjecture (repr(O1,A1) & h0(O1,O2) -> dom[m0](A1))
conjecture (repr(O1, A1) & h0(O1, O2) & repr(O2, A2) & m0(A1, A3)) -> (A2 = A3 | copied_to(A3, A2))
conjecture (taddr(A1) & m0(A1,A2) & A1 < tnext) -> (taddr(A2) & A2 < talloc)
conjecture (tnext <= A1 & A1 < talloc & m0(A1,A2)) -> faddr(A2)
conjecture (repr(O1, A1) & repr(O2, A2) & m0(A1, A2)) -> h0(O1, O2)
conjecture (faddr(A1) & m0(A1,A2)) -> faddr(A2)
conjecture (repr(O1, A1) & repr(O2, A3) & m0(A1, A2) & copied_to(A2, A3)) -> h0(O1, O2)
conjecture (repr(O1,A1) & h0(O1,O2) & m0(A1,A2) & taddr(A2)) -> repr(O2,A2)
conjecture (repr(O1,A1) & h0(O1,O2) & m0(A1,A2) & copied_to(A2, A3)) -> repr(O2,A3)
conjecture ~(m0(A1,A2) & faddr(A1) & ~faddr(A2))
conjecture copied_to(A1,A2) -> faddr(A1)
conjecture copied_to(A1,A2) -> tlo <= A2
conjecture copied_to(A1,A2) -> A2 < tallocยค
conjecture (copied_to(A,A1) & copied_to(A,A2)) -> A1 = A2
conjecture (copied_to(A1,A) & copied_to(A2,A)) -> A1 = A2
well, actually, it turn's out we can do without it by using strong enought universal clauses, and put all of the existential that we need in the unproved "assert rng[repr]" in copy_obj. But it might stil be a useful idea.