Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LaCasa: Lightweight Affinity and Object Capabilities in Scala

Philipp Haller
November 02, 2016
460

LaCasa: Lightweight Affinity and Object Capabilities in Scala

Philipp Haller

November 02, 2016
Tweet

Transcript

  1. 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
  2. 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
  3. 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”?
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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!
  9. 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
  10. Goal Static prevention of data races • using a lightweight

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

    type system • that minimizes the effort to reuse existing code Focus: 5
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. Example Image data apply filter Image processing pipeline: filter 1

    filter 2 7 Pipeline stages run concurrently
  21. 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
  22. 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
  23. Preventing Data Races • Approach: safe transfer of ownership •

    Sending stage loses ownership • Type system prevents sender from accessing transferred objects 10
  24. 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
  25. Ownership Transfer in Scala • Enter LaCasa: Affine references for

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

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

    Scala • “Transferable” references • At most one owner per transferable reference • LaCasa combines two concepts: 11
  28. 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
  29. 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
  30. Access Permissions • Permissions control access to transferable objects •

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

    Type member C uniquely identifies box CanAccess { type C } Box[T] { type C } 12
  32. 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
  33. 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
  34. Creating Boxes and Permissions mkBox[Message] { packed => } class

    Message { var arr: Array[Int] = _ } 14 LaCasa library
  35. 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
  36. Creating Boxes and Permissions mkBox[Message] { packed => } class

    Message { var arr: Array[Int] = _ } implicit val access = packed.access val box = packed.box … 14
  37. 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
  38. 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
  39. 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
  40. Consuming Permissions Example: transfering a box from one actor to

    another consumes its access permission 16
  41. 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
  42. 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?
  43. Permissions and Continuations • Make implicit permission unavailable in continuation

    of permission-consuming call • Scala’s type system is flow-insensitive => use continuation passing 17
  44. 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
  45. Continuation-Passing Style mkBox[Message] { packed => implicit val access =

    packed.access val box = packed.box … someActor.send(box) { // make `access` unavailable … } } 18
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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` … } }
  51. 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”
  52. Recall Example mkBox[Message] { packed => implicit val access =

    packed.access val box = packed.box … someActor.send(box) { // `access` unavailable … } } 21
  53. 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] = _ }
  54. 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
  55. 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
  56. 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
  57. 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%)
  58. 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%)
  59. 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!
  60. 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
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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