Skip to content

Commit

Permalink
Merge pull request #12132 from emberjs/fix-super
Browse files Browse the repository at this point in the history
[BUGFIX beta] Fix stack overflow in wrap.
  • Loading branch information
rwjblue committed Aug 18, 2015
2 parents 6258271 + 4599f70 commit eeed334
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 28 deletions.
7 changes: 5 additions & 2 deletions packages/ember-metal/lib/mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ import {
} from 'ember-metal/events';
import { isStream } from 'ember-metal/streams/utils';

function ROOT() {}
ROOT.__hasSuper = false;

var REQUIRED;
var a_slice = [].slice;

Expand Down Expand Up @@ -185,7 +188,7 @@ function applyMergedProperties(obj, key, value, values) {
}

if (hasFunction) {
newBase._super = function () {};
newBase._super = ROOT;
}

return newBase;
Expand Down Expand Up @@ -372,7 +375,7 @@ function applyMixin(obj, mixins, partial) {
var keys = [];
var key, value, desc;

obj._super = function () {};
obj._super = ROOT;

// Go through all mixins and hashes passed in, and:
//
Expand Down
70 changes: 44 additions & 26 deletions packages/ember-metal/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,31 @@ export function guidFor(obj) {
}


var sourceAvailable = (function() {
return this;
}).toString().indexOf('return this;') > -1;
const checkHasSuper = (function () {
let sourceAvailable = (function() {
return this;
}).toString().indexOf('return this;') > -1;

if (sourceAvailable) {
return function checkHasSuper(func) {
return func.toString().indexOf('_super') > -1;
};
}

return function checkHasSuper() {
return true;
};
}());

function ROOT() {}
ROOT.__hasSuper = false;

function hasSuper(func) {
if (func.__hasSuper === undefined) {
func.__hasSuper = checkHasSuper(func);
}
return func.__hasSuper;
}

/**
Wraps the passed function so that `this._super` will point to the superFunc
Expand All @@ -270,43 +292,39 @@ var sourceAvailable = (function() {
@param {Function} superFunc The super function.
@return {Function} wrapped function.
*/
export function wrap(func, _superFunc) {
var superFunc = _superFunc;
var hasSuper;
if (sourceAvailable) {
hasSuper = func.__hasSuper;

if (hasSuper === undefined) {
hasSuper = func.toString().indexOf('_super') > -1;
func.__hasSuper = hasSuper;
}

if (!hasSuper) {
return func;
}
export function wrap(func, superFunc) {
if (!hasSuper(func)) {
return func;
}

if (superFunc.wrappedFunction === undefined) {
// terminate _super to prevent infinite recursion
superFunc = wrap(superFunc, function () {});
// ensure an unwrapped super that calls _super is wrapped with a terminal _super
if (!superFunc.wrappedFunction && hasSuper(superFunc)) {
return _wrap(func, _wrap(superFunc, ROOT));
}

return _wrap(func, superFunc);
}

function _wrap(func, superFunc) {
function superWrapper() {
var ret;
var orig = this._super;
let orig = this._super;
let length = arguments.length;
let ret;
this._super = superFunc;
switch (arguments.length) {
switch (length) {
case 0: ret = func.call(this); break;
case 1: ret = func.call(this, arguments[0]); break;
case 2: ret = func.call(this, arguments[0], arguments[1]); break;
case 3: ret = func.call(this, arguments[0], arguments[1], arguments[2]); break;
case 4: ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3]); break;
case 5: ret = func.call(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]); break;
default: ret = func.apply(this, arguments); break;
default:
// v8 bug potentially incorrectly deopts this function: https://code.google.com/p/v8/issues/detail?id=3709
// we may want to keep this around till this ages out on mobile
let args = new Array(length);
for (var x = 0; x < length; x++) {
args[x] = arguments[x];
}
ret = func.apply(this, args);
break;
}
this._super = orig;
return ret;
Expand Down

0 comments on commit eeed334

Please sign in to comment.