V8: JavaScript Engine
Modern problems of JavaScript and the formula of the cure



                     by Burcu Dogan
“JavaScript is the most misunderstood programming language.”
                                        - Douglas Crockford
Some JS History
Some JS History
Brendan Eich, the lead designer
   Scheme + Self with C syntax
Some JS History
     Brendan Eich, the lead designer
        Scheme + Self with C syntax


Mocha LiveScript by Netscape (‘95)
Some JS History
     Brendan Eich, the lead designer
         Scheme + Self with C syntax


Mocha LiveScript by Netscape (‘95)
JavaScript by Netscape and Sun (’96)
Some JS History
      Brendan Eich, the lead designer
         Scheme + Self with C syntax


Mocha LiveScript by Netscape (‘95)
JavaScript by Netscape and Sun (’96)
JScript by Microsoft (‘96)
Some JS History
      Brendan Eich, the lead designer
         Scheme + Self with C syntax


Mocha LiveScript by Netscape (‘95)
JavaScript by Netscape and Sun (’96)
JScript by Microsoft (‘96)
ECMAScript by ECMA International (Nov ’96)
JavaScript is highly
         dynamic!
no-class definitions and prototype-based inheritance
function Base(args){ ... }
Base.prototype.myFirstMethod = function(){ ... }

function Super(args){ ... }
Super.prototype = new Base();
Super.prototype.myMethod = function() { ... }

Super.myStaticMethod = function(){ ... }
function Base(args){ ... }
Base.prototype.myFirstMethod = function(){ ... }   var s = new Super();
function Super(args){ ... }                        s.myMethod();
Super.prototype = new Base();                      s.myFirstMethod();
Super.prototype.myMethod = function() { ... }
                                                   s.myStaticMethod();
Super.myStaticMethod = function(){ ... }
Super
                 prototype


                        new
                       Base()         myMethod = function(){}

                      myStaticMethod = function(){}
function Base(args){ ... }
Base.prototype.myFirstMethod = function(){ ... }   var s = new Super();
function Super(args){ ... }                        s.myMethod();
Super.prototype = new Base();                      s.myFirstMethod();
Super.prototype.myMethod = function() { ... }
                                                   s.myStaticMethod();
Super.myStaticMethod = function(){ ... }
new
     Super                                 Object()
                 prototype
                                  prototype

                        new
                       Base()          myMethod = function(){}

                      myStaticMethod = function(){}
function Base(args){ ... }
Base.prototype.myFirstMethod = function(){ ... }      var s = new Super();
function Super(args){ ... }                           s.myMethod();
Super.prototype = new Base();                         s.myFirstMethod();
Super.prototype.myMethod = function() { ... }
                                                      s.myStaticMethod();
Super.myStaticMethod = function(){ ... }
Problems with JS


• JS is dynamic, objects are hash tables
• Properties may change at runtime
• Prototype chain may change at runtime
• We have eval (changes the context)
V8 Design Goals
• Make large object-oriented JS programs
  perform well
• Faster property access
• Faster function calls
• Faster and more scalable memory
  management
V8 History

• Initial design by Lars Bak in 2006
• Released and open sourced in 2008
• Significant appearances: Being shipped
  inside Google Chrome and node.js
V8 Internals


• JIT compiling
• Hidden classes for faster property accesses
• Inline caching
• Precise garbage collection
JIT Compiling

• Adopted by other JavaScript engines too!
• No intermediate code.
• Methods are compiled upon access.
• HotSpot-like JIT decisions
Hidden classes
In less dynamic languages such as Java,

         + 0x00000020    int x = 6

         + 0x00000060    int y = 1

         + 0x00000080
                         area() {
                            return x * y;
                         }
Hidden classes
In less dynamic languages such as Java,

         + 0x00000020    int x = 6

         + 0x00000060    int y = 1

         + 0x00000080
                         area() {
                            return x * y;
                         }



Attribute access costs just a few CPU instructions!
Hidden classes (cont.)
function Rectangle(p1, p2) {
   this.p1 = p1;
   this.p2 = p2;
}

Rectangle.prototype.area = function(){
  return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y);
}
Hidden classes (cont.)
function Rectangle(p1, p2) {
   this.p1 = p1;
   this.p2 = p2;
}

Rectangle.prototype.area = function(){
  return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y);
}
var rect1 = new Rectangle(new Point(3,4), new Point(6,0));
Hidden classes (cont.)
function Rectangle(p1, p2) {
   this.p1 = p1;                                              Rectangle
   this.p2 = p2;                                   rect1        p1: 0
}                                                               p2: 2
                                                               area: 4
Rectangle.prototype.area = function(){
  return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y);
}
var rect1 = new Rectangle(new Point(3,4), new Point(6,0));
Hidden classes (cont.)
function Rectangle(p1, p2) {
   this.p1 = p1;                                              Rectangle
   this.p2 = p2;                                   rect1        p1: 0
}                                                               p2: 2
                                                               area: 4
Rectangle.prototype.area = function(){
  return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y);
}
var rect1 = new Rectangle(new Point(3,4), new Point(6,0));

var rect2 = new Rectangle(new Point(3,7), new Point(9,-1));
rect2.fillColor = “#ff0”;
Hidden classes (cont.)
function Rectangle(p1, p2) {
   this.p1 = p1;                                              Rectangle
   this.p2 = p2;                                   rect1        p1: 0
}                                                               p2: 2
                                                               area: 4
Rectangle.prototype.area = function(){
  return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y);
}                                                             Rectangle
var rect1 = new Rectangle(new Point(3,4), new Point(6,0));        p1: 0
                                                                  p2: 2
                                                                 area: 4
var rect2 = new Rectangle(new Point(3,7), new Point(9,-1));   fillColor: 7
rect2.fillColor = “#ff0”;

                                                     rect2
Inline Caching
Because: Iterating over hidden classes are still costly.
Inline Caching
Because: Iterating over hidden classes are still costly.



We need to generate code and cache it for property
                    retrieval.
Inline Caching (cont.)
p.toString();


                       Premono-
    Unitialized         morphic
                                         Monomorphic       Megamorphic




           Object* toString_of_p_premorphic(Object* p){
           
  Class* c = p->class();
           
  int offset = c->lookup_offset("toString");
           
  update_cache(c, offset);
           
  return p->properties[offset];
           }
Inline Caching (cont.)
p2.toString();

                 Premono-
 Unitialized      morphic
                                 Monomorphic       Megamorphic




                   Object* toString_of_p_monomorphic(Object* p){
                   
  if(cachedClass() == p->class()){
                          return p->properties[cachedOffset()];
                      } else {
                          return look_up_monomorphic(p, “toString”);
                      }
                   }
Megamorphic stub
  var values = [1, "a", 2, "b", 3, "c", 4, "d"];
  for (var i in values) {
    document.write(values[i].toString());
  }
Megamorphic stub
             var values = [1, "a", 2, "b", 3, "c", 4, "d"];
             for (var i in values) {
               document.write(values[i].toString());
             }




Object* toString_of_p_megamorhic(Object* p){

  Stub* s = look_up_cache_for(p->class(), “toString”);
   if(s != NULL){
       return p->properties[s->cachedOffset()];
   }
   return look_up_property_megamorphic(p->class(), “toString”);
}
Precise Garbage Collection

• Stop-the-world collector
• Objects have 2-byte tags (precise collect)
• Two generation garbage collector
  •   Young generation: small, contiguous space (collected often)

  •   Old generation: Code space, Map space (hidden classes), Large
      object space, Non-pointer object space, Pointer object space
Go, involve in.
http://code.google.com/p/v8/

V8

  • 1.
    V8: JavaScript Engine Modernproblems of JavaScript and the formula of the cure by Burcu Dogan
  • 2.
    “JavaScript is themost misunderstood programming language.” - Douglas Crockford
  • 3.
  • 4.
    Some JS History BrendanEich, the lead designer Scheme + Self with C syntax
  • 5.
    Some JS History Brendan Eich, the lead designer Scheme + Self with C syntax Mocha LiveScript by Netscape (‘95)
  • 6.
    Some JS History Brendan Eich, the lead designer Scheme + Self with C syntax Mocha LiveScript by Netscape (‘95) JavaScript by Netscape and Sun (’96)
  • 7.
    Some JS History Brendan Eich, the lead designer Scheme + Self with C syntax Mocha LiveScript by Netscape (‘95) JavaScript by Netscape and Sun (’96) JScript by Microsoft (‘96)
  • 8.
    Some JS History Brendan Eich, the lead designer Scheme + Self with C syntax Mocha LiveScript by Netscape (‘95) JavaScript by Netscape and Sun (’96) JScript by Microsoft (‘96) ECMAScript by ECMA International (Nov ’96)
  • 9.
    JavaScript is highly dynamic! no-class definitions and prototype-based inheritance
  • 10.
    function Base(args){ ...} Base.prototype.myFirstMethod = function(){ ... } function Super(args){ ... } Super.prototype = new Base(); Super.prototype.myMethod = function() { ... } Super.myStaticMethod = function(){ ... }
  • 11.
    function Base(args){ ...} Base.prototype.myFirstMethod = function(){ ... } var s = new Super(); function Super(args){ ... } s.myMethod(); Super.prototype = new Base(); s.myFirstMethod(); Super.prototype.myMethod = function() { ... } s.myStaticMethod(); Super.myStaticMethod = function(){ ... }
  • 12.
    Super prototype new Base() myMethod = function(){} myStaticMethod = function(){} function Base(args){ ... } Base.prototype.myFirstMethod = function(){ ... } var s = new Super(); function Super(args){ ... } s.myMethod(); Super.prototype = new Base(); s.myFirstMethod(); Super.prototype.myMethod = function() { ... } s.myStaticMethod(); Super.myStaticMethod = function(){ ... }
  • 13.
    new Super Object() prototype prototype new Base() myMethod = function(){} myStaticMethod = function(){} function Base(args){ ... } Base.prototype.myFirstMethod = function(){ ... } var s = new Super(); function Super(args){ ... } s.myMethod(); Super.prototype = new Base(); s.myFirstMethod(); Super.prototype.myMethod = function() { ... } s.myStaticMethod(); Super.myStaticMethod = function(){ ... }
  • 14.
    Problems with JS •JS is dynamic, objects are hash tables • Properties may change at runtime • Prototype chain may change at runtime • We have eval (changes the context)
  • 15.
    V8 Design Goals •Make large object-oriented JS programs perform well • Faster property access • Faster function calls • Faster and more scalable memory management
  • 16.
    V8 History • Initialdesign by Lars Bak in 2006 • Released and open sourced in 2008 • Significant appearances: Being shipped inside Google Chrome and node.js
  • 17.
    V8 Internals • JITcompiling • Hidden classes for faster property accesses • Inline caching • Precise garbage collection
  • 18.
    JIT Compiling • Adoptedby other JavaScript engines too! • No intermediate code. • Methods are compiled upon access. • HotSpot-like JIT decisions
  • 19.
    Hidden classes In lessdynamic languages such as Java, + 0x00000020 int x = 6 + 0x00000060 int y = 1 + 0x00000080 area() { return x * y; }
  • 20.
    Hidden classes In lessdynamic languages such as Java, + 0x00000020 int x = 6 + 0x00000060 int y = 1 + 0x00000080 area() { return x * y; } Attribute access costs just a few CPU instructions!
  • 21.
    Hidden classes (cont.) functionRectangle(p1, p2) { this.p1 = p1; this.p2 = p2; } Rectangle.prototype.area = function(){ return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y); }
  • 22.
    Hidden classes (cont.) functionRectangle(p1, p2) { this.p1 = p1; this.p2 = p2; } Rectangle.prototype.area = function(){ return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y); } var rect1 = new Rectangle(new Point(3,4), new Point(6,0));
  • 23.
    Hidden classes (cont.) functionRectangle(p1, p2) { this.p1 = p1; Rectangle this.p2 = p2; rect1 p1: 0 } p2: 2 area: 4 Rectangle.prototype.area = function(){ return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y); } var rect1 = new Rectangle(new Point(3,4), new Point(6,0));
  • 24.
    Hidden classes (cont.) functionRectangle(p1, p2) { this.p1 = p1; Rectangle this.p2 = p2; rect1 p1: 0 } p2: 2 area: 4 Rectangle.prototype.area = function(){ return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y); } var rect1 = new Rectangle(new Point(3,4), new Point(6,0)); var rect2 = new Rectangle(new Point(3,7), new Point(9,-1)); rect2.fillColor = “#ff0”;
  • 25.
    Hidden classes (cont.) functionRectangle(p1, p2) { this.p1 = p1; Rectangle this.p2 = p2; rect1 p1: 0 } p2: 2 area: 4 Rectangle.prototype.area = function(){ return (this.p2.x - this.p1.x) * (this.p2.y - this.p1.y); } Rectangle var rect1 = new Rectangle(new Point(3,4), new Point(6,0)); p1: 0 p2: 2 area: 4 var rect2 = new Rectangle(new Point(3,7), new Point(9,-1)); fillColor: 7 rect2.fillColor = “#ff0”; rect2
  • 26.
    Inline Caching Because: Iteratingover hidden classes are still costly.
  • 27.
    Inline Caching Because: Iteratingover hidden classes are still costly. We need to generate code and cache it for property retrieval.
  • 28.
    Inline Caching (cont.) p.toString(); Premono- Unitialized morphic Monomorphic Megamorphic Object* toString_of_p_premorphic(Object* p){ Class* c = p->class(); int offset = c->lookup_offset("toString"); update_cache(c, offset); return p->properties[offset]; }
  • 29.
    Inline Caching (cont.) p2.toString(); Premono- Unitialized morphic Monomorphic Megamorphic Object* toString_of_p_monomorphic(Object* p){ if(cachedClass() == p->class()){ return p->properties[cachedOffset()]; } else { return look_up_monomorphic(p, “toString”); } }
  • 30.
    Megamorphic stub var values = [1, "a", 2, "b", 3, "c", 4, "d"]; for (var i in values) { document.write(values[i].toString()); }
  • 31.
    Megamorphic stub var values = [1, "a", 2, "b", 3, "c", 4, "d"]; for (var i in values) { document.write(values[i].toString()); } Object* toString_of_p_megamorhic(Object* p){ Stub* s = look_up_cache_for(p->class(), “toString”); if(s != NULL){ return p->properties[s->cachedOffset()]; } return look_up_property_megamorphic(p->class(), “toString”); }
  • 32.
    Precise Garbage Collection •Stop-the-world collector • Objects have 2-byte tags (precise collect) • Two generation garbage collector • Young generation: small, contiguous space (collected often) • Old generation: Code space, Map space (hidden classes), Large object space, Non-pointer object space, Pointer object space
  • 33.