Search code examples
javascriptv8

Destructuring, polymorphic arguments, and inline caches


When operating on objects, one can have the property access either on:

  • call site: const f = (x, y) => x + y;, f(o.x, o.y).
  • inside the function: const f = o => o.x + o.y;, f(o); (or similarly, const f = ({ x, y }) => x + y;, f(o);).

From my naive understanding, the first likely uses the call-site's inline caches, while the latter takes those of the function itself. In a scenario, where f is being called with all kinds of objects, as long as they have properties x and y, this in my mind could lead to a megamorphic scenario for the latter, not utilizing inline-caches anymore.


Some general disclaimers here:

  • Caring about this is almost always premature optimization. I am interested in obtaining a better understanding how things work in general.
  • Other optimizations the compiler does, e.g. inlining f into the call-site, likely makes this irrelevant in typical cases.
  • While I do try to read some of the assembler output, my ability to understand it is still rather limited. Multiple places are "and then something I don't understand happens".

With my current knowledge, for destructured parameters, it looks like V8 could potentially swap to the first case, replacing all calls with the property accesses, followed by a call to a modified function that takes the values directly. This is primarily, as the function's body never has access to the object itself in the first place. In a way a "light inlining", though perhaps fully inlining is always preferred. This doesn't seem to be done, but I cannot tell for sure.


Is something about my understanding flawed, does function inlining really solve this almost entirely already, or are there problem-cases? Are there any articles I should read, to strengthen my understanding?


Solution

  • (V8 developer here.)

    Your understanding wrt. type feedback sounds about right: doing object shape specific operations at the caller can avoid type feedback pollution in callees that get called from different places. (Whether this actually matters depends a lot on the overall situation.)

    I share Bergi's skepticism about the viability of "light inlining". In particular, to do anything like that, the engine would have to know exactly what the call target is -- and if it does know that, it might as well fully inline it. Additionally, compiling the callee differently (by dropping some operations there) is only correct for a particular site that calls it, and that's not something we currently track (or would likely want to rely on) in V8.