Slide 1

Slide 1 text

LaCasa: Lightweight Affinity and Object Capabilities in Scala 1 Philipp Haller1 and Alex Loiko2* OOPSLA 2016 Amsterdam, Netherlands November 2nd, 2016 1 KTH Royal Institute of Technology, Sweden 2 Google Stockholm, Sweden * Work done while at KTH

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Problem • Problem: Scala cannot ensure concurrency safety for library-based concurrency abstractions • This also applies to Java, C++, and most other widely-used programming languages 4

Slide 10

Slide 10 text

Goal 5

Slide 11

Slide 11 text

Goal Static prevention of data races 5

Slide 12

Slide 12 text

Goal Static prevention of data races • using a lightweight type system 5

Slide 13

Slide 13 text

Goal Static prevention of data races • using a lightweight type system • that minimizes the effort to reuse existing code 5

Slide 14

Slide 14 text

Goal Static prevention of data races • using a lightweight type system • that minimizes the effort to reuse existing code Focus: 5

Slide 15

Slide 15 text

Goal Static prevention of data races • using a lightweight type system • that minimizes the effort to reuse existing code Focus: • Existing, full-featured languages like Scala 5

Slide 16

Slide 16 text

Goal Static prevention of data races • using a lightweight type system • that minimizes the effort to reuse existing code Focus: • Existing, full-featured languages like Scala 5 In contrast to new language designs like Rust

Slide 17

Slide 17 text

Isn’t it a Solved Problem? 6

Slide 18

Slide 18 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) 6

Slide 19

Slide 19 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) • Challenges: 6

Slide 20

Slide 20 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) • Challenges: • Sound integration with advanced type system features 6

Slide 21

Slide 21 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) • Challenges: • Sound integration with advanced type system features 6 Example: local type inference

Slide 22

Slide 22 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) • Challenges: • Sound integration with advanced type system features • Adoption on large scale 6 Example: local type inference

Slide 23

Slide 23 text

Isn’t it a Solved Problem? • A lot of progress in type systems for safe concurrency (linear and affine types, static capabilities, uniqueness types, ownership types, region inference, etc.) • Challenges: • Sound integration with advanced type system features • Adoption on large scale • Key: reuse of existing code 6 Example: local type inference

Slide 24

Slide 24 text

Example Image data 7

Slide 25

Slide 25 text

Example Image data apply filter 7

Slide 26

Slide 26 text

Example Image data apply filter 7

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

Example: Implementation 8

Slide 30

Slide 30 text

Example: Implementation • Assumptions: • Main memory expensive (image data large) 8

Slide 31

Slide 31 text

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

Slide 32

Slide 32 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 9

Slide 33

Slide 33 text

Preventing Data Races 10

Slide 34

Slide 34 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Type system prevents sender from accessing transferred objects 10

Slide 35

Slide 35 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Type system prevents sender from accessing transferred objects • Advantages: • No run-time overhead • Errors caught at compile time 10

Slide 36

Slide 36 text

Ownership Transfer in Scala 11

Slide 37

Slide 37 text

Ownership Transfer in Scala • Enter LaCasa: Affine references for Scala 11

Slide 38

Slide 38 text

Ownership Transfer in Scala • Enter LaCasa: Affine references for Scala • “Transferable” references 11

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

Ownership Transfer in Scala • Enter LaCasa: Affine references for Scala • “Transferable” references • At most one owner per transferable reference • LaCasa combines two concepts: 11

Slide 41

Slide 41 text

Ownership Transfer in Scala • Enter LaCasa: Affine references for Scala • “Transferable” references • At most one owner per transferable reference • LaCasa combines two concepts: • Access permissions 11

Slide 42

Slide 42 text

Ownership Transfer in Scala • Enter LaCasa: Affine references for Scala • “Transferable” references • At most one owner per transferable reference • LaCasa combines two concepts: • Access permissions • Encapsulated boxes 11

Slide 43

Slide 43 text

Access Permissions 12

Slide 44

Slide 44 text

Access Permissions • Permissions control access to transferable objects 12

Slide 45

Slide 45 text

Access Permissions • Permissions control access to transferable objects CanAccess { type C } 12

Slide 46

Slide 46 text

Access Permissions • Permissions control access to transferable objects • Type member C uniquely identifies box CanAccess { type C } 12

Slide 47

Slide 47 text

Access Permissions • Permissions control access to transferable objects • Type member C uniquely identifies box CanAccess { type C } Box[T] { type C } 12

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Creating Boxes and Permissions 14

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 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 } } 14

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 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 box = packed.box … someActor.send(box) // illegal to access `box` here! } 16

Slide 64

Slide 64 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 box = packed.box … someActor.send(box) // illegal to access `box` here! } 16 How to enforce this?

Slide 65

Slide 65 text

Permissions and Continuations 17

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 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 17

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

Restricting Continuations 19

Slide 71

Slide 71 text

Restricting Continuations • Continuation disallows capturing variables of the type of access 19

Slide 72

Slide 72 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores [1] 19 [1] Miller, Haller, and Odersky. Spores: A type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 73

Slide 73 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores [1] def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = msg.C }) (implicit p: CanAccess { type C = msg.C }): Nothing 19 [1] Miller, Haller, and Odersky. Spores: A type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 74

Slide 74 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores [1] def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = msg.C }) (implicit p: CanAccess { type C = msg.C }): Nothing 19 [1] Miller, Haller, and Odersky. Spores: A type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 75

Slide 75 text

Restricting Continuations • Continuation disallows capturing variables of the type of access • Leverage spores [1] def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = msg.C }) (implicit p: CanAccess { type C = msg.C }): Nothing 19 “May not occur in captured types” [1] Miller, Haller, and Odersky. Spores: A type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

Slide 76

Slide 76 text

Stack Locality 20

Slide 77

Slide 77 text

Stack Locality • Permissions are restricted to be stack local 
 (or “stack confined”) 20

Slide 78

Slide 78 text

Stack Locality • Permissions are restricted to be stack local 
 (or “stack confined”) • This prevents problematic “indirect capturing”: 20 def method[T](box: Box[T]) (implicit p: CanAccess { type C = box.C }) = { val fun = () => p someActor.send(box) { implicit val forbidden = fun() // could still access `box` … } }

Slide 79

Slide 79 text

Stack Locality • Permissions are restricted to be stack local 
 (or “stack confined”) • This prevents problematic “indirect capturing”: 20 def method[T](box: Box[T]) (implicit p: CanAccess { type C = box.C }) = { val fun = () => p someActor.send(box) { implicit val forbidden = fun() // could still access `box` … } } “error: p stack local”

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

Encapsulation Problem: not all types safe to transfer! 22

Slide 82

Slide 82 text

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

Slide 83

Slide 83 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” 23 * simplified

Slide 84

Slide 84 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” 23 “Safe” = conforms to object capability model [2] * simplified [2] Mark S. Miller. Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control. PhD thesis, 2006

Slide 85

Slide 85 text

Object Capabilities in Scala • How common is object-capability safe code in Scala? • Empirical study of over 75,000 SLOC of open-source Scala code: 24 Project Version SLOC GitHub stats Scala stdlib 2.11.7 33,107 ✭5,795 257 Signal/Collect 8.0.6 10,159 ✭123 11 GeoTrellis 0.10.0-RC2 35,351 ✭400 38 -engine 3,868 -raster 22,291 -spark 9,192

Slide 86

Slide 86 text

Object Capabilities in Scala Results of empirical study: 25 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%)

Slide 87

Slide 87 text

Object Capabilities in Scala Results of empirical study: 25 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%)

Slide 88

Slide 88 text

Object Capabilities in Scala Results of empirical study: 25 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%) Paper: immutability increases these percentages!

Slide 89

Slide 89 text

In the Paper 26

Slide 90

Slide 90 text

In the Paper • Implementation: • Compiler plugin for Scala 2.11.x and integration with actors • Enforcement of continuation-passing style • Formalization: object-oriented core languages • CLC1: type-based notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension • Soundness proof • Isolation theorem for processes with shared heap 26 Formal model in Coq

Slide 91

Slide 91 text

Conclusion 27

Slide 92

Slide 92 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial 27

Slide 93

Slide 93 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline 27

Slide 94

Slide 94 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline • Binary check whether a class is reusable unchanged 27

Slide 95

Slide 95 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline • Binary check whether a class is reusable unchanged • Sound integration with advanced type system features of Scala 27

Slide 96

Slide 96 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline • Binary check whether a class is reusable unchanged • Sound integration with advanced type system features of Scala • In medium to large open-source Scala projects, 21-67% of all classes conform to the object capability discipline 27

Slide 97

Slide 97 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline • Binary check whether a class is reusable unchanged • Sound integration with advanced type system features of Scala • In medium to large open-source Scala projects, 21-67% of all classes conform to the object capability discipline 27 Open-source implementation: https://github.com/phaller/lacasa

Slide 98

Slide 98 text

Conclusion • Type-based notion of the object capability discipline is possible and benefitial • Safe ownership transfer is possible for objects conforming to the object capability discipline • Binary check whether a class is reusable unchanged • Sound integration with advanced type system features of Scala • In medium to large open-source Scala projects, 21-67% of all classes conform to the object capability discipline 27 Thank you! Open-source implementation: https://github.com/phaller/lacasa