• Aucun résultat trouvé

Type Soundness and Race Freedom for Mezzo

N/A
N/A
Protected

Academic year: 2022

Partager "Type Soundness and Race Freedom for Mezzo"

Copied!
93
0
0

Texte intégral

(1)

Type Soundness and Race Freedom for Mezzo

Thibaut Balabonski François Pottier Jonathan Protzenko

INRIA

FLOPS 2014

(2)

Mezzo in a few words

Mezzo is a high-level programming language, equipped with:

algebraic data types;

first-class functions;

garbage collection;

mutable state;

shared-memoryconcurrency.

Its static discipline is based onpermissions...

(3)

Permissions by example

val r1 = newref () (* r1 @ ref () *)

val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(4)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *)

(* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(5)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *)

val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(6)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *)

val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(7)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *)

val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(8)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *)

val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(9)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *)

val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(10)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *)

val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(11)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

.

.

Why do this?

.

For fun and profit,of course!

(12)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(13)

Permissions by example

val r1 = newref () (* r1 @ ref () *) val r2 = r1

(* r1 @ ref () * r2 @ =r1 *) (* r1 @ ref () * r2 = r1 *) val () = r1 := 0

(* r1 @ ref int * r2 = r1 *) val x2 = !r2 + 1

(* r1 @ ref int * r2 = r1 * x2 @ int *) val p = (r1, r2)

(* r1 @ ref int * r2 = r1 * x2 @ int * p @ (=r1, =r2) *) val () = assert p @ (ref int, ref int) (* REJECTED *) val () = assert p @ (r: ref int, =r) (* ACCEPTED *) val () = assert p @ (=r, r: ref int) (* ACCEPTED *)

. .

Why do this?

.

For fun and profit,of course!

(14)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. .. .

(15)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. .. .

(16)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. .. .

(17)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x);

..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. .. .

(18)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. ..

(19)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. ..

. .

error in sequential code:

protocol violation

(20)

Motivation

Imagine an imperative implementation of sets:

val make: [a] () -> set a

val insert: [a] (set a, consumes a) -> () val merge: [a] (set a, consumes set a) -> ()

Then,

let s = make() in ... producess @ set t

cannot domerge(s, s);

cannot domerge(s1, s2); insert(s2, x); ..

cannot doinsert(s, x1)andinsert(s, x2)

in independent threads. ..

error in concurrent code:

data race

(21)

Permissions, in a nutshell

Like a program logic, Mezzo'sstaticdiscipline is flow-sensitive.

Acurrent(set of)permission(s) existsat each program point.

Differentpermissions exist at different points.

There is no such thing asthetype of a variable.

A permission haslayoutandownershipreadings.

A permission is eitherduplicableoraffine.

(22)

What this talk is not about

The paper and talk donotdiscuss:

algebraic data types, which describetree-shapeddata,

(static) regions, which can describenon-tree-shapeddata,

adoption & abandon, adynamicalternative to regions, and much more (ICFP 2013).

(23)

Algebraic data types

data list a =

| Nil

| Cons { head: a; tail: list a }

data mutable mlist a =

| MNil

| MCons { head: a; tail: mlist a }

.

.

Censor

ed

(24)

Melding mutable lists

val rec meld_aux [a]

(xs: MCons { head: a; tail: mlist a }, consumes ys: mlist a) : () =

match xs.tail with

| MNil ->

xs.tail <- ys

| MCons ->

meld_aux (xs.tail, ys)

. end

.

Censor

ed

(25)

Concatenating immutable lists

val rec append_aux [a] (consumes ( dst: MCons { head: a; tail: () }, xs: list a, ys: list a

)) : (| dst @ list a) = match xs with

| Cons ->

let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst';

tag of dst <- Cons;

append_aux (dst', xs.tail, ys)

| Nil ->

dst.tail <- ys;

tag of dst <- Cons

. end

.

Censor

ed

(26)

Regions

abstract region

val newregion: () -> region abstract rref (rho : value) a fact duplicable (rref rho a)

val newrref: (consumes x: a | rho @ region) -> rref rho a val get: (r: rref rho a | duplicable a | rho @ region) -> a val set: (r: rref rho a, consumes x: a | rho @ region) -> ()

.

.

Censor

ed

(27)

Adoption and abandon

val dfs [a] (g: graph a, f: a -> ()) : () = let s = stack::new g.roots in

stack::work (s, fun (n: dynamic

| g @ graph a * s @ stack dynamic) : () = take n from g;

if not n.visited then begin n.visited <- true;

f n.content;

stack::push (n.neighbors, s) end;

give n to g

. )

.

Censor

ed

(28)

What this talk is about

So, whatarethe paper and talk about?

extend Mezzo withthreadsandlocks;

describe amodular,machine-checkedproof of

type soundness;

data race freedom.

(29)

Outline

Threads, data races, and locks (by example)

Mezzo's architecture

The kernel and its proof (glimpses) Conclusion

(30)

A data race

open thread val r = newref 0

val f (| r @ ref int) : () =..

r := !r + 1

val () = spawn f ;..

spawn f ..

(31)

A data race

open thread val r = newref 0

val f (| r @ ref int) : () =..

r := !r + 1

val () = spawn f ;..

spawn f ..

.

. f requires r @ ref int

and gives it back

(32)

A data race

open thread val r = newref 0

val f (| r @ ref int) : () =..

r := !r + 1

val () = spawn f ;..

spawn f .. spawn f requires r @ ref int

(33)

A data race

open thread val r = newref 0

val f (| r @ ref int) : () =..

r := !r + 1

val () = spawn f ;..

spawn f ..

.

. TYPE ERROR!

(in fact, this code is racy)

(34)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ; spawn f ..

(35)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ; spawn f ..

.

. this consumes r @ ref int

the lock now mediates access to it

(36)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ;

spawn f .. f requires no permission

(37)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ; spawn f ..

.

. acquiring the lock

produces r @ ref int

(38)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ;

spawn f .. r @ ref int allows updating r

(39)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ; spawn f ..

.

. releasing the lock

consumes r @ ref int

(40)

Introducing synchronization

open thread open lock

val r = newref 0

val l : lock (r @ ref int) = new()..

val f () : () =..

acquire l; ..

r := !r + 1; ..

release l ..

val () = spawn f ;

spawn f .. WELL-TYPED!

(41)

Abstracting synchronization

(* A second-order function. *)

val hide : [a, b, s : perm] (..

f : (consumes a | s) -> b..|

consumes s..

) -> (consumes a) -> b..

.

(42)

Abstracting synchronization

(* A second-order function. *)

val hide : [a, b, s : perm] (..

f : (consumes a | s) -> b..|

consumes s..

) -> (consumes a) -> b..

. .

hide is polymorphic in s e.g., r @ ref int

(43)

Abstracting synchronization

(* A second-order function. *)

val hide : [a, b, s : perm] (..

f : (consumes a | s) -> b..|

consumes s..

) -> (consumes a) -> b..

. .

hide takes a function f which has a side effect on s

(44)

Abstracting synchronization

(* A second-order function. *)

val hide : [a, b, s : perm] (..

f : (consumes a | s) -> b..|

consumes s..

) -> (consumes a) -> b..

. .

hide consumes s

which becomes owned by the lock

(45)

Abstracting synchronization

(* A second-order function. *)

val hide : [a, b, s : perm] (..

f : (consumes a | s) -> b..|

consumes s..

) -> (consumes a) -> b..

. .

hide produces a new function which has no advertised effect

(46)

A synchronization pattern

open lock

val hide [a, b, s : perm] ( f : (consumes a | s) -> b | consumes s

) : (consumes a) -> b = let l : lock s = new () in fun (consumes x : a) : b =

acquire l;

let y = f x in release l;

.

(47)

Introducing synchronization, revisited

open thread open hide

val r = newref 0..

val f (| r @ ref int) : () =..

r := !r + 1

val f = hide f..

val () = spawn f;

spawn f ..

.

(48)

Introducing synchronization, revisited

open thread open hide

val r = newref 0..

val f (| r @ ref int) : () =..

r := !r + 1

val f = hide f..

val () = spawn f;

spawn f .. r @ ref int

(49)

Introducing synchronization, revisited

open thread open hide

val r = newref 0..

val f (| r @ ref int) : () =..

r := !r + 1

val f = hide f..

val () = spawn f;

spawn f ..

.

. r @ ref int

f @ (| r @ ref int) -> ()

(50)

Introducing synchronization, revisited

open thread open hide

val r = newref 0..

val f (| r @ ref int) : () =..

r := !r + 1

val f = hide f..

val () = spawn f;

spawn f ..

(51)

Introducing synchronization, revisited

open thread open hide

val r = newref 0..

val f (| r @ ref int) : () =..

r := !r + 1

val f = hide f..

val () = spawn f;

spawn f ..

.

. WELL-TYPED!

(yup, this code is race free)

(52)

Outline

Threads, data races, and locks (by example) Mezzo's architecture

The kernel and its proof (glimpses) Conclusion

(53)

What is Mezzo?

A kernel:

aλ-calculus with threads;

affine, polymorphic, value-dependent, with type erasure.

Several extensions:

mutable state: references;

hidden state: locks;

dynamic ownership control: adoption and abandon.

Allmachine-checkedin Coq (14KLOC).

(54)

Modularity

We wish to prove that well-typed programs:

do not go wrong;

are data-race free.

This is trivial - true ofallprograms - in the kernel calculus!

Subject reductionandprogressare non-trivial results.

We set up their proof so that it isrobustin the face of extensions.

(55)

Modularity

Weparameterizethe kernel with:

a type ofmachine statess;

a type ofinstrumented statesR, orresources;

which must form amonotonic separation algebra;

a correspondence relation,s∼R.

Subject reduction and progress holdfor allsuch parameters.

(56)

Pseudo-Modularity

The kernel isnotparameterized w.r.t. the extensions.

We add the extensions, one after another, on top of the kernel.

So, the Coq code ismonolithic. Fortunately,

each extension is (morally)independentof the others;

the key statementsdo not changewith extensions;

only new proof cases appear.

(57)

Outline

Threads, data races, and locks (by example) Mezzo's architecture

The kernel and its proof (glimpses) Conclusion

(58)

Values and terms

A fairly unremarkable untypedλ-calculus with threads.

κ ::= value|term|soup|. . . (Kinds)

v ::= x|λx.t (Values)

t ::= v|v t.. |spawnv v.. (Terms)

(59)

Operational semantics

initial configuration new configuration

s/ (λx.t)v −→s / [v/x]t

s/E[t] −→s.. /E[t] ifs/t−→s/t s/thread(t) −→s /thread(t) ifs/t−→s/t s/t1 ∥t2 −→s /t1 ∥t2

ifs/t1−→s/t1 s/t1 ∥t2 −→s /t1 ∥t2

ifs/t2−→s/t2

s/thread(D[spawnv1v2])−→s /thread(D[()])thread(v1v2) .

(60)

Operational semantics

initial configuration new configuration

s/ (λx.t)v −→s / [v/x]t

s/E[t] −→s.. /E[t] ifs/t−→s/t s/thread(t) −→s /thread(t) ifs/t−→s/t s/t1 ∥t2 −→s /t1 ∥t2

ifs/t1−→s/t1 s/t1 ∥t2 −→s /t1 ∥t2

ifs/t −→s/t

an abstract notion of machine state

(61)

Types and permissions

κ ::= . . .|type|perm (Kinds) T,U ::= x|=v|T→T|(T|P) (Types)

∀x:κ.T| ∃x:κ.T

P,Q ::= x|v@T|empty|P P (Permissions)

∀x:κ.P| ∃x:κ.P

duplicableθ θ ::= T|P

(62)

The typing judgement

A traditional type system uses a listΓoftype assumptions:

Γ⊢t:T

Mezzo splits it into a listKofkind assumptionsand apermissionP:

K,P⊢t:T

This can be read like a Hoare triple: K⊢ {..P}t{..T}.

(63)

The typing judgement

A typing judgement about arunningprogram (or thread) depends on a resourceR:

R,K,P⊢t:T

Ris the thread'spartial,instrumented viewof the machine state...

(64)

Resources

A resource is:

partial: a resource could be, say, a heap fragment;

instrumented: a resource could record whether each location is mutable or immutable.

At this stage, though, resources areabstract. What properties must we require of them?

(65)

Resources

A resource is:

partial: a resource could be, say, a heap fragment;

instrumented: a resource could record whether each location is mutable or immutable.

At this stage, though, resources areabstract.

What properties must we require of them?

(66)

Monotonic separation algebra

R resource

e.g., an instrumented heap fragment maps every address to , N, X v, or D v R1 R2 conjunction

e.g., requires separation at mutable addresses requires agreement at immutable addresses Rb duplicable core

e.g., throws away mutable addresses keeps immutable addresses R1R2 tolerable interference (rely)

(67)

Working with abstract resources

Staris commutative and associative.

R1 R2okimpliesR1 ok.

R Rb=R.

R1 R2 =RandR okimplyRc1=bR.

R R=RimpliesR=R.b

Rb Rb=bR.

RR.

R1 okandR1R2implyR2ok.

R1R2impliesRc1Rc2.

rely preserves splits:

R1 R2R R1 R2ok

∃R1R2,R1 R2 =R∧R1R1∧R2R2

(68)

A small set of typing rules

Singleton R;K;P v:=v

Frame

R;K;P t:T R;K;PQ t:T|Q

Function

bR;K,x:value;Px@Tt:U R;K; (duplicableP)P λx.t:TU ForallIntro

t is harmless R;K,x:κ;P t:T R;K;∀x:κ.P t:∀x:κ.T

ExistsIntro R;K;P v: [U/x]T R;K;P v:∃x:κ.T

Cut

R2;K;P1 P2 t:T R1;KP1 R1 R2;K;P2 t:T ExistsElim

R;K,x:κ;Pt:T R;K;∃x:κ.Pt:T

SubLeft

KP1P2 R;K;P2t:T R;K;P1t:T

SubRight

R;K;Pt:T1 KT1T2 R;K;Pt:T2 Application

R;K;Qt:T R;K; (v@TU)Qv t:U

Spawn

R;K; (v1@TU)(v2@T)spawnv1v2:

(69)

Selected typing rules

The kernel typing rules manipulateRabstractly.

Rb..;K,x:value;P x@T⊢t:U R;K; (duplicableP) P⊢λx.t:T→U

R2;K;P1 P2⊢t:T R1;KP1

R1.. R2;K;P2⊢t:T .

(70)

Selected typing rules

The kernel typing rules manipulateRabstractly.

Rb..;K,x:value;P x@T⊢t:U R;K; (duplicableP) P⊢λx.t:T→U

R2;K;P1 P2⊢t:T R1;KP1

R1.. R2;K;P2⊢t:T .

.

cannot capture an arbitrary resource R

can capture its duplicable core bR

(71)

Selected typing rules

The kernel typing rules manipulateRabstractly.

Rb..;K,x:value;P x@T⊢t:U R;K; (duplicableP) P⊢λx.t:T→U

R2;K;P1 P2⊢t:T R1;KP1

R1.. R2;K;P2⊢t:T .

.

if a typing rule has two premises then R must be split between them

(72)

Subject reduction

Lemma (S.R., preliminary form)

s1/t1 −→s2/t2..

s1 ∼R1 R1..

R1;∅;empty⊢t1 :T..

∃R2R2..



s2 ∼R2 R2..

R2;∅;empty⊢t2:T..

R1R2..

. .

(73)

Subject reduction

Lemma (S.R., preliminary form)

s1/t1 −→s2/t2..

s1 ∼R1 R1..

R1;∅;empty⊢t1 :T..

∃R2R2..



s2 ∼R2 R2..

R2;∅;empty⊢t2:T..

R1R2..

. .

one thread takes a step

.

(74)

Subject reduction

Lemma (S.R., preliminary form)

s1/t1 −→s2/t2..

s1 ∼R1 R1..

R1;∅;empty⊢t1 :T..

∃R2R2..



s2 ∼R2 R2..

R2;∅;empty⊢t2:T..

R1R2..

. .

this thread's view is R1 the other threads' view is R1

.

Références

Documents relatifs

The evaluation results show that: (i) Using the Mixer table based interface, administrators can conceive of, create, and use forms that effectively communicate

1 Toy data example illustrating sequential time-shifted kCCA and tkCCA; A: signal s(t ) (top) and two two-dimensional measurement time series X (blue, no delay) and Y (green, 6

Sur le modèle du retour d’Ulysse dans sa patrie, Marcel- lo Fois raconte l’arrivée en Sardaigne d’un jeune homme à la recherche de sa famille et de sa patrie.. Les

The subsumption rule U NADOPTED A DOPTABLE states that, when one holds the affine permission v @ unadopted, one can obtain, in addition, the duplicable permission v @ adoptable.. is

val append: [a] (consumes xs: list a, consumes ys: list a) -&gt; zs: list a To allow the user to express fine-grained control over which arguments are lost and which are preserved,

To summarize, if we extend the kernel with both references (§3) and locks, then a machine state s is a pair of a value heap and a lock heap; a resource R is a pair of an

• must perform frame inference, abduction, join Type errors are very difficult to explain, debug, fix. Safe interoperability with OCaml is

Algebraic data structures Sharing mutable data Conclusion... A first example and a