Перейти к содержимому

Inline Caches (IC)

Inline Caches — механизм V8 для кэширования результатов lookup свойств прямо в точке вызова; переход из monomorphic → polymorphic → megamorphic резко снижает производительность и диагностируется через —trace-ic.

// IC состояния и их влияние на производительность
function getX(obj) { return obj.x; } // IC site внутри функции
// Monomorphic: один тип входящего объекта → кэш одной Map
const a = { x: 1 };
for (let i = 0; i < 1e5; i++) getX(a); // IC: monomorphic
// TurboFan: прямой доступ по fixed offset → почти бесплатно
// Polymorphic: 2-4 разных Map → IC как небольшой vtable
const b = { x: 2, y: 3 }; // другая Map!
getX(b); // IC: polymorphic (2 entries)
// Megamorphic: 5+ разных Map → IC отказывается кэшировать
const shapes = [
{ x: 1 }, { x: 2, a: 1 }, { x: 3, b: 1 },
{ x: 4, c: 1 }, { x: 5, d: 1 }, // 5+ форм
];
shapes.forEach(o => getX(o)); // megamorphic → generic lookup каждый раз
// Загрузочные IC (LOAD) vs вызывные IC (CALL)
class Animal { speak() { return 'sound'; } }
class Dog extends Animal { speak() { return 'woof'; } }
class Cat extends Animal { speak() { return 'meow'; } }
function makeSpeak(animal) {
return animal.speak(); // CALL IC
}
const dog = new Dog();
for (let i = 0; i < 1e5; i++) makeSpeak(dog); // monomorphic → inlined
makeSpeak(new Cat()); // polymorphic — V8 создаёт двойную проверку
// Паттерн: держать CALL IC monomorphic в hot path → inlining работает
// Если нужен полиморфизм — интерфейс с одинаковой скрытой структурой
// Диагностика через Node.js
// node --trace-ic --allow-natives-syntax script.js
// → LOAD/STORE/CALL IC переходы: 0→1 (mono), 1→2 (poly), ...→X (mega)
// Benchmark: monomorphic vs megamorphic IC
function bench() {
const mono = { x: 1 };
function readMono() { return mono.x; }
// прогрев
for (let i = 0; i < 1e5; i++) readMono();
console.time('mono');
for (let i = 0; i < 1e8; i++) mono.x; // ~50ms
console.timeEnd('mono');
// megamorphic — передаём 10 разных форм
const poly = Array.from({ length: 10 }, (_, i) =>
Object.assign({ x: i }, ...Array.from({ length: i }, (_, j) => ({ [j]: j })))
);
console.time('mega');
for (let i = 0; i < 1e8; i++) poly[i % 10].x; // ~400ms
console.timeEnd('mega');
}

Итог: IC — ключевой механизм оптимизации доступа к свойствам; monomorphic IC = почти бесплатный доступ с возможностью inlining, megamorphic = полный generic lookup при каждом обращении.