timers: dispatch ontimeout callback by array index
authorBen Noordhuis <info@bnoordhuis.nl>
Thu, 15 Aug 2013 17:23:36 +0000 (19:23 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Thu, 15 Aug 2013 17:33:34 +0000 (19:33 +0200)
Achieve a minor speed-up by looking up the timeout callback on the timer
object by using an array index rather than a named property.

Gives a performance boost of about 1% on the misc/timers benchmarks.

lib/timers.js
src/timer_wrap.cc

index 76a9cda..93dd65e 100644 (file)
@@ -23,6 +23,8 @@ var Timer = process.binding('timer_wrap').Timer;
 var L = require('_linklist');
 var assert = require('assert').ok;
 
+var kOnTimeout = Timer.kOnTimeout | 0;
+
 // Timeout values > TIMEOUT_MAX are set to 1.
 var TIMEOUT_MAX = 2147483647; // 2^31-1
 
@@ -62,7 +64,7 @@ function insert(item, msecs) {
 
     lists[msecs] = list;
     list.msecs = msecs;
-    list.ontimeout = listOnTimeout;
+    list[kOnTimeout] = listOnTimeout;
   }
 
   L.append(list, item);
@@ -109,7 +111,7 @@ function listOnTimeout() {
       } finally {
         if (threw) {
           process.nextTick(function() {
-            list.ontimeout();
+            list[kOnTimeout]();
           });
         }
       }
@@ -215,8 +217,8 @@ exports.setTimeout = function(callback, after) {
 
 
 exports.clearTimeout = function(timer) {
-  if (timer && (timer.ontimeout || timer._onTimeout)) {
-    timer.ontimeout = timer._onTimeout = null;
+  if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
+    timer[kOnTimeout] = timer._onTimeout = null;
     if (timer instanceof Timeout) {
       timer.close(); // for after === 0
     } else {
@@ -283,7 +285,7 @@ Timeout.prototype.unref = function() {
     if (delay < 0) delay = 0;
     exports.unenroll(this);
     this._handle = new Timer();
-    this._handle.ontimeout = this._onTimeout;
+    this._handle[kOnTimeout] = this._onTimeout;
     this._handle.start(delay, 0);
     this._handle.domain = this.domain;
     this._handle.unref();
@@ -300,7 +302,7 @@ Timeout.prototype.ref = function() {
 Timeout.prototype.close = function() {
   this._onTimeout = null;
   if (this._handle) {
-    this._handle.ontimeout = null;
+    this._handle[kOnTimeout] = null;
     this._handle.close();
   } else {
     exports.unenroll(this);
@@ -439,7 +441,7 @@ exports._unrefActive = function(item) {
     unrefTimer = new Timer();
     unrefTimer.unref();
     unrefTimer.when = -1;
-    unrefTimer.ontimeout = unrefTimeout;
+    unrefTimer[kOnTimeout] = unrefTimeout;
   }
 
   var now = Timer.now();
index 8abe33e..1f84de5 100644 (file)
@@ -22,6 +22,8 @@
 #include "node.h"
 #include "handle_wrap.h"
 
+#include <stdint.h>
+
 namespace node {
 
 using v8::Function;
@@ -35,7 +37,7 @@ using v8::Object;
 using v8::String;
 using v8::Value;
 
-static Cached<String> ontimeout_sym;
+const uint32_t kOnTimeout = 0;
 
 class TimerWrap : public HandleWrap {
  public:
@@ -45,6 +47,8 @@ class TimerWrap : public HandleWrap {
     Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
     constructor->InstanceTemplate()->SetInternalFieldCount(1);
     constructor->SetClassName(FIXED_ONE_BYTE_STRING(node_isolate, "Timer"));
+    constructor->Set(FIXED_ONE_BYTE_STRING(node_isolate, "kOnTimeout"),
+                     Integer::New(kOnTimeout, node_isolate));
 
     NODE_SET_METHOD(constructor, "now", Now);
 
@@ -58,8 +62,6 @@ class TimerWrap : public HandleWrap {
     NODE_SET_PROTOTYPE_METHOD(constructor, "getRepeat", GetRepeat);
     NODE_SET_PROTOTYPE_METHOD(constructor, "again", Again);
 
-    ontimeout_sym = FIXED_ONE_BYTE_STRING(node_isolate, "ontimeout");
-
     target->Set(FIXED_ONE_BYTE_STRING(node_isolate, "Timer"),
                 constructor->GetFunction());
   }
@@ -138,7 +140,7 @@ class TimerWrap : public HandleWrap {
     assert(wrap);
 
     Local<Value> argv[1] = { Integer::New(status, node_isolate) };
-    MakeCallback(wrap->object(), ontimeout_sym, ARRAY_SIZE(argv), argv);
+    MakeCallback(wrap->object(), kOnTimeout, ARRAY_SIZE(argv), argv);
   }
 
   static void Now(const FunctionCallbackInfo<Value>& args) {