Skip to content

Commit

Permalink
Optimize supercall installation
Browse files Browse the repository at this point in the history
Do not lookup on which methods we need to install supercalls each time an
instance is created.

Instead, we cache in a non-enumerable variable `methodsWithSuperCall` on each
class all method names that need supercall installation.
  • Loading branch information
NicolasPetton authored and DamienCassou committed May 2, 2017
1 parent 2b28df5 commit 17a476e
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 23 deletions.
48 changes: 37 additions & 11 deletions dist/klassified.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,10 @@ define('object',[], function() {
});

builder(instance, my);

if (superCallRegex.test(builder)) {
installSuper(instance, superInstance);
installSuper(my, superMy);
installSuper(my, superMy, klass, "my");
installSuper(instance, superInstance, klass, "that");
}

if (!notFinal) {
Expand Down Expand Up @@ -704,15 +705,12 @@ define('object',[], function() {
* `super` from within each public function of `obj` to the function in
* `proto`.
*/
function installSuper(obj, proto) {
Object.keys(obj).forEach(function(name) {
if (typeof proto[name] === "function" &&
typeof obj[name] === "function" &&
superCallRegex.test(obj[name]) &&
!obj[name].superInstalled) {
var superFn = proto[name];
obj[name] = (function(name, fn) {
function installSuper(obj, proto, klass, receiverName) {
methodsWithSuperCall(obj, proto, klass, receiverName).forEach(function(name) {
if (!obj[name].superInstalled) {
obj[name] = (function(obj, fn, superFn) {
return function() {

var tmp = obj.super;
obj.super = superFn;
var returnValue = fn.apply(obj, arguments);
Expand All @@ -726,12 +724,40 @@ define('object',[], function() {

return returnValue;
};
})(name, obj[name]);
})(obj, obj[name], proto[name]);
obj[name].superInstalled = true;
}
});
}

/**
* Return the list of methods in `obj` that perform a supercall to `proto`.
* The list is cached in `klass`.
*
* `receiverName` is either "that" or "my".
*/
function methodsWithSuperCall(obj, proto, klass, receiverName) {
if (!klass.methodsWithSuperCall) {
Object.defineProperty(klass, "methodsWithSuperCall", {
enumerable: false,
writable: true,
value: {}
});
}

if (klass.methodsWithSuperCall[receiverName]) {
return klass.methodsWithSuperCall[receiverName];
}

klass.methodsWithSuperCall[receiverName] = Object.keys(obj).filter(function(name) {
return typeof(proto[name]) === "function" &&
typeof(obj[name]) === "function" &&
superCallRegex.test(obj[name]);
});

return klass.methodsWithSuperCall[receiverName];
}

/**
* Extend the class with new methods/properties.
* @param{function} builder takes the same arguments as
Expand Down
Loading

0 comments on commit 17a476e

Please sign in to comment.