Course contentsShow
← Node.js
Lesson 1932 of 1,98017. Performance Tuning and ProfilingFree lesson

Optimizing Monomorphic vs Polymorphic Calls

You will refactor polymorphic function sites to benefit from V8 monomorphic inline caching.

In this lesson, you will learn how to identify and refactor polymorphic function sites to leverage V8’s monomorphic Inline Caching (IC) for significant performance gains.

Understanding the IC State

V8 optimizes property access and function calls using Inline Caches. When V8 executes a call, it observes the "shape" (Hidden Class) of the objects passed as arguments.

  • Monomorphic: The call site consistently receives the same object shape. V8 generates highly optimized machine code specifically for that shape, making the call essentially a direct jump.
  • Polymorphic: The call site receives a small number of different shapes. V8 handles this with a "stub" that checks the shape before executing, adding overhead.
  • Megamorphic: The site receives many different shapes. V8 gives up on caching and performs a slow, generic lookup.

The Problem: Polymorphic Calls

Consider a function that processes different user objects:

function getName(user) {
  return user.name;
}

// Site becomes polymorphic if we pass different object structures
getName({ name: 'Alice', age: 25 });
getName({ name: 'Bob', role: 'admin' });

Because the keys are added in different orders or exist in different configurations, V8 sees these as different Hidden Classes. The call to getName is now polymorphic, slowing down your hot loops.

The Fix: Ensuring Monomorphism

To restore monomorphism, you must ensure objects passed to hot functions have identical shapes. You can achieve this by using a constructor function or factory pattern to guarantee consistent initialization:

class User {
  constructor(name, extra) {
    this.name = name;
    this.extra = extra; // Always initialize the same properties in the same order
  }
}

const u1 = new User('Alice', 25);
const u2 = new User('Bob', 'admin');

// Now 'getName' is monomorphic because all inputs share the same Hidden Class
getName(u1);
getName(u2);

By ensuring that your objects are "shape-consistent"—always initializing properties in the same order—you allow V8 to generate specialized machine code, bypassing the expensive polymorphic lookup logic. Always keep your object shapes stable when iterating over large collections of data.

Key Takeaway: By keeping object shapes consistent through constructors or factory functions, you trigger monomorphic inline caching, allowing V8 to generate highly optimized, high-speed execution paths for your functions.