Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Reasoning about memory-critical algorithms by Theo D'Hondt

62 views

Published on

Reasoning about memory-critical algorithms by Theo D'Hondt

Published in: Technology
  • Login to see the comments

  • Be the first to like this

Reasoning about memory-critical algorithms by Theo D'Hondt

  1. 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. 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
  3. 3. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Smaltalkers: [ . ] vs. { ; } Sista: a Metacircular Architecture for Runtime Optimisation Persistence Clément Béra Laboratoire d’Informatique Fondamentale de Lille INRIA Lille - Nord Europe 2017 ... As most of the Smalltalk community has high skills in Smalltalk but little skills in low- level programming, the design aims here to allow the community to contribute to a project in Smalltalk doing Smalltalk-specific optimisations, improving performance while staying away from low-level details and machine-specific optimisations ... 3
  4. 4. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Smaltalkers: [ . ] vs. { ; } Sista: a Metacircular Architecture for Runtime Optimisation Persistence Clément Béra Laboratoire d’Informatique Fondamentale de Lille INRIA Lille - Nord Europe 2017 ... As most of the Smalltalk community has high skills in Smalltalk but little skills in low- level programming, the design aims here to allow the community to contribute to a project in Smalltalk doing Smalltalk-specific optimisations, improving performance while staying away from low-level details and machine-specific optimisations ... Slang 3
  5. 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
  6. 6. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms begin-garbage-collection (assign free (const 0)) (assign scan (const 0)) (assign old (reg root)) (assign relocate-continue (label reassign-root)) (goto (label relocate-old-result-in-new)) reassign-root (assign root (reg new)) (goto (label gc-loop)) gc-loop (test (op =) (reg scan) (reg free)) (branch (label gc-flip)) (assign old (op vector-ref) (reg new-cars) (reg scan)) (assign relocate-continue (label update-car)) (goto (label relocate-old-result-in-new)) update-car (perform (op vector-set!) (reg new-cars) (reg scan) (reg new)) (assign old (op vector-ref) (reg new-cdrs) (reg scan)) (assign relocate-continue (label update-cdr)) (goto (label relocate-old-result-in-new)) update-cdr (perform (op vector-set!) (reg new-cdrs) (reg scan) (reg new)) (assign scan (op +) (reg scan) (const 1)) (goto (label gc-loop)) relocate-old-result-in-new (test (op pointer-to-pair?) (reg old)) (branch (label pair)) (assign new (reg old)) (goto (reg relocate-continue)) pair (assign oldcr (op vector-ref) (reg the-cars) (reg old)) (test (op broken-heart?) (reg oldcr)) (branch (label already-moved)) (assign new (reg free)) ;new location for pair ;; update free pointer (assign free (op +) (reg free) (const 1)) ;; Copy the car and cdr to new memory. (perform (op vector-set!) (reg new-cars) (reg new) (reg oldcr)) (assign oldcr (op vector-ref) (reg the-cdrs) (reg old)) (perform (op vector-set!) (reg new-cdrs) (reg new) (reg oldcr)) ;; Construct the broken heart. (perform (op vector-set!) (reg the-cars) (reg old) (const broken-heart)) (perform (op vector-set!) (reg the-cdrs) (reg old) (reg new)) (goto (reg relocate-continue)) already-moved (assign new (op vector-ref) (reg the-cdrs) (reg old)) (goto (reg relocate-continue)) gc-flip (assign temp (reg the-cdrs)) (assign the-cdrs (reg new-cdrs)) (assign new-cdrs (reg temp)) (assign temp (reg the-cars)) (assign the-cars (reg new-cars)) (assign new-cars (reg temp)) Cheney's algorithm Hal Abelson, Jerry Sussman and Julie Sussman Structure and Interpretation of Computer Programs MIT Press (1984) 5
  7. 7. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Schorr-Waite algorithm* H. Schorr and W. M. Waite An efficient 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. 8. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Schorr-Waite algorithm Alfred V. Aho, John E. Hopcroft, and Jeffrey 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 field 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 field 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. 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 fields 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 find 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 finaliser is called before the calling release API provided by the underlying memory manager. (In our implementation this amounts to calling a compiler-generated finaliser.) 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 fixed set of threads for an entire program run which are fixed 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 efficiently. 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 inefficient, 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 benefit 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 modified 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  40. 40. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Compacting mark-sweep 0 1 6 2 3 1 12 6 1 2 6 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 14 9 2 2 1 2 13 1 8 3 7 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 1 2 2 3 0 6 2 1 2 2 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 9 0 1 2 3 0 6 6 2 2 0 6 ➠ ➠ ➠ H. B. M. Jonkers A fast garbage compaction algorithm Information Processing Letters, 9(1):25–30, July 1979 24
  41. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
  52. 52. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms 0 1 6 2 3 1 12 6 1 2 6 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 14 9 2 2 1 2 13 1 8 3 7 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 9 0 1 2 3 0 6 6 2 2 0 6 Fixing CMS: the problem application#2 0 1 2 2 3 0 6 2 1 2 2 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 ➠ ➠ ➠ 30 30
  53. 53. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms 0 1 6 2 3 1 12 6 1 2 6 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 14 9 2 2 1 2 13 1 8 3 7 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 9 0 1 2 3 0 6 6 2 2 0 6 Fixing CMS: the problem application#2 0 1 2 2 3 0 6 2 1 2 2 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 free root 15 1 ➠ ➠ ➠ 30 30
  54. 54. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Fixing CMS: partial solution 31
  55. 55. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Fixing CMS: partial solution sequential scan of complete heap 31
  56. 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. 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
  58. 58. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Fixing CMS: testcase (define (xTree-balance xTree) (define root (cadr xTree)) (define size (caddr xTree)) (define (traverse root size required) (if (pair? root) (begin (define lCount (car root)) (define lTree (cadr root)) (define rTree (caddr root)) (define rCount (- size required)) (if (> lCount required) (begin (define lTree (traverse lTree lCount required)) (define llTree (cadr lTree)) (define rlTree (caddr lTree)) (define rTree (list (- lCount required) rlTree rTree)) (define rrTree (traverse rTree rCount (quotient rCount 2))) (list required llTree rrTree)) (if (< lCount required) (begin (define rTree (traverse rTree (- size lCount) (- required lCount))) (define lrTree (cadr rTree)) (define rrTree (caddr rTree)) (define lTree (list lCount lTree lrTree)) (define llTree (traverse lTree required (quotient required 2))) (list required llTree rrTree)) (begin (define lTree (traverse lTree lCount (quotient lCount 2))) (define rTree (traverse rTree rCount (quotient rCount 2))) (list lCount lTree rTree))))) (if (null? root) 'error root))) (traverse root size (quotient size 2))) 32
  59. 59. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Fixing CMS: testcase (define (xTree-balance xTree) (define root (cadr xTree)) (define size (caddr xTree)) (define (traverse root size required) (if (pair? root) (begin (define lCount (car root)) (define lTree (cadr root)) (define rTree (caddr root)) (define rCount (- size required)) (if (> lCount required) (begin (define lTree (traverse lTree lCount required)) (define llTree (cadr lTree)) (define rlTree (caddr lTree)) (define rTree (list (- lCount required) rlTree rTree)) (define rrTree (traverse rTree rCount (quotient rCount 2))) (list required llTree rrTree)) (if (< lCount required) (begin (define rTree (traverse rTree (- size lCount) (- required lCount))) (define lrTree (cadr rTree)) (define rrTree (caddr rTree)) (define lTree (list lCount lTree lrTree)) (define llTree (traverse lTree required (quotient required 2))) (list required llTree rrTree)) (begin (define lTree (traverse lTree lCount (quotient lCount 2))) (define rTree (traverse rTree rCount (quotient rCount 2))) (list lCount lTree rTree))))) (if (null? root) 'error root))) (traverse root size (quotient size 2))) nested scope lots of interpreter garbage 32
  60. 60. Buenos Aires, November 2017 Smalltalks 2017: Reasoning about memory- critical algorithms Fixing CMS: testcase (define (xTree-balance xTree) (define root (cadr xTree)) (define size (caddr xTree)) (define (traverse root size required) (if (pair? root) (begin (define lCount (car root)) (define lTree (cadr root)) (define rTree (caddr root)) (define rCount (- size required)) (if (> lCount required) (begin (define lTree (traverse lTree lCount required)) (define llTree (cadr lTree)) (define rlTree (caddr lTree)) (define rTree (list (- lCount required) rlTree rTree)) (define rrTree (traverse rTree rCount (quotient rCount 2))) (list required llTree rrTree)) (if (< lCount required) (begin (define rTree (traverse rTree (- size lCount) (- required lCount))) (define lrTree (cadr rTree)) (define rrTree (caddr rTree)) (define lTree (list lCount lTree lrTree)) (define llTree (traverse lTree required (quotient required 2))) (list required llTree rrTree)) (begin (define lTree (traverse lTree lCount (quotient lCount 2))) (define rTree (traverse rTree rCount (quotient rCount 2))) (list lCount lTree rTree))))) (if (null? root) 'error root))) (traverse root size (quotient size 2))) nested scope lots of interpreter garbage functional style lots of application garbage 32
  61. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

×