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

Miniboxing presentation at OOPSLA 2013

Miniboxing presentation at OOPSLA 2013

Miniboxing presentation at OOPSLA 2013. Website: http://splashcon.org/2013/program/oopsla-research-papers

Project website: http://scala-miniboxing.org

Vlad Ureche

October 29, 2013
Tweet

More Decks by Vlad Ureche

Other Decks in Programming

Transcript

  1. scala-miniboxing.org
    Miniboxing
    Miniboxing
    Load-time Specialization on the JVM
    OOPSLA, 29th of October 2013
    Vlad Ureche
    Cristian Talau
    Martin Odersky

    View Slide

  2. 2
    scala-miniboxing.org
    We all like generics
    We all like generics

    View Slide

  3. 3
    scala-miniboxing.org
    We all like generics
    We all like generics
    a trivial example
    a trivial example

    View Slide

  4. 4
    scala-miniboxing.org
    We all like generics
    We all like generics
    def identity[T](t: T): T = t
    a trivial example
    a trivial example

    View Slide

  5. 5
    scala-miniboxing.org
    We all like generics
    We all like generics
    def identity[T](t: T): T = t

    will take any type and

    will return that same type
    a trivial example
    a trivial example

    View Slide

  6. 6
    scala-miniboxing.org
    We all like generics
    We all like generics
    def identity[T](t: T): T = t

    will take any type and

    will return that same type
    a trivial example
    a trivial example

    View Slide

  7. 7
    scala-miniboxing.org
    We all like generics
    We all like generics
    def identity[T](t: T): T = t
    a trivial example
    a trivial example
    but under erasure:
    def identity(t: Any): Any = t

    View Slide

  8. 8
    scala-miniboxing.org
    We all like generics
    We all like generics
    def identity[T](t: T): T = t
    a trivial example
    a trivial example
    but under erasure:
    def identity(t: Any): Any = t
    Any is the top of the
    Scala type system

    View Slide

  9. 9
    scala-miniboxing.org
    We all like generics
    We all like generics
    x = identity(3)
    a trivial example
    a trivial example

    View Slide

  10. 10
    scala-miniboxing.org
    We all like generics
    We all like generics
    x = identity(3)
    under erasure:
    a trivial example
    a trivial example
    x = unbox(identity(box(3)))

    View Slide

  11. 11
    scala-miniboxing.org
    We all like generics
    We all like generics
    but under
    but under erasure
    erasure

    View Slide

  12. 12
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    but under
    but under erasure
    erasure

    View Slide

  13. 13
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    – generic values lose their type information
    but under
    but under erasure
    erasure

    View Slide

  14. 14
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    – generic values lose their type information
    – primitives need boxing
    but under
    but under erasure
    erasure

    View Slide

  15. 15
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    – generic values lose their type information
    – primitives need boxing
    – performance is affected
    but under
    but under erasure
    erasure

    View Slide

  16. 16
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    – generic values lose their type information
    – primitives need boxing
    – performance is affected
    but under
    but under erasure
    erasure
    Dynamic language VMs use
    specialization to improve performance*

    View Slide

  17. 17
    scala-miniboxing.org
    We all like generics
    We all like generics
    generics execute similarly to dynamic
    languages
    – generic values lose their type information
    – primitives need boxing
    – performance is affected
    but under
    but under erasure
    erasure
    Dynamic language VMs use
    specialization to improve performance*
    *but the HotSpot JVM doesn't

    View Slide

  18. 18
    scala-miniboxing.org
    WE ARE HERE
    Generics
    Specialization
    Miniboxing
    Performance
    Evaluation

    View Slide

  19. 19
    scala-miniboxing.org
    Scala has a solution
    Scala has a solution

    View Slide

  20. 20
    scala-miniboxing.org
    Scala has a solution
    Scala has a solution
    it's called specialization
    it's called specialization*
    *
    * Iulian Dragos – PhD thesis, EPFL, 2010

    View Slide

  21. 21
    scala-miniboxing.org
    Scala has a solution
    Scala has a solution
    Compile-time (static) transformation
    – duplicates the original code
    – adapts it for each primitive type
    – rewrites programs to use the adapted code
    it's called specialization
    it's called specialization*
    *
    * Iulian Dragos – PhD thesis, EPFL, 2010

    View Slide

  22. 22
    scala-miniboxing.org
    Scala has a solution
    Scala has a solution
    Compile-time (static) transformation
    – duplicates the original code
    – adapts it for each primitive type
    – rewrites programs to use the adapted code
    it's called specialization
    it's called specialization*
    *
    Adapted code doesn't need to box
    * Iulian Dragos – PhD thesis, EPFL, 2010

    View Slide

  23. 23
    scala-miniboxing.org
    Scala has a solution
    Scala has a solution
    Compile-time (static) transformation
    – duplicates the original code
    – adapts it for each primitive type
    – rewrites programs to use the adapted code
    it's called specialization
    it's called specialization*
    *
    Adapted code doesn't need to box
    Performance is regained.
    * Iulian Dragos – PhD thesis, EPFL, 2010

    View Slide

  24. 24
    scala-miniboxing.org
    Specialization
    Specialization
    let's revisit `def identity`
    let's revisit `def identity`

    View Slide

  25. 25
    scala-miniboxing.org
    Specialization
    Specialization
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t

    View Slide

  26. 26
    scala-miniboxing.org
    Specialization
    Specialization
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_V(t: Unit): Unit = t
    def identity_Z(t: Boolean): Boolean = t
    def identity_B(t: Byte): Byte = t
    def identity_C(t: Char): Char = t
    def identity_S(t: Short): Short = t
    def identity_I(t: Int): Int = t
    def identity_J(t: Long): Long = t
    def identity_F(t: Float): Float = t
    def identity_D(t: Double): Double = t

    View Slide

  27. 27
    scala-miniboxing.org
    Specialization
    Specialization
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_V(t: Unit): Unit = t
    def identity_Z(t: Boolean): Boolean = t
    def identity_B(t: Byte): Byte = t
    def identity_C(t: Char): Char = t
    def identity_S(t: Short): Short = t
    def identity_I(t: Int): Int = t
    def identity_J(t: Long): Long = t
    def identity_F(t: Float): Float = t
    def identity_D(t: Double): Double = t
    Generates 10 times the original code

    View Slide

  28. 28
    scala-miniboxing.org
    Specialization
    Specialization

    … it gets even worse
    it gets even worse

    View Slide

  29. 29
    scala-miniboxing.org
    Specialization
    Specialization

    … it gets even worse
    it gets even worse
    def pack[T1, T2](t1: T1, t2: T2) = ...

    View Slide

  30. 30
    scala-miniboxing.org
    def pack_VV(t1: Unit, t2: Unit)
    def pack_VZ(t1: Unit, t2: Boolean)
    def pack_VB(t1: Unit, t2: Byte)
    def pack_VC(t1: Unit, t2: Char)
    def pack_VS(t1: Unit, t2: Short)
    def pack_VI(t1: Unit, t2: Int)
    def pack_VJ(t1: Unit, t2: Long)
    def pack_VF(t1: Unit, t2: Float)
    def pack_VD(t1: Unit, t2: Double)
    Specialization
    Specialization

    … it gets even worse
    it gets even worse
    def pack[T1, T2](t1: T1, t2: T2) = ...

    View Slide

  31. 31
    scala-miniboxing.org
    def pack_VV(t1: Unit, t2: Unit)
    def pack_VZ(t1: Unit, t2: Boolean)
    def pack_VB(t1: Unit, t2: Byte)
    def pack_VC(t1: Unit, t2: Char)
    def pack_VS(t1: Unit, t2: Short)
    def pack_VI(t1: Unit, t2: Int)
    def pack_VJ(t1: Unit, t2: Long)
    def pack_VF(t1: Unit, t2: Float)
    def pack_VD(t1: Unit, t2: Double)
    Specialization
    Specialization

    … it gets even worse
    it gets even worse
    def pack[T1, T2](t1: T1, t2: T2) = ...
    10^n, where n is the number of type params

    View Slide

  32. 32
    scala-miniboxing.org
    def pack_VV(t1: Unit, t2: Unit)
    def pack_VZ(t1: Unit, t2: Boolean)
    def pack_VB(t1: Unit, t2: Byte)
    def pack_VC(t1: Unit, t2: Char)
    def pack_VS(t1: Unit, t2: Short)
    def pack_VI(t1: Unit, t2: Int)
    def pack_VJ(t1: Unit, t2: Long)
    def pack_VF(t1: Unit, t2: Float)
    def pack_VD(t1: Unit, t2: Double)
    Specialization
    Specialization

    … it gets even worse
    it gets even worse
    def pack[T1, T2](t1: T1, t2: T2) = ...
    10^n, where n is the number of type params
    And this is common: Maps, Tuples, Functions

    View Slide

  33. 33
    scala-miniboxing.org
    def pack_VV(t1: Unit, t2: Unit)
    def pack_VZ(t1: Unit, t2: Boolean)
    def pack_VB(t1: Unit, t2: Byte)
    def pack_VC(t1: Unit, t2: Char)
    def pack_VS(t1: Unit, t2: Short)
    def pack_VI(t1: Unit, t2: Int)
    def pack_VJ(t1: Unit, t2: Long)
    def pack_VF(t1: Unit, t2: Float)
    def pack_VD(t1: Unit, t2: Double)
    Specialization
    Specialization

    … it gets even worse
    it gets even worse
    def pack[T1, T2](t1: T1, t2: T2) = ...
    10^n, where n is the number of type params
    And this is common: Maps, Tuples, Functions

    View Slide

  34. 34
    scala-miniboxing.org
    WE ARE HERE
    Generics
    Specialization
    Miniboxing
    Performance
    Evaluation

    View Slide

  35. 35
    scala-miniboxing.org
    Miniboxing
    Miniboxing

    View Slide

  36. 36
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants

    View Slide

  37. 37
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)

    View Slide

  38. 38
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    Stores the
    original type

    View Slide

  39. 39
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    Stores the
    original type
    Stores the encoded value
    in a long integer

    View Slide

  40. 40
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)

    View Slide

  41. 41
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    BOOL 0x0
    false =

    View Slide

  42. 42
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    BOOL 0x0
    false =
    BOOL 0x1
    true =

    View Slide

  43. 43
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    BOOL 0x0
    false =
    BOOL 0x1
    true =
    INT 0x2A
    42 =

    View Slide

  44. 44
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)

    View Slide

  45. 45
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    reduces the variants
    reduces the variants
    by using something like a tagged union
    TAG DATA (VALUE)
    and using the static type information
    – tags are attached to code, not to values

    View Slide

  46. 46
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t

    View Slide

  47. 47
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_M(T_tag: Byte, t: Long): Long

    View Slide

  48. 48
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_M(T_tag: Byte, t: Long): Long
    TAG

    View Slide

  49. 49
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_M(T_tag: Byte, t: Long): Long
    TAG DATA (VALUE)

    View Slide

  50. 50
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_M(T_tag: Byte, t: Long): Long
    TAG DATA (VALUE)
    T_tag corresponds to the type
    parameter, instead of the
    values being passed around.

    View Slide

  51. 51
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    def identity_M(T_tag: Byte, t: Long): Long
    TAG DATA (VALUE)
    T_tag corresponds to the type
    parameter, instead of the
    values being passed around.
    Tag hoisting

    View Slide

  52. 52
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    Two variants per type parameter (reference + minibox)
    def identity_M(T_tag: Byte, t: Long): Long

    View Slide

  53. 53
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    Two variants per type parameter (reference + minibox)
    `def pack` will have 4 variants
    def identity_M(T_tag: Byte, t: Long): Long

    View Slide

  54. 54
    scala-miniboxing.org
    Miniboxing
    Miniboxing
    let's revisit `def identity`
    let's revisit `def identity`
    def identity[T](t: T): T = t
    Two variants per type parameter (reference + minibox)
    `def pack` will have 4 variants
    Tag hoisting is instrumental in
    obtaining good performance
    def identity_M(T_tag: Byte, t: Long): Long

    View Slide

  55. 55
    scala-miniboxing.org
    WE ARE HERE
    Generics
    Specialization
    Miniboxing
    Performance
    Evaluation

    View Slide

  56. 56
    scala-miniboxing.org
    Performance
    Performance
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient

    View Slide

  57. 57
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient

    View Slide

  58. 58
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???

    View Slide

  59. 59
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???
    Why do we need a secret ingredient?

    View Slide

  60. 60
    scala-miniboxing.org
    Switching on tags
    Switching on tags
    kills performance
    kills performance

    View Slide

  61. 61
    scala-miniboxing.org
    def toString(T_tag: Byte,
    value: Long): String =
    T_tag match {
    case UNIT => ...
    case BOOL => ...
    ...
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance

    View Slide

  62. 62
    scala-miniboxing.org
    def toString(T_tag: Byte,
    value: Long): String =
    T_tag match {
    case UNIT => ...
    case BOOL => ...
    ...
    }
    Even more so for consecutive switches
    Switching on tags
    Switching on tags
    kills performance
    kills performance

    View Slide

  63. 63
    scala-miniboxing.org
    T_tag match {
    case X => op1
    }
    T_tag match {
    case X => op2
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance

    View Slide

  64. 64
    scala-miniboxing.org
    T_tag match {
    case X => op1
    }
    T_tag match {
    case X => op2
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    Redundant
    switch

    View Slide

  65. 65
    scala-miniboxing.org
    T_tag match {
    case X => op1
    }
    T_tag match {
    case X => op2
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    Redundant
    switch

    View Slide

  66. 66
    scala-miniboxing.org
    T_tag match {
    case X => op1; op2
    }
    T_tag match {
    case X =>
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    Redundant
    switch

    View Slide

  67. 67
    scala-miniboxing.org
    T_tag match {
    case X => op1; op2
    }
    T_tag match {
    case X =>
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    Redundant
    switch

    View Slide

  68. 68
    scala-miniboxing.org
    T_tag match {
    case X => op1; op2
    }
    T_tag match {
    case X =>
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    Redundant
    switch
    Fused
    together

    View Slide

  69. 69
    scala-miniboxing.org
    T_tag match {
    case X => op1; op2
    }
    T_tag match {
    case X =>
    }
    Switching on tags
    Switching on tags
    kills performance
    kills performance
    This is critical for array operations
    Redundant
    switch
    Fused
    together

    View Slide

  70. 70
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    Switching
    Switching

    View Slide

  71. 71
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT => ...
    ...
    }
    Switching
    Switching

    View Slide

  72. 72
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT => ...
    ...
    } T_tag match {
    case INT => ...
    ...
    }
    Switching
    Switching

    View Slide

  73. 73
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT => ...
    ...
    } T_tag match {
    case INT => ...
    ...
    }
    T_tag match {
    case INT => ...
    ...
    }
    T_tag match {
    case INT => ...
    ...
    }
    Switching
    Switching

    View Slide

  74. 74
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT => ...
    ...
    } T_tag match {
    case INT => ...
    ...
    }
    T_tag match {
    case INT => ...
    ...
    }
    T_tag match {
    case INT => ...
    ...
    }
    Fuse the operations together?
    Switching
    Switching

    View Slide

  75. 75
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT =>
    val tmp1 = ...
    val tmp2 = ...
    array(.) = ...
    array(.) = ...
    ...
    }
    Switching
    Switching

    View Slide

  76. 76
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_tag match {
    case INT =>
    val tmp1 = ...
    val tmp2 = ...
    array(.) = ...
    array(.) = ...
    ...
    }
    Hoist the switch out of the loop?
    Switching
    Switching

    View Slide

  77. 77
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    Switching
    Switching
    T_tag match {
    case INT =>
    var index = 0
    while (...) {
    ...
    index += 1
    }
    }

    View Slide

  78. 78
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(opposite)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    Is that enough? Method may be called from a loop
    Switching
    Switching
    T_tag match {
    case INT =>
    var index = 0
    while (...) {
    ...
    index += 1
    }
    }

    View Slide

  79. 79
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???

    View Slide

  80. 80
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???
    Can't be switching

    View Slide

  81. 81
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???
    Can't be switching
    Must be something else

    View Slide

  82. 82
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    Dispatching
    Dispatching

    View Slide

  83. 83
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    class Dispatcher[T] {
    def array_get(...): Long
    def array_set(...): Unit
    }
    Dispatching
    Dispatching

    View Slide

  84. 84
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    class Dispatcher[T] {
    def array_get(...): Long
    def array_set(...): Unit
    }
    Dispatching
    Dispatching
    def identity_M(T_dispatcher: Dispatcher[T],
    t: Long): Long

    View Slide

  85. 85
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    class Dispatcher[T] {
    def array_get(...): Long
    def array_set(...): Unit
    }
    Dispatching
    Dispatching
    def identity_M(T_dispatcher: Dispatcher[T],
    t: Long): Long
    instead of tag

    View Slide

  86. 86
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    Dispatching
    Dispatching
    object IntDispatcher extends Dispatcher[Int] {
    def array_get(...): Long = ...
    def array_set(...): Unit = ...
    }

    View Slide

  87. 87
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    Dispatching
    Dispatching
    object IntDispatcher extends Dispatcher[Int] {
    def array_get(...): Long = ...
    def array_set(...): Unit = ...
    }
    object LongDispatcher ...
    object CharDispatcher ...

    View Slide

  88. 88
    scala-miniboxing.org

    Dispatch object
    – Encodes array interactions
    Passing a dispatcher = hoisted already
    Dispatching
    Dispatching
    object IntDispatcher extends Dispatcher[Int] {
    def array_get(...): Long = ...
    def array_set(...): Unit = ...
    }
    object LongDispatcher ...
    object CharDispatcher ...

    View Slide

  89. 89
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(other)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    Dispatching
    Dispatching

    View Slide

  90. 90
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(other)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_dispatcher.array_get
    Dispatching
    Dispatching

    View Slide

  91. 91
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(other)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_dispatcher.array_get
    T_dispatcher.array_get
    Dispatching
    Dispatching

    View Slide

  92. 92
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(other)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_dispatcher.array_get
    T_dispatcher.array_get
    T_dispatcher.array_set
    T_dispatcher.array_set
    Dispatching
    Dispatching

    View Slide

  93. 93
    scala-miniboxing.org
    ArrayBuffer.reverse()
    def reverse(): Unit {
    var index = 0
    while (index * 2 < length) {
    val opposite = length-index-1
    val tmp1: T = array(index)
    val tmp2: T = array(other)
    array(index) = tmp2
    array(opposite) = tmp1
    index += 1
    }
    }
    T_dispatcher.array_get
    T_dispatcher.array_get
    T_dispatcher.array_set
    T_dispatcher.array_set
    Dispatching
    Dispatching
    With inlining, we get good performance

    View Slide

  94. 94
    scala-miniboxing.org
    ArrayBuffer.reverse()
    T_dispatcher.array_get
    Dispatching
    Dispatching

    View Slide

  95. 95
    scala-miniboxing.org
    ArrayBuffer.reverse()
    T_dispatcher.array_get
    Dispatching
    Dispatching
    IntDispatcher
    Monomorphic, okay

    View Slide

  96. 96
    scala-miniboxing.org
    ArrayBuffer.reverse()
    T_dispatcher.array_get
    Dispatching
    Dispatching
    LongDispatcher
    Polymorphic, okay
    IntDispatcher
    Monomorphic, okay

    View Slide

  97. 97
    scala-miniboxing.org
    DoubleDispatcher
    Megamorphic* no more inlining

    * for the HotSpot JVM
    ArrayBuffer.reverse()
    T_dispatcher.array_get
    Dispatching
    Dispatching
    LongDispatcher
    Polymorphic, okay
    IntDispatcher
    Monomorphic, okay

    View Slide

  98. 98
    scala-miniboxing.org
    DoubleDispatcher
    Megamorphic* no more inlining

    * for the HotSpot JVM
    ArrayBuffer.reverse()
    T_dispatcher.array_get
    Dispatching
    Dispatching
    LongDispatcher
    Polymorphic, okay
    IntDispatcher
    Monomorphic, okay
    No more inlining bad performance

    View Slide

  99. 99
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???

    View Slide

  100. 100
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    ???
    Object oriented dispatch isn't that

    View Slide

  101. 101
    scala-miniboxing.org
    The secret ingredient
    The secret ingredient

    View Slide

  102. 102
    scala-miniboxing.org

    Switch-based dispatching T_tag match {
    case INT => ...
    ...
    }
    The secret ingredient
    The secret ingredient

    View Slide

  103. 103
    scala-miniboxing.org

    Switch-based dispatching

    When instantiating the class
    – T_tag is known
    T_tag match {
    case INT => ...
    ...
    }
    The secret ingredient
    The secret ingredient

    View Slide

  104. 104
    scala-miniboxing.org

    Switch-based dispatching

    When instantiating the class
    – T_tag is known
    – T_tag is a constant
    T_tag match {
    case INT => ...
    ...
    }
    The secret ingredient
    The secret ingredient

    View Slide

  105. 105
    scala-miniboxing.org

    Switch-based dispatching

    When instantiating the class
    – T_tag is known
    – T_tag is a constant
    T_tag match {
    case INT => ...
    ...
    }
    Encode T_tag in the class name?
    The secret ingredient
    The secret ingredient

    View Slide

  106. 106
    scala-miniboxing.org

    Switch-based dispatching

    When instantiating the class
    – T_tag is known
    – T_tag is a constant
    T_tag match {
    case INT => ...
    ...
    }
    Encode T_tag in the class name?
    The secret ingredient
    The secret ingredient
    Staticly? Code explosion!

    View Slide

  107. 107
    scala-miniboxing.org
    T_tag match {
    case INT => ...
    case CHAR => ...
    case UNIT => ...
    ...
    }
    Load-time specialization
    Load-time specialization

    Load-time transformation

    View Slide

  108. 108
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    T_tag match {
    case INT => ...
    case CHAR => ...
    case UNIT => ...
    ...
    }
    Load-time specialization
    Load-time specialization
    INT

    View Slide

  109. 109
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    – perform constant folding
    T_tag match {
    case INT => ...
    case CHAR => ...
    case UNIT => ...
    ...
    }
    Load-time specialization
    Load-time specialization
    ...
    INT

    View Slide

  110. 110
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    – perform constant folding
    – perform dead code elimination
    Load-time specialization
    Load-time specialization
    ...

    View Slide

  111. 111
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    – perform constant folding
    – perform dead code elimination
    Load-time specialization
    Load-time specialization
    ... Only the useful code

    View Slide

  112. 112
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    – perform constant folding
    – perform dead code elimination
    Load-time specialization
    Load-time specialization
    ... Only the useful code
    No dispatching

    View Slide

  113. 113
    scala-miniboxing.org

    Load-time transformation
    – set T_tag statically
    – perform constant folding
    – perform dead code elimination
    Is this the secret ingredient? Yes!
    Load-time specialization
    Load-time specialization
    ... Only the useful code
    No dispatching

    View Slide

  114. 114
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    Load-time specialization

    View Slide

  115. 115
    scala-miniboxing.org
    Performance
    Performance
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    needs one more ingredient
    needs one more ingredient
    +
    Load-time specialization
    Attaching tags to code enables
    load-time specialization

    View Slide

  116. 116
    scala-miniboxing.org
    WE ARE HERE
    Generics
    Specialization
    Miniboxing
    Performance
    Evaluation

    View Slide

  117. 117
    scala-miniboxing.org
    (less is better)
    Evaluation - Performance
    Evaluation - Performance
    Best Performance
    Worst Performance

    View Slide

  118. 118
    scala-miniboxing.org
    (less is better)
    Evaluation - Performance
    Evaluation - Performance
    Best Performance
    Worst Performance

    View Slide

  119. 119
    scala-miniboxing.org
    (less is better)
    Evaluation - Performance
    Evaluation - Performance
    Best Performance
    Worst Performance
    Predictable performance

    View Slide

  120. 120
    scala-miniboxing.org
    (less is better)
    Evaluation - Performance
    Evaluation - Performance
    Best Performance
    Worst Performance
    Predictable performance
    5x less bytecode

    View Slide

  121. 121
    scala-miniboxing.org
    (less is better)
    Evaluation - Performance
    Evaluation - Performance
    Best Performance
    Worst Performance
    Predictable performance
    5x less bytecode
    Similar results on other benchmarks

    View Slide

  122. 122
    scala-miniboxing.org
    Spire – numeric abstractions library (12KLOC)
    Evaluation - Code size
    Evaluation - Code size
    (less is better)

    View Slide

  123. 123
    scala-miniboxing.org
    Spire – numeric abstractions library (12KLOC)
    2.8x bytecode reduction (4.7x for Vector in std. lib)
    Evaluation - Code size
    Evaluation - Code size
    (less is better)

    View Slide

  124. 124
    scala-miniboxing.org
    Contributions
    Contributions
    Miniboxing

    View Slide

  125. 125
    scala-miniboxing.org
    Contributions
    Contributions
    Miniboxing Tagged union
    =

    View Slide

  126. 126
    scala-miniboxing.org
    Contributions
    Contributions
    Tag hoisting
    +
    Miniboxing Tagged union
    =

    View Slide

  127. 127
    scala-miniboxing.org
    Contributions
    Contributions
    Tag hoisting
    +
    Miniboxing Tagged union
    =
    Load-time specialization
    +

    View Slide

  128. scala-miniboxing.org

    improves performance

    reduces bytecode size
    Conclusions
    Conclusions
    visit
    visit scala-miniboxing.org
    scala-miniboxing.org!
    !

    View Slide