Permalink
Browse files

Speed impact of node::MakeCallback

This is first attempt towards the performance discussion in the mailing thread
https://groups.google.com/group/nodejs-dev/browse_thread/thread/ea4451616ff9314d?hl=en
  • Loading branch information...
1 parent 78eb174 commit b6a3e243b103550a8de792d7e280a706d0a48c4e Sambasiva Suda committed Apr 9, 2012
Showing with 127 additions and 27 deletions.
  1. +1 −1 src/fs_event_wrap.cc
  2. +15 −0 src/handle_wrap.cc
  3. +43 −0 src/handle_wrap.h
  4. +19 −1 src/node.cc
  5. +4 −1 src/node.h
  6. +1 −10 src/node_file.cc
  7. +2 −2 src/pipe_wrap.cc
  8. +1 −1 src/process_wrap.cc
  9. +31 −1 src/req_wrap.h
  10. +4 −4 src/stream_wrap.cc
  11. +2 −2 src/tcp_wrap.cc
  12. +1 −1 src/timer_wrap.cc
  13. +3 −3 src/udp_wrap.cc
View
@@ -165,7 +165,7 @@ void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
filename ? (Local<Value>)String::New(filename) : Local<Value>::New(v8::Null())
};
- MakeCallback(wrap->object_, "onchange", 3, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONCHANGE], 3, argv);
}
View
@@ -51,6 +51,11 @@ using v8::Integer;
return scope.Close(Integer::New(-1)); \
}
+#define X(a, b) b,
+const char *HandleWrap::callbackNames[CALLBACK_COUNT + 1] = {
+ CALLBACK_TABLE
+};
+#undef X
void HandleWrap::Initialize(Handle<Object> target) {
/* Doesn't do anything at the moment. */
@@ -125,6 +130,13 @@ HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
assert(object->InternalFieldCount() > 0);
object_ = v8::Persistent<v8::Object>::New(object);
object_->SetPointerInInternalField(0, this);
+
+ object_->SetAccessor(String::New(callbackNames[ONCONNECTION]), Getter<ONCONNECTION>, Setter<ONCONNECTION>);
+ object_->SetAccessor(String::New(callbackNames[ONREAD]), Getter<ONREAD>, Setter<ONREAD>);
+ object_->SetAccessor(String::New(callbackNames[ONMESSAGE]), Getter<ONMESSAGE>, Setter<ONMESSAGE>);
+ object_->SetAccessor(String::New(callbackNames[ONTIMEOUT]), Getter<ONTIMEOUT>, Setter<ONTIMEOUT>);
+ object_->SetAccessor(String::New(callbackNames[ONEXIT]), Getter<ONEXIT>, Setter<ONEXIT>);
+ object_->SetAccessor(String::New(callbackNames[ONCHANGE]), Getter<ONCHANGE>, Setter<ONCHANGE>);
}
@@ -152,6 +164,9 @@ void HandleWrap::OnClose(uv_handle_t* handle) {
wrap->object_.Dispose();
wrap->object_.Clear();
+ for (int i = 0; i < CALLBACK_COUNT; ++i ) {
+ wrap->callbacks_[i].Dispose();
+ }
delete wrap;
}
View
@@ -43,6 +43,21 @@ namespace node {
// - uv_ref, uv_unref counts are managed at this layer to avoid needless
// js/c++ boundary crossing. At the javascript layer that should all be
// taken care of.
+//
+#define CALLBACK_TABLE \
+ X(ONCONNECTION, "onconnection") \
+ X(ONREAD, "onread") \
+ X(ONMESSAGE, "onmessage") \
+ X(ONTIMEOUT, "ontimeout") \
+ X(ONEXIT, "onexit") \
+ X(ONCHANGE, "onchange") \
+ X(CALLBACK_COUNT, NULL)
+
+#define X(a, b) a,
+ enum CALLBACKS {
+ CALLBACK_TABLE
+ };
+#undef X
class HandleWrap {
public:
@@ -59,8 +74,36 @@ class HandleWrap {
virtual void StateChange() {}
v8::Persistent<v8::Object> object_;
+ v8::Persistent<v8::Function> callbacks_[CALLBACK_COUNT];
private:
+
+ static const char *callbackNames[CALLBACK_COUNT + 1];
+
+ template<int index>
+ static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info) {
+ v8::Local<v8::Object> self = info.Holder();
+ HandleWrap* ptr = static_cast<HandleWrap*>(self->GetPointerFromInternalField(0));
+ if (ptr) {
+ return ptr->callbacks_[index];
+ }
+
+ return v8::Null();
+ }
+
+ template<int index>
+ static void Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info) {
+ v8::Local<v8::Object> self = info.Holder();
+ HandleWrap* ptr = static_cast<HandleWrap*>(self->GetPointerFromInternalField(0));
+
+ if (ptr) {
+ ptr->callbacks_[index] = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(value));
+ }
+ }
+
+
static void OnClose(uv_handle_t* handle);
// Using double underscore due to handle_ member in tcp_wrap. Probably
// tcp_wrap should rename it's member to 'handle'.
View
@@ -972,7 +972,7 @@ Handle<Value> FromConstructorTemplate(Persistent<FunctionTemplate>& t,
//
// Maybe make this a method of a node::Handle super class
//
-void MakeCallback(Handle<Object> object,
+void MakeCallback(const Handle<Object>& object,
const char* method,
int argc,
Handle<Value> argv[]) {
@@ -996,6 +996,24 @@ void MakeCallback(Handle<Object> object,
}
}
+void MakeCallback(const Handle<Object>& object,
+ const Handle<Function>& callback,
+ int argc,
+ Handle<Value> argv[]) {
+ HandleScope scope;
+
+ // TODO Hook for long stack traces to be made here.
+
+ TryCatch try_catch;
+
+ callback->Call(object, argc, argv);
+
+ if (try_catch.HasCaught()) {
+ FatalException(try_catch);
+ }
+}
+
+
void SetErrno(uv_err_t err) {
HandleScope scope;
View
@@ -243,10 +243,13 @@ node_module_struct* get_builtin_module(const char *name);
extern "C" node::node_module_struct modname ## _module;
NODE_EXTERN void SetErrno(uv_err_t err);
-NODE_EXTERN void MakeCallback(v8::Handle<v8::Object> object,
+NODE_EXTERN void MakeCallback(const v8::Handle<v8::Object>& object,
const char* method,
int argc,
v8::Handle<v8::Value> argv[]);
+NODE_EXTERN void MakeCallback(const v8::Handle<v8::Object> &object, const v8::Handle<v8::Function>& func,
+ int argc,
+ v8::Handle<v8::Value> argv[]);
} // namespace node
#endif // SRC_NODE_H_
View
@@ -82,9 +82,6 @@ static void After(uv_fs_t *req) {
FSReqWrap* req_wrap = (FSReqWrap*) req->data;
assert(&req_wrap->req_ == req);
- Local<Value> callback_v = req_wrap->object_->Get(oncomplete_sym);
- assert(callback_v->IsFunction());
- Local<Function> callback = Local<Function>::Cast(callback_v);
// there is always at least one argument. "error"
int argc = 1;
@@ -196,13 +193,7 @@ static void After(uv_fs_t *req) {
}
}
- TryCatch try_catch;
-
- callback->Call(req_wrap->object_, argc, argv);
-
- if (try_catch.HasCaught()) {
- FatalException(try_catch);
- }
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, argc, argv);
uv_fs_req_cleanup(&req_wrap->req_);
delete req_wrap;
View
@@ -215,7 +215,7 @@ void PipeWrap::OnConnection(uv_stream_t* handle, int status) {
// Successful accept. Call the onconnection callback in JavaScript land.
Local<Value> argv[1] = { client_obj };
- MakeCallback(wrap->object_, "onconnection", 1, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONCONNECTION], 1, argv);
}
// TODO Maybe share this with TCPWrap?
@@ -247,7 +247,7 @@ void PipeWrap::AfterConnect(uv_connect_t* req, int status) {
Local<Value>::New(Boolean::New(writable))
};
- MakeCallback(req_wrap->object_, "oncomplete", 5, argv);
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, 5, argv);
delete req_wrap;
}
View
@@ -223,7 +223,7 @@ class ProcessWrap : public HandleWrap {
String::New(signo_string(term_signal))
};
- MakeCallback(wrap->object_, "onexit", 2, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONEXIT], 2, argv);
}
uv_process_t process_;
View
@@ -29,15 +29,21 @@ class ReqWrap {
public:
ReqWrap() {
v8::HandleScope scope;
- object_ = v8::Persistent<v8::Object>::New(v8::Object::New());
+ v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
+ templ->SetInternalFieldCount(1);
+ templ->SetAccessor(v8::String::New("oncomplete"), OnCompleteGetter, OnCompleteSetter);
+ object_ = v8::Persistent<v8::Object>::New(templ->NewInstance());
+ object_->SetPointerInInternalField(0, this);
}
~ReqWrap() {
// Assert that someone has called Dispatched()
assert(req_.data == this);
assert(!object_.IsEmpty());
+ object_->SetPointerInInternalField(0, NULL);
object_.Dispose();
object_.Clear();
+ oncomplete_.Dispose();
}
// Call this after the req has been dispatched.
@@ -46,8 +52,32 @@ class ReqWrap {
}
v8::Persistent<v8::Object> object_;
+ v8::Persistent<v8::Function> oncomplete_;
T req_;
void* data_;
+
+ private:
+ static v8::Handle<v8::Value> OnCompleteGetter(v8::Local<v8::String> property,
+ const v8::AccessorInfo& info) {
+ v8::Local<v8::Object> self = info.Holder();
+ ReqWrap* ptr = static_cast<ReqWrap*>(self->GetPointerFromInternalField(0));
+ if (ptr) {
+ return ptr->oncomplete_;
+ }
+
+ return v8::Null();
+ }
+
+ static void OnCompleteSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value,
+ const v8::AccessorInfo& info) {
+ v8::Local<v8::Object> self = info.Holder();
+ ReqWrap* ptr = static_cast<ReqWrap*>(self->GetPointerFromInternalField(0));
+
+ if (ptr) {
+ ptr->oncomplete_ = v8::Persistent<v8::Function>::New(v8::Handle<v8::Function>::Cast(value));
+ }
+ }
+
};
View
@@ -168,7 +168,7 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
if (nread < 0) {
SetErrno(uv_last_error(uv_default_loop()));
- MakeCallback(wrap->object_, "onread", 0, NULL);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONREAD], 0, NULL);
return;
}
@@ -201,7 +201,7 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
argc++;
}
- MakeCallback(wrap->object_, "onread", argc, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONREAD], argc, argv);
}
@@ -306,7 +306,7 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
req_wrap->object_->GetHiddenValue(buffer_sym),
};
- MakeCallback(req_wrap->object_, "oncomplete", 4, argv);
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, 4, argv);
delete req_wrap;
}
@@ -353,7 +353,7 @@ void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
Local<Value>::New(req_wrap->object_)
};
- MakeCallback(req_wrap->object_, "oncomplete", 3, argv);
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, 3, argv);
delete req_wrap;
}
View
@@ -376,7 +376,7 @@ void TCPWrap::OnConnection(uv_stream_t* handle, int status) {
argv[0] = Local<Value>::New(Null());
}
- MakeCallback(wrap->object_, "onconnection", 1, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONCONNECTION], 1, argv);
}
@@ -402,7 +402,7 @@ void TCPWrap::AfterConnect(uv_connect_t* req, int status) {
Local<Value>::New(v8::True())
};
- MakeCallback(req_wrap->object_, "oncomplete", 5, argv);
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, 5, argv);
delete req_wrap;
}
View
@@ -200,7 +200,7 @@ class TimerWrap : public HandleWrap {
wrap->StateChange();
Local<Value> argv[1] = { Integer::New(status) };
- MakeCallback(wrap->object_, "ontimeout", 1, argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONTIMEOUT], 1, argv);
}
uv_timer_t handle_;
View
@@ -394,7 +394,7 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
req_wrap->object_->GetHiddenValue(buffer_sym),
};
- MakeCallback(req_wrap->object_, "oncomplete", 4, argv);
+ MakeCallback(req_wrap->object_, req_wrap->oncomplete_, 4, argv);
delete req_wrap;
}
@@ -422,7 +422,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
if (nread < 0) {
Local<Value> argv[] = { Local<Object>::New(wrap->object_) };
SetErrno(uv_last_error(uv_default_loop()));
- MakeCallback(wrap->object_, "onmessage", ARRAY_SIZE(argv), argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONMESSAGE], ARRAY_SIZE(argv), argv);
return;
}
@@ -433,7 +433,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
Integer::NewFromUnsigned(nread),
AddressToJS(addr)
};
- MakeCallback(wrap->object_, "onmessage", ARRAY_SIZE(argv), argv);
+ MakeCallback(wrap->object_, wrap->callbacks_[ONMESSAGE], ARRAY_SIZE(argv), argv);
}

0 comments on commit b6a3e24

Please sign in to comment.