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

The Performance of Object Encodings in JavaScript

The Performance of Object Encodings in JavaScript

ICOOOLPS Workshop

July 18, 2016
Tweet

More Decks by ICOOOLPS Workshop

Other Decks in Science

Transcript

  1. Context • JavaScript as a compilation target • Source language:

    Grace - Simple object-based language, lexical scope - Objects created using generative object constructors 2
  2. A Point in Grace • Classes aren't primitive 3 class

    point2D(xc, yc) { 2 method x { xc } method y { yc } 4 method length { (x ∗ x + y ∗ y).sqrt } } Figure 1: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the parameters of the class. successor function in a continuation-passing style. When the stack fills up, an exception-handler (the trampoline) restarts the computation. They report that the function-calling tech- nique introduces far more overhead (250%) than the case + continue technique (50%) [Ibid., Fig 13]. They do not com- pare two other “obvious” alternatives. The first (currently adopted by minigrace), is to use an exception to represent ”u 2 fu 4 6 8 } 10 ”u fu 12 class point2D(xc, yc) { 2 method x { xc } method y { yc } 4 method length { (x ∗ x + y ∗ y).sqrt } } Figure 1: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the parameters of the class. method point2D(xc, yc) { 2 object { method x { xc } 4 method y { yc } method length { (x ∗ x + y ∗ y).sqrt } 6 } } Figure 2: A simple immutable point object in Grace. Note that there are no ”u 2 fu 4 6 8 } 10 ”u fu 12 ≡
  3. • Method bodies are closures • self can be left

    implicit 4 • Explicit fields are possible too: class point2D(xc, yc) { 2 method x { xc } method y { yc } 4 method length { (x ∗ x + y ∗ y).sqrt } } Figure 1: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the parameters of the class. successor function in a continuation-passing style. When the stack fills up, an exception-handler (the trampoline) restarts the computation. They report that the function-calling tech- nique introduces far more overhead (250%) than the case + continue technique (50%) [Ibid., Fig 13]. They do not com- ”u 2 fu 4 6 8 } 10 ”u fu Figure 1: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the parameters of the class. method point2D(xc, yc) { 2 object { method x { xc } 4 method y { yc } method length { (x ∗ x + y ∗ y).sqrt } 6 } } Figure 2: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the parameters of the class. class point2D(xc, yc) { 2 def x is public = xc def y is public = yc 4 method length { (x ∗ x + y ∗ y).sqrt } } Figure 3: A simple immutable point object in Grace. Note that there are no explicit fields; instead, the methods x and y refer to (and thus capture) the 8 } 2. Start show enco illus cons tions data, tions the o In the c =
  4. JavaScript • Not so much a language, more an
 O-O

    implementor’s toolkit - Objects can have data & function attributes - Functions be executed with the owning object — or any other object — as self - Prototype chain allows objects to share attributes 5
  5. How best to implement Grace Objects with JavaScript Objects? •

    Don’t treat JavaScript as an assembly language … • Instead, use JavaScript objects to implement Grace objects • Use JavaScript’s method dispatch rather than “rolling our own” 6
  6. Choices P: Methods in prototype, or in objects R: Reify

    data as attributes of the object, or 
 capture it in the closure of the methods A: Use accessor methods, or access fields
 directly 7
  7. 8 P0 R0 A1 P0 R1 A1 P1 R0 A1

    P1 R1 A1 P0 R1 A0 P1 R1 A0 P0 R0 A0 P1 R0 A0 8 combinations of options, not all sensible:
  8. JavaScript “getters” (ECMAScript 5.1) • Normally, the client of an

    object must distinguish between method request object.request( ) and field access object.field • JavaScript getters hijack the field-access syntax to request parameterless methods object.request 9
  9. • Grace (deliberately) uses the same object.request syntax for field

    access and method request • The client does not (and should not) know how an object chooses to implement an attribute • Should we abstract over the distinction between fields and methods ourselves, or use JavaScript getters (and setters) to do this for us? 10
  10. 11 Add variations for “getters” … P0 R0 G1 P0

    R1 G1 P1 R1 G1 P0 R0 A1 P0 R1 A1 P1 R1 A1 P0 R1 A0 P1 R1 A0
  11. Experiment: Do choices matter? • Generate 8 variations of 2-D

    points by hand - Benchmarked: ‣ access: request & execute length on 20k points ‣ construct 20k points ‣ access + construct: build 20k new points based on 20k old points ‣ modify coordinates of 20k points • Run in Chrome 50.0.2661 on MacOS 10.11.3 12
  12. 13 0.1 1 10 100 1000 P0R 0A1 P0R 0G

    1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Access 0.1 1 10 100 1000 P0R 0A1 P0R 0G 1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Construct 0.1 1 10 100 1000 P0R 0A1 P0R 0G 1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Access + Construct 0.1 1 10 100 1000 P0R 0A1 P0R 0G 1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Modify 20x 100x
  13. 14 0.1 1 10 100 1000 P0R 0A1 P0R 0G

    1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Access 0.1 1 10 100 1000 Time for 20k ops / ms Not using prototypes costs ~3x
  14. 15 G 1 0.1 1 10 100 1000 P0R 0A1

    P0R 0G 1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Construct Not surprising: prototypes
 are much faster
  15. 16 0.1 1 10 100 1000 P0R 0A1 P0R 0G

    1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Access + Construct 0 1 10 100 Time for 20k ops / ms Not surprising: prototypes are much faster
  16. 17 1 0.1 1 10 100 1000 P0R 0A1 P0R

    0G 1 P0R 1A0 P0R 1A1 P0R 1G 1 P1R 1A0 P1R 1A1 P1R 1G 1 Time for 20k ops / ms Modify Not surprising: new methods on each update
  17. What else should we consider? • Non-local control flow •

    Inheritance • Blocks: => or function? • let vs. var? • … 18
  18. Conclusions Small differences in encoding lead to enormous differences in

    runtime Experiment carefully before investing 
 in a code-generation strategy Pay-off Google 19
  19. 20 ”use strict”; 2 function P0R0A1(xc, yc) { this.x =

    function() { return xc; } ; 4 this.y = function() { return yc; } ; this.length = function() { 6 return Math.sqrt((this.x() ∗ this.x()) + (this.y() ∗ this.y())); 8 } ; } Figure 4: A possible Javascript implementation of Figure 1. 2. Experiment Design Starting with the Grace code for a 2-dimensional point, shown in Figure 1, we designed eight different JavaScript encodings and generated them by hand. In the first encoding, illustrated in Figure 4, a Grace class compiles to a JavaScript constructor that returns an object. This object contains func- 10 ”use strict”; function P1R1A1(xc, yc) { 12 this.xc = xc; this.yc = yc; } 14 P1R1A1.prototype.x = function() { return this.xc; } ; 16 P1R1A1.prototype.y = function() { return this.yc; } ; P1R1A1.prototype.length = function() { 18 return Math.sqrt((this.x() ∗ this.x()) + (this.y() ∗ this.y())) } ; Figure 5: An alternative Javascript implementation of Figure 1, which