SlideShare a Scribd company logo
Implementing one feature set
in two JavaScript engines
Caio Lima & Joyee Cheung
Igalia & Bloomberg
1
Overview of the class features
ES6
- Public class methods (instance & static)
3 follow-up proposals
- Class instance fields: https://tc39.es/proposal-class-fields/
- Public fields
- Private fields
- Private methods & accessors: https://tc39.es/proposal-private-methods/
- Static class features: https://tc39.es/proposal-static-class-features/
- Static public fields
- Static private fields
- Static private methods & accessors
2
Overview of the class features
- The class features entered Stage 3 in July 2017
- Stage 3 is when
- TC39 settles down the design of language features
- JavaScript engines start implementing language features, giving feedback to
TC39, and shipping the implementation
- https://tc39.es/process-document/
- Thanks Bloomberg for sponsoring Igalia’s work!
- Implementing the 3 proposals in JavaScriptCore
- Implementing private methods (instance and static) as well as improving other
class features in V8
3
Public fields
let i = 0;
function count() {
return i++;
}
class C {
field = count();
}
(new C).field; // returns 0
(new C).field; //returns 1
- Instance fields are defined during object construction.
- The initializer is executed every time a new object is
instantiated.
4
Private fields
class C {
#field = 1;
access() {
return this.#field;
}
}
(new C).access(); // returns 1
(new C).access.call({}); // TypeError
- Private fields are not common JS properties.
- When a private field is not present, we throw
an TypeError.
- They don’t have a property descriptor.
- They are only visible inside the scope of a class.
5
Private fields
class C {
#field = 1;
access() {
return this.#field;
}
}
(new C).access(); // returns 1
(new C).access.call({}); // TypeError
class D {
#field = 1;
// ...
}
- Private fields are not common JS properties.
- When a private field is not present, we throw
an TypeError.
- They don’t have a property descriptor.
- They are only visible inside the scope of a class.
- Every new evaluation of a class creates a new
private name.
6
Private methods & static fields
class C {
#method() {
return “I am instance”
};
static #staticMethod() {
return “I am Static”;
}
}
class C {
static field = 1;
static #field;
}
C.field; // returns 1
7
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
8
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
9
What to change in the engines: parser
- Support new production “#identifier”
- Easy: both JSC and V8 use recursive descent parsers
- Add new AST nodes for the bytecode generator to visit later
10
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
11
What to change in the engines: scope analysis
- Specialize the resolution of private names to identify usage of undeclared
fields whenever we finish parsing a class literal
- Add additional fields to the variables to carry information about the kind of
property access
- In V8: rewrote the scope analysis of class scopes
class C {
#field = 1;
method() { this.#filed = 2; } // typo: SyntaxError
}
class C {
#duplicateField = 1;
#duplicateField = 2; // SyntaxError
} 12
What to change in the engines: scope analysis
- With lazy parsing, errors are identified and the variables are serialized in the
pre-parsing.
- Deserialize variables when generating the bytecode
class C {
#field = 1; // Serialized
getField() { this.#field; /* Deserialized */ }
}
(new C).getField(); // Triggers bytecode generation of getField
13
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
14
What to change in the engines: bytecode generator
- Generate bytecode for these new features
- Change the bytecode emitted for
- Class evaluation
- Class constructors
- Property access
15
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
16
What to change in the engines: interpreter
- Add new handlers for new operations added for the features, if any.
- JSC added a new `get_by_val_direct` instruction.
17
What to change in the engines
Parser
Scope
Analysis
Bytecode
generator
Interpreter
JIT
Compiler
Runtime
Source Text
Variables,
scopes
AST
Analyzed
variables
and scopes
Bytecode
Compiled
code
18
What to change in the engines: runtime
- Runtime: property lookup is desugared to static lexical lookups
- Special path to lookup private symbols (different semantics)
- Methods and accessors need to validate if receiver has the correct brand
- Static: validate the receivers and change where things are installed
19
Bytecode generated for instance private fields
During class evaluation
V8
CallRuntime [CreatePrivateNameSymbol] // #instanceField
StaCurrentContextSlot [4] // known index to a fixed array
...
CreateClosure // instance_members_initializer
// Store instance_members_initializer in the class
StaNamedProperty <class_constructor> ...
class C {
#instanceField = 1;
}
20
Bytecode generated for instance private fields
During class evaluation
JSC
create_lexical_environment loc4, ...
...
call loc12, “@createPrivateSymbol”
put_to_scope loc4, “#instanceField”, loc12
new_fuc_exp loc13, ...
put_by_id <C>, “@instanceFieldInitializer”, loc13
...
class C {
#instanceField = 1;
}
21
Bytecode generated for instance private fields
In the constructor
V8
// In the class C constructor
LdaNamedProperty // load instance_members_initializer
CallProperty0 // run instance_members_initializer
// In instance_members_initializer
LdaCurrentContextSlot [4] // Load the #instanceField symbol from the context
Star r1
LdaSmi [1]
Star r2
Mov <this>, r0
CallRuntime [AddPrivateField], r0-r2 // Define this.#instanceField as 1
class C {
#instanceField = 1;
}
22
Bytecode generated for instance private fields
In the constructor
JSC
// In the C constructor
get_by_id_direct loc7, callee, “@instanceFieldInitializer”
mov loc8, this
call loc9, loc7, 1
ret this
//In the “@instanceFieldInitializer”
mov loc6, Int32: 1
resolve_scope loc7, loc4, “#inscanteField”
get_from_scope loc8, loc7, “#inscanteField”
put_by_val_direct this, loc8, loc6, PrivateName|ThrowIfExists
ret Undefined(const1)
class C {
#instanceField = 1;
}
23
Bytecode generated for instance private fields
When evaluating getInstanceField()
V8
LdaCurrentContextSlot [4] // Load the private symbol
LdaKeyedProperty <this>, [0] // Error in the IC if the field does not exist
class C {
#instanceField = 1;
getInstanceField() { return this.#instanceField; }
}
24
Bytecode generated for instance private fields
When evaluating getInstanceField()
JSC
resolve_scope loc7, loc4, “#instanceField”
get_from_scope loc8, loc7, “#instanceField” // get PrivateSymbol
get_by_val_direct loc6, this, loc8
ret loc6
class C {
#instanceField = 1;
getInstanceField() { return this.#instanceField; }
}
25
Other class features
- Private methods are shared among the instances, the validation of the receiver
is guarded by a per-class special symbol property (the “brand”).
- Static features are implemented similarly to instance features, but handled
during class evaluation time.
26
Implementation status
- Class Fields
- Chrome: Shipped full implementation in 74 (23 April 2019).
- WebKit: In progress (link).
- Private Methods & accessors
- Chrome: Fully implemented behind --harmony-private-methods on master (link).
- WebKit: In progress (methods and accessors).
- Static features
- Chrome: Static class fields shipped in 74, static private methods are fully
implemented behind --harmony-private-methods on master (link).
- WebKit: In progress (link).
27
Implementation status
Spec issues discovered during implementation
- https://github.com/tc39/proposal-class-fields/issues/263
- https://github.com/tc39/proposal-private-methods/issues/69
28
Test262 status
- Already complete (last PR from 30 August 2019).
- Total of 6325 new tests.
29
Questions?
30
Desugaring public fields (incorrect, just conceptual)
class C {
field = 1;
}
class C {
constructor() {
Object.defineProperty(this, ‘field’, {value: 1});
}
}
31
Desugaring private fields (incorrect, just conceptual)
class C {
#field = 1;
getField() { return this.#field; }
}
class C {
// Imagine it's possible to declare a fieldSymbol here.
constructor() {
Object.defineProperty(this, fieldSymbol, {value: 1});
}
getField() { return this[fieldSymbol]; }
}
32
Desugaring private methods (incorrect, just conceptual)
class C {
#method() { }
runMethod() { this.#method(); }
}
class C {
// Imagine it's possible to declare a brandSymbol and a <method>() here.
constructor() { Object.defineProperty(this, brandSymbol, {value: /*?*/}); }
runMethod() {
if (!(brandSymbol in this)) { throw TypeError('...'); }
<method>.call(this);
}
}
33
Desugaring static methods and fields (incorrect)
class C {
static #method() { }
static #field = 1;
static runMethod() { this.#method(); }
}
// Imagine it's possible to declare a brandSymbol and a <method>() here.
Object.defineProperty(C, brandSymbol, {value: /*?*/});
Object.defineProperty(C, fieldSymbol, {value: 1});
C.runMethod = function() {
if (!(brandSymbol in this)) { throw TypeError('...'); }
<method>.call(this);
}
34
Bytecode generated for instance private methods
During class evaluation
V8
CallRuntime [CreatePrivateNameSymbol] // brand symbol
StaCurrentContextSlot [5]
......
...
// Create the private method
CreateClosure
StaCurrentContextSlot [4]
class C {
#instanceMethod() {}
}
35
Bytecode generated for instance private methods
During class evaluation
JSC
create_lexical_environment loc9, loc4
...
call loc13, “@createPrivateSymbol”
put_to_scope loc4, “@privateBrand”, loc13
new_func_exp loc12, loc4, ...
put_by_id loc12, “@homeObject”, loc11
put_to_scope loc4, “#inscanceMethod”, loc12
class C {
#instanceMethod() {}
}
36
Bytecode generated for instance private methods
In the constructor
V8
LdaCurrentContextSlot [5] // brand symbol
Star r1
Mov <this>, r0
CallRuntime [AddPrivateBrand], r0-r1
class C {
#instanceMethod() {}
}
37
Bytecode generated for instance private methods
In the constructor
JSC
resolve_scope loc7, loc4, “@privateBrand”
get_from_scope loc8, loc7, “@privateBrand”
put_by_val_direct this, loc8, loc8, PrivateName|ThrowIfExists
ret this
class C {
#instanceMethod() {}
}
38
Bytecode generated for instance private methods
When evaluating runInstanceMethod()
V8
LdaCurrentContextSlot [5] // Load the brand symbol
LdaKeyedProperty <this>, [0] // brand check - errors if it does not exist
LdaCurrentContextSlot [4] // Load the method
Star r0
CallAnyReceiver r0, <this>-<this>, [2]
class C {
#instanceMethod() {};
runInstanceMethod() { this.#instanceMethod(); }
}
39
Bytecode generated for instance private methods
When evaluating runInstanceMethod()
JSC
mov loc8, this
resolve_scope loc9, loc4, “#instanceMethod”
get_from_scope loc10, loc9, “@privateBrand”
get_by_val_direct loc10, loc8, loc10 // Brand Check
get_from_scope loc6, loc9, “#instanceMethod”
call loc6, loc6, 1
...
class C {
#instanceMethod() {};
runInstanceMethod() { this.#instanceMethod(); }
}
40
Brand checking saves memory
class C {
constructor() { Object.defineProperty(this, brandSymbol, {value: /*?*/}); }
runMethod() {
if (!(brandSymbol in this)) { throw TypeError('...'); }
<methodA>.call(this);
<methodB>.call(this);
}
}
41
Brand checking saves memory
class C {
constructor() {
Object.defineProperty(this, methodASymbol, {value: <methodA>, ...});
Object.defineProperty(this, methodBSymbol, {value: <methodB>, ...});
// More symbols and references in proportion to the number of private methods
}
runMethod() {
this[methodASymbol]();
this[methodBSymbol]();
}
}
42
Bytecode generated for static private methods
During class evaluation
V8
// During class evaluation
CreateClosure
StaCurrentContextSlot [4]
class C {
static #staticMethod() {}
static runStaticMethod() { this.#staticMethod(); }
}
43
Bytecode generated for static private methods
When evaluating runStaticMethod()
V8
LdaCurrentContextSlot [5] // Load the class that declares the static method
TestReferenceEqual <this> // Make sure the receiver is the class
Mov <this>, r1
JumpIfTrue
LdaSmi.Wide
Star r2
LdaConstant [0]
Star r3
CallRuntime [NewTypeError], r2-r3
Throw
LdaCurrentContextSlot [4] // Where JumpIfTrue jumps to: load the static method
Star r0
CallAnyReceiver r0, r1-r1, [0]
class C {
static #staticMethod() {}
static runStaticMethod() { this.#staticMethod(); }
}
44
Bytecode generated for static private methods
JSC
create_lexical_environment loc9, loc4
call loc13, “@createPrivateSymbol”
put_to_scope loc4, “@privateStaticBrand”, loc13
new_func_exp loc12, loc4, 1
put_by_id loc12, “@homeObject”, loc11,
put_to_scope loc4, “#staticMethod”, loc12
...
resolve_scope loc7, loc4, “@privateStaticBrand”
get_from_scope loc8, loc7, “@privateStaticBrand”
put_by_val_direct <C>, loc8, loc8, PrivateName|ThrowIfExists
class C {
static #staticMethod() {}
static runStaticMethod() { this.#staticMethod(); }
}
45
Bytecode generated for private accessors
- Similar to private methods, guarded by brand checks
- Complementary accessors are stored in AccessorPairs in V8, but
separately in JSC
- Generate TypeError statically for incorrect usage to read-only or
write-only private accessors
class C {
get #value() { }
set #value(val) { }
inc() { return this.#value++; }
}
46
Bytecode generated for static public fields
- Defined in static field initializers in V8 and accessed as usual
- Inlined in the class evaluation in JSC
class C {
static publicField = 1;
static publicMethod() { return this.publicField; }
}
C.publicMethod();
47
Bytecode generated for static private fields
V8
// During class evaluation
// Create the #staticField symbol
CallRuntime [CreatePrivateNameSymbol]
StaCurrentContextSlot [4]
...
CreateClosure // static_fields_initializer
CallProperty0 // calls static_fields_initializer on the class
// In the static_fields_initializer
LdaCurrentContextSlot [4] // Load the #staticField symbol
Star r1
LdaSmi [1]
Star r2
Mov <this>, r0
CallRuntime [AddPrivateField], r0-r2 // Define C.#staticField as 1
class C {
static #staticField = 1;
static getStaticField() { return this.#staticField; }
}
48
Bytecode generated for static private fields
JSC
create_lexical_environment loc4, ...
...
call loc12, “@createPrivateSymbol”
put_to_scope loc4, “#instanceField”, loc12
...
mov loc6, Int32: 1
resolve_scope loc7, loc4, “#inscanteField”
get_from_scope loc8, loc7, “#inscanteField”
put_by_val_direct <C>, loc8, loc6, ...
class C {
static #staticField = 1;
static getStaticField() { return
this.#staticField; }
}
49

More Related Content

PPT
Constructors.16
PDF
05. inheritance
PDF
Core Java Certification
PPTX
Java Reflection @KonaTechAdda
PPT
SystemVerilog OOP Ovm Features Summary
PDF
Recording Finer-Grained Software Evolution with IDE: An Annotation-Based Appr...
PPTX
LISP:Program structure in lisp
PPTX
Interactive Java Support to your tool -- The JShell API and Architecture
Constructors.16
05. inheritance
Core Java Certification
Java Reflection @KonaTechAdda
SystemVerilog OOP Ovm Features Summary
Recording Finer-Grained Software Evolution with IDE: An Annotation-Based Appr...
LISP:Program structure in lisp
Interactive Java Support to your tool -- The JShell API and Architecture

What's hot (20)

PDF
Classes and objects
PPTX
JShell: An Interactive Shell for the Java Platform
PDF
(7) cpp abstractions inheritance_part_ii
PPTX
A (too) Short Introduction to Scala
PPTX
Virtual function complete By Abdul Wahab (moon sheikh)
PPT
Introduction to llvm
PPTX
Java moderno java para Jedis episodio I
PDF
Part II: LLVM Intermediate Representation
PDF
Module 2: C# 3.0 Language Enhancements (Material)
PDF
Spring IO 2015 Spock Workshop
PPTX
Constructors and destructors
PDF
Introduction to the Java bytecode - So@t - 20130924
PDF
Lambda: A Peek Under The Hood - Brian Goetz
PDF
Better Code: Concurrency
PDF
Unit 5 quesn b ans5
PDF
CORBA Programming with TAOX11/C++11 tutorial
PDF
Java SE 8 library design
PDF
Comparing IDL to C++ with IDL to C++11
PDF
Java Presentation For Syntax
PDF
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術
Classes and objects
JShell: An Interactive Shell for the Java Platform
(7) cpp abstractions inheritance_part_ii
A (too) Short Introduction to Scala
Virtual function complete By Abdul Wahab (moon sheikh)
Introduction to llvm
Java moderno java para Jedis episodio I
Part II: LLVM Intermediate Representation
Module 2: C# 3.0 Language Enhancements (Material)
Spring IO 2015 Spock Workshop
Constructors and destructors
Introduction to the Java bytecode - So@t - 20130924
Lambda: A Peek Under The Hood - Brian Goetz
Better Code: Concurrency
Unit 5 quesn b ans5
CORBA Programming with TAOX11/C++11 tutorial
Java SE 8 library design
Comparing IDL to C++ with IDL to C++11
Java Presentation For Syntax
ScalaMatsuri 2016 ドワンゴアカウントシステムを支えるScala技術

Similar to Implementing one feature set in two JavaScript engines (Web Engines Hackfest 2019) (20)

PPT
Csharp4 objects and_types
PDF
Scala.IO 2024: Mill builds in Scala 3, a migration story
PPT
Software Design Patterns
PDF
How Does Kubernetes Build OpenAPI Specifications?
PDF
EA User Group London 2018 - Extending EA with custom scripts to cater for spe...
PDF
Mini-Training: TypeScript
PPTX
Customizing the Presentation Model and Physical Renderer in Siebel Open UI
PPT
Java programming concept
PDF
Commenting in Agile Development
PDF
Daggerate your code - Write your own annotation processor
PPTX
Desing pattern prototype-Factory Method, Prototype and Builder
PDF
Discover Tasty Query: The library for Scala program analysis
PPT
Chapter 4 - Defining Your Own Classes - Part I
PPT
Java căn bản - Chapter4
PPT
C++ classes tutorials
PPTX
Yaml as Pipeline GSoC 218 Phase 2 evaluation
PPTX
Learning C++ - Class 4
PPTX
Contexts and Dependency Injection
PDF
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019
PPSX
Writing code that writes code - Nguyen Luong
Csharp4 objects and_types
Scala.IO 2024: Mill builds in Scala 3, a migration story
Software Design Patterns
How Does Kubernetes Build OpenAPI Specifications?
EA User Group London 2018 - Extending EA with custom scripts to cater for spe...
Mini-Training: TypeScript
Customizing the Presentation Model and Physical Renderer in Siebel Open UI
Java programming concept
Commenting in Agile Development
Daggerate your code - Write your own annotation processor
Desing pattern prototype-Factory Method, Prototype and Builder
Discover Tasty Query: The library for Scala program analysis
Chapter 4 - Defining Your Own Classes - Part I
Java căn bản - Chapter4
C++ classes tutorials
Yaml as Pipeline GSoC 218 Phase 2 evaluation
Learning C++ - Class 4
Contexts and Dependency Injection
Breaking Dependencies Legacy Code - Cork Software Crafters - September 2019
Writing code that writes code - Nguyen Luong

More from Igalia (20)

PDF
Life of a Kernel Bug Fix
PDF
Unlocking the Full Potential of WPE to Build a Successful Embedded Product
PDF
Advancing WebDriver BiDi support in WebKit
PDF
Jumping Over the Garden Wall - WPE WebKit on Android
PDF
Collective Funding, Governance and Prioritiation of Browser Engine Projects
PDF
Don't let your motivation go, save time with kworkflow
PDF
Solving the world’s (localization) problems
PDF
The Whippet Embeddable Garbage Collection Library
PDF
Nobody asks "How is JavaScript?"
PDF
Getting more juice out from your Raspberry Pi GPU
PDF
WebRTC support in WebKitGTK and WPEWebKit with GStreamer: Status update
PDF
Demystifying Temporal: A Deep Dive into JavaScript New Temporal API
PDF
CSS :has() Unlimited Power
PDF
Device-Generated Commands in Vulkan
PDF
Current state of Lavapipe: Mesa's software renderer for Vulkan
PDF
Vulkan Video is Open: Application showcase
PDF
Scheme on WebAssembly: It is happening!
PDF
EBC - A new backend compiler for etnaviv
PDF
RISC-V LLVM State of the Union
PDF
Device-Generated Commands in Vulkan
Life of a Kernel Bug Fix
Unlocking the Full Potential of WPE to Build a Successful Embedded Product
Advancing WebDriver BiDi support in WebKit
Jumping Over the Garden Wall - WPE WebKit on Android
Collective Funding, Governance and Prioritiation of Browser Engine Projects
Don't let your motivation go, save time with kworkflow
Solving the world’s (localization) problems
The Whippet Embeddable Garbage Collection Library
Nobody asks "How is JavaScript?"
Getting more juice out from your Raspberry Pi GPU
WebRTC support in WebKitGTK and WPEWebKit with GStreamer: Status update
Demystifying Temporal: A Deep Dive into JavaScript New Temporal API
CSS :has() Unlimited Power
Device-Generated Commands in Vulkan
Current state of Lavapipe: Mesa's software renderer for Vulkan
Vulkan Video is Open: Application showcase
Scheme on WebAssembly: It is happening!
EBC - A new backend compiler for etnaviv
RISC-V LLVM State of the Union
Device-Generated Commands in Vulkan

Recently uploaded (20)

DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PPTX
A Presentation on Artificial Intelligence
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Approach and Philosophy of On baking technology
PDF
Encapsulation theory and applications.pdf
PPTX
Big Data Technologies - Introduction.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Encapsulation_ Review paper, used for researhc scholars
PPTX
Machine Learning_overview_presentation.pptx
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
The AUB Centre for AI in Media Proposal.docx
Spectral efficient network and resource selection model in 5G networks
Programs and apps: productivity, graphics, security and other tools
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
A Presentation on Artificial Intelligence
MIND Revenue Release Quarter 2 2025 Press Release
Network Security Unit 5.pdf for BCA BBA.
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Approach and Philosophy of On baking technology
Encapsulation theory and applications.pdf
Big Data Technologies - Introduction.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
NewMind AI Weekly Chronicles - August'25-Week II
Encapsulation_ Review paper, used for researhc scholars
Machine Learning_overview_presentation.pptx
Dropbox Q2 2025 Financial Results & Investor Presentation
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Building Integrated photovoltaic BIPV_UPV.pdf

Implementing one feature set in two JavaScript engines (Web Engines Hackfest 2019)

  • 1. Implementing one feature set in two JavaScript engines Caio Lima & Joyee Cheung Igalia & Bloomberg 1
  • 2. Overview of the class features ES6 - Public class methods (instance & static) 3 follow-up proposals - Class instance fields: https://tc39.es/proposal-class-fields/ - Public fields - Private fields - Private methods & accessors: https://tc39.es/proposal-private-methods/ - Static class features: https://tc39.es/proposal-static-class-features/ - Static public fields - Static private fields - Static private methods & accessors 2
  • 3. Overview of the class features - The class features entered Stage 3 in July 2017 - Stage 3 is when - TC39 settles down the design of language features - JavaScript engines start implementing language features, giving feedback to TC39, and shipping the implementation - https://tc39.es/process-document/ - Thanks Bloomberg for sponsoring Igalia’s work! - Implementing the 3 proposals in JavaScriptCore - Implementing private methods (instance and static) as well as improving other class features in V8 3
  • 4. Public fields let i = 0; function count() { return i++; } class C { field = count(); } (new C).field; // returns 0 (new C).field; //returns 1 - Instance fields are defined during object construction. - The initializer is executed every time a new object is instantiated. 4
  • 5. Private fields class C { #field = 1; access() { return this.#field; } } (new C).access(); // returns 1 (new C).access.call({}); // TypeError - Private fields are not common JS properties. - When a private field is not present, we throw an TypeError. - They don’t have a property descriptor. - They are only visible inside the scope of a class. 5
  • 6. Private fields class C { #field = 1; access() { return this.#field; } } (new C).access(); // returns 1 (new C).access.call({}); // TypeError class D { #field = 1; // ... } - Private fields are not common JS properties. - When a private field is not present, we throw an TypeError. - They don’t have a property descriptor. - They are only visible inside the scope of a class. - Every new evaluation of a class creates a new private name. 6
  • 7. Private methods & static fields class C { #method() { return “I am instance” }; static #staticMethod() { return “I am Static”; } } class C { static field = 1; static #field; } C.field; // returns 1 7
  • 8. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 8
  • 9. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 9
  • 10. What to change in the engines: parser - Support new production “#identifier” - Easy: both JSC and V8 use recursive descent parsers - Add new AST nodes for the bytecode generator to visit later 10
  • 11. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 11
  • 12. What to change in the engines: scope analysis - Specialize the resolution of private names to identify usage of undeclared fields whenever we finish parsing a class literal - Add additional fields to the variables to carry information about the kind of property access - In V8: rewrote the scope analysis of class scopes class C { #field = 1; method() { this.#filed = 2; } // typo: SyntaxError } class C { #duplicateField = 1; #duplicateField = 2; // SyntaxError } 12
  • 13. What to change in the engines: scope analysis - With lazy parsing, errors are identified and the variables are serialized in the pre-parsing. - Deserialize variables when generating the bytecode class C { #field = 1; // Serialized getField() { this.#field; /* Deserialized */ } } (new C).getField(); // Triggers bytecode generation of getField 13
  • 14. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 14
  • 15. What to change in the engines: bytecode generator - Generate bytecode for these new features - Change the bytecode emitted for - Class evaluation - Class constructors - Property access 15
  • 16. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 16
  • 17. What to change in the engines: interpreter - Add new handlers for new operations added for the features, if any. - JSC added a new `get_by_val_direct` instruction. 17
  • 18. What to change in the engines Parser Scope Analysis Bytecode generator Interpreter JIT Compiler Runtime Source Text Variables, scopes AST Analyzed variables and scopes Bytecode Compiled code 18
  • 19. What to change in the engines: runtime - Runtime: property lookup is desugared to static lexical lookups - Special path to lookup private symbols (different semantics) - Methods and accessors need to validate if receiver has the correct brand - Static: validate the receivers and change where things are installed 19
  • 20. Bytecode generated for instance private fields During class evaluation V8 CallRuntime [CreatePrivateNameSymbol] // #instanceField StaCurrentContextSlot [4] // known index to a fixed array ... CreateClosure // instance_members_initializer // Store instance_members_initializer in the class StaNamedProperty <class_constructor> ... class C { #instanceField = 1; } 20
  • 21. Bytecode generated for instance private fields During class evaluation JSC create_lexical_environment loc4, ... ... call loc12, “@createPrivateSymbol” put_to_scope loc4, “#instanceField”, loc12 new_fuc_exp loc13, ... put_by_id <C>, “@instanceFieldInitializer”, loc13 ... class C { #instanceField = 1; } 21
  • 22. Bytecode generated for instance private fields In the constructor V8 // In the class C constructor LdaNamedProperty // load instance_members_initializer CallProperty0 // run instance_members_initializer // In instance_members_initializer LdaCurrentContextSlot [4] // Load the #instanceField symbol from the context Star r1 LdaSmi [1] Star r2 Mov <this>, r0 CallRuntime [AddPrivateField], r0-r2 // Define this.#instanceField as 1 class C { #instanceField = 1; } 22
  • 23. Bytecode generated for instance private fields In the constructor JSC // In the C constructor get_by_id_direct loc7, callee, “@instanceFieldInitializer” mov loc8, this call loc9, loc7, 1 ret this //In the “@instanceFieldInitializer” mov loc6, Int32: 1 resolve_scope loc7, loc4, “#inscanteField” get_from_scope loc8, loc7, “#inscanteField” put_by_val_direct this, loc8, loc6, PrivateName|ThrowIfExists ret Undefined(const1) class C { #instanceField = 1; } 23
  • 24. Bytecode generated for instance private fields When evaluating getInstanceField() V8 LdaCurrentContextSlot [4] // Load the private symbol LdaKeyedProperty <this>, [0] // Error in the IC if the field does not exist class C { #instanceField = 1; getInstanceField() { return this.#instanceField; } } 24
  • 25. Bytecode generated for instance private fields When evaluating getInstanceField() JSC resolve_scope loc7, loc4, “#instanceField” get_from_scope loc8, loc7, “#instanceField” // get PrivateSymbol get_by_val_direct loc6, this, loc8 ret loc6 class C { #instanceField = 1; getInstanceField() { return this.#instanceField; } } 25
  • 26. Other class features - Private methods are shared among the instances, the validation of the receiver is guarded by a per-class special symbol property (the “brand”). - Static features are implemented similarly to instance features, but handled during class evaluation time. 26
  • 27. Implementation status - Class Fields - Chrome: Shipped full implementation in 74 (23 April 2019). - WebKit: In progress (link). - Private Methods & accessors - Chrome: Fully implemented behind --harmony-private-methods on master (link). - WebKit: In progress (methods and accessors). - Static features - Chrome: Static class fields shipped in 74, static private methods are fully implemented behind --harmony-private-methods on master (link). - WebKit: In progress (link). 27
  • 28. Implementation status Spec issues discovered during implementation - https://github.com/tc39/proposal-class-fields/issues/263 - https://github.com/tc39/proposal-private-methods/issues/69 28
  • 29. Test262 status - Already complete (last PR from 30 August 2019). - Total of 6325 new tests. 29
  • 31. Desugaring public fields (incorrect, just conceptual) class C { field = 1; } class C { constructor() { Object.defineProperty(this, ‘field’, {value: 1}); } } 31
  • 32. Desugaring private fields (incorrect, just conceptual) class C { #field = 1; getField() { return this.#field; } } class C { // Imagine it's possible to declare a fieldSymbol here. constructor() { Object.defineProperty(this, fieldSymbol, {value: 1}); } getField() { return this[fieldSymbol]; } } 32
  • 33. Desugaring private methods (incorrect, just conceptual) class C { #method() { } runMethod() { this.#method(); } } class C { // Imagine it's possible to declare a brandSymbol and a <method>() here. constructor() { Object.defineProperty(this, brandSymbol, {value: /*?*/}); } runMethod() { if (!(brandSymbol in this)) { throw TypeError('...'); } <method>.call(this); } } 33
  • 34. Desugaring static methods and fields (incorrect) class C { static #method() { } static #field = 1; static runMethod() { this.#method(); } } // Imagine it's possible to declare a brandSymbol and a <method>() here. Object.defineProperty(C, brandSymbol, {value: /*?*/}); Object.defineProperty(C, fieldSymbol, {value: 1}); C.runMethod = function() { if (!(brandSymbol in this)) { throw TypeError('...'); } <method>.call(this); } 34
  • 35. Bytecode generated for instance private methods During class evaluation V8 CallRuntime [CreatePrivateNameSymbol] // brand symbol StaCurrentContextSlot [5] ...... ... // Create the private method CreateClosure StaCurrentContextSlot [4] class C { #instanceMethod() {} } 35
  • 36. Bytecode generated for instance private methods During class evaluation JSC create_lexical_environment loc9, loc4 ... call loc13, “@createPrivateSymbol” put_to_scope loc4, “@privateBrand”, loc13 new_func_exp loc12, loc4, ... put_by_id loc12, “@homeObject”, loc11 put_to_scope loc4, “#inscanceMethod”, loc12 class C { #instanceMethod() {} } 36
  • 37. Bytecode generated for instance private methods In the constructor V8 LdaCurrentContextSlot [5] // brand symbol Star r1 Mov <this>, r0 CallRuntime [AddPrivateBrand], r0-r1 class C { #instanceMethod() {} } 37
  • 38. Bytecode generated for instance private methods In the constructor JSC resolve_scope loc7, loc4, “@privateBrand” get_from_scope loc8, loc7, “@privateBrand” put_by_val_direct this, loc8, loc8, PrivateName|ThrowIfExists ret this class C { #instanceMethod() {} } 38
  • 39. Bytecode generated for instance private methods When evaluating runInstanceMethod() V8 LdaCurrentContextSlot [5] // Load the brand symbol LdaKeyedProperty <this>, [0] // brand check - errors if it does not exist LdaCurrentContextSlot [4] // Load the method Star r0 CallAnyReceiver r0, <this>-<this>, [2] class C { #instanceMethod() {}; runInstanceMethod() { this.#instanceMethod(); } } 39
  • 40. Bytecode generated for instance private methods When evaluating runInstanceMethod() JSC mov loc8, this resolve_scope loc9, loc4, “#instanceMethod” get_from_scope loc10, loc9, “@privateBrand” get_by_val_direct loc10, loc8, loc10 // Brand Check get_from_scope loc6, loc9, “#instanceMethod” call loc6, loc6, 1 ... class C { #instanceMethod() {}; runInstanceMethod() { this.#instanceMethod(); } } 40
  • 41. Brand checking saves memory class C { constructor() { Object.defineProperty(this, brandSymbol, {value: /*?*/}); } runMethod() { if (!(brandSymbol in this)) { throw TypeError('...'); } <methodA>.call(this); <methodB>.call(this); } } 41
  • 42. Brand checking saves memory class C { constructor() { Object.defineProperty(this, methodASymbol, {value: <methodA>, ...}); Object.defineProperty(this, methodBSymbol, {value: <methodB>, ...}); // More symbols and references in proportion to the number of private methods } runMethod() { this[methodASymbol](); this[methodBSymbol](); } } 42
  • 43. Bytecode generated for static private methods During class evaluation V8 // During class evaluation CreateClosure StaCurrentContextSlot [4] class C { static #staticMethod() {} static runStaticMethod() { this.#staticMethod(); } } 43
  • 44. Bytecode generated for static private methods When evaluating runStaticMethod() V8 LdaCurrentContextSlot [5] // Load the class that declares the static method TestReferenceEqual <this> // Make sure the receiver is the class Mov <this>, r1 JumpIfTrue LdaSmi.Wide Star r2 LdaConstant [0] Star r3 CallRuntime [NewTypeError], r2-r3 Throw LdaCurrentContextSlot [4] // Where JumpIfTrue jumps to: load the static method Star r0 CallAnyReceiver r0, r1-r1, [0] class C { static #staticMethod() {} static runStaticMethod() { this.#staticMethod(); } } 44
  • 45. Bytecode generated for static private methods JSC create_lexical_environment loc9, loc4 call loc13, “@createPrivateSymbol” put_to_scope loc4, “@privateStaticBrand”, loc13 new_func_exp loc12, loc4, 1 put_by_id loc12, “@homeObject”, loc11, put_to_scope loc4, “#staticMethod”, loc12 ... resolve_scope loc7, loc4, “@privateStaticBrand” get_from_scope loc8, loc7, “@privateStaticBrand” put_by_val_direct <C>, loc8, loc8, PrivateName|ThrowIfExists class C { static #staticMethod() {} static runStaticMethod() { this.#staticMethod(); } } 45
  • 46. Bytecode generated for private accessors - Similar to private methods, guarded by brand checks - Complementary accessors are stored in AccessorPairs in V8, but separately in JSC - Generate TypeError statically for incorrect usage to read-only or write-only private accessors class C { get #value() { } set #value(val) { } inc() { return this.#value++; } } 46
  • 47. Bytecode generated for static public fields - Defined in static field initializers in V8 and accessed as usual - Inlined in the class evaluation in JSC class C { static publicField = 1; static publicMethod() { return this.publicField; } } C.publicMethod(); 47
  • 48. Bytecode generated for static private fields V8 // During class evaluation // Create the #staticField symbol CallRuntime [CreatePrivateNameSymbol] StaCurrentContextSlot [4] ... CreateClosure // static_fields_initializer CallProperty0 // calls static_fields_initializer on the class // In the static_fields_initializer LdaCurrentContextSlot [4] // Load the #staticField symbol Star r1 LdaSmi [1] Star r2 Mov <this>, r0 CallRuntime [AddPrivateField], r0-r2 // Define C.#staticField as 1 class C { static #staticField = 1; static getStaticField() { return this.#staticField; } } 48
  • 49. Bytecode generated for static private fields JSC create_lexical_environment loc4, ... ... call loc12, “@createPrivateSymbol” put_to_scope loc4, “#instanceField”, loc12 ... mov loc6, Int32: 1 resolve_scope loc7, loc4, “#inscanteField” get_from_scope loc8, loc7, “#inscanteField” put_by_val_direct <C>, loc8, loc6, ... class C { static #staticField = 1; static getStaticField() { return this.#staticField; } } 49