diff --git a/lib/fibers/runtime.js b/lib/fibers/runtime.js index 09d708f..ce41176 100644 --- a/lib/fibers/runtime.js +++ b/lib/fibers/runtime.js @@ -9,6 +9,16 @@ var g = util.getGlobals('fibers'); var keys = []; +function applyFast(fn, that, args) { + switch (args.length) { + case 1: return fn.call(that, args[0]); + case 2: return fn.call(that, args[0], args[1]); + case 3: return fn.call(that, args[0], args[1], args[2]); + case 4: return fn.call(that, args[0], args[1], args[2], args[3]); + default: return fn.apply(that, args); + } +} + exports.await = function(file, line, object, property, index1, index2, returnArray, args) { var bound = typeof property !== "function"; var fn = bound ? object[property] : property; @@ -18,7 +28,7 @@ exports.await = function(file, line, object, property, index1, index2, returnArr key = keys[index1] || (keys[index1] = 'fiberized-' + index1); wrapper = fn[key]; if (!wrapper && bound) { - // second chance for foo.call(bar, _, ...). + // second chance for foo.call(bar, _, ...). Optimize if bar.foo['fiberized-0'] exists if ((property === 'call') && index1 > 0 && typeof object === 'function') { var key2 = keys[index1 - 1] || (keys[index1 - 1] = 'fiberized-' + (index1 - 1)); var fn2 = object[key2]; @@ -30,7 +40,8 @@ exports.await = function(file, line, object, property, index1, index2, returnArr } if (wrapper) { if (g.emitter) wrapper = frameModule.wrap(file, line, wrapper); - if (Array.isArray(args)) return wrapper.apply(object, args); + // streamline < 2.0 does not pass args - return wrapper in this case + if (Array.isArray(args)) return applyFast(wrapper, object, args); else return bound ? wrapper.bind(object) : wrapper; } } @@ -86,7 +97,7 @@ function awaitSlow(file, line, object, property, index1, index2, returnArray, ar // Invoke the function and yield var frame = g.emitter && frameModule.pushFrame(file, line, fn.name); - fn.apply(that, args); + applyFast(fn, that, args); if (yielded) { if (frame) frame.pop(); @@ -117,7 +128,7 @@ function awaitSlow(file, line, object, property, index1, index2, returnArray, ar if (!bound && key) { fn[key] = wrapper; } - return Array.isArray(args) ? wrapper.apply(object, args) : wrapper; + return Array.isArray(args) ? applyFast(wrapper, object, args) : wrapper; }; function arityWrapper(template) { @@ -173,7 +184,7 @@ var asyncTemplate = arityWrapper(function(fn, index) { g.context = cx; cx = null; try { - val = fn.apply(lthat, largs); + val = applyFast(fn, lthat, largs); } catch (e) { err = e; } finally { @@ -196,7 +207,7 @@ exports.new = function(file, line, constructor, index) { return function() { var that = Object.create(constructor.prototype); arguments[index] = true; - exports.await(file, line, null, constructor, index, null, false).apply(that, arguments); + applyFast(exports.await(file, line, null, constructor, index, null, false), that, arguments); return that; }; } @@ -225,7 +236,7 @@ Function.prototype.apply_['fiberized-0'] = function(dummy, thisObj, args, index) if (this['fiberized-0']) { args = Array.prototype.slice.call(args, 0); args.splice(index != null && index >= 0 ? index : args.length, 0, dummy); - return this['fiberized-0'].apply(thisObj, args); + return applyFast(this['fiberized-0'], thisObj, args); } else { return Function.prototype.apply_.call(this, dummy, thisObj, args, index); }