Skip to content

Quiz: Spot the Deopt

advanced9 min read

Test Your V8 Knowledge

Alright, you've made it through hidden classes, inline caches, element kinds, feedback vectors, and deoptimization triggers. Time to put it all together.

For each code example below, your job is to identify the deoptimization trigger -- or determine that the code is V8-friendly. These aren't theoretical puzzles. Every single one comes from real production codebases. Let's see how sharp your V8 intuition has gotten.


Challenge 1: The Shape Shift

function getArea(shape) {
  return shape.width * shape.height;
}

const rect = { width: 10, height: 20 };
const square = { width: 10, height: 10, isSquare: true };

for (let i = 0; i < 100000; i++) {
  getArea(i % 2 === 0 ? rect : square);
}
Quiz
What's the IC state of shape.width after this loop?

Challenge 2: The Array Trap

function sum(arr) {
  let total = 0;
  for (let i = 0; i < arr.length; i++) {
    total += arr[i];
  }
  return total;
}

const data = new Array(10000);
for (let i = 0; i < 10000; i++) {
  data[i] = i;
}

sum(data);
Quiz
Will TurboFan generate optimal code for the sum loop?

Challenge 3: The Sneaky Coercion

This one's subtle.

function multiply(a, b) {
  return a * b;
}

for (let i = 0; i < 50000; i++) {
  multiply(i, i + 1);
}

// Later, in a different code path:
multiply(2n, 3n); // BigInt
Quiz
What happens when multiply receives BigInt arguments after being optimized for Smis?

Challenge 4: The Prototype Pollution

function processItems(items) {
  const results = [];
  for (let i = 0; i < items.length; i++) {
    if (items[i] !== undefined) {
      results.push(items[i] * 2);
    }
  }
  return results;
}

const data = [1, 2, 3, 4, 5];
processItems(data);
Quiz
Is this code V8-friendly?

Challenge 5: The Delete Disaster

By now you should smell this one coming.

function createCache() {
  const cache = {};

  return {
    set(key, value) { cache[key] = value; },
    get(key) { return cache[key]; },
    remove(key) { delete cache[key]; },
  };
}

const c = createCache();
for (let i = 0; i < 1000; i++) {
  c.set('key' + i, i);
}
c.remove('key500');

// Now 999 get() calls
for (let i = 0; i < 1000; i++) {
  if (i !== 500) c.get('key' + i);
}
Quiz
What happens to get() performance after remove('key500')?

Challenge 6: The Feedback Polluter

function add(a, b) {
  return a + b;
}

// Warm-up with mixed types during initialization
add("config", "value");
add(true, false);
add(null, undefined);

// Hot path: always integers
for (let i = 0; i < 1000000; i++) {
  add(i, i + 1);
}
Quiz
How well does TurboFan optimize the integer loop?

Challenge 7: The Innocent Refactor

This one's a trick question -- and a good reminder not to over-optimize.

// Version A: Original
function processPoint(p) {
  return p.x + p.y;
}

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

const points = Array.from({length: 100000}, (_, i) => new Point(i, i * 2));
let total = 0;
for (const p of points) total += processPoint(p);
// Version B: "Improved" with destructuring
function processPoint({ x, y }) {
  return x + y;
}

// ... same Point class and array creation ...
Quiz
Does Version B (destructuring parameter) perform differently from Version A?

How'd You Do?

7/7: You genuinely understand V8 internals. You'd catch these in code review before they ship.

5-6/7: Strong foundation. Go back and re-read the topics for the ones you missed -- the details matter.

3-4/7: You're getting there. The earlier topics in this module will fill the gaps.

0-2/7: No shame in that -- start from the beginning of this module. These concepts build on each other, and it clicks fast once the mental model lands.

Key Rules

Key Rules
  1. 1Object shape consistency is the most impactful optimization. Different shapes through the same code path = polymorphic ICs = measurable slowdown.
  2. 2new Array(n) creates holey arrays permanently. Use push() or Array.from() for packed arrays.
  3. 3Type pollution from initialization code degrades hot-path optimization. Separate cold and hot functions.
  4. 4delete transitions objects to dictionary mode, slowing all property access — not just the deleted property.
  5. 5BigInt, null, undefined, and boolean all create type pollution when mixed with integer arithmetic.
  6. 6Modern V8 handles many patterns (destructuring, spread, optional chaining) efficiently. Test before assuming a pattern is slow.
  7. 7When in doubt, use --trace-deopt to see exactly what V8 is doing.