Skip to content

Commit

Permalink
[BUGFIX beta] Fix stack overflow in wrap.
Browse files Browse the repository at this point in the history
Fix stack overflow when adding terminating wrapper to superFunc in wrap.

For some reason, the recursive call to wrap that doesn’t have an obvious termination, yet wasn’t causing a stack overflow until minified.

Something is wrong with our tests that are supposed to run against the minified build.
  • Loading branch information
krisselden committed Aug 17, 2015
1 parent 6258271 commit 4599f70
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 4599f70

Please sign in to comment.