jQuery.extend / jQuery.fn.extend triggers slow path in V8 (and it looks like easy to fix) #4245
Description
Description
In V8, adding properties into the prototype chain, interleaved with property access, results in copying fast mode maps repeatedly. (A "map" describes the internal layout of an object.)
Example:
function Foo() { ... }
// Add properties (prototype in setup stage)
Foo.prototype.a = function() { ... }
Foo.prototype.b = function() { ... }
let f = new Foo();
for (let i = 0; i < 100; ++i) {
f.a; // Second access from the same code location turns prototype into fast mode
Foo.prototype.a; // This kind of access triggers the behavior too
}
// Add more properties (prototype stays in fast mode; map copied)
Foo.prototype.c = function() { ... }
// Map copied again
Foo.prototype.d = function() { ... }
jQuery init phase also has this access pattern:
- jQuery.fn is set as prototype (it's jQuery.prototype and also init.prototype).
- jQuery.fn.extend is called repeatedly
- The property access comes from the line src = target[ name ]; inside jQuery.fn.extend
- And we also keep adding properties to jQuery.fn as part of jQuery.fn.extend: target[ name ] = ...;
This is a lot of V8 internals (also fixing this on V8 side is on our radar), but looks like the jQuery side fix is simple and also makes sense software-engineering-wise: move "src = target[ name ];" into the branch where it's used. When calling extend with an object which contains functions, we don't go into that branch.
Link to test case
This is not a functional change.