Verifying a Concurrent Garbage Collector Delphine Demange Suresh - - PowerPoint PPT Presentation

verifying a concurrent garbage collector
SMART_READER_LITE
LIVE PREVIEW

Verifying a Concurrent Garbage Collector Delphine Demange Suresh - - PowerPoint PPT Presentation

Verifying a Concurrent Garbage Collector Delphine Demange Suresh Jagannathan Gustavo Petri David Pichardie Jan Vitek Yannick Zakowski Why are high level languages difficult to compile? Easy to compile in C Obj.f := v What about Java? A


slide-1
SLIDE 1

Verifying a Concurrent Garbage Collector

Delphine Demange Suresh Jagannathan Gustavo Petri David Pichardie Jan Vitek Yannick Zakowski

slide-2
SLIDE 2

Why are high level languages difficult to compile?

slide-3
SLIDE 3

Easy to compile in C What about Java?

Obj.f := v

slide-4
SLIDE 4

A Store in Java

void FIVMR_CONCAT(FIVMBUILD_GC_NAME,_markSlow)(fivmr_ThreadState *ts, fivmr_Object obj) { fivmr_SPC_incBarrierSlowPath(); if (FIVMR_LOG_GC_MARK_TRAPS) { uint64_t stamp=fivmr_readCPUTimestamp(); fp_log(ts->id, "mark trap at %u:%u on %u",3, (uintptr_t)((stamp>>32)&0xffffffff), (uintptr_t)((stamp>>0)&0xffffffff),
  • bj);
} fivmr_assert(ts->execStatus==FIVMR_TSES_IN_JAVA || ts->execStatus==FIVMR_TSES_IN_JAVA_TO_BLOCK); fivmr_assert(obj); if (FIVMR_ASSERTS_ON || FIVMR_LOG_LEVEL>=2) { fivmr_GCPhase curPhase; curPhase=ts->vm->gc.phase; /* this code is more verbose and careful */ /* should never see stack-allocated objects */ if (!FIVMR_HFGC_FAIL_FAST_PATHS(&ts->vm->settings)) { fivmr_assert( fivmr_GCHeader_markBits( fivmr_GCHeader_fromObject(&ts->vm->settings,
  • bj))!=0);
} /* we don’t want to mark when we’re idle because during the idle phase at the beginning of GC we may be rotating mark bits. this prevents races where two threads end up double-marking an object because they see different values of curShaded. this is particularly why we query ts->gc.tracing. it’s possible that a thread will have used stale shade values in its fast path check. worse, memory model issues could mean that the value of gc->curShaded we see here could be stale. we don’t want to perform marking with a stale value of curShaded. checking ts->gc.tracing, which is set by safepoints and hence side-steps cache coherence, ensures that we only proceed when we have the latest shade values. */ if (fivmr_GCHeader_markBits( fivmr_GCHeader_fromObject(&ts->vm->settings,
  • bj))!=0) {
if (ts->gc.tracing && fivmr_GC_isTracing(curPhase)) { if (mutatorMark(ts, fivmr_GCHeader_fromObject(&ts->vm->settings,
  • bj))) {
LOG(3,("Thread %u barrier marked %p (of type %s)", ts->id,obj, fivmr_TypeData_forObject(&ts->vm->settings,obj)->name)); } } else if (curPhase==FIVMR_GCP_PRE_INIT || fivmr_GC_isTracing(curPhase)) { LOG(3,("Thread %u barrier would have marked marked %p (of type %s); " "phase = %d (now %d), status = %" PRIuPTR, ts->id,obj, fivmr_TypeData_forObject(&ts->vm->settings,obj)->name, curPhase,ts->vm->gc.phase,ts->execStatus)); } else if (!FIVMR_HFGC_FAIL_FAST_PATHS(&ts->vm->settings)) { LOG(0,("Thread %u barrier incorrectly saw %p (of type %s)", ts->id,obj, fivmr_TypeData_forObject(&ts->vm->settings,obj)->name)); fivmr_abort("barrier error"); } } } else { /* this code is carefully written to ensure performance, but doesn’t do the same verification as the above. */ if (ts->gc.tracing) { fivmr_GCHeader *hdr; fivmr_GCHeader oldHdr; uintptr_t markBits; uintptr_t curShaded; fivmr_GC *gc; gc=&ts->vm->gc; hdr = fivmr_GCHeader_fromObject(&ts->vm->settings,
  • bj);
  • ldHdr = *hdr;
markBits = fivmr_GCHeader_markBits(&oldHdr); curShaded = gc->curShaded; if (markBits!=0 && (markBits&curShaded)==0 && markUnmarked(gc, &ts->gc.queue,
slide-5
SLIDE 5

A Store in Java

/* we don’t want to mark when we’re idle because during the idle phase at the beginning of GC we may be rotating mark bits. this prevents races where two threads end up double-marking an object because they see different values of curShaded. this is particularly why we query ts->gc.tracing. it’s possible that a thread will have used stale shade values in its fast path check. worse, memory model issues could mean that the value of gc->curShaded we see here could be stale. we don’t want to perform marking with a stale value of curShaded. checking ts->gc.tracing, which is set by safepoints and hence side-steps cache coherence, ensures that we only proceed when we have the latest shade values. */

slide-6
SLIDE 6

This work

Challenge: Certify a state-of-the-art Concurrent Garbage Collector Methodology: An IR to Implement and Verify Runtime Services

slide-7
SLIDE 7

The set-up

slide-8
SLIDE 8

The set-up

TSO

slide-9
SLIDE 9

The set-up

TSO

slide-10
SLIDE 10

What do we prove ?

This tutorial closely follows Damien Doligez’s phd (1995)

slide-11
SLIDE 11

Garbage collection

How to automatically reclaim unused memory ? unused

root root root

Theorem: Reachable memory is never reclaimed

slide-12
SLIDE 12

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-13
SLIDE 13

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-14
SLIDE 14

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-15
SLIDE 15

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-16
SLIDE 16

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-17
SLIDE 17

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-18
SLIDE 18

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-19
SLIDE 19

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-20
SLIDE 20

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-21
SLIDE 21

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-22
SLIDE 22

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-23
SLIDE 23

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-24
SLIDE 24

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-25
SLIDE 25

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-26
SLIDE 26

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-27
SLIDE 27

Sequential mark & sweep

Periodically stop user code and perform:

  • Mark: graph traversal from the root

marking cells black

  • Sweep: scan of the whole memory to

free non-black cells Color conventions:

  • Black: marked
  • White: not marked
  • Grey: to be marked (pending nodes)
  • Blue: free cells
slide-28
SLIDE 28

Concurrent mark & sweep

Version 1

  • two threads (1 mutator, 1 collector),
  • no thread local variables (every roots are global)

Version 2

  • two threads (1 mutator, 1 collector),
  • thread local variables

Version 3

  • N+1 threads (N mutators, 1 collector),
  • thread local variables
slide-29
SLIDE 29
  • 1 mutator,
  • 1 collector,
  • Only Global Variables

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables

slide-30
SLIDE 30

Update(x,f,y) ==
 MarkGray(y);
 x.f = y MarkGray(x) ==
 if x.color = WHITE
 then x.color = GRAY


COLLECTOR

Mark:
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 foreach x ∈ OBJECTS
 if x.color == GRAY
 foreach f ∈ fields(x) do
 MarkGray(x.f);
 x.color = BLACK
 until < ∀x, x.color ≠ GRAY > 
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables MUTATOR [...]
 Udpate(x1,f1,y1);
 [...]
 Udpate(x2,f2,y2);
 [...]
 Alloc(); x1.f1 = y1 x2.f2 = y2 new O();

slide-31
SLIDE 31

Update(x,f,y) ==
 MarkGray(y);
 x.f = y MarkGray(x) ==
 if x.color = WHITE
 then x.color = GRAY


COLLECTOR

Mark:
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 foreach x ∈ OBJECTS
 if x.color == GRAY
 foreach f ∈ fields(x) do
 MarkGray(x.f);
 x.color = BLACK
 until < ∀x, x.color ≠ GRAY > 
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

Invariants 1.During Scan, every reachable white object is reachable from at least one grey object 2.Every path from a black object to a white object contains a grey

  • bject

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables

slide-32
SLIDE 32

Why we need mutator’s help

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables COLLECTOR

Mark:
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 foreach x ∈ OBJECTS
 if x.color == GRAY
 foreach f ∈ fields(x) do
 MarkGray(x.f);
 x.color = BLACK
 until < ∀x, x.color ≠ GRAY > 
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

slide-33
SLIDE 33

Why we need mutator’s help

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables COLLECTOR

Mark:
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 foreach x ∈ OBJECTS
 if x.color == GRAY
 foreach f ∈ fields(x) do
 MarkGray(x.f);
 x.color = BLACK
 until < ∀x, x.color ≠ GRAY > 
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

slide-34
SLIDE 34

Why we need mutator’s help

Concurrent mark & sweep V1

1 mutator, 1 collector, no thread local variables COLLECTOR

Mark:
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 foreach x ∈ OBJECTS
 if x.color == GRAY
 foreach f ∈ fields(x) do
 MarkGray(x.f);
 x.color = BLACK
 until < ∀x, x.color ≠ GRAY > 
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

slide-35
SLIDE 35
  • 1 mutator,
  • 1 collector,
  • Global + Local Variables

Mutator

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-36
SLIDE 36

Mark:
 
 
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

The collector has not access to all mutator roots...

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-37
SLIDE 37

Mark:
 
 
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

The collector has not access to all mutator roots...

mark your roots please

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-38
SLIDE 38

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

MUTATOR [...]
 Udpate(x1,f1,y1);
 [...]
 Cooperate();
 [...]
 Alloc();
 [...]


Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-39
SLIDE 39

Handshake() = 
 statusC = Next(statusC); 
 while (statusm ≠ statusC) skip;

Cooperate() = 
 if statusm ≠ statusC
 then 
 foreach r ∈ LOCAL_ROOTS do
 MarkGray(r);
 statusm = statusC;

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

Threads mark their roots Collector waits for mutators to mark their roots

slide-40
SLIDE 40

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-41
SLIDE 41

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-42
SLIDE 42

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-43
SLIDE 43

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-44
SLIDE 44

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-45
SLIDE 45

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

thread local

r

This is not correct yet!

Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-46
SLIDE 46

Mark:
 Handshake();
 foreach x ∈ GLOBALS
 do MarkGray(x)
 Scan:
 repeat
 no_gray = true;
 foreach x ∈ OBJECTS
 if x.color == GRAY
 no_gray = false;
 foreach f ∈ fields(x) do 
 MarkGray(x.f);
 x.color = BLACK
 until no_gray
 Sweep:
 foreach x ∈ OBJECTS
 if x.color == WHITE
 then FREE(x)
 Clear:
 foreach x ∈ OBJECTS
 x.color = WHITE

MUTATOR [...]
 Udpate(x1,f1,y1);
 [...]
 Cooperate();
 [...]
 Alloc();
 [...]


Update(x,f,y) ==
 MarkGray(x.f);
 MarkGray(y)
 x.f = y MarkGray(x) ==
 if x.color = WHITE
 then x.color = GRAY


Concurrent mark & sweep V2

1 mutator, 1 collector, thread local variables

slide-47
SLIDE 47

Mutator N Mutator 1

...

Concurrent mark & sweep V3

N mutators, 1 collector, thread local variables

  • N mutators,
  • 1 Collector,
  • Global + Local Variables
slide-48
SLIDE 48

Handshake() = 
 statusC = Next(statusC); 
 while not (∀t, status[t] == statusC) skip; Cooperate() = 
 if status[t] ≠ statusC
 then 
 if ... then
 foreach r ∈ LOCAL_ROOTS do 
 MarkGray(r);
 status[t] = statusC

During this busy waiting, some mutators may not be in the same status!

Concurrent mark & sweep V3

N mutators, 1 collector, thread local variables

slide-49
SLIDE 49

Mark:
 Handshake(); // phaseC = SYNCH1
 Handshake(); // phaseC = SYNCH2
 stageC = SCANNING;
 Handshake(); // phaseC = ASYNCH
 Scan:
 Scan();
 stageC = SWEEPING;
 Sweep:
 Sweep();
 stageC = RESTING;
 Clear:
 < foreach x ∈ OBJECTS do 
 x.color = WHITE >

  • Mutators may be in different

phases

  • Several handshakes are

required per collection cycle

  • Several concurrent data

structures are necessary to track grey objects...

Concurrent mark & sweep V3

N mutators, 1 collector, thread local variables

slide-50
SLIDE 50

Mark:
 Handshake(); // phaseC = SYNCH1
 Handshake(); // phaseC = SYNCH2
 stageC = SCANNING;
 Handshake(); // phaseC = ASYNCH
 Scan:
 Scan();
 stageC = SWEEPING;
 Sweep:
 Sweep();
 stageC = RESTING;
 Clear:
 < foreach x ∈ OBJECTS do 
 x.color = WHITE >

  • Mutators may be in different

phases

  • Several handshakes are

required per collection cycle

  • Several concurrent data

structures are necessary to track grey objects...

Lots of complicated thread interactions + Fragile Invariants

Concurrent mark & sweep V3

N mutators, 1 collector, thread local variables

slide-51
SLIDE 51

SYNCH1 SYNCH2 ASYNCH SYNCH1

SYNCH2 ASYNCH

phase[C] phase[m]

collector cycle begins

| {z }

publish roots sweep collection ends

z }| { z

}| {

C-or-M TRACING SWEEPING RESTING

stageC

write barrier

black allocation white allocation

atomic black → white

scan

H a n d s h a k e ( ) ; / / p h a s e C = S Y N C H 1 H a n d s h a k e ( ) ; / / p h a s e C = S Y N C H 2 H a n d s h a k e ( ) ; / / p h a s e C = A S Y N C H S c a n ( ) ; S w e e p ( ) ;

slide-52
SLIDE 52

How do we prove it?

slide-53
SLIDE 53

An IR for Runtime Services

Right level of abstraction :

  • Not too low: decouple

algorithm’s logic from implementation details

  • Not too high: proofs at the level
  • f code (vs. an abstract machine)

managed langage
 dyn alloc, well typed GC injected code


with abstract sets, atomic blocks

managed langage
 dynamic alloc, well typed managed langage
 dyn alloc, well typed GC injected code
 executable Low level IR

Intermediate Representation:

  • Used to program the CGC
  • Equipped with an RG logic
slide-54
SLIDE 54

An IR for Runtime Services

  • Abstract Concurrent Data Structures
  • Strong Guarantees by Typing
  • Intrinsic (high-level) Iterators for:

  • Threads

  • Roots Management, Free Objects

  • Inspection of Object Layout
slide-55
SLIDE 55

An IR for Runtime Services

cmd := | skip | assume e | x = [y].f | [x].f = e | atomic c | d = cas(o, n, X) | x = alloc rn | free x | free x | x = empty?(y) | x = top(y) | push(x, y) | x.pop() | c1; c2 | c1 c2 | loop { c } | foreach (x in l) do c od

slide-56
SLIDE 56

An IR for Runtime Services

cmd := | skip | assume e | x = [y].f | [x].f = e | atomic c | d = cas(o, n, X) | x = alloc rn | free x | free x | x = empty?(y) | x = top(y) | push(x, y) | x.pop() | c1; c2 | c1 c2 | loop { c } | foreach (x in l) do c od

slide-57
SLIDE 57
  • Abstract collections:

  • concrete implementations are linearizable


MarkGray(m, x) ==
 if x.color = WHITE then
 push(bucket[m], x)

An IR for Runtime Services

cmd := | skip | assume e | x = [y].f | [x].f = e | atomic c | d = cas(o, n, X) | x = alloc rn | free x | free x | x = empty?(y) | x = top(y) | push(x, y) | x.pop() | c1; c2 | c1 c2 | loop { c } | foreach (x in l) do c od

slide-58
SLIDE 58
  • Intrinsic support for threads, roots, and objects
  • built-in iterator constructs : disciplined access
  • dedicated proof rules (high-level reasoning)

An IR for Runtime Services

cmd := | skip | assume e | x = [y].f | [x].f = e | atomic c | d = cas(o, n, X) | x = alloc rn | free x | free x | x = empty?(y) | x = top(y) | push(x, y) | x.pop() | c1; c2 | c1 c2 | loop { c } | foreach (x in l) do c od

slide-59
SLIDE 59

RG Logic

  • Rely-Guarantee Based Logic
  • syntax directed proof rules (automation)
  • minimize stability checks
  • proof engineering necessary to scale
  • Type-based invariants:
  • separation by typing: ownership
  • Clean soundness result

Theorem soundness : ∀ ts gs , reachable init_state p (ts ,gs) ⇒ I gs.

slide-60
SLIDE 60

Some Invariants

trace_grey_reach_white_inv = stage[C]gs = TRACING

  • >

forall t, phase[t]gs = ASYNCH

  • >

forall r, Reachable_from t gs r -> (exists r0 , Grey gs r0 /\ reachable gs r0 r) \/ Black gs r

slide-61
SLIDE 61

Some Invariants

SYNCH1 SYNCH2

ASYNCH

SYNCH1 SYNCH2

ASYNCH phase[C]

phase[m]

handshake_inv gs = (forall t, In t TID , (phase[C]gs = phase[t]gs \/ phase[C]gs = phase[t]gs ⊕ 1))

slide-62
SLIDE 62

Some Invariants

sweeping_no_grey = stage[C] = SWEEPING ⇒ (∀ o, ¬ Grey gs o)

slide-63
SLIDE 63

Final Theorem

Theorem gc_sound: ∀ gs , reachable_state_mgc gs ⇒ (∀ t r, Reachable_from t gs r ∨ In_bucket gs t r ⇒ ¬ Blue gs r)

Most General GC Client

slide-64
SLIDE 64

What about TSO?

slide-65
SLIDE 65

Racy Write-Barrier Implem.

...

  • .f

v

lastRead lastWrite

T0 T1 T2


 Update(m, o,f, v) ==
 MarkGray(o.f);
 MarkGray(v);


  • .f = v;

MarkGray(m, x) ==
 if x.color = WHITE then
 bucket[m][lastWrite[m]] = x;
 lastWrite[m]++;

slide-66
SLIDE 66


 Update(m, o,f, v) ==
 MarkGray(o.f);
 MarkGray(v);


  • .f = v;

...

  • .f

v

lastRead lastWrite

T0

T1 T2

MarkBucket(m) == 
 nr = lastRead[m];
 nw = lastWrite[m];
 while (nr < nw) do
 MarkBlack(bucket[m][nr]);
 nr++;


  • d

MarkGray(m, x) ==
 if x.color = WHITE then
 bucket[m][lastWrite[m]] = x;
 lastWrite[m]++;

Racy Write Barrier Implem.

slide-67
SLIDE 67


 Update(m, o,f, v) ==
 MarkGray(o.f);
 MarkGray(v);


  • .f = v;

...

  • .f

v

lastRead lastWrite

T0

T1 T2

MarkBucket(m) == 
 nr = lastRead[m];
 nw = lastWrite[m];
 while (nr < nw) do
 MarkBlack(bucket[m][nr]);
 nr++;


  • d

MarkGray(m, x) ==
 if x.color = WHITE then
 bucket[m][lastWrite[m]] = x;
 lastWrite[m]++;

Racy Write Barrier Implem.

slide-68
SLIDE 68


 Update(m, o,f, v) ==
 MarkGray(o.f);
 MarkGray(v);


  • .f = v;

...

  • .f

v

lastRead lastWrite

T0

T1 T2

MarkBucket(m) == 
 nr = lastRead[m];
 nw = lastWrite[m];
 while (nr < nw) do
 MarkBlack(bucket[m][nr]);
 nr++;


  • d

MarkGray(m, x) ==
 if x.color = WHITE then
 bucket[m][lastWrite[m]] = x;
 lastWrite[m]++;

Racy Write Barrier Implem.

slide-69
SLIDE 69

Data Races

// Cooperate[m]
 if phase[m] != phase[C] then
 if phase[C] = ASYNCH then
 foreach r in Roots[m] do
 markGrey(m, r);


  • d


phase[m] = phase[C];

SYNCH1 SYNCH2 ASYNCH SYNCH1 SYNCH2

ASYNCH

phase[C] phase[m]

// Handshake
 switch phase[C] {
 SYNCH1 : phase[C] = SYNCH2;
 SYNCH2 : phase[C] = ASYNCH;
 ASYNCH : phase[C] = SYNCH1;
 }
 foreach m in Mutators do 
 wait(phase[m] = phase[C]);


  • d
slide-70
SLIDE 70

Data Races

// Cooperate[m]
 if phase[m] != phase[C] then
 if phase[C] = ASYNCH then
 foreach r in Roots[m] do
 markGrey(m, r);


  • d


phase[m] = phase[C];

SYNCH1 SYNCH2 ASYNCH SYNCH1 SYNCH2

ASYNCH

phase[C] phase[m]

// Handshake
 switch phase[C] {
 SYNCH1 : phase[C] = SYNCH2;
 SYNCH2 : phase[C] = ASYNCH;
 ASYNCH : phase[C] = SYNCH1;
 }
 foreach m in Mutators do 
 wait(phase[m] = phase[C]);


  • d
slide-71
SLIDE 71

Data Races

// Cooperate[m]
 if phase[m] != phase[C] then
 if phase[C] = ASYNCH then
 foreach r in Roots[m] do
 markGrey(m, r);


  • d


phase[m] = phase[C];

SYNCH1 SYNCH2 ASYNCH SYNCH1 SYNCH2

ASYNCH

phase[C] phase[m]

// Handshake
 switch phase[C] {
 SYNCH1 : phase[C] = SYNCH2;
 SYNCH2 : phase[C] = ASYNCH;
 ASYNCH : phase[C] = SYNCH1;
 }
 foreach m in Mutators do 
 wait(phase[m] = phase[C]);


  • d
slide-72
SLIDE 72

Publication in TSO

MarkGray(m, x) ==
 if x.color = WHITE then
 bucket[m][lastWrite[m]] = x; // @local
 lastWrite[m]++; // release MarkBucket(m) == 
 nr = lastRead[m]; // @private
 nw = lastWrite[m]; // acquire
 while (nr < nw) do
 MarkBlack(bucket[m][nr]); // @local
 nr++;


  • d

Atomicity Refinement for Verified Compilation. 
 Jagannathan et al. [TOPLAS’14]

  • We add visibility annotations representing the
  • wnership of memory
  • Ownership transfers must respect the

Publication Idiom

  • Annotations are discharged by considering

Relies of each thread

slide-73
SLIDE 73

managed langage
 dynamic alloc, well typed GC injected code


with abstract sets, atomic blocks

managed langage
 dynamic alloc, well typed managed langage
 dynamic alloc, well typed GC injected code
 executable Low level IR