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

LaCasa: Lightweight Affinity and Object Capabilities in Scala

Philipp Haller
September 29, 2016
340

LaCasa: Lightweight Affinity and Object Capabilities in Scala

Philipp Haller

September 29, 2016
Tweet

Transcript

  1. LaCasa: Lightweight Affinity and Object Capabilities in Scala 1 Philipp

    Haller Northeastern University, USA September 29, 2016 KTH Royal Institute of Technology, Sweden
  2. Concurrency is Difficult Hazards: • Race conditions • Deadlocks •

    Livelocks • etc. 2 Monitors Futures, promises Actors CSP Join-calculus STM Async/await Reactive streams … Remedies?
  3. 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
  4. 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”?
  5. 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
  6. 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
  7. 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
  8. 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!
  9. Example Image data apply filter Image processing pipeline: filter 1

    filter 2 6 Pipeline stages run concurrently
  10. 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
  11. 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
  12. Preventing Data Races • Approach: safe transfer of ownership •

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

    Sending stage loses ownership • Compiler prevents sender from accessing objects that have been transferred • Advantages: 9
  14. 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
  15. 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
  16. 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
  17. Ownership Transfer in Scala • Enter LaCasa • LaCasa: Scala

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

    extension for affine references • “Transferable” references • At most one owner per transferable reference 10
  19. Motivation • Interesting applications of linearity/affinity/ ownership transfer • Data-race

    safety • Safe memory management without GC • Session types (with extensions) 11
  20. 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
  21. 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
  22. Isn’t it a Solved Problem? • Adoption surprisingly challenging •

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

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

    Ownership not available in mainstream languages • Contender: Rust 12 What about existing languages?
  25. 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?
  26. 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
  27. 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
  28. 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
  29. Affine References in Scala • LaCasa provides affine references by

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

    combining two concepts: • Access permissions • Encapsulated boxes 13
  31. Access Permissions • Access to transferable objects controlled by implicit

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

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

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

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

    another consumes its access permission 18
  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 theBox = packed.box … someActor.send(theBox) // illegal to access `theBox` here! } 18
  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 theBox = packed.box … someActor.send(theBox) // illegal to access `theBox` here! } 18 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 19
  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 19
  45. Continuation-Passing Style mkBox[Message] { packed => implicit val access =

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

    packed.access val theBox = packed.box … someActor.send(theBox) { // `access` unavailable … } } 25
  52. 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] = _ }
  53. 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
  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” 27 “Safe” = conforms to object capability model [3] * 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” 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
  56. Object Capabilities in Scala • How common are object-capability safe

    classes in Scala? • Results from empirical study: 28
  57. 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
  58. More Contributions • Formalization: object-oriented core languages • CLC1: type-based

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

    notion of object capabilities • CLC2: uniqueness via flow-insensitive permissions • CLC3: concurrent extension 30
  60. 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
  61. 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
  62. Details • Paper to appear at OOPSLA ’16 • Technical

    report: [arXiv:1607.05609] • Mechanization of formal model in Coq 31
  63. 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
  64. 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
  65. 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