Move EventEmitter.prototype.emit() completely into C++.
authorRyan <ry@tinyclouds.org>
Fri, 24 Jul 2009 20:23:50 +0000 (22:23 +0200)
committerRyan <ry@tinyclouds.org>
Fri, 24 Jul 2009 20:23:50 +0000 (22:23 +0200)
This shows a healthy speed up.

src/events.cc
src/events.h
src/events.js

index 0116087..47bbba4 100644 (file)
 #include <arpa/inet.h> /* inet_ntop */
 #include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
 
+#ifndef RAMP
+# define RAMP(x) ((x) > 0 ? (x) : 0)
+#endif
+
 using namespace v8;
 using namespace node;
 
@@ -22,39 +26,41 @@ EventEmitter::Initialize (v8::Handle<v8::Object> target)
   HandleScope scope;
 
   Local<FunctionTemplate> t = FunctionTemplate::New();
+
   constructor_template = Persistent<FunctionTemplate>::New(t);
 
-  // All prototype methods are defined in events.js
+  Local<FunctionTemplate> __emit = FunctionTemplate::New(Emit);
+  constructor_template->PrototypeTemplate()->Set(String::NewSymbol("emit"), __emit);
+
+  // All other prototype methods are defined in events.js
 
   target->Set(String::NewSymbol("EventEmitter"),
               constructor_template->GetFunction());
 }
 
-bool
-EventEmitter::Emit (const char *type, int argc, Handle<Value> argv[])
+static bool
+ReallyEmit (Handle<Object> self, Handle<String> event, int argc, Handle<Value> argv[])
 {
   HandleScope scope; 
 
-  Local<Value> emit_v = handle_->Get(String::NewSymbol("emit"));
-  assert(emit_v->IsFunction());
-  Local<Function> emit = Local<Function>::Cast(emit_v);
-
-  Local<Value> events_v = handle_->Get(String::NewSymbol("_events"));
+  Local<Value> events_v = self->Get(String::NewSymbol("_events"));
   if (!events_v->IsObject()) return false;
   Local<Object> events = events_v->ToObject();
 
-  Local<Value> listeners_v = events->Get(String::NewSymbol(type));
+  Local<Value> listeners_v = events->Get(event);
   if (!listeners_v->IsArray()) return false;
   Local<Array> listeners = Local<Array>::Cast(listeners_v);
 
-  TryCatch try_catch;
+  for (unsigned int i = 0; i < listeners->Length(); i++) {
+    HandleScope scope; 
 
-  for (int i = 0; i < listeners->Length(); i++) {
     Local<Value> listener_v = listeners->Get(Integer::New(i));
     if (!listener_v->IsFunction()) continue;
     Local<Function> listener = Local<Function>::Cast(listener_v);
 
-    listener->Call(handle_, argc, argv);
+    TryCatch try_catch;
+
+    listener->Call(self, argc, argv);
 
     if (try_catch.HasCaught()) {
       FatalException(try_catch);
@@ -65,6 +71,36 @@ EventEmitter::Emit (const char *type, int argc, Handle<Value> argv[])
   return true;
 }
 
+Handle<Value>
+EventEmitter::Emit (const Arguments& args)
+{
+  HandleScope scope; 
+  Local<String> event = args[0]->ToString();
+  int argc = 0;
+  Local<Array> emit_args;
+  if (args[1]->IsArray()) {
+    emit_args = Local<Array>::Cast(args[1]);
+    argc = emit_args->Length();
+  }
+  Local<Value> argv[argc];
+
+  for (int i = 0; i < argc; i++) {
+    argv[i] = emit_args->Get(Integer::New(i));
+  }
+
+  bool r = ReallyEmit(args.Holder(), event, argc, argv); 
+
+  return scope.Close(r ? True() : False());
+}
+
+bool
+EventEmitter::Emit (const char *event_s, int argc, Handle<Value> argv[])
+{
+  HandleScope scope; 
+  Local<String> event = String::NewSymbol(event_s);
+  return ReallyEmit(handle_, event, argc, argv);
+}
+
 Persistent<FunctionTemplate> Promise::constructor_template;
 
 void 
index ca3d5fd..ded7c00 100644 (file)
@@ -11,10 +11,12 @@ class EventEmitter : public ObjectWrap {
   static void Initialize (v8::Handle<v8::Object> target);
   static v8::Persistent<v8::FunctionTemplate> constructor_template;
 
-  bool Emit (const char *type, int argc, v8::Handle<v8::Value> argv[]);
+  bool Emit (const char *event, int argc, v8::Handle<v8::Value> argv[]);
 
  protected:
-  EventEmitter () : ObjectWrap() { }
+  static v8::Handle<v8::Value> Emit (const v8::Arguments& args);
+
+  EventEmitter () : ObjectWrap () { }
 };
 
 class Promise : public EventEmitter {
index 0430533..86cf74c 100644 (file)
@@ -1,9 +1,8 @@
 (function () {
 
 // node.EventEmitter is defined in src/events.cc
-var emitter = node.EventEmitter.prototype;
-
-emitter.addListener = function (type, listener) {
+// node.EventEmitter.prototype.emit() is also defined there.
+node.EventEmitter.prototype.addListener = function (type, listener) {
   if (listener instanceof Function) {
     if (!this._events) this._events = {};
     if (!this._events.hasOwnProperty(type)) this._events[type] = [];
@@ -11,27 +10,12 @@ emitter.addListener = function (type, listener) {
   }
 };
 
-emitter.listeners = function (type) {
+node.EventEmitter.prototype.listeners = function (type) {
   if (!this._events) this._events = {};
   if (!this._events.hasOwnProperty(type)) this._events[type] = [];
   return this._events[type];
 };
 
-// This function is called often from C++. 
-// FIXME there is a counterpart for this function in C++
-// both must have the same behavior.
-// See events.cc 
-emitter.emit = function (type, args) {
-  if (!this._events) return;
-  if (!this._events.hasOwnProperty(type)) return;
-
-  var listeners = this._events[type];
-
-  for (var i = 0; i < listeners.length; i++) {
-    listeners[i].apply(this, args);
-  }
-};
-
 // node.Promise is defined in src/events.cc
 var promise = node.Promise.prototype;