Based on:
So these two objects will have different shapes:
function ObjA(a, b) {
this.a = a;
this.b = b;
}
function ObjB(a, b) {
return {
a: a,
b: b
};
}
// shape: { b } -> { a } -> {}
var a = new ObjA(1, 2);
// shape: { a, b }
var b = ObjB(1, 2);
But will these objects have the same shape?
function ObjA(a, b) {
this.a = a;
this.b = b;
}
function ObjB(a, b) {
this.a = a;
this.b = b;
}
var a = new ObjA(1, 2);
var b = new ObjB(1, 2);
- So the fact that they're different classes doesn't mean anything to the js engine?
- If I were to add a function to ObjB's prototype, would that result in ObjA and ObjB instances having different shapes?
- From a performance perspective, are object literals "better" as long as you don't plan to use the prototype, or doesn't it matter?
Say I have the following function:
function biggerThanFive(obj) {
var some_val = obj.getValue();
if (some_val > 5) {
return true;
} else {
return false;
}
}
Imagine that during the lifetime of my application, I pass 100 objects with different shapes to biggerThanFive
.
This would result in biggerThanFive
being megamorphic.
- Am I correct in assuming that this function wouldn't be optimized at all?
- Would this function still be megamorphic even though all these objects has
getValue
stored on their prototype objects, and that the prototype objects are all the same shape? - Would it be possible to limit megamorphic code by dividing megamorphic pieces into their own function? Like this:
// monomorphic?
function biggerThanFive(obj) {
var some_val = getValue(obj);
if (some_val > 5) {
return true;
} else {
return false;
}
}
// megamorphic?
function getValue(obj) {
return obj.getValue();
}
Re: the first question, see this part of the article on prototypes: https://mathiasbynens.be/notes/prototypes#:~:text=and%20that%E2%80%99s%20essentially%20what%20engines%20do%20with%20a%20simple%20trick%3A%20instead%20of%20storing%20the%20prototype%20link%20on%20the%20instance%20itself%2C%20engines%20store%20it%20on%20the%20shape.
"And that’s essentially what engines do with a simple trick: instead of storing the prototype link on the instance itself, engines store it on the
Shape
. […] Each shape points to the prototype. This also means that every time the prototype offoo
changes, the engine transitions to a new shape. Now we only need to check the shape of an object to both assert absence of certain properties and also guard the prototype link."For the other questions involving the very specific examples, I’ll do you one better by telling you how you can find the answer yourself :) Grab a
d8
binary (jsvu is the easiest way to do it) and run it with the--trace-ic
flag on any given*.js
file. Benedikt’s blog post at https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/ walks through an example you could use as a basis. This allows you to figure out which IC loads are uninitialized, premonomorphic, monomorphic, polymorphic, or megamorphic — for any code snippet you want to test!Hope this helps.