Monomorphism
Blake Newman / @blakenewman
Monomorphism
vs
Polymorphism
vs
Lotsamorphism
Polymorphism
- Object-oriented based polymorphism usually means subtyping
- In Haskell there is parametric polymorphism
- In Javascript there is call site polymorphism
- Lots more Polymophism...
Dynamic Lookup
- Applies to any dynamically bound operation
- Property lookup
- Arithmetic operations
- VM's want to avoid costly generic property lookups
- Thus Inline Caching
- Cache based object property lookups
const f = o => o.x
f({ x: 1 })
f({ x: 2 })
Inline Cache Lookup
- Fastest path to discover the property shape
-
The cache is the path to property with the object’s shape as a key
- As with most cache systems there is
- Size (number of currently cached entries)
- Capacity (maximum number of cached entries).
Stages of call site polymorphism
- { x: 1 } { x: 2 } have the same shape (Monomorphism)
-
{ x: 1 } { x: 2, y: 3 } have a different shape (Polymorphism)
{ x: 1 } { x: 'string' } have a different shape (Polymorphism)
- After a certain stage the function will become deoptimized as we pass different shapes to its parameters
- This is known in call site polymorphism as Megamorphism
- For each shape used this is known as the degree of polymorphism
Degrees of polymorphism
f({ x: 4 }) // monomorphic, degree 1
f({ x: 4, y: 1 }) // polymorphic, degree 2
f({ x: 5, z: 1 }) // polymorphic, degree 3
f({ x: 6, a: 1 }) // polymorphic, degree 4
f({ x: 7, b: 1 }) // megamorphic
- VM's have different degrees of polymorphism before becoming megamorphic
- V8 has 4 stages
- At this point the VM starts to dislike your code
- Depending on the VM it may still do some caching techniques
Different shapes?
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
class Point2 {
constructor(x, y) {
this.x = x
this.y = y
}
}
const a = new Point(1, 2)
const b = new Point2(1, 2)
const c = { x: 1, y: 2 }
const d = { x: 1, y: 2, z: 3}
delete d.z
Different shapes?
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
const a = Point(1, 2)
const b = Point(1, 3) // Same shape
a.z = 2 // Different shapes
Performance Implications
-
Monomorphic is the fastest possible
-
Polymorphic state performs linear search among cached entries
-
megamorphic state probe global hash table
- hitting global cache is still better than complete miss
- A miss has expensive costs
- transitioning to runtime
- generic operation
Performance Gains
Not the full story
-
Inline Cache acts on its own, knowing nothing about its neighbours
- Individual Inline Cache can ultimately fallback to runtime
const f = o => o.x * o.x - o.y / o.y
f({ x: 1, y: 1 })
-
7 states of inline monomorphic cache
.x .x * .y .y / +
- Arithmetic operations in JavaScript are inherently typed, with no guarantees
- ahead-of-time optimizing compiler for JavaScript is extremely difficult
Why
- JavaScript does not contain enough inherent type information for full static typing and AOT compilation
How
- execute without any optimizations
- compiled with a baseline non-optimizing compiler
- Hot functions are later recompiled by an optimizing compiler
Benefits
- Decreases startup latency
- It gives inline caches a chance to collect type feedback.
Code warm up
The benchmarks
Why? When? How?
- Obvious performance improvements
- Simpler object shapes
- Improved application performance
- Leads to further under the hood optimizations
Why?
-
Hot functions
- functions that are used very often
-
Libraries
- Code in libraries can be very hot
-
Only when it makes sense
- Only worry about it when you have extremely high profile number crunching
- Don't over optimise (but be considerate when defining object shapes)
When?
-
Typescript / Flow
- Adding static types to portions of you application can give you the safe guards needed to enforce monomorphic code
-
Resouces
- https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html
- http://mrale.ph/blog/2012/06/03/explaining-js-vms-in-js-inline-caches.html
How?
20% off
MEETUP-VJS-20
Competition Time
2 Free tickets
Q&A
Monomorphism
By Blake Newman
Monomorphism
A talk on monomophism, and how Typescript can help you reduce your poly count
- 2,226