Skip to content

Commit 842eaf4

Browse files
committed
Move EventEmitter.prototype.emit() completely into C++.
This shows a healthy speed up.
1 parent 4aac515 commit 842eaf4

File tree

3 files changed

+55
-33
lines changed

3 files changed

+55
-33
lines changed

src/events.cc

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include <arpa/inet.h> /* inet_ntop */
1212
#include <netinet/in.h> /* sockaddr_in, sockaddr_in6 */
1313

14+
#ifndef RAMP
15+
# define RAMP(x) ((x) > 0 ? (x) : 0)
16+
#endif
17+
1418
using namespace v8;
1519
using namespace node;
1620

@@ -22,39 +26,41 @@ EventEmitter::Initialize (v8::Handle<v8::Object> target)
2226
HandleScope scope;
2327

2428
Local<FunctionTemplate> t = FunctionTemplate::New();
29+
2530
constructor_template = Persistent<FunctionTemplate>::New(t);
2631

27-
// All prototype methods are defined in events.js
32+
Local<FunctionTemplate> __emit = FunctionTemplate::New(Emit);
33+
constructor_template->PrototypeTemplate()->Set(String::NewSymbol("emit"), __emit);
34+
35+
// All other prototype methods are defined in events.js
2836

2937
target->Set(String::NewSymbol("EventEmitter"),
3038
constructor_template->GetFunction());
3139
}
3240

33-
bool
34-
EventEmitter::Emit (const char *type, int argc, Handle<Value> argv[])
41+
static bool
42+
ReallyEmit (Handle<Object> self, Handle<String> event, int argc, Handle<Value> argv[])
3543
{
3644
HandleScope scope;
3745

38-
Local<Value> emit_v = handle_->Get(String::NewSymbol("emit"));
39-
assert(emit_v->IsFunction());
40-
Local<Function> emit = Local<Function>::Cast(emit_v);
41-
42-
Local<Value> events_v = handle_->Get(String::NewSymbol("_events"));
46+
Local<Value> events_v = self->Get(String::NewSymbol("_events"));
4347
if (!events_v->IsObject()) return false;
4448
Local<Object> events = events_v->ToObject();
4549

46-
Local<Value> listeners_v = events->Get(String::NewSymbol(type));
50+
Local<Value> listeners_v = events->Get(event);
4751
if (!listeners_v->IsArray()) return false;
4852
Local<Array> listeners = Local<Array>::Cast(listeners_v);
4953

50-
TryCatch try_catch;
54+
for (unsigned int i = 0; i < listeners->Length(); i++) {
55+
HandleScope scope;
5156

52-
for (int i = 0; i < listeners->Length(); i++) {
5357
Local<Value> listener_v = listeners->Get(Integer::New(i));
5458
if (!listener_v->IsFunction()) continue;
5559
Local<Function> listener = Local<Function>::Cast(listener_v);
5660

57-
listener->Call(handle_, argc, argv);
61+
TryCatch try_catch;
62+
63+
listener->Call(self, argc, argv);
5864

5965
if (try_catch.HasCaught()) {
6066
FatalException(try_catch);
@@ -65,6 +71,36 @@ EventEmitter::Emit (const char *type, int argc, Handle<Value> argv[])
6571
return true;
6672
}
6773

74+
Handle<Value>
75+
EventEmitter::Emit (const Arguments& args)
76+
{
77+
HandleScope scope;
78+
Local<String> event = args[0]->ToString();
79+
int argc = 0;
80+
Local<Array> emit_args;
81+
if (args[1]->IsArray()) {
82+
emit_args = Local<Array>::Cast(args[1]);
83+
argc = emit_args->Length();
84+
}
85+
Local<Value> argv[argc];
86+
87+
for (int i = 0; i < argc; i++) {
88+
argv[i] = emit_args->Get(Integer::New(i));
89+
}
90+
91+
bool r = ReallyEmit(args.Holder(), event, argc, argv);
92+
93+
return scope.Close(r ? True() : False());
94+
}
95+
96+
bool
97+
EventEmitter::Emit (const char *event_s, int argc, Handle<Value> argv[])
98+
{
99+
HandleScope scope;
100+
Local<String> event = String::NewSymbol(event_s);
101+
return ReallyEmit(handle_, event, argc, argv);
102+
}
103+
68104
Persistent<FunctionTemplate> Promise::constructor_template;
69105

70106
void

src/events.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ class EventEmitter : public ObjectWrap {
1111
static void Initialize (v8::Handle<v8::Object> target);
1212
static v8::Persistent<v8::FunctionTemplate> constructor_template;
1313

14-
bool Emit (const char *type, int argc, v8::Handle<v8::Value> argv[]);
14+
bool Emit (const char *event, int argc, v8::Handle<v8::Value> argv[]);
1515

1616
protected:
17-
EventEmitter () : ObjectWrap() { }
17+
static v8::Handle<v8::Value> Emit (const v8::Arguments& args);
18+
19+
EventEmitter () : ObjectWrap () { }
1820
};
1921

2022
class Promise : public EventEmitter {

src/events.js

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,21 @@
11
(function () {
22

33
// node.EventEmitter is defined in src/events.cc
4-
var emitter = node.EventEmitter.prototype;
5-
6-
emitter.addListener = function (type, listener) {
4+
// node.EventEmitter.prototype.emit() is also defined there.
5+
node.EventEmitter.prototype.addListener = function (type, listener) {
76
if (listener instanceof Function) {
87
if (!this._events) this._events = {};
98
if (!this._events.hasOwnProperty(type)) this._events[type] = [];
109
this._events[type].push(listener);
1110
}
1211
};
1312

14-
emitter.listeners = function (type) {
13+
node.EventEmitter.prototype.listeners = function (type) {
1514
if (!this._events) this._events = {};
1615
if (!this._events.hasOwnProperty(type)) this._events[type] = [];
1716
return this._events[type];
1817
};
1918

20-
// This function is called often from C++.
21-
// FIXME there is a counterpart for this function in C++
22-
// both must have the same behavior.
23-
// See events.cc
24-
emitter.emit = function (type, args) {
25-
if (!this._events) return;
26-
if (!this._events.hasOwnProperty(type)) return;
27-
28-
var listeners = this._events[type];
29-
30-
for (var i = 0; i < listeners.length; i++) {
31-
listeners[i].apply(this, args);
32-
}
33-
};
34-
3519
// node.Promise is defined in src/events.cc
3620
var promise = node.Promise.prototype;
3721

0 commit comments

Comments
 (0)