Browse Source

src: replace CONTAINER_OF with type-safe function

Replace the CONTAINER_OF macro with a template function that is as
type-safe as a reinterpret_cast<> of an arbitrary pointer can be made.

Signed-off-by: Fedor Indutny <fedor@indutny.com>
archived-io.js-v0.10
Ben Noordhuis 11 years ago
committed by Fedor Indutny
parent
commit
820aaf5b3d
  1. 5
      src/cares_wrap.cc
  2. 8
      src/env-inl.h
  3. 4
      src/node.cc
  4. 16
      src/node_crypto.cc
  5. 4
      src/node_http_parser.cc
  6. 2
      src/node_v8.cc
  7. 4
      src/node_zlib.cc
  8. 2
      src/signal_wrap.cc
  9. 2
      src/stream_wrap.cc
  10. 4
      src/tls_wrap.cc
  11. 20
      src/util-inl.h
  12. 24
      src/util.h

5
src/cares_wrap.cc

@ -88,7 +88,7 @@ static void ares_timeout(uv_timer_t* handle) {
static void ares_poll_cb(uv_poll_t* watcher, int status, int events) { static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher); ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher, watcher);
Environment* env = task->env; Environment* env = task->env;
/* Reset the idle timer */ /* Reset the idle timer */
@ -109,7 +109,8 @@ static void ares_poll_cb(uv_poll_t* watcher, int status, int events) {
static void ares_poll_close_cb(uv_handle_t* watcher) { static void ares_poll_close_cb(uv_handle_t* watcher) {
ares_task_t* task = CONTAINER_OF(watcher, ares_task_t, poll_watcher); ares_task_t* task = ContainerOf(&ares_task_t::poll_watcher,
reinterpret_cast<uv_poll_t*>(watcher));
free(task); free(task);
} }

8
src/env-inl.h

@ -276,7 +276,7 @@ inline bool Environment::in_domain() const {
inline Environment* Environment::from_immediate_check_handle( inline Environment* Environment::from_immediate_check_handle(
uv_check_t* handle) { uv_check_t* handle) {
return CONTAINER_OF(handle, Environment, immediate_check_handle_); return ContainerOf(&Environment::immediate_check_handle_, handle);
} }
inline uv_check_t* Environment::immediate_check_handle() { inline uv_check_t* Environment::immediate_check_handle() {
@ -289,7 +289,7 @@ inline uv_idle_t* Environment::immediate_idle_handle() {
inline Environment* Environment::from_idle_prepare_handle( inline Environment* Environment::from_idle_prepare_handle(
uv_prepare_t* handle) { uv_prepare_t* handle) {
return CONTAINER_OF(handle, Environment, idle_prepare_handle_); return ContainerOf(&Environment::idle_prepare_handle_, handle);
} }
inline uv_prepare_t* Environment::idle_prepare_handle() { inline uv_prepare_t* Environment::idle_prepare_handle() {
@ -297,7 +297,7 @@ inline uv_prepare_t* Environment::idle_prepare_handle() {
} }
inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) { inline Environment* Environment::from_idle_check_handle(uv_check_t* handle) {
return CONTAINER_OF(handle, Environment, idle_check_handle_); return ContainerOf(&Environment::idle_check_handle_, handle);
} }
inline uv_check_t* Environment::idle_check_handle() { inline uv_check_t* Environment::idle_check_handle() {
@ -345,7 +345,7 @@ inline void Environment::set_printed_error(bool value) {
} }
inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) { inline Environment* Environment::from_cares_timer_handle(uv_timer_t* handle) {
return CONTAINER_OF(handle, Environment, cares_timer_handle_); return ContainerOf(&Environment::cares_timer_handle_, handle);
} }
inline uv_timer_t* Environment::cares_timer_handle() { inline uv_timer_t* Environment::cares_timer_handle() {

4
src/node.cc

@ -1523,7 +1523,7 @@ static void GetActiveRequests(const FunctionCallbackInfo<Value>& args) {
int i = 0; int i = 0;
QUEUE_FOREACH(q, &req_wrap_queue) { QUEUE_FOREACH(q, &req_wrap_queue) {
ReqWrap<uv_req_t>* w = CONTAINER_OF(q, ReqWrap<uv_req_t>, req_wrap_queue_); ReqWrap<uv_req_t>* w = ContainerOf(&ReqWrap<uv_req_t>::req_wrap_queue_, q);
if (w->persistent().IsEmpty()) if (w->persistent().IsEmpty())
continue; continue;
ary->Set(i++, w->object()); ary->Set(i++, w->object());
@ -1546,7 +1546,7 @@ void GetActiveHandles(const FunctionCallbackInfo<Value>& args) {
Local<String> owner_sym = env->owner_string(); Local<String> owner_sym = env->owner_string();
QUEUE_FOREACH(q, &handle_wrap_queue) { QUEUE_FOREACH(q, &handle_wrap_queue) {
HandleWrap* w = CONTAINER_OF(q, HandleWrap, handle_wrap_queue_); HandleWrap* w = ContainerOf(&HandleWrap::handle_wrap_queue_, q);
if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref)) if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref))
continue; continue;
Local<Object> object = w->object(); Local<Object> object = w->object();

16
src/node_crypto.cc

@ -4027,7 +4027,6 @@ class PBKDF2Request : public AsyncWrap {
error_ = err; error_ = err;
} }
// TODO(trevnorris): Make private and make work with CONTAINER_OF macro.
uv_work_t work_req_; uv_work_t work_req_;
private: private:
@ -4059,7 +4058,7 @@ void EIO_PBKDF2(PBKDF2Request* req) {
void EIO_PBKDF2(uv_work_t* work_req) { void EIO_PBKDF2(uv_work_t* work_req) {
PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_); PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req);
EIO_PBKDF2(req); EIO_PBKDF2(req);
} }
@ -4078,7 +4077,7 @@ void EIO_PBKDF2After(PBKDF2Request* req, Local<Value> argv[2]) {
void EIO_PBKDF2After(uv_work_t* work_req, int status) { void EIO_PBKDF2After(uv_work_t* work_req, int status) {
assert(status == 0); assert(status == 0);
PBKDF2Request* req = CONTAINER_OF(work_req, PBKDF2Request, work_req_); PBKDF2Request* req = ContainerOf(&PBKDF2Request::work_req_, work_req);
Environment* env = req->env(); Environment* env = req->env();
HandleScope handle_scope(env->isolate()); HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context()); Context::Scope context_scope(env->context());
@ -4257,7 +4256,6 @@ class RandomBytesRequest : public AsyncWrap {
error_ = err; error_ = err;
} }
// TODO(trevnorris): Make private and make work with CONTAINER_OF macro.
uv_work_t work_req_; uv_work_t work_req_;
private: private:
@ -4269,9 +4267,8 @@ class RandomBytesRequest : public AsyncWrap {
template <bool pseudoRandom> template <bool pseudoRandom>
void RandomBytesWork(uv_work_t* work_req) { void RandomBytesWork(uv_work_t* work_req) {
RandomBytesRequest* req = CONTAINER_OF(work_req, RandomBytesRequest* req =
RandomBytesRequest, ContainerOf(&RandomBytesRequest::work_req_, work_req);
work_req_);
int r; int r;
// Ensure that OpenSSL's PRNG is properly seeded. // Ensure that OpenSSL's PRNG is properly seeded.
@ -4317,9 +4314,8 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
void RandomBytesAfter(uv_work_t* work_req, int status) { void RandomBytesAfter(uv_work_t* work_req, int status) {
assert(status == 0); assert(status == 0);
RandomBytesRequest* req = CONTAINER_OF(work_req, RandomBytesRequest* req =
RandomBytesRequest, ContainerOf(&RandomBytesRequest::work_req_, work_req);
work_req_);
Environment* env = req->env(); Environment* env = req->env();
HandleScope handle_scope(env->isolate()); HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context()); Context::Scope context_scope(env->context());

4
src/node_http_parser.cc

@ -77,7 +77,7 @@ const uint32_t kOnMessageComplete = 3;
#define HTTP_CB(name) \ #define HTTP_CB(name) \
static int name(http_parser* p_) { \ static int name(http_parser* p_) { \
Parser* self = CONTAINER_OF(p_, Parser, parser_); \ Parser* self = ContainerOf(&Parser::parser_, p_); \
return self->name##_(); \ return self->name##_(); \
} \ } \
int name##_() int name##_()
@ -85,7 +85,7 @@ const uint32_t kOnMessageComplete = 3;
#define HTTP_DATA_CB(name) \ #define HTTP_DATA_CB(name) \
static int name(http_parser* p_, const char* at, size_t length) { \ static int name(http_parser* p_, const char* at, size_t length) { \
Parser* self = CONTAINER_OF(p_, Parser, parser_); \ Parser* self = ContainerOf(&Parser::parser_, p_); \
return self->name##_(at, length); \ return self->name##_(at, length); \
} \ } \
int name##_(const char* at, size_t length) int name##_(const char* at, size_t length)

2
src/node_v8.cc

@ -83,7 +83,7 @@ void Environment::IsolateData::AfterGarbageCollection(GCType type,
q = QUEUE_HEAD(&queue); q = QUEUE_HEAD(&queue);
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
QUEUE_INSERT_TAIL(&gc_tracker_queue_, q); QUEUE_INSERT_TAIL(&gc_tracker_queue_, q);
Environment* env = CONTAINER_OF(q, Environment, gc_tracker_queue_); Environment* env = ContainerOf(&Environment::gc_tracker_queue_, q);
env->AfterGarbageCollectionCallback(&gc_info_before_, &gc_info_after_); env->AfterGarbageCollectionCallback(&gc_info_before_, &gc_info_after_);
} }
} }

4
src/node_zlib.cc

@ -246,7 +246,7 @@ class ZCtx : public AsyncWrap {
// for a single write() call, until all of the input bytes have // for a single write() call, until all of the input bytes have
// been consumed. // been consumed.
static void Process(uv_work_t* work_req) { static void Process(uv_work_t* work_req) {
ZCtx *ctx = CONTAINER_OF(work_req, ZCtx, work_req_); ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
// If the avail_out is left at 0, then it means that it ran out // If the avail_out is left at 0, then it means that it ran out
// of room. If there was avail_out left over, then it means // of room. If there was avail_out left over, then it means
@ -320,7 +320,7 @@ class ZCtx : public AsyncWrap {
static void After(uv_work_t* work_req, int status) { static void After(uv_work_t* work_req, int status) {
assert(status == 0); assert(status == 0);
ZCtx* ctx = CONTAINER_OF(work_req, ZCtx, work_req_); ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
Environment* env = ctx->env(); Environment* env = ctx->env();
HandleScope handle_scope(env->isolate()); HandleScope handle_scope(env->isolate());

2
src/signal_wrap.cc

@ -105,7 +105,7 @@ class SignalWrap : public HandleWrap {
} }
static void OnSignal(uv_signal_t* handle, int signum) { static void OnSignal(uv_signal_t* handle, int signum) {
SignalWrap* wrap = CONTAINER_OF(handle, SignalWrap, handle_); SignalWrap* wrap = ContainerOf(&SignalWrap::handle_, handle);
Environment* env = wrap->env(); Environment* env = wrap->env();
HandleScope handle_scope(env->isolate()); HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context()); Context::Scope context_scope(env->context());

2
src/stream_wrap.cc

@ -510,7 +510,7 @@ void StreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
} }
void StreamWrap::AfterWrite(uv_write_t* req, int status) { void StreamWrap::AfterWrite(uv_write_t* req, int status) {
WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_); WriteWrap* req_wrap = ContainerOf(&WriteWrap::req_, req);
StreamWrap* wrap = req_wrap->wrap(); StreamWrap* wrap = req_wrap->wrap();
Environment* env = wrap->env(); Environment* env = wrap->env();

4
src/tls_wrap.cc

@ -114,7 +114,7 @@ TLSCallbacks::~TLSCallbacks() {
QUEUE* q = QUEUE_HEAD(&pending_write_items_); QUEUE* q = QUEUE_HEAD(&pending_write_items_);
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
WriteItem* wi = QUEUE_DATA(q, WriteItem, member_); WriteItem* wi = ContainerOf(&WriteItem::member_, q);
delete wi; delete wi;
} }
} }
@ -145,7 +145,7 @@ bool TLSCallbacks::InvokeQueued(int status) {
QUEUE* q = QUEUE_HEAD(&pending_write_items_); QUEUE* q = QUEUE_HEAD(&pending_write_items_);
QUEUE_REMOVE(q); QUEUE_REMOVE(q);
WriteItem* wi = QUEUE_DATA(q, WriteItem, member_); WriteItem* wi = ContainerOf(&WriteItem::member_, q);
wi->cb_(&wi->w_->req_, status); wi->cb_(&wi->w_->req_, status);
delete wi; delete wi;
} }

20
src/util-inl.h

@ -28,6 +28,26 @@
namespace node { namespace node {
template <typename Inner, typename Outer>
ContainerOfHelper<Inner, Outer>::ContainerOfHelper(Inner Outer::*field,
Inner* pointer)
: pointer_(reinterpret_cast<Outer*>(
reinterpret_cast<uintptr_t>(pointer) -
reinterpret_cast<uintptr_t>(&(static_cast<Outer*>(0)->*field)))) {
}
template <typename Inner, typename Outer>
template <typename TypeName>
ContainerOfHelper<Inner, Outer>::operator TypeName*() const {
return static_cast<TypeName*>(pointer_);
}
template <typename Inner, typename Outer>
inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
Inner* pointer) {
return ContainerOfHelper<Inner, Outer>(field, pointer);
}
template <class TypeName> template <class TypeName>
inline v8::Local<TypeName> PersistentToLocal( inline v8::Local<TypeName> PersistentToLocal(
v8::Isolate* isolate, v8::Isolate* isolate,

24
src/util.h

@ -29,13 +29,6 @@
namespace node { namespace node {
#define OFFSET_OF(TypeName, Field) \
(reinterpret_cast<uintptr_t>(&(reinterpret_cast<TypeName*>(8)->Field)) - 8)
#define CONTAINER_OF(Pointer, TypeName, Field) \
reinterpret_cast<TypeName*>( \
reinterpret_cast<uintptr_t>(Pointer) - OFFSET_OF(TypeName, Field))
#define FIXED_ONE_BYTE_STRING(isolate, string) \ #define FIXED_ONE_BYTE_STRING(isolate, string) \
(node::OneByteString((isolate), (string), sizeof(string) - 1)) (node::OneByteString((isolate), (string), sizeof(string) - 1))
@ -63,6 +56,23 @@ namespace node {
#define UNREACHABLE() abort() #define UNREACHABLE() abort()
// The helper is for doing safe downcasts from base types to derived types.
template <typename Inner, typename Outer>
class ContainerOfHelper {
public:
inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
template <typename TypeName>
inline operator TypeName*() const;
private:
Outer* const pointer_;
};
// Calculate the address of the outer (i.e. embedding) struct from
// the interior pointer to a data member.
template <typename Inner, typename Outer>
inline ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
Inner* pointer);
// If persistent.IsWeak() == false, then do not call persistent.Reset() // If persistent.IsWeak() == false, then do not call persistent.Reset()
// while the returned Local<T> is still in scope, it will destroy the // while the returned Local<T> is still in scope, it will destroy the
// reference to the object. // reference to the object.

Loading…
Cancel
Save