Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Β
Reasoning about memory-critical algorithms by Theo D'Hondt
1. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Growing an Abstract Grammar
Teaching Language
EngineeringTheo D'Hondt
Software Languages Lab
Vrije Universiteit Brussel
soft.vub.ac.be
tjdhondt@vub.ac.be
Reasoning about
memory-critical algorithms
1
2. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Abstract
We call algorithms memory-critical if their actual dependence on memory is such that their
implementation cannot use abstractions that indirectly require memory of their own. An
obvious example of such an abstraction is a recursion stack. An equally obvious example
of a memory-critical algorithm is a garbage collector.
Generally, memory-critical algorithms are designed as state machines that apply a clever
technique to embed a greatly resized version of the abstraction-related memory within the
actual memory. Typically these algorithms end up being very terse and hard to conceive or
comprehend, and when expressed as actual code they are equally hard to debug or
optimise.
Memory-critical algorithms have been the object of scientific publications, educational
material and actual software since the early 60ies. In order to present these algorithms,
techniques ranging from mathematical formalisms, graphical representations to
pseudocode have been proposed. Unfortunately, these all suffer from the pithy nature of
these algorithms and the lack of a uniform medium to reason about them. Hence their
notoriously bad reputation for instance with students of advanced algorithms courses.
This talk will report on an initiative to bind formalism, graphics and (executable) code in a
framework to reason about memory-critical algorithms. It started out as an accumulation
of convenient representations, and grew into something that has the hallmark of a
systematic approach. It will be introduced by applying it to two historical algorithms, and
subsequently two non-trivial experiments will be briefly described.
2
5. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cheney's algorithm
C. J. Cheney
A nonrecursive list compacting algorithm.
Comm. ACM 13, 11 (1970)
h coding. It
that are de-
ple, efficient,
s few probes
Comm. ACM 11, 1 (Jan. 1968), 38--44.
3. BELL, J. R. The quadratic quotient method: A hash code
eliminating secondary clustering. Comm. ACM 13, 2 (Feb.
1970), 107-109.
4. RADKE,E.E. The use of quadratic residue research. Comm.
ACM 13, 2 (Feb. 1970), 103-105.
acting
dge, England
g scheme or
and LISP-like
the need for
ilt up to keep
ollection, compacl
[2] have pre-
uctures. One
a list pointer,
he authors of
but complex
m of Deutsch,
ler algorithm
T to copy a
list area (the
copied with-
new list area
s found will
the structure
r from them,
ect the list in
"nonitems."
The structure is accessed via the pointer HEAD. This
structure has two lists, the first consisting of three atoms
A, B, C and a list pointer to the second list which consists
solely of a list pointer to the atom A of the first list. Lists
+o
(a)
HEAD I q/q
SCAN't NEXT~
(b)
:: i i .... :HEAD
,+AIBIΒ’I I/1
SCANT NEXTT
(c)
I ,..... '.---5....,_.,,I I I
, I , .~ Itl/l
I I I Is
I
I I I
+
HEAD dAiSlCi ~,iA i,i/, 1
TNEXT
SCAN
(d)
old
list
area
new
list
area
FIG. 1. Compacting a structure without looped lists: (a) initial
structure; (b) and (c) during processing; (d) final structure.
Communications of the ACM 677
are terminated by NIL cells. The algorithm with some
modification can be applied to LISP-type structures.
To compact the structure, the list pointed to by HEAD
is copied by COPYLIST into the new area--the contents
of each item (not nonitems) are placed in consecutive cells
in the new area, and the cells in the old area are changed
to nonitems pointing to their equivalent cells in the new
area. COPYLIST returns as a result the address of the
first cell of the list in the new area. This value is used to
update HEAD. A pointer NEXT is kept pointing to the
next free cell in the new area. This intermediate structure
is shown in Figure 1(b).
A further pointer SCAN now scans the new area from
the beginning. If SCAN points to a NIL or an atom, it is
moved on to the next cell. If SCAN points to a list pointer,
COPYLIST is entered with this list pointer as its param-
eter. The sublist is therefore copied, updating NEXT,
and the value returned is used to make the list pointer
pointed at by SCAN point to the copied list in the new
area. The structure resulting when SCAN has processed
the first list pointer is shown in Figure 1(c). Note that, in
copying, COPYLIST omits the nonitems of the original
structure.
SCAN continues its traverse of the new area and will
pass over the NIL to the second list to reach another list
pointer. COPYLIST is again applied, but this time it
finds the first item is already in the new area (e.g. by com-
paring core addresses), and the function returns with the
address of this cell in the new area, which is used to update
the list pointer, but without recopying the list.
The compact structure is complete when SCAN reaches
the cell pointed to by NEXT. The procedure is capable of
dealing with looped lists as COPYLIST will place a non-
item in the new area when necessary (see Figure 2).
(o)
o,0
HEAD listorgc]
i i
I i
i I fleW
A version has been written in assembly language in-
volving the execution of between 30 and 40 orders on an
Atlas computer for each item of the structure transferred
to the new area.
The algorithm is presented below in two parts--the
"main program" first, and then the function COPYLIST.
Step 1. Initialize the pointers SCAN and NEXT to point to the
beginning of the new list area.
Step 2. Apply the function COPYLIST--described below--to
the pointer that points to the whole structure and assign
the result of COPYLIST to that pointer.
Step 3. If SCAN points to a list-pointer, then apply COPYLIST
to that list pointer, the result of COPYLIST replaces the
contents of the cell pointed at by SCAN.
Step 4. Increment SCAN, unless SCAN now points to the same
cell pointed at by NEXT, go to step 3 above. Otherwise the
compacting is complete.
The function COPYLIST takes one parameter,
POINTER, called by value; the function does the follow-
ing:
Step 1. If POINTER points to a cell that is a nonitem, make
POINTER point to the cell pointed at by the nonitem. Re-
peat this step while POINTER points to a nonitem.
Step 2. If POINTER is pointing to a cell in the new area, return
with the value of POINTER as the result.
Step 3. Save the current value of NEXT in a variable V.
Step 4. If POINTER is pointing to a cell in the new area, make
the cell pointed at by NEXT into a nonitem pointing to the
cell that is pointed at by POINTER, and go to step 11 below.
Step 5. Copy the contents of the cell pointed at by POINTER to
the cell pointed at by NEXT.
Step 6. If POINTER is pointing to a NIL, then go to step 11 below.
Step 7. Make the cell pointed at by POINTER into a nonitem
that points to the cell pointed at by NEXT, i.e. the corre-
sponding cell in the new area.
Step 8. Increment NEXT, increment POINTER.
Step 9. If POINTER points to a nonitem, make POINTER point
to the cell pointed at by the nonitem, repeat this step while
POINTER is pointing to a nonitem.
Step 10. Go to step 4 of the function COPYLIST.
Step 11. Increment NEXT and return with the value of V as the
result.
Acknowledgments. The author is particularly grateful
for many discussions with N. E. Wiseman and for the4
7. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite algorithm*
H. Schorr and W. M. Waite
An eο¬cient machine-independent procedure for
garbage collection in various list structures
Comm. ACM 10, 8 (1967)
dex registers and the accumulator for temporary storage,
though in general any three storage locations could be used.
One contains the address of the previous list element ex-
amined, the second the address of the element currently
being examined and the third the address of the next ele-
ment on the list. This is necessary for the reversal of the
pointers during the forward scan and their restoration
during the reverse scan.
In order to evaluate the speed of the routine, a Wise
program was written which created five complete binary
trees of depth 12. The remaining registers were discarded
and the garbage collector called. Thus it was forced to
trace a list structure containing over 20,000 registers, half
of which were branch points. The elapsed time, according
to the system clock, was 1.85 seconds. This list structure
seems far more complex than any which would be en-
countered in practice, and therefore a normal garbage col-
lection should take far less time. The space occupied is also
Q
F
ENTRY
i
SETI TO Ii
FIRSTCELL
OF L ST
lNO
IMAKE'TIMINUS
1I REVERSEPOINTER
OFCELLI
YES
YES
W:l
scanned many times, and the program would fail by enter-
ing a loop when attempting to trace a circular list. When
run under the above conditions (5 binary trees of depth 12)
the routine required 2.75 seconds for a complete trace.
As a final comparison, a routine which stored branch
points was coded and run using the same list structure. The
program occupied 34 words, and an additional 48 words
were allotted as a storage area for the branch points. Any
given part of the list structure was only traversed once, so
that this routine could trace any list for which the number
of branch points it was required to store was less than 49.
Only .448 seconds were required to complete the trace of
the test structure.
EXIT
YES
RESTORE POINTER
OF CELL I
LI - ~ I
TO~~~iYES
REVERSE POINTERI
IN CAR OF I
SET BRANCH
PO NT FLAG
1SET 2: TO
FIRST CELL
OF BRANCH
NO
(
FIG. 3. Trace algorithm for a one-way list. Forward scan; reverse scan
RESTOREPOINTER
IN CAROFI.
CLEAR BRANCH
POINT FLAG.
504 Communications of the ACM Volume 10 / Number 8 / August, 1967
venience in drawing the flowchart, the list elements are
assumed to be numbered sequentially. Thus, list element
I + 1 follows list element I (i.e., list element I + 1 is pointed
to by the TAIL of list element I). The routine uses two in-
dex registers and the accumulator for temporary storage,
though in general any three storage locations could be used.
One contains the address of the previous list element ex-
amined, the second the address of the element currently
being examined and the third the address of the next ele-
ment on the list. This is necessary for the reversal of the
pointers during the forward scan and their restoration
during the reverse scan.
In order to evaluate the speed of the routine, a Wise
program was written which created five complete binary
trees of depth 12. The remaining registers were discarded
and the garbage collector called. Thus it was forced to
trace a list structure containing over 20,000 registers, half
of which were branch points. The elapsed time, according
to the system clock, was 1.85 seconds. This list structure
seems far more complex than any which would be en-
countered in practice, and therefore a normal garbage col-
lection should take far less time. The space occupied is also
Q
F
ENTRY
i
SETI TO Ii
FIRSTCELL
OF L ST
lNO
IMAKE'TIMINUS
1I REVERSEPOINTER
OFCELLI
YES
YES
W:l
For purposes of comparison, a trace routine proposed by
Wilkes was coded for the 7094. It required only two tempo-
rary storage locations, and occupied 35 words of memory.
This routine traversed a path from the head of a list to each
terminal register separately. Thus much of the list was
scanned many times, and the program would fail by enter-
ing a loop when attempting to trace a circular list. When
run under the above conditions (5 binary trees of depth 12)
the routine required 2.75 seconds for a complete trace.
As a final comparison, a routine which stored branch
points was coded and run using the same list structure. The
program occupied 34 words, and an additional 48 words
were allotted as a storage area for the branch points. Any
given part of the list structure was only traversed once, so
that this routine could trace any list for which the number
of branch points it was required to store was less than 49.
Only .448 seconds were required to complete the trace of
the test structure.
EXIT
YES
RESTORE POINTER
OF CELL I
LI - ~ I
TO~~~iYES
REVERSE POINTERI
IN CAR OF I
SET BRANCH
PO NT FLAG
1SET 2: TO
FIRST CELL
OF BRANCH
NO
(
FIG. 3. Trace algorithm for a one-way list. Forward scan; reverse scan
RESTOREPOINTER
IN CAROFI.
CLEAR BRANCH
POINT FLAG.
504 Communications of the ACM Volume 10 / Number 8 / August, 1967
*also attributed to Peter Deutsch
6
8. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite algorithm
Alfred V. Aho, John E. Hopcroft, and Jeο¬rey Ullman
Data Structures and Algorithms (1st ed.)
Addison-Wesley (1983)
type
atomtype = { some appropriate type; preferably of the same size as pointers }
patterns = (PP, PA, AP, AA);
celltype = record
mark: boolean;β¨
case pattern: patterns of
PP: (left: β celltype; right: β celltype);
PA: (left: β celltype; right: atomtype);
AP: (left: atomtype; right: β celltype);
AA: (left: atomtype; right: atomtype);
end;
var
source: β celltype;β¨
memory: array [1..memorysize ] of celltype;
procedure rotate ( var p1, p2, p3: β celltype );
var
temp: β celltype;
begin
temp := p1; p1 := p2; p2 := p3; p3 := temp
end; { rotate }β¨
function blockleft ( cell: celltype ): boolean;
{ test if left ο¬eld is atom or null pointer }
begin
with cell doβ¨
if (pattern = PP) or (pattern = PA) then
if left <> nil then return (false);
return (true)
end; { blockleft }
β¨
function blockright ( cell : celltype ): boolean;
{ test if right ο¬eld is atom or null pointer }
beginβ¨
with cell do
if (pattern = PP) or (pattern = AP) then
if right <> nil then return (false);
return (true)
end; { blockright }
...
...
...
...
7
9. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
ISMM 2017
Albert Mingkun Yang and Tobias Wrigstad
Type-assisted automatic garbage collection for
lock-free data structures
ACM SIGPLAN International Symposium on
Memory Management (ISMM 2017)
struct cds_t {
int global_epoch;
int max_entry;
int size;
per_thread_t *threads;
};
struct per_thread_t {
int in_critical;
int local_epoch;
int entry;
wrapper_t limbo_list[3];
};
Figure 7. Central data structures for EBR implementation.
1. At allocation sites of spine objects, which are statically known
from their types, one allocation call was replaced with calloc()
(because Encore assumes memory is zeroed).
2. At the release point, a call to free() was used instead of
the ORCA API. Freeing the spine object immediately is safe
because of its guaranteed isolation inside the hot object.
3. The ACQUIRE was removed as there is no need for opaque
roots when the underlying memory manager is not automatic.
Previously, this was an increase of the foreign reference count
for each object moved into the Isolde heap.
4.1 Implementation Details
The C library contains three main public APIs. The function cri-
tical_enter() should be called before loading any ο¬elds in the
concurrent data structure (e.g., top in the Treiber Stack example)
into a local variable. The function critical_exit() should be
called when all pointers-on-stack-frame will not be used until the
next call of critical_enter(). In our implementation, those two
functions are placed at the entrance and the exit point of every
method of a hot class. It is possible that using static analysis, one
could ο¬nd more precise boundary of the critical region.
void critical_enter(cds_t *this) // entering critical region
void critical_exit(cds_t *this) // exiting critical region
void defer_dec(void *node) // safe version of rc decrement
Full code for these functions is found in Figure 8 and the main
data structures in Figure 7. Each concurrent data structure holds
a cds_t object at run-time; max_entry is used to control the
frequency of updating global epoch counter, as we discussed in
previous section. size is set to be the max number of threads that
could interact with concurrent data structure, which is used to iterate
along the array referenced by threads. per_thread_t holds the
info each thread maintains; determining if this thread is in critical
region, local epoch, the number entrance into critical region, and a
limbo list for each epoch. The thread local variable thread_index
is used to store and retrieve thread-local EBR meta data. The details
how it is initialized are provided later. In the implementation of
critical_enter, we can see entry and max_entry is used to
amortize the cost across multiple entrance into critical region. An
extra level of indirection, wrapper_t, is used around spine objects
in defer_dec because an object could be added into multiple limbo
lists and even the same list multiple times. Notably, the original
EBR scheme [11] does not need this because it requires developers
to manually decide the unlinking point.
Helper Functions The helper functions update_global(), try-
_lock() and clean_list() are used internally by the functions
in the public API. They are shown in Figure 9. The function
update_global() limits the use of writes to the global epoch
counter in critical sections. In our implementation, we implement
1 void critical_enter(cds_t *this) {
2 per_thread_t *thread = &this.threads[thread_index];
3 while (true) {
4 thread.in_critical = 1;
5 int global_epoch = this.global_epoch;
6
7 if (thread->local_epoch != global_epoch) {
8 clean_list(&thread->limbo_list[global_epoch]);
9 thread->local_epoch = global_epoch;
10 thread->entry = 0;
11 }
12
13 if (thread->entry++ < this->max_entry) {
14 return;
15 }
16
17 thread->in_critical = 0;
18 thread->entry = 0;
19 update_global(this);
20 }
21 }
22
23 void critical_exit(cds_t *this) {
24 this->threads[thread_index].in_critical = 0;
25 }
26
27 void defer_dec(so_gc_t *so_gc, void *p) {
28 wrapper_t *w = new_wrapper();
29 w->p = p;
30 per_thread_t *thread =
31 &so_gc->threads[so_thread_index];
32 w->next = thread->limbo_list[thread->local_epoch];
33 thread->limbo_list[thread->local_epoch] = w;
34 }
Figure 8. Functions.
The function clean_list() iterates over all objects in a limbo
list, decrementing their reference counts, and reclaiming the objects
whose RC reaches zero. In our implementation, this amounts to
telling the actor on whose heap the object is allocated that the object
is no longer needed externally, through an asynchronous message
send. This allows the actor to free this memory during the next
garbage collection cycle after receipt of this message.
The body of the if-statement on Line 23 marks the moment when
a spine object becomes βeffectivelyβ unreachable, and its ο¬naliser
is called before the calling release API provided by the underlying
memory manager. (In our implementation this amounts to calling
a compiler-generated ο¬naliser.) Switching the underlying memory
manager requires a change to this code, for example, in the case of
using malloc() and free(), this is a call to free().
4.2 Limitations
An inherent limitation of the epoch-based management of stack
pointers requires that the maximum number threads that can in-
teract with a concurrent data structure must be known when the
program starts. In the case of the Encore, this limitation is unprob-
lematic as Encore uses a ο¬xed set of threads for an entire program
run which are ο¬xed at the start of the program. On thread cre-
1 hot Stack[t]
2 spec top : Node[t]
3
4 def push(element:t) : t
5 ββ signaling into critical region
6 CRITICAL_ENTER(this);
7 ββ element managed by H
8 var new_top = new Node()
9 ββ RC(new_top) = 0, new_top owned by current thread
10 new_top.element = move_in element
11 ACQUIRE(element); NULLIFY(element);
12 ββ element managed by S
13 do
14 val old_top = this.top
15 ββ RC(old_top) = 1
16 new_top.next = old_top
17 INC_RC(old_top); DEFER_DEC_RC(new_top.next);
18 ββ RC(old_top) = 2
19 until CAT(this.top, new_top.next, new_top)
20 ββ Added to limbo list for deferred decrement
21 DEFER_DEC_RC(new_top.next);
22 INC_RC(new_top); NULLIFY(new_top);
23 ββ RC(new_top) = 1, new_top owned by stack object
24 ββ leaving critical region
25 CRITICAL_EXIT(this);
26 end
27
28 def pop() : t
29 CRITICAL_ENTER(this);
30 do
31 val old_top = this.top
32 ββ RC(old_top) = 1, old_top owned by stack object
33 ββ old_top.element managed by S
34 until CAT(this.top, old_top, old_top.next)
35 ββ Added to limbo list for deferred decrement
36 DEFER_DEC_RC(old_top);
37 var tmp = move_out old_top.element
38 ACQUIRE(element); NULLIFY(old_top.element)
39 ββ tmp managed by H
40 CRITICAL_EXIT(this);
41 return tmp
42 end
43 end
Figure 5. Complete example with GC instructions elaborated in.
they may be in a cycle. The Recycler [1] implements trial deletio
in the presence of mutators running concurrently.
Having described reference counts for references on the hea
we now describe our version of Fraserβs epoch-based reclamatio
scheme [11] for dealing with stack-based references efο¬ciently.
3. An Epoch-Based Reclamation Primer
Reference counting is an intuitive technique: an object is live if an
only if its reference count is positive. A naive implementation cou
use a write barrier that increments and decrements RCs around a
pointer writes, regardless of whether the destination is on the stac
or on the heap. While likely inefο¬cient, such an implementatio
is correct in a sequential case. In a concurrent setting, howev
before INC_RC(A) happens on reading a reference with RC=1
one thread, DEC_RC(A) could be happening concurrently in anoth
thread, causing A to be prematurely collected. As a result, th
reference count increase would be a write to a invalid memory.
The root cause of this problem is the race between loadin
the reference and incrementing the RC. Valois [23] solves th
problem by assuming type persistence, i.e., once a block of memo
is allocated for a type of objects, it could only be used for th
particular type. A late increment may still write to invalid memo
but it is guaranteed to be a slot reserved for RC only, and th
effect could be reverted back if revalidation fails (the object h
been collected). Detlefs et al. [8] show that this constraint ca
be removed using a double CAS, which is able to operate on tw
independent memory locations atomically. Sadly, no current CP
supports such an atomic primitive. Neither type-persistence n
double CAS constitutes a viable option in an automatic memo
management solution, but, fortunately, the data race on counte
can be avoided by applying RC to pointers on heap only. This h
been used before (see e.g., Deutsch & Bobrow [9]), but as a wa
of reducing the amount of RC manipulation due to local variable
While our motivation differs, we can reap the beneο¬t of reduce
RC manipulation. Because RC attributed from pointers-on-stack
discarded, RC becomes imprecise. Deutsch & Bobrow [9], place a
object with RC = 0 in a Zero Count Table, and use stack scannin
to either restore to correct RC for still reachable objects or reclai
those surely dead ones. In the contrast, we use a modiο¬ed versio
of Fraserβs epoch-based [11] reclamation (EBR) scheme, whic
addresses pointers on stack in a non-intrusive fashion.
Due to its low synchronization, EBR compares favourably
hazard pointers and reference counting according to [10], but to th
best of our knowledge, it has never been used in automatic GC.
EBR maintains a global epoch counter and a local epoch count
8
10. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
new
old root
S
root
rootnew
old
free
!
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
11. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
new
old root
S
root
rootnew
old
free
!cell
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
12. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
new
old root
S
root
rootnew
old
free
!cell pointer into memory
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
13. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
scan pointer
new
old root
S
root
rootnew
old
free
!cell pointer into memory
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
14. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
scan pointer
new
old root
S
root
rootnew
old
free
!cell pointer into memory
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
free pointer
15. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
scan pointer
co-assign
new
old root
S
root
rootnew
old
free
!cell pointer into memory
start
9
{ βold , new , new + 1 } β { βnew , S , free }
Cheney revisited (step 1)
free pointer
16. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ S + 1 } β { S }
(S < free ) β§ (Sβ = πΆ)
Cheney revisited (step 2)
atom
10
S
A
S
A
free free
17. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ S + 1 } β { S }
(S < free ) β§ (Sβ = πΆ)
Cheney revisited (step 2)
atom
10
pointers = β
types = { πΆ(tom), π (ointer), π·(roken heart) }
cells = pointers Γ types
S
A
S
A
free free
18. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ S + 1 } β { S }
(S < free ) β§ (Sβ = πΆ)
Cheney revisited (step 2)
atom
10
pointers = β
types = { πΆ(tom), π (ointer), π·(roken heart) }
cells = pointers Γ types
β: pointers β· cells : p β· [π, π]
β: pointers βΆ pointers : p βΌ pββ‘βp π
β: pointers βΆ types : p βΌ pββ‘βp π
S
A
S
A
free free
19. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ S + 1 } β { S }
(S < free ) β§ (Sβ = πΆ)
Cheney revisited (step 2)
atomA
atom
10
pointers = β
types = { πΆ(tom), π (ointer), π·(roken heart) }
cells = pointers Γ types
β: pointers β· cells : p β· [π, π]
β: pointers βΆ pointers : p βΌ pββ‘βp π
β: pointers βΆ types : p βΌ pββ‘βp π
S
A
S
A
free free
20. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
predicate
{ S + 1 } β { S }
(S < free ) β§ (Sβ = πΆ)
Cheney revisited (step 2)
atomA
atom
10
pointers = β
types = { πΆ(tom), π (ointer), π·(roken heart) }
cells = pointers Γ types
β: pointers β· cells : p β· [π, π]
β: pointers βΆ pointers : p βΌ pββ‘βp π
β: pointers βΆ types : p βΌ pββ‘βp π
S
A
S
A
free free
21. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ βSβ , [ β , π· ] , β(Sβ + 1) , [ free , π ] , free + 2 , S + 1 } β { βfree , βSβ , β(free + 1) , β(Sβ + 1) , free , S }
Cheney revisited (step 3)
unvisited
11
(S < free ) β§ (Sβ = π ) β§ (Sββ β π·)
S
car cdr
S
car cdr
!
free free
22. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ βSβ , [ β , π· ] , β(Sβ + 1) , [ free , π ] , free + 2 , S + 1 } β { βfree , βSβ , β(free + 1) , β(Sβ + 1) , free , S }
Cheney revisited (step 3)
broken heart!
unvisited
11
(S < free ) β§ (Sβ = π ) β§ (Sββ β π·)
S
car cdr
S
car cdr
!
free free
23. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ βSβ , [ β , π· ] , β(Sβ + 1) , [ free , π ] , free + 2 , S + 1 } β { βfree , βSβ , β(free + 1) , β(Sβ + 1) , free , S }
Cheney revisited (step 3)
broken heart!
a car cellcar
a cdr cellcdr
unvisited
11
(S < free ) β§ (Sβ = π ) β§ (Sββ β π·)
S
car cdr
S
car cdr
!
free free
24. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ β(Sβ + 1) , S + 1 } β { βS , S }
(S < free ) β§ (Sβ = π ) β§ (Sββ = π·)
Cheney revisited (step 4)
visited
12
S S
! !
free free
25. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
{ new + 1 , old , new } β { free , new , old }
S = free
Cheney revisited (step 5)
stop
13
root new
old
new
old
free
S
root
free
26. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cheney revisited (graph)
Sββ β π·
Pointer to a
pointer not to a
broken heart
S = some
pointer
Pointer to a
pointer to a
broken heartSββ = π·Pointer to
an atom
Sβ = πΆ
S + 1 β S
βSβ β βfree
[ β , π· ] β βSβ
(Sβ + 1)β β β(free + 1)
[ free , π ] β β(Sβ + 1)
free + 2 β free
S + 1 β S
(Sβ + 1)β β Sβ
S + 1 β S
Pointer to
a pointer
Sβ = π
!
βold β βnew
new β S
new + 1 β free
"
S = free
All cells
updated
old β new
new β old
Pointer to a
pointer
S < free
14
27. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cheney revisited (code)
typedef struct CEL * ptr;
typedef enum {a, p, b} typ;
typedef struct CEL { ptr P; typ T; } cel;
static ptr free, new, old;
static void Cheney(void)
{ ptr S, S_;
*new = *old; // *new <- *old
S = new; // S <- new
for (free = new + 1; // free <- new + 1
S < free; // S < free
S += 1) // S <- S + 1
if (S->T == p) // Sv = p
{ S_ = S->P; // S^
if (S_->T != b) // S^v β b
{ *free = *S_; // *free <- *S^
*S_ = (cel){ 0, b }; // *S^ <- [β , b]
*(free + 1) = *(S_ + 1); // *(free + 1) <- *(S^ + 1)
*(S_ + 1) = (cel){ free, p };// *(S^ + 1) <- [free, p]
free += 2; } // free <- free + 2
else // S^v = b
*S = *(S_ + 1); } // *S <- *(S^ + 1)
else; // Sv = a
free = new + 1; // free <- new + 1
S = old; // old
old = new; // old <- new
new = S; } // new <- old
15
28. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 1)
P P
C
root
memorymemory
!
start
16
{ β , memory } β { P , C }
29. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 1)
P P
C
root
memorymemory
!
types = { πΆ(tom), π (ointer) }
marks = { π(arked), π(nmarked) }
cells = pointers Γ types Γ marks
β: pointers β· cells : p β· [π, π, π]
β: pointers βΆ pointers : p βΌ pβ β‘βp π
β: pointers βΆ types :p βΌ p β‘βp π
β£: pointers βΆ marks : p βΌ pβ£ β‘βp π
start
16
{ β , memory } β { P , C }
30. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 1)
P P
C
root
memorymemory
!
types = { πΆ(tom), π (ointer) }
marks = { π(arked), π(nmarked) }
cells = pointers Γ types Γ marks
β: pointers β· cells : p β· [π, π, π]
β: pointers βΆ pointers : p βΌ pβ β‘βp π
β: pointers βΆ types :p βΌ p β‘βp π
β£: pointers βΆ marks : p βΌ pβ£ β‘βp π
start
16
{ β , memory } β { P , C }
current pointer
31. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 1)
P P
C
root
memorymemory
!
types = { πΆ(tom), π (ointer) }
marks = { π(arked), π(nmarked) }
cells = pointers Γ types Γ marks
β: pointers β· cells : p β· [π, π, π]
β: pointers βΆ pointers : p βΌ pβ β‘βp π
β: pointers βΆ types :p βΌ p β‘βp π
β£: pointers βΆ marks : p βΌ pβ£ β‘βp π
start
16
{ β , memory } β { P , C }
current pointer
previous pointer
32. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 2)
C C
A A
P
unvisitedatom
17
{ [P , π , π] , C , Cβ } β { βC , P , C }
(Cβ£ = π) β§ (Cβ = πΆ)
33. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
C
C
P
P
Schorr-Waite revisited (step 3)
unvisitedptr
18
{ [P , π , π] , C , Cβ } β { βC , P , C }
(Cβ£ = π) β§ (Cβ = π )
34. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 4)
C C
P
visitedcar
19
{ C + 1 } β { C }
(Cβ£ = π) β§ (P β β ) β§ even?(C)
35. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 4)
C C
P
even pointer into memory
pointer into memory
odd pointer into memory
visitedcar
19
{ C + 1 } β { C }
(Cβ£ = π) β§ (P β β ) β§ even?(C)
36. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
P
C
P
C
Schorr-Waite revisited (step 5)
visitedcdr
20
{ [C β 1 , π , π] , P , Pβ } β { βP , C , P }
(Cβ£ = π) β§ (P β β ) β§ odd?(C)
37. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (step 6)
stop
21
{ } β { }
(Cβ£ = π) β§ (P = β )
P
C
!root
38. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (graph)
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
22
39. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Schorr-Waite revisited (code)
typedef struct CEL * ptr;
typedef enum {a, p} typ;
typedef enum {m, u} mrk;
typedef struct CEL { ptr P; typ T; mrk M; } cel;
static unsigned is_even(ptr);
static void mark(ptr);
static const ptr null = (ptr)0;
static ptr memory;
static void Schorr_Waite(void)
{ ptr C, C_, P, P_;
P = null; // P <- null
for (C = memory;; ) // C <- memory
if (C->M == u) // Cw = u
if (C->P == a) // Cv = a
mark(C); // Cw = m
else // Cv = p
{ C_ = C->P; // C^
*C = (cel){ P, p, m }; // *C = [P, p, m]
P = C; // P <- C
C = C_; } // C <- C^
else // Cw = m
if (P != null) // P β null
if (is_even(C)) // even?(C)
C = C + 1; // C <- C + 1
else // odd?(C)
{ P_ = P->P; // P^
*P = (cel){ C - 1, p, m };// *P = [C - 1, p, m]
C = P; // C <- P
P = P_; } // P <- P^
else // P = null
break; } // stop
23
41. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Compacting mark-sweep
typedef struct CEL * ptr;
typedef enum {a, m, u} flg;
typedef struct CEL { ptr P; flg F; } cel;
static ptr memory;
static unsigned is_raw(ptr), size(ptr);
static void mark_sweep(ptr root)
{ ptr C, C_, C__;
for (C = memory;;) // C <- memory
if (C->F == a) // Cv = a
C -= 1; // C = C - 1
else // Cv β a
{ C_ = C->P; // C^
if (C->F == m) // Cv = m
if (C_ == memory) // C^ = memory
break; // stop
else // C^ β memory
C = C_ - 1; // C <- C^ - 1
else // Cv = u
{ C__ = C_->P; // C^^
if (C_->F == m) // C^v = m
{ *C = *C__; // *C <- *C^^
*C__ = (cel){ C, m }; // *C__ <- [C, m]
C -= 1; } // C <- C - 1
else // C^v = u
{ *C = *C_; // *C <- *C^
*C_ = (cel){ C, m }; // *C_ <- [C, m]
if (is_raw(C__)) // raw?(C^^)
C -= 1; // C <- C - 1
else // regular?(C^^)
C = C_ + size(C__); }}}} // C <- C^ + size(C^^)
25
42. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
β
β
application#1
26
43. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
β
β
Why?
application#1
26
44. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
β
β
Why?
save storage on pairs
application#1
26
45. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
β
β
Why?
save storage on pairs
fixed data
far references
application#1
26
46. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
CMS + Schorr-Waite
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
β
β
27
47. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
CMS + Schorr-Waite
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
β
β
7 transitions
27
48. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
CMS + Schorr-Waite
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
β
β
7 transitions 6 transitions
27
49. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Cβ = πΆ
Pointer to
an atom
C = some
pointer
Cβ = π
Pointer to an
unmarked
pointer
regular?(Cββ)
Pointer to an
unmarked pointer to
a marked pointer
Cββ = π
βCββ β βC
[C, π] β βCββ
C - 1 β C
Cβ = π
Pointer to a
marked cell
C - 1 β C
Cβ - 1 β C
Pointer to an unmarked
pointer to an unmarked
raw header
raw?(Cββ)
βCβ β βC
[C, π] β Cβ
C - 1 β C
Pointer to an unmarked
pointer to an unmarked
regular header
!
[root, π] β βmemory
memory β C
" Cβ= memory
Pointer to an
unmarked pointer to
an unmarked header
Cββ = π
βCβ β βC
[C, π] β Cβ
Cβ + size(Cββ) β C
Pointer to a
marked non-
terminal pointer
Cββ memory
Cβ = πΆ
Pointer to an
unmarked
atom
C = some
pointer
Pointer to an
unmarked
pointer
Cβ = π
Pointer to a
marked cell
Cβ£ = π
even?(C)odd?(C)
Odd pointer to
a non-terminal
marked cell
[P , π , π] β βC
C β P
Cβ β C
C + 1 β C
Pointer to an
unmarked
cell
Cβ£ = π
!
β β P
memory β C
"
Even pointer to
a non-terminal
marked cell
P β β
π β Cβ£
P = β
Stop Pointer to a
non-terminal
marked cell
[C β 1 , π , π] β βP
P β C
Pβ β P
CMS + Schorr-Waite
pair?(Cβ)
[C - 1, π , π] β βP
P β C
Pβ β P
[C - 1, p, π] β βP
P - 1 β C
Pβ β P
βCββ β βC
[C, π , π] β βCββ
C - 1 β C
[Cββ, π½, π] β βC
[C, π , π] β βCβ
chunk?(C)
Cβ = πΆ Chunk pointer to an
unmarked atom
Pointer to an
unmarked atom
pair?(C)
Pair pointer to an
unmarked atom
Some pointer
chunk?(Cβ)
Pointer to an
unmarked
chunk pointer
Pointer to an unmarked
chunk pointer to an
unmarked regular header
regular?(Cββ)
Pointer to an unmarked
chunk pointer to a
marked cell
Cββ = π
Chunk pointer to an
unmarked chunk pointer
to a marked header
chunk?(C)
Pair pointer to an
unmarked chunk pointer
to a marked header
pair?(C)
Pointer to an
unmarked pair
pointer
Pointer to a
marked cell
Cβ = π
Pointer to a
marked chunk
chunk?(C)
Chunk pointer to a
marked chunk with a
chunk thread
chunk?(Cβ)
Chunk pointer to a
marked chunk with
pair thread
pair?(Cβ)
Even pair pointer
to a marked cell
even?(C)
Odd pair pointer
to a marked cellodd?(C)
Odd pair pointer to a
marked cell with
chunk thread
Odd pair pointer to
a marked cell with
pair thread
pair?(P)
chunk?(P)
Pointer to an
unmarked cell
Cβ = π
C - 1 β C
π β Cβ
Pointer to an unmarked
chunk pointer to an
unmarked raw header
raw?(Cββ)
Pair pointer to an unmarked
chunk pointer to an
unmarked raw header
Chunk pointer to an
unmarked chunk pointer to
an unmarked raw header
chunk?(C)
[Cββ, π½, π] β βC
[C, π , π] β βCβ
C - 1 β C
[[Cββ, π½, π] β βC
[C, π , π] β βCβ
Cβ + size(Cββ) β C
pair?(C)
βCββ β βC
[C, π , π] β βCββ
[P, π , π] β βC
C β P
Cβ β C
Cβ - 1 β C
Cβ β C C + 1 β C
β β P
memory β C
!
Pointer to an unmarked
chunk pointer to an
unmarked cell
Cββ = π
Cβ = memory"
Pointer to a non-
terminal marked cell
Cβ β memory Pair pointer to a
marked cell
pair?(C)
Pointer to an
unmarked pointer
Cβ = π
β
β
7 transitions 6 transitions
15 transitions
27
50. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
typedef struct CEL * ptr;
typedef enum { a, h = a, p } typ;
typedef enum { m, u } mrk;
typedef struct CEL { ptr P; typ T; mrk M; } cel;
static const ptr null = (ptr)0;
static const unsigned max;
static ptr free, memory;
static unsigned is_chunk(ptr), size(ptr);
static ptr hdr(unsigned);
static void jonkers_schorr_waite(void)
{ ptr A, D, S, S_;
unsigned C, L1;
A = null; // A <- null
*free = (cel){0, h, m }; // *free <- [0, h, m]
for (S = D = memory + 1;;) // S <- D <- memory + 1
{ S_ = S->P; // S^
if (A == null) // A = null
if (S->M == m) // Sv = m
if (S < free) // S < free
{ A = S; // A <- S
S = S_; // S <- S^
C = 0; } // C <- 0
else // S = free
break; // stop
else // Sv = u
{ A = S; // A <- S
C = size(S_) + 1; // C <- size(S^) + 1
S += C; } // S <- S + size(S^) + 1
else // A β null
if (C == 0) // C = 0
if (S->T == h) // Sw = h
{ L1 = size(S_) + 1; // size(S^) + 1
*A = *S; // *A <- *S
if (is_chunk(S)) // chunk?(S)
*S = (cel){ D, p, u };// *S <- [D, p, u]
else // pair?(S)
*S = (cel){ D, p, m };// *S <- [D, p, m]
S = A + L1; // S <- A + size(S^) + 1
D += L1; // D <- D + size(S^) + 1
A = null; } // A <- null
else // Sw = p
{ if (is_chunk(S)) // chunk?(S)
*S = (cel){ D, p, u }; // *S <- [D, p, u]
else // pair?(S)
*S = (cel){ D, p, m }; // *S <- [D, p, m]
S = S_; } // S <- S^
else // C > 0
if (S->M == m) // Sv = m
{ *A = (cel){ hdr(C - 1), h, u }; // *A <- [hdr(C-1), h, u]
A = null; // A <- null
C = 0; } // C = 0
else // Sv = u
{ L1 = size(S_) + 1; // size(S^) + 1
if (C + L1 > max) // C + size(S^) β₯ max
{ *A = (cel){ hdr(C - 1), h, u };// *A <- [hdr(C-1), h, u]
A = null; // A <- null
C = 0; } // C = 0
else // C + size(S^) β€ max
{ S += L1; // S <- S + size(S^) + 1
C += L1; }}}} // C <- C + size(S^) + 1
28
51. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
CMS + Schorr-Waite
29
typedef struct CEL * ptr;
typedef enum { a, h = a, p } typ;
typedef enum { m, u } mrk;
typedef struct CEL { ptr P; typ T; mrk M; } cel;
static const ptr null = (ptr)0;
static const unsigned max;
static ptr free, memory;
static unsigned is_chunk(ptr), size(ptr);
static ptr hdr(unsigned);
static void jonkers_schorr_waite(void)
{ ptr A, D, S, S_;
unsigned C, L1;
A = null; // A <- null
*free = (cel){0, h, m }; // *free <- [0, h, m]
for (S = D = memory + 1;;) // S <- D <- memory + 1
{ S_ = S->P; // S^
if (A == null) // A = null
if (S->M == m) // Sv = m
if (S < free) // S < free
{ A = S; // A <- S
S = S_; // S <- S^
C = 0; } // C <- 0
else // S = free
break; // stop
else // Sv = u
{ A = S; // A <- S
C = size(S_) + 1; // C <- size(S^) + 1
S += C; } // S <- S + size(S^) + 1
else // A β null
if (C == 0) // C = 0
if (S->T == h) // Sw = h
{ L1 = size(S_) + 1; // size(S^) + 1
*A = *S; // *A <- *S
if (is_chunk(S)) // chunk?(S)
*S = (cel){ D, p, u };// *S <- [D, p, u]
else // pair?(S)
*S = (cel){ D, p, m };// *S <- [D, p, m]
S = A + L1; // S <- A + size(S^) + 1
D += L1; // D <- D + size(S^) + 1
A = null; } // A <- null
else // Sw = p
{ if (is_chunk(S)) // chunk?(S)
*S = (cel){ D, p, u }; // *S <- [D, p, u]
else // pair?(S)
*S = (cel){ D, p, m }; // *S <- [D, p, m]
S = S_; } // S <- S^
else // C > 0
if (S->M == m) // Sv = m
{ *A = (cel){ hdr(C - 1), h, u }; // *A <- [hdr(C-1), h, u]
A = null; // A <- null
C = 0; } // C = 0
else // Sv = u
{ L1 = size(S_) + 1; // size(S^) + 1
if (C + L1 > max) // C + size(S^) β₯ max
{ *A = (cel){ hdr(C - 1), h, u };// *A <- [hdr(C-1), h, u]
A = null; // A <- null
C = 0; } // C = 0
else // C + size(S^) β€ max
{ S += L1; // S <- S + size(S^) + 1
C += L1; }}}} // C <- C + size(S^) + 1
50 lines of executable
specification
54. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Fixing CMS: partial solution
31
55. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Fixing CMS: partial solution
sequential scan of complete heap
31
56. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Fixing CMS: partial solution
sequential scan of complete heap
compress mark bits in bitmap
31
57. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Fixing CMS: partial solution
sequential scan of complete heap
compress mark bits in bitmap
but: in dynamical languages
this bitmap is sparse
31
61. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
>(load "CODE/xTrees.slip")
left count = 1
left count = 2499
elapsed: 24.4990180000 sec
<unspecified>
>(collect)
Collecting garbage ...
mark-thread: 0.004518
unthread: 0.555821
compact-link: 0.133263
used chunk space before GC: 601131564(66.79%)
used chunk space after GC: 110831(00.01%)
used pair space before GC: 226478924(25.16%)
used pair space after GC: 30004(00.00%)
<unspecified>
>
Fixing CMS: straight
33
preliminary
62. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
>(load "CODE/xTrees.slip")
left count = 1
left count = 2499
elapsed: 24.4990180000 sec
<unspecified>
>(collect)
Collecting garbage ...
mark-thread: 0.004518
unthread: 0.555821
compact-link: 0.133263
used chunk space before GC: 601131564(66.79%)
used chunk space after GC: 110831(00.01%)
used pair space before GC: 226478924(25.16%)
used pair space after GC: 30004(00.00%)
<unspecified>
>
Fixing CMS: straight
32 bits
900Mcell
33
preliminary
63. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
>(load "CODE/xTrees.slip")
left count = 1
left count = 2499
elapsed: 24.1853520000 sec
<unspecified>
>(collect)
Collecting garbage ...
mark-thread: 0.007855
unthread: 0.047346
compact-link: 0.032718
used chunk space before GC: 601131564(66.79%)
used chunk space after GC: 110831(00.01%)
used pair space before GC: 226478924(25.16%)
used pair space after GC: 30002(00.00%)
<unspecified>
>
Fixing CMS: bitmap
34
preliminary
64. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
>(load "CODE/xTrees.slip")
left count = 1
left count = 2499
elapsed: 24.7884030000 sec
<unspecified>
>(collect)
Collecting garbage ...
mark-thread: 0.008640
unthread: 0.001088
compact-link: 0.001118
used chunk space before GC: 601131564(66.79%)
used chunk space after GC: 110831(00.01%)
used pair space before GC: 226478924(25.16%)
used pair space after GC: 30002(00.00%)
<unspecified>
>
Fixing CMS: bitheap
35
preliminary
65. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
66. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
67. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
68. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
69. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
70. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
71. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
36
Bitheaps
Name is taken ...
Implements a priority queue
Leaves are (all) memory cells
Are (static) heaps with arity 32*
Each node contains 32 bits
Each bit indicates whether the subtree
contains at least one bit = 1
*will scale up to 32Gby on a 64bit architecture
32 32
32 32 32
i = (a >> 27) + 1
a &= (1 << 27) - 1
i = 32*i + (a >> 22) + 1
a &= (1 << 22) - 1
i = 32*i + (a >> 17) + 1
a &= (1 << 17) - 1
72. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
static void set(unsigned a)
{ unsigned b, i = 0;
b = a >> 25; a &= (1 << 25) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 20; a &= (1 << 20) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 15; a &= (1 << 15) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 10; a &= (1 << 10) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 5; a &= (1 << 5) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
memory[i] |= 1 << a; }
(Bitheaps)
static UNS_type Bitheap[34636833] = { 0x0 };
37
// Sigma i=0,5 32^i = (32^6 - 1)/(32 - 1)
static UNS_type Bitheap[34636833] = { 0x0 };
static void do_(void (* lambda)(unsigned))
{ unsigned i0 = 0;
unsigned w1 = memory[i0];
if (w1)
{ i0 = 1 + (i0 << 5);
for (unsigned b1 = 0; b1 < 32; b1 += 1)
if (w1 & (1 << b1))
{ unsigned i1 = i0 + b1;
unsigned w2 = memory[i1];
if (w2)
{ i1 = 1 + (i1 << 5);
for (unsigned b2 = 0; b2 < 32; b2 += 1)
{ unsigned i6 = i5 + b6;
lambda(i6 - memory_size); }}}}}}}}}}}}}
73. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
static void set(unsigned a)
{ unsigned b, i = 0;
b = a >> 25; a &= (1 << 25) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 20; a &= (1 << 20) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 15; a &= (1 << 15) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 10; a &= (1 << 10) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
b = a >> 5; a &= (1 << 5) - 1; memory[i] |= 1 << b; i = 1 + (i << 5) + b;
memory[i] |= 1 << a; }
(Bitheaps)
static UNS_type Bitheap[34636833] = { 0x0 };
32 bits
4Gby
37
// Sigma i=0,5 32^i = (32^6 - 1)/(32 - 1)
static UNS_type Bitheap[34636833] = { 0x0 };
static void do_(void (* lambda)(unsigned))
{ unsigned i0 = 0;
unsigned w1 = memory[i0];
if (w1)
{ i0 = 1 + (i0 << 5);
for (unsigned b1 = 0; b1 < 32; b1 += 1)
if (w1 & (1 << b1))
{ unsigned i1 = i0 + b1;
unsigned w2 = memory[i1];
if (w2)
{ i1 = 1 + (i1 << 5);
for (unsigned b2 = 0; b2 < 32; b2 += 1)
{ unsigned i6 = i5 + b6;
lambda(i6 - memory_size); }}}}}}}}}}}}}
74. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
75. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
76. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
77. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
78. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
79. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
80. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
81. Buenos Aires, November 2017
Smalltalks 2017:
Reasoning about memory-
critical algorithms
Conclusion
Early days but promising
Scalability
Complexity
Formal support
Tool support
Non-gc algorithms
38
convenience
leads to
procedure