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.
  • Loading branch information
trevnorris committed Jun 4, 2015
1 parent a804026 commit e0268e3
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/async-wrap-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ inline AsyncWrap::AsyncWrap(Environment* env,
ProviderType provider,
AsyncWrap* parent)
: BaseObject(env, object), bits_(static_cast<uint32_t>(provider) << 1) {
// Shift provider value over to prevent id collision.
persistent().SetWrapperClassId(ASYNC_ID_OFFSET + provider);

// Check user controlled flag to see if the init callback should run.
if (!env->using_asyncwrap())
return;
Expand Down
83 changes: 83 additions & 0 deletions src/async-wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,99 @@
#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, Handle<Value> wrapper);

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_;
char* data_;
int length_;
};


RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, Handle<Value> wrapper)
: label_(provider_names[class_id - ASYNC_ID_OFFSET]),
data_(nullptr),
length_(0) {
CHECK(wrapper->IsObject());
CHECK(!wrapper.IsEmpty());
Local<Object> object = wrapper.As<Object>();
AsyncWrap* wrap = Unwrap<AsyncWrap>(object);
CHECK_NE(nullptr, wrap);
data_ = static_cast<char*>(static_cast<void*>(wrap));
length_ = sizeof(*wrap);
}


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


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


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


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


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


RetainedObjectInfo* WrapperInfo(uint16_t class_id, Handle<Value> wrapper) {
return new RetainedAsyncInfo(class_id, wrapper);
}


// 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 @@ -68,6 +144,13 @@ static void Initialize(Handle<Object> target,
NODE_ASYNC_PROVIDER_TYPES(V)
#undef V
target->Set(FIXED_ONE_BYTE_STRING(isolate, "Providers"), async_providers);

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


Expand Down
2 changes: 2 additions & 0 deletions src/async-wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace node {

#define ASYNC_ID_OFFSET 0xA1C

#define NODE_ASYNC_PROVIDER_TYPES(V) \
V(NONE) \
V(CARES) \
Expand Down
3 changes: 3 additions & 0 deletions src/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@

startup.processRawDebug();

// Load async_wrap to init the wrapper class info provider.
process.binding('async_wrap');

process.argv[0] = process.execPath;

// There are various modes that Node can run in. The most common two
Expand Down

0 comments on commit e0268e3

Please sign in to comment.