Search code examples
javascriptperformancejavascript-objectsv8

JS V8 Compiler Optimization, Monomorph Polymorph, (sealed) Object and Classes, OOP


All articles I found about V8 and Monomorphism / Polymorphism just mention that the shape of an object should stay the same, so the JIT compiler can optimize it as a monomorphic function. But what about similar shaped objects like you get with OOP and inheritance?

I'm interested in the following pretty common OOP case, where you have a bunch of similar shaped objects, like when having a class hierarchy, where classes (and their objects) share common properties. For example:

obj1 = {
  foo: 42,
  bar: true
}

obj2 = {
  baz: "abc",
  foo: 666,
  qux: null
}

Now when having some function that only uses the foo property, I can pass all those different objects to it. From the function's perspective they all have the same shape { foo: number } + *, but their real shape of course is different due to the additional properties bar, baz and qux.

Is such a case somehow covered by the JIT compiler?

And if not, how to refactor similar shaped objects to fit the "monomorphic" pattern?


Solution

  • (V8 developer here.)

    Short answer: "same" != "similar".

    From the function's perspective they all have the same shape { foo: number } + *

    No, that's very much not what "the same shape" means. "The same shape" doesn't mean "they all have a foo property somewhere". "The same shape" means, for example, "they each have exactly three properties foo, bar, baz, in that order". (The actual internal definition includes more, but that's the upshot.)

    Monomorphic code is fast because it can always do the same thing, for example always load the first property. Whereas when it has to decide what to do every time ("oh, this is one of the objects where foo is the second property... oh, this is an object with a shape I've never seen before, let's see if it has a foo property at all and where that might be..."), then all that figuring-out-what-to-do costs time.

    If it helps your mental model, you can compare this with physical work. When a factory produces exactly one car model, you can build a simple and fast robot that tightens the exact same screw on every car, which it always finds in the exact same spot. Whereas in a garage that repairs arbitrary old cars, a robot that's supposed to tighten their screws first has to figure out where the screws even are in this particular car that it's looking at, and how to get to them. It doesn't help the robot that all cars are "similar" in that they each have a loose screw somewhere; what makes the robot's life hard is that each car is different.

    Is such a case somehow covered by the JIT compiler?

    Sure, it's more work under the hood, but it works just fine, and usually it's fast enough. Don't worry about premature optimizations when you don't have a performance problem.

    how to refactor similar shaped objects to fit the "monomorphic" pattern?

    Make the objects have exactly the same shape. For example, construct them all with the same constructor, and then don't add any properties afterwards. (And, of course, don't make some of the properties that the constructor adds conditional either, that would defeat the point.)

    With class hierarchies, polymorphism is typically hard or impossible to avoid. See here for a related question.