Slide 1

Slide 1 text

LaCasa: Lightweight Affinity and Object Capabilities in Scala 1 Philipp Haller Northeastern University, USA September 29, 2016 KTH Royal Institute of Technology, Sweden

Slide 2

Slide 2 text

Concurrency is Difficult 2

Slide 3

Slide 3 text

Concurrency is Difficult Hazards: • Race conditions • Deadlocks • Livelocks • etc. 2

Slide 4

Slide 4 text

Concurrency is Difficult Hazards: • Race conditions • Deadlocks • Livelocks • etc. 2 Remedies?

Slide 5

Slide 5 text

Concurrency is Difficult Hazards: • Race conditions • Deadlocks • Livelocks • etc. 2 Monitors Futures, promises Actors CSP Join-calculus STM Async/await Reactive streams … Remedies?

Slide 6

Slide 6 text

Concurrency in Scala • Scala = “Scalable Language” • cf. Guy Steele. Growing a Language. OOPSLA ’98 keynote • Concurrency models as libraries • Reuse of compilers, debuggers, and IDEs • Flexible extension and adaptation 3

Slide 7

Slide 7 text

Concurrency in Scala • Scala = “Scalable Language” • cf. Guy Steele. Growing a Language. OOPSLA ’98 keynote • Concurrency models as libraries • Reuse of compilers, debuggers, and IDEs • Flexible extension and adaptation 3 Do not have to guess the answer to the question: Which concurrency model is going to “win”?

Slide 8

Slide 8 text

Background • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures/promises (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 4 Haller and Sommers Artima Press, 2012

Slide 9

Slide 9 text

Background • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures/promises (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 4 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others

Slide 10

Slide 10 text

Background • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures/promises (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 4 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others Production use at Morgan Stanley, Gawker and others

Slide 11

Slide 11 text

Background • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures/promises (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 4 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others Production use at Morgan Stanley, Gawker and others The programming-models-as-libraries approach has been successful in Scala!

Slide 12

Slide 12 text

Problem: Programming-models-as-libraries typically cannot prevent common concurrency hazards statically! 5

Slide 13

Slide 13 text

Example Image data 6

Slide 14

Slide 14 text

Example Image data apply filter 6

Slide 15

Slide 15 text

Example Image data apply filter 6

Slide 16

Slide 16 text

Example Image data apply filter Image processing pipeline: filter 1 filter 2 6

Slide 17

Slide 17 text

Example Image data apply filter Image processing pipeline: filter 1 filter 2 6 Pipeline stages run concurrently

Slide 18

Slide 18 text

Example: Implementation 7

Slide 19

Slide 19 text

Example: Implementation • Assumptions: • Image data large • Main memory expensive 7

Slide 20

Slide 20 text

Example: Implementation • Assumptions: • Image data large • Main memory expensive • Approach for high performance: • In-place update of image buffers • Pass mutable buffers by-reference 7

Slide 21

Slide 21 text

Example: Problem Easy to produce data races: 1. Stage 1 sends a reference to a buffer to stage 2 2. Following the send, both stages have a reference to the same buffer 3. Stages can concurrently access the buffer 8

Slide 22

Slide 22 text

Preventing Data Races 9

Slide 23

Slide 23 text

Preventing Data Races • Approach: safe transfer of ownership 9

Slide 24

Slide 24 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership 9

Slide 25

Slide 25 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred 9

Slide 26

Slide 26 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred • Advantages: 9

Slide 27

Slide 27 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred • Advantages: • No run-time overhead 9

Slide 28

Slide 28 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred • Advantages: • No run-time overhead • Safety does not compromise performance 9

Slide 29

Slide 29 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred • Advantages: • No run-time overhead • Safety does not compromise performance • Errors caught at compile time 9

Slide 30

Slide 30 text

Ownership Transfer in Scala 10

Slide 31

Slide 31 text

Ownership Transfer in Scala • Enter LaCasa 10

Slide 32

Slide 32 text

Ownership Transfer in Scala • Enter LaCasa • LaCasa: Scala extension for affine references 10

Slide 33

Slide 33 text

Ownership Transfer in Scala • Enter LaCasa • LaCasa: Scala extension for affine references • “Transferable” references 10

Slide 34

Slide 34 text

Ownership Transfer in Scala • Enter LaCasa • LaCasa: Scala extension for affine references • “Transferable” references • At most one owner per transferable reference 10

Slide 35

Slide 35 text

Motivation 11

Slide 36

Slide 36 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer 11

Slide 37

Slide 37 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race safety 11

Slide 38

Slide 38 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race safety • Safe memory management without GC 11

Slide 39

Slide 39 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race safety • Safe memory management without GC • Session types (with extensions) 11

Slide 40

Slide 40 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race safety • Safe memory management without GC • Session types (with extensions) • Scala for embedded real-time systems? 11

Slide 41

Slide 41 text

Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race safety • Safe memory management without GC • Session types (with extensions) • Scala for embedded real-time systems? • No GC/run-time system 11

Slide 42

Slide 42 text

Isn’t it a Solved Problem? 12

Slide 43

Slide 43 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging 12

Slide 44

Slide 44 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages 12

Slide 45

Slide 45 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust 12

Slide 46

Slide 46 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust 12 What about existing languages?

Slide 47

Slide 47 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust • Own system [1] influential, but: 12 [1] Haller and Odersky. Capabilities for uniqueness and borrowing. ECOOP ’10 What about existing languages?

Slide 48

Slide 48 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust • Own system [1] influential, but: 12 [2] Gordon et al. Uniqueness and reference immutability for safe parallelism. OOPSLA ’12 [1] Haller and Odersky. Capabilities for uniqueness and borrowing. ECOOP ’10 What about existing languages? Influenced M# language [2] of Microsoft’s Midori project

Slide 49

Slide 49 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust • Own system [1] influential, but: • Interaction with type inference unclear 12 [2] Gordon et al. Uniqueness and reference immutability for safe parallelism. OOPSLA ’12 [1] Haller and Odersky. Capabilities for uniqueness and borrowing. ECOOP ’10 What about existing languages? Influenced M# language [2] of Microsoft’s Midori project

Slide 50

Slide 50 text

Isn’t it a Solved Problem? • Adoption surprisingly challenging • Ownership not available in mainstream languages • Contender: Rust • Own system [1] influential, but: • Interaction with type inference unclear • Midori project not continued 12 [2] Gordon et al. Uniqueness and reference immutability for safe parallelism. OOPSLA ’12 [1] Haller and Odersky. Capabilities for uniqueness and borrowing. ECOOP ’10 What about existing languages? Influenced M# language [2] of Microsoft’s Midori project

Slide 51

Slide 51 text

Affine References in Scala 13

Slide 52

Slide 52 text

Affine References in Scala • LaCasa provides affine references by combining two concepts: 13

Slide 53

Slide 53 text

Affine References in Scala • LaCasa provides affine references by combining two concepts: • Access permissions 13

Slide 54

Slide 54 text

Affine References in Scala • LaCasa provides affine references by combining two concepts: • Access permissions • Encapsulated boxes 13

Slide 55

Slide 55 text

Access Permissions 14

Slide 56

Slide 56 text

Access Permissions • Access to transferable objects controlled by implicit permissions 14

Slide 57

Slide 57 text

Access Permissions • Access to transferable objects controlled by implicit permissions CanAccess { type C } 14

Slide 58

Slide 58 text

Access Permissions • Access to transferable objects controlled by implicit permissions • Type member C uniquely identifies box CanAccess { type C } 14

Slide 59

Slide 59 text

Access Permissions • Access to transferable objects controlled by implicit permissions • Type member C uniquely identifies box CanAccess { type C } Box[T] { type C } 14

Slide 60

Slide 60 text

Matching Boxes and Permissions • Type members match permissions and boxes • Via path-dependent types • Example: def method(box: Box[T]) (implicit p: CanAccess { type C = box.C }): Unit 15

Slide 61

Slide 61 text

Matching Boxes and Permissions • Type members match permissions and boxes • Via path-dependent types • Example: def method(box: Box[T]) (implicit p: CanAccess { type C = box.C }): Unit 15

Slide 62

Slide 62 text

Creating Boxes and Permissions 16

Slide 63

Slide 63 text

Creating Boxes and Permissions class Message { var arr: Array[Int] = _ } 16

Slide 64

Slide 64 text

Creating Boxes and Permissions mkBox[Message] { packed => } class Message { var arr: Array[Int] = _ } 16

Slide 65

Slide 65 text

Creating Boxes and Permissions mkBox[Message] { packed => } class Message { var arr: Array[Int] = _ } 16 LaCasa library

Slide 66

Slide 66 text

Creating Boxes and Permissions mkBox[Message] { packed => } class Message { var arr: Array[Int] = _ } 16

Slide 67

Slide 67 text

Creating Boxes and Permissions mkBox[Message] { packed => } class Message { var arr: Array[Int] = _ } implicit val access = packed.access val theBox = packed.box … 16

Slide 68

Slide 68 text

Creating Boxes and Permissions mkBox[Message] { packed => } class Message { var arr: Array[Int] = _ } sealed trait Packed[+T] { val box: Box[T] val access: CanAccess { type C = box.C } } implicit val access = packed.access val theBox = packed.box … 16

Slide 69

Slide 69 text

Accessing Boxes • Boxes are encapsulated • Boxes must be opened for access 17

Slide 70

Slide 70 text

Accessing Boxes • Boxes are encapsulated • Boxes must be opened for access mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box theBox open { msg => msg.arr = Array(1, 2, 3, 4) } } 17

Slide 71

Slide 71 text

Accessing Boxes • Boxes are encapsulated • Boxes must be opened for access mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box theBox open { msg => msg.arr = Array(1, 2, 3, 4) } } Requires implicit access permission 17

Slide 72

Slide 72 text

Consuming Permissions Example: transfering a box from one actor to another consumes its access permission 18

Slide 73

Slide 73 text

Consuming Permissions Example: transfering a box from one actor to another consumes its access permission mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box … someActor.send(theBox) // illegal to access `theBox` here! } 18

Slide 74

Slide 74 text

Consuming Permissions Example: transfering a box from one actor to another consumes its access permission mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box … someActor.send(theBox) // illegal to access `theBox` here! } 18 How to enforce this?

Slide 75

Slide 75 text

Permissions and Continuations 19

Slide 76

Slide 76 text

Permissions and Continuations • Make implicit permission unavailable in continuation of permission-consuming call 19

Slide 77

Slide 77 text

Permissions and Continuations • Make implicit permission unavailable in continuation of permission-consuming call • Scala’s type system is flow-insensitive => use continuation passing 19

Slide 78

Slide 78 text

Permissions and Continuations • Make implicit permission unavailable in continuation of permission-consuming call • Scala’s type system is flow-insensitive => use continuation passing • Restrict continuation to exclude consumed permission 19

Slide 79

Slide 79 text

Continuation-Passing Style mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box … someActor.send(theBox) { // make `access` unavailable … } } 20

Slide 80

Slide 80 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores 21

Slide 81

Slide 81 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = msg.C }) (implicit p: CanAccess { type C = msg.C }): Nothing 21

Slide 82

Slide 82 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = msg.C }) (implicit p: CanAccess { type C = msg.C }): Nothing 21

Slide 83

Slide 83 text

Intermezzo: Spores Spore [3] = closure • with explicit environment • with function type refined by captured types val msg = "hello" val num = 5 spore { val s = msg val x = num (p: Int) => s”Captured vars and param: $s, $x, $p” } 22 [3] Miller, Haller and Odersky. Spores: a type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 84

Slide 84 text

Intermezzo: Spores Spore [3] = closure • with explicit environment • with function type refined by captured types val msg = "hello" val num = 5 spore { val s = msg val x = num (p: Int) => s”Captured vars and param: $s, $x, $p” } Spore[Int, String] { type Captured = (String, Int) } 22 [3] Miller, Haller and Odersky. Spores: a type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 85

Slide 85 text

Spore Trait trait Spore[-T, +R] extends Function1[T, R] { type Captured type Excluded } 23

Slide 86

Slide 86 text

Implicit Conversions • Goal:
 Implicitly convert function literals to spores • Enables more lightweight syntax • Enables checking excluded types • Example: 24 type SafeSpore[A, B] = Spore[A, B] { type Excluded = SomeExcludedType } val s: SafeSpore[A, B] = (x: A) => { … }

Slide 87

Slide 87 text

Recall Example mkBox[Message] { packed => implicit val access = packed.access val theBox = packed.box … someActor.send(theBox) { // `access` unavailable … } } 25

Slide 88

Slide 88 text

Encapsulation Problem: not all types safe to transfer! 26

Slide 89

Slide 89 text

Encapsulation Problem: not all types safe to transfer! 26 class Message { var arr: Array[Int] = _ def leak(): Unit = { SomeObject.fld = arr } } object SomeObject { var fld: Array[Int] = _ }

Slide 90

Slide 90 text

Encapsulation • Ensuring absence of data races (“concurrency safety”) requires restricting types put into boxes • Requirements for “safe” classes:* • Methods only access parameters and this • Methods only instantiate “safe” classes • Types of fields are “safe” 27 * simplified

Slide 91

Slide 91 text

Encapsulation • Ensuring absence of data races (“concurrency safety”) requires restricting types put into boxes • Requirements for “safe” classes:* • Methods only access parameters and this • Methods only instantiate “safe” classes • Types of fields are “safe” 27 “Safe” = conforms to object capability model [3] * simplified

Slide 92

Slide 92 text

Encapsulation • Ensuring absence of data races (“concurrency safety”) requires restricting types put into boxes • Requirements for “safe” classes:* • Methods only access parameters and this • Methods only instantiate “safe” classes • Types of fields are “safe” 27 “Safe” = conforms to object capability model [3] * simplified [3] Mark S. Miller. Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control. PhD dissertation, 2006

Slide 93

Slide 93 text

Object Capabilities in Scala • How common are object-capability safe classes in Scala? • Results from empirical study: 28

Slide 94

Slide 94 text

LaCasa: Summary • Encapsulated boxes • Alias protection via object capability model • Reusing a class requires only a single bit of information • Access permissions via implicits + path-dependent types • Can statically prevent data races • Sound integration with Scala’s local type inference • Not shown: unique fields 29

Slide 95

Slide 95 text

More Contributions 30

Slide 96

Slide 96 text

More Contributions • Formalization: object-oriented core languages 30

Slide 97

Slide 97 text

More Contributions • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities 30

Slide 98

Slide 98 text

More Contributions • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions 30

Slide 99

Slide 99 text

More Contributions • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension 30

Slide 100

Slide 100 text

More Contributions • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension • Soundness proof, establishing heap separation and uniqueness invariants 30

Slide 101

Slide 101 text

More Contributions • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension • Soundness proof, establishing heap separation and uniqueness invariants • Isolation theorem for processes with shared heap 30

Slide 102

Slide 102 text

Details • Paper to appear at OOPSLA ’16 • Technical report: [arXiv:1607.05609] • Mechanization of formal model in Coq 31

Slide 103

Slide 103 text

Status and Plans 32

Slide 104

Slide 104 text

Status and Plans • Prototype implementation:1 • Compiler plug-in for Scala 2.11 • Integration with actors (straw man) 32 1 https://github.com/phaller/lacasa

Slide 105

Slide 105 text

Status and Plans • Prototype implementation:1 • Compiler plug-in for Scala 2.11 • Integration with actors (straw man) • Ongoing and future work: • Adapters for Akka and other libraries • Empirical study on the effort to adapt existing code • Port to Dotty Scala Compiler 32 1 https://github.com/phaller/lacasa

Slide 106

Slide 106 text

Status and Plans • Prototype implementation:1 • Compiler plug-in for Scala 2.11 • Integration with actors (straw man) • Ongoing and future work: • Adapters for Akka and other libraries • Empirical study on the effort to adapt existing code • Port to Dotty Scala Compiler 32 Thank you! 1 https://github.com/phaller/lacasa