Skip to content

Commit

Permalink
async-wrap: add provider id and object info cb
Browse files Browse the repository at this point in the history
Re-add the wrapper class id to AsyncWrap instances so they can be
tracked directly in a heapdump.

Previously the class id was given without setting the heap dump wrapper
class info provider. Causing a segfault when a heapdump was taken. This
has been added, and the label_ set to the given provider name so each
instance can be identified.

The id will not be set of the passed object has no internal field count.
As the class pointer cannot be retrieved from the object.

In order to properly report the allocated size of each class, the new
pure virtual method self_size() has been introduces.

PR-URL: #1896
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
  • Loading branch information
trevnorris committed Jun 17, 2015
1 parent 5d0cee4 commit e56758a
Show file tree
Hide file tree
Showing 25 changed files with 175 additions and 5 deletions.
5 changes: 5 additions & 0 deletions src/async-wrap-inl.h
Expand Up @@ -18,6 +18,11 @@ inline AsyncWrap::AsyncWrap(Environment* env,
ProviderType provider,
AsyncWrap* parent)
: BaseObject(env, object), bits_(static_cast<uint32_t>(provider) << 1) {
// Only set wrapper class id if object will be Wrap'd.
if (object->InternalFieldCount() > 0)
// Shift provider value over to prevent id collision.
persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider);

// Check user controlled flag to see if the init callback should run.
if (!env->using_asyncwrap())
return;
Expand Down
90 changes: 90 additions & 0 deletions src/async-wrap.cc
Expand Up @@ -6,23 +6,103 @@
#include "util-inl.h"

#include "v8.h"
#include "v8-profiler.h"

using v8::Array;
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Handle;
using v8::HandleScope;
using v8::HeapProfiler;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::RetainedObjectInfo;
using v8::TryCatch;
using v8::Value;
using v8::kExternalUint32Array;

namespace node {

static const char* const provider_names[] = {
#define V(PROVIDER) \
#PROVIDER,
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V
};


class RetainedAsyncInfo: public RetainedObjectInfo {
public:
explicit RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap);

virtual void Dispose() override;
virtual bool IsEquivalent(RetainedObjectInfo* other) override;
virtual intptr_t GetHash() override;
virtual const char* GetLabel() override;
virtual intptr_t GetSizeInBytes() override;

private:
const char* label_;
const AsyncWrap* wrap_;
const int length_;
};


RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap)
: label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]),
wrap_(wrap),
length_(wrap->self_size()) {
}


void RetainedAsyncInfo::Dispose() {
delete this;
}


bool RetainedAsyncInfo::IsEquivalent(RetainedObjectInfo* other) {
return label_ == other->GetLabel() &&
wrap_ == static_cast<RetainedAsyncInfo*>(other)->wrap_;
}


intptr_t RetainedAsyncInfo::GetHash() {
return reinterpret_cast<intptr_t>(wrap_);
}


const char* RetainedAsyncInfo::GetLabel() {
return label_;
}


intptr_t RetainedAsyncInfo::GetSizeInBytes() {
return length_;
}


RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle<Value> wrapper) {
// No class_id should be the provider type of NONE.
CHECK_NE(NODE_ASYNC_ID_OFFSET, class_id);
CHECK(wrapper->IsObject());
CHECK(!wrapper.IsEmpty());

Local<Object> object = wrapper.As<Object>();
CHECK_GT(object->InternalFieldCount(), 0);

AsyncWrap* wrap = Unwrap<AsyncWrap>(object);
CHECK_NE(nullptr, wrap);

return new RetainedAsyncInfo(class_id, wrap);
}


// end RetainedAsyncInfo


static void EnableHooksJS(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
env->async_hooks()->set_enable_callbacks(1);
Expand Down Expand Up @@ -71,6 +151,16 @@ static void Initialize(Handle<Object> target,
}


void LoadAsyncWrapperInfo(Environment* env) {
HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler();
#define V(PROVIDER) \
heap_profiler->SetWrapperClassInfoProvider( \
(NODE_ASYNC_ID_OFFSET + AsyncWrap::PROVIDER_ ## PROVIDER), WrapperInfo);
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V
}


Handle<Value> AsyncWrap::MakeCallback(const Handle<Function> cb,
int argc,
Handle<Value>* argv) {
Expand Down
6 changes: 6 additions & 0 deletions src/async-wrap.h
Expand Up @@ -8,6 +8,8 @@

namespace node {

#define NODE_ASYNC_ID_OFFSET 0xA1C

#define NODE_ASYNC_PROVIDER_TYPES(V) \
V(NONE) \
V(CARES) \
Expand Down Expand Up @@ -64,6 +66,8 @@ class AsyncWrap : public BaseObject {
int argc,
v8::Handle<v8::Value>* argv);

virtual size_t self_size() const = 0;

private:
inline AsyncWrap();
inline bool has_async_queue() const;
Expand All @@ -74,6 +78,8 @@ class AsyncWrap : public BaseObject {
uint32_t bits_;
};

void LoadAsyncWrapperInfo(Environment* env);

} // namespace node


Expand Down
28 changes: 26 additions & 2 deletions src/cares_wrap.cc
Expand Up @@ -51,6 +51,8 @@ using v8::Value;
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
public:
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);

size_t self_size() const override { return sizeof(*this); }
};

GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
Expand All @@ -66,8 +68,10 @@ static void NewGetAddrInfoReqWrap(const FunctionCallbackInfo<Value>& args) {


class GetNameInfoReqWrap : public ReqWrap<uv_getnameinfo_t> {
public:
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
public:
GetNameInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);

size_t self_size() const override { return sizeof(*this); }
};

GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env,
Expand Down Expand Up @@ -385,6 +389,8 @@ class QueryAWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -422,6 +428,8 @@ class QueryAaaaWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -459,6 +467,8 @@ class QueryCnameWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -498,6 +508,8 @@ class QueryMxWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -547,6 +559,8 @@ class QueryNsWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -583,6 +597,8 @@ class QueryTxtWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -638,6 +654,8 @@ class QuerySrvWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -692,6 +710,8 @@ class QueryNaptrWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -754,6 +774,8 @@ class QuerySoaWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(unsigned char* buf, int len) override {
HandleScope handle_scope(env()->isolate());
Expand Down Expand Up @@ -820,6 +842,8 @@ class GetHostByAddrWrap: public QueryWrap {
return 0;
}

size_t self_size() const override { return sizeof(*this); }

protected:
void Parse(struct hostent* host) override {
HandleScope handle_scope(env()->isolate());
Expand Down
2 changes: 2 additions & 0 deletions src/fs_event_wrap.cc
Expand Up @@ -31,6 +31,8 @@ class FSEventWrap: public HandleWrap {
static void Start(const FunctionCallbackInfo<Value>& args);
static void Close(const FunctionCallbackInfo<Value>& args);

size_t self_size() const override { return sizeof(*this); }

private:
FSEventWrap(Environment* env, Handle<Object> object);
virtual ~FSEventWrap() override;
Expand Down
2 changes: 2 additions & 0 deletions src/js_stream.h
Expand Up @@ -28,6 +28,8 @@ class JSStream : public StreamBase, public AsyncWrap {
size_t count,
uv_stream_t* send_handle) override;

size_t self_size() const override { return sizeof(*this); }

protected:
JSStream(Environment* env, v8::Handle<v8::Object> obj, AsyncWrap* parent);

Expand Down
1 change: 1 addition & 0 deletions src/node.cc
Expand Up @@ -3872,6 +3872,7 @@ Environment* CreateEnvironment(Isolate* isolate,
env->set_process_object(process_object);

SetupProcessObject(env, argc, argv, exec_argc, exec_argv);
LoadAsyncWrapperInfo(env);

return env;
}
Expand Down
4 changes: 4 additions & 0 deletions src/node_crypto.cc
Expand Up @@ -4546,6 +4546,8 @@ class PBKDF2Request : public AsyncWrap {
error_ = err;
}

size_t self_size() const override { return sizeof(*this); }

uv_work_t work_req_;

private:
Expand Down Expand Up @@ -4776,6 +4778,8 @@ class RandomBytesRequest : public AsyncWrap {
error_ = err;
}

size_t self_size() const override { return sizeof(*this); }

uv_work_t work_req_;

private:
Expand Down
4 changes: 4 additions & 0 deletions src/node_crypto.h
Expand Up @@ -308,6 +308,8 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
v8::Persistent<v8::String> servername_;
#endif

size_t self_size() const override { return sizeof(*this); }

protected:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EncIn(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down Expand Up @@ -702,6 +704,8 @@ class Certificate : public AsyncWrap {
const char* ExportPublicKey(const char* data, int len);
const char* ExportChallenge(const char* data, int len);

size_t self_size() const override { return sizeof(*this); }

protected:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void VerifySpkac(const v8::FunctionCallbackInfo<v8::Value>& args);
Expand Down
2 changes: 2 additions & 0 deletions src/node_file.cc
Expand Up @@ -73,6 +73,8 @@ class FSReqWrap: public ReqWrap<uv_fs_t> {
const char* syscall() const { return syscall_; }
const char* data() const { return data_; }

size_t self_size() const override { return sizeof(*this); }

private:
FSReqWrap(Environment* env,
Local<Object> req,
Expand Down
2 changes: 2 additions & 0 deletions src/node_stat_watcher.h
Expand Up @@ -22,6 +22,8 @@ class StatWatcher : public AsyncWrap {
static void Start(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Stop(const v8::FunctionCallbackInfo<v8::Value>& args);

size_t self_size() const override { return sizeof(*this); }

private:
static void Callback(uv_fs_poll_t* handle,
int status,
Expand Down
2 changes: 2 additions & 0 deletions src/node_zlib.cc
Expand Up @@ -535,6 +535,8 @@ class ZCtx : public AsyncWrap {
}
}

size_t self_size() const override { return sizeof(*this); }

private:
void Ref() {
if (++refs_ == 1) {
Expand Down
2 changes: 2 additions & 0 deletions src/pipe_wrap.cc
Expand Up @@ -37,6 +37,8 @@ using v8::Value;
class PipeConnectWrap : public ReqWrap<uv_connect_t> {
public:
PipeConnectWrap(Environment* env, Local<Object> req_wrap_obj);

size_t self_size() const override { return sizeof(*this); }
};


Expand Down
2 changes: 2 additions & 0 deletions src/pipe_wrap.h
Expand Up @@ -16,6 +16,8 @@ class PipeWrap : public StreamWrap {
v8::Handle<v8::Value> unused,
v8::Handle<v8::Context> context);

size_t self_size() const override { return sizeof(*this); }

private:
PipeWrap(Environment* env,
v8::Handle<v8::Object> object,
Expand Down
2 changes: 2 additions & 0 deletions src/process_wrap.cc
Expand Up @@ -46,6 +46,8 @@ class ProcessWrap : public HandleWrap {
constructor->GetFunction());
}

size_t self_size() const override { return sizeof(*this); }

private:
static void New(const FunctionCallbackInfo<Value>& args) {
// This constructor should not be exposed to public javascript.
Expand Down
2 changes: 2 additions & 0 deletions src/signal_wrap.cc
Expand Up @@ -40,6 +40,8 @@ class SignalWrap : public HandleWrap {
constructor->GetFunction());
}

size_t self_size() const override { return sizeof(*this); }

private:
static void New(const FunctionCallbackInfo<Value>& args) {
// This constructor should not be exposed to public javascript.
Expand Down

0 comments on commit e56758a

Please sign in to comment.