lib: don't penalize setInterval() common case
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 20 Mar 2015 16:20:43 +0000 (17:20 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Fri, 20 Mar 2015 22:42:26 +0000 (23:42 +0100)
The common case is where setInterval() is called with two arguments,
the callback and the timeout.  Specifying optional arguments in
the parameter list forces common case calls to go through an arguments
adaptor stack frame.

PR-URL: https://github.com/iojs/io.js/pull/1221
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
lib/timers.js

index 72f275a6421e62bae75522bfff5e1a7cc31b1bd5..102a927a19c6a191d6b0ad2ae111fda06b9f11f6 100644 (file)
@@ -229,24 +229,40 @@ exports.clearTimeout = function(timer) {
 };
 
 
-exports.setInterval = function(callback, repeat, arg1, arg2, arg3) {
+exports.setInterval = function(callback, repeat) {
   repeat *= 1; // coalesce to number or NaN
 
   if (!(repeat >= 1 && repeat <= TIMEOUT_MAX)) {
     repeat = 1; // schedule on next tick, follows browser behaviour
   }
 
-  var args, i;
   var timer = new Timeout(repeat);
-  var len = arguments.length - 2;
-  timer._onTimeout = wrapper;
-  timer._repeat = true;
-  // Initialize args once for repeated invocation of slow case below
-  if (len > 3) {
-    args = new Array(len);
-    for (i = 0; i < len; i++)
-      args[i] = arguments[i + 2];
+  var length = arguments.length;
+  var ontimeout = callback;
+  switch (length) {
+    case 0:
+    case 1:
+    case 2:
+      break;
+    case 3:
+      ontimeout = callback.bind(timer, arguments[2]);
+      break;
+    case 4:
+      ontimeout = callback.bind(timer, arguments[2], arguments[3]);
+      break;
+    case 5:
+      ontimeout =
+          callback.bind(timer, arguments[2], arguments[3], arguments[4]);
+      break;
+    default:
+      var args = new Array(length - 2);
+      for (var i = 2; i < length; i += 1)
+        args[i - 2] = arguments[i];
+      ontimeout = callback.apply.bind(callback, timer, args);
+      break;
   }
+  timer._onTimeout = wrapper;
+  timer._repeat = ontimeout;
 
   if (process.domain) timer.domain = process.domain;
   exports.active(timer);
@@ -254,27 +270,9 @@ exports.setInterval = function(callback, repeat, arg1, arg2, arg3) {
   return timer;
 
   function wrapper() {
-    switch (len) {
-      // fast cases
-      case 0:
-        callback.call(this);
-        break;
-      case 1:
-        callback.call(this, arg1);
-        break;
-      case 2:
-        callback.call(this, arg1, arg2);
-        break;
-      case 3:
-        callback.call(this, arg1, arg2, arg3);
-        break;
-      // slow case
-      default:
-        callback.apply(this, args);
-        break;
-    }
+    timer._repeat.call(this);
     // If callback called clearInterval().
-    if (timer._repeat === false) return;
+    if (timer._repeat === null) return;
     // If timer is unref'd (or was - it's permanently removed from the list.)
     if (this._handle) {
       this._handle.start(repeat, 0);