I'm debugging a performance regression in a hot code path and found that V8 is deoptimizing a function that uses closures in a monomorphic way. Here’s a simplified version of the pattern
function createGetter(prop) {
return function(obj) {
return obj[prop];
};
}
const getX = createGetter("x");
const getY = createGetter("y");
const obj1 = { x: 10, y: 20 };
const obj2 = { x: 15, y: 25 };
for (let i = 0; i < 1e6; i++) {
getX(obj1);
getY(obj2);
}
Despite obj1 and obj2 sharing the same hidden class and the call site being monomorphic per closure, --trace-opt --trace-deopt deoptimizations related to LoadIC and context mismatches.
It verified that both closures are optimized initially.
Shapes are hidden classes and stable and verified via --print-opt-code.
Deopt seems to relate to the context or inline cache confusion between closures.
Is V8's inline cache strategy per-closure or per-site in this case? and could context isolation be triggering unnecessary polymorphism? Would defining getX and getY inline rather than through a shared factory mitigate this, or is there a deeper reason for deopt? Is this related to feedback vector sharing or context-specific feedback slots for closures created from the same outer function?
tried a lot..haven't figgerd it out.