From 1449739de00859d44a2eff9a676172fdabbfcd60 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 9 Aug 2013 04:48:10 +0200 Subject: [PATCH] dgram: don't call into js when send cb is omitted Speed up dgram.Socket#send()-heavy code a little by omitting the call into JS land when the user doesn't pass us a completion callback. --- lib/dgram.js | 29 ++++++++++++++++++----------- src/udp_wrap.cc | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/lib/dgram.js b/lib/dgram.js index f5a2ae21a7..502537f796 100644 --- a/lib/dgram.js +++ b/lib/dgram.js @@ -36,11 +36,6 @@ var net = null; var errnoException = util._errnoException; -// no-op callback -function noop() { -} - - function isIP(address) { if (!net) net = require('net'); @@ -272,7 +267,10 @@ Socket.prototype.send = function(buffer, if (port <= 0 || port > 65535) throw new RangeError('Port should be > 0 and < 65536'); - callback = callback || noop; + // Normalize callback so it's either a function or undefined but not anything + // else. + if (!util.isFunction(callback)) + callback = undefined; self._healthCheck(); @@ -303,9 +301,19 @@ Socket.prototype.send = function(buffer, self.emit('error', ex); } else if (self._handle) { - var req = { cb: callback, oncomplete: afterSend }; - var err = self._handle.send(req, buffer, offset, length, port, ip); - if (err) { + var req = {}; + if (callback) { + req.callback = callback; + req.oncomplete = afterSend; + } + var err = self._handle.send(req, + buffer, + offset, + length, + port, + ip, + !!callback); + if (err && callback) { // don't emit as error, dgram_legacy.js compatibility process.nextTick(function() { callback(errnoException(err, 'send')); @@ -317,8 +325,7 @@ Socket.prototype.send = function(buffer, function afterSend(err) { - if (this.cb) - this.cb(err ? errnoException(err, 'send') : null); + this.callback(err ? errnoException(err, 'send') : null); } diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 5577f7a85b..345cf58421 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -46,7 +46,15 @@ using v8::Uint32; using v8::Undefined; using v8::Value; -typedef ReqWrap SendWrap; + +class SendWrap : public ReqWrap { + public: + SendWrap(Local req_wrap_obj, bool have_callback); + inline bool have_callback() const; + private: + const bool have_callback_; +}; + static Persistent constructor; static Cached buffer_sym; @@ -54,6 +62,17 @@ static Cached oncomplete_sym; static Cached onmessage_sym; +SendWrap::SendWrap(Local req_wrap_obj, bool have_callback) + : ReqWrap(req_wrap_obj) + , have_callback_(have_callback) { +} + + +inline bool SendWrap::have_callback() const { + return have_callback_; +} + + UDPWrap::UDPWrap(Handle object) : HandleWrap(object, reinterpret_cast(&handle_)) { int r = uv_udp_init(uv_default_loop(), &handle_); @@ -228,6 +247,7 @@ void UDPWrap::DoSend(const FunctionCallbackInfo& args, int family) { assert(args[3]->IsUint32()); assert(args[4]->IsUint32()); assert(args[5]->IsString()); + assert(args[6]->IsBoolean()); Local req_wrap_obj = args[0].As(); Local buffer_obj = args[1].As(); @@ -235,11 +255,12 @@ void UDPWrap::DoSend(const FunctionCallbackInfo& args, int family) { size_t length = args[3]->Uint32Value(); const unsigned short port = args[4]->Uint32Value(); String::Utf8Value address(args[5]); + const bool have_callback = args[6]->IsTrue(); assert(offset < Buffer::Length(buffer_obj)); assert(length <= Buffer::Length(buffer_obj) - offset); - SendWrap* req_wrap = new SendWrap(req_wrap_obj); + SendWrap* req_wrap = new SendWrap(req_wrap_obj, have_callback); req_wrap->object()->SetHiddenValue(buffer_sym, buffer_obj); uv_buf_t buf = uv_buf_init(Buffer::Data(buffer_obj) + offset, @@ -328,19 +349,13 @@ void UDPWrap::GetSockName(const FunctionCallbackInfo& args) { // TODO(bnoordhuis) share with StreamWrap::AfterWrite() in stream_wrap.cc void UDPWrap::OnSend(uv_udp_send_t* req, int status) { - HandleScope scope(node_isolate); - - assert(req != NULL); - SendWrap* req_wrap = static_cast(req->data); - UDPWrap* wrap = static_cast(req->handle->data); - - assert(req_wrap->persistent().IsEmpty() == false); - assert(wrap->persistent().IsEmpty() == false); - - Local req_wrap_obj = req_wrap->object(); - Local arg = Integer::New(status, node_isolate); - MakeCallback(req_wrap_obj, oncomplete_sym, 1, &arg); + if (req_wrap->have_callback()) { + HandleScope scope(node_isolate); + Local req_wrap_obj = req_wrap->object(); + Local arg = Integer::New(status, node_isolate); + MakeCallback(req_wrap_obj, oncomplete_sym, 1, &arg); + } delete req_wrap; }