Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Extend ObjectWrap instead of EventEmitter for node v0.6.0 compatibilty #9

Open
wants to merge 1 commit into from

4 participants

tungj this account is no more maintained Woody Anderson ripcurld
tungj

This makes the Gzip, Gunzip, Bzip and Bunzip classes extend ObjectWrap instead of EventEmitter since the latter has been removed from node v0.5 and the stable v0.6.0, as described in Woodya/node-gzbz2#8

I'm not certain I'm doing this correctly, but 'node test.js' does work in both node v0.4.11 and v0.6.0 (assuming the symlink to gzbz2 is updated to point to build/debug instead of build/Release which v0.6.0 uses)

this account is no more maintained

it works, thanks

Woody Anderson
Owner

@tungj can you explain the static Persistent s_ct; part of the change?

ripcurld

@Woodya I have no idea why he set Persistent<Function> to be static. However, he is right that we have to use Persistent<Function> and pass it to target->Set.
According to Chrome V8 developers guide (I think):

A handle provides a reference to a JavaScript object's location in the heap. 
The V8 garbage collector reclaims memory used by objects that can no longer
again be accessed.[...]

There are several types of handles:
   * Local handles are held on a stack and are deleted when the appropriate destructor
     is called. These handles' lifetime is determined by a handle scope, which is often
     created at the beginning of a function call. [...]
   * Persistent handles provide a reference to a heap-allocated JavaScript Object,
     just like a local handle.[...]  Use a persistent handle when you need to keep
     a reference to an object for more than one function call, or when handle lifetimes
     do not correspond to C++ scopes.

https://developers.google.com/v8/embed

Woody Anderson
Owner

@ripcurld00d so i've read that section now, and i don't yet see that Persistent is correct v Local in this case.

... Use a persistent handle when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes ...

this is not true in this case, at least afaict. The handle is only used inside the Initialize (static) method of each class, which in turn is called from the extern'd init().

I do see that various stackoverflow and web tutorials use the " .. s_ct = new .. (t)" pattern, but i don't see how any of them are more correct. It seems to me that they simply burden the system with a minor additional heap allocation. B/c unless a second function call will use the object, it's pointless.
for reference, the links i found in favor of this methodology:

however (and if i'm still wrong here, please point me in the right direction), i think they're simply re-using a pattern isn't appropriate, as they never use the s_ct outside their 1 function.
the s_ct pattern is not used in the nodejs addon docs for class prototype definitions

Also, per above comment about target->Set(), the commit actually leaves that reference as
target->Set(String::NewSymbol("Gzip"), t->GetFunction());

in short, i think it's an unnecessary involvement of the heap & additional unused symbols in the class.
I don't think it's needed.

ripcurld

OK, I haven't done any deep investigation but from what I have seen so far, the Persistent in gzbz2 seems useless. Nevertheless, I will submit a PR with more testings (we don't test bz2/bunzip + memory leaks) just to cover more scenarios and make sure there will be no regressions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 50 additions and 33 deletions.
  1. +46 −29 compress.cc
  2. +2 −2 package.json
  3. +2 −2 wscript
75 compress.cc
View
@@ -1,5 +1,4 @@
#include <node.h>
-#include <node_events.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
@@ -58,19 +57,21 @@ class FBuffer {
};
#ifdef WITH_GZIP
-class Gzip : public EventEmitter {
+class Gzip : public ObjectWrap {
public:
+ static Persistent<FunctionTemplate> s_ct;
static void Initialize(v8::Handle<v8::Object> target) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
- t->Inherit(EventEmitter::constructor_template);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("Gzip"));
- NODE_SET_PROTOTYPE_METHOD(t, "init", GzipInit);
- NODE_SET_PROTOTYPE_METHOD(t, "deflate", GzipDeflate);
- NODE_SET_PROTOTYPE_METHOD(t, "end", GzipEnd);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "init", GzipInit);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "deflate", GzipDeflate);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "end", GzipEnd);
target->Set(String::NewSymbol("Gzip"), t->GetFunction());
}
@@ -279,7 +280,7 @@ class Gzip : public EventEmitter {
}
}
- Gzip() : EventEmitter(), use_buffers(true), encoding(BINARY) {
+ Gzip() : ObjectWrap(), use_buffers(true), encoding(BINARY) {
}
~Gzip() {
@@ -292,19 +293,23 @@ class Gzip : public EventEmitter {
enum encoding encoding;
};
-class Gunzip : public EventEmitter {
+Persistent<FunctionTemplate> Gzip::s_ct;
+
+class Gunzip : public ObjectWrap {
public:
+ static Persistent<FunctionTemplate> s_ct;
static void Initialize(v8::Handle<v8::Object> target) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
- t->Inherit(EventEmitter::constructor_template);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("Gunzip"));
- NODE_SET_PROTOTYPE_METHOD(t, "init", GunzipInit);
- NODE_SET_PROTOTYPE_METHOD(t, "inflate", GunzipInflate);
- NODE_SET_PROTOTYPE_METHOD(t, "end", GunzipEnd);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "init", GunzipInit);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "inflate", GunzipInflate);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "end", GunzipEnd);
target->Set(String::NewSymbol("Gunzip"), t->GetFunction());
}
@@ -467,7 +472,7 @@ class Gunzip : public EventEmitter {
return scope.Close(Undefined());
}
- Gunzip() : EventEmitter(), use_buffers(true), encoding(BINARY) {
+ Gunzip() : ObjectWrap(), use_buffers(true), encoding(BINARY) {
}
~Gunzip() {
@@ -479,23 +484,28 @@ class Gunzip : public EventEmitter {
bool use_buffers;
enum encoding encoding;
};
+
+Persistent<FunctionTemplate> Gunzip::s_ct;
+
#endif//WITH_GZIP
#ifdef WITH_BZIP
-class Bzip : public EventEmitter {
+class Bzip : public ObjectWrap {
public:
+ static Persistent<FunctionTemplate> s_ct;
static void Initialize(v8::Handle<v8::Object> target) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
- t->Inherit(EventEmitter::constructor_template);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("Bzip"));
- NODE_SET_PROTOTYPE_METHOD(t, "init", BzipInit);
- NODE_SET_PROTOTYPE_METHOD(t, "deflate", BzipDeflate);
- NODE_SET_PROTOTYPE_METHOD(t, "end", BzipEnd);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "init", BzipInit);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "deflate", BzipDeflate);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "end", BzipEnd);
target->Set(String::NewSymbol("Bzip"), t->GetFunction());
}
@@ -706,7 +716,7 @@ class Bzip : public EventEmitter {
}
}
- Bzip() : EventEmitter(), use_buffers(true), encoding(BINARY) {
+ Bzip() : ObjectWrap(), use_buffers(true), encoding(BINARY) {
}
~Bzip() {
@@ -719,19 +729,23 @@ class Bzip : public EventEmitter {
enum encoding encoding;
};
-class Bunzip : public EventEmitter {
+Persistent<FunctionTemplate> Bzip::s_ct;
+
+class Bunzip : public ObjectWrap {
public:
+ static Persistent<FunctionTemplate> s_ct;
static void Initialize(v8::Handle<v8::Object> target) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
- t->Inherit(EventEmitter::constructor_template);
- t->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("Bunzip"));
- NODE_SET_PROTOTYPE_METHOD(t, "init", BunzipInit);
- NODE_SET_PROTOTYPE_METHOD(t, "inflate", BunzipInflate);
- NODE_SET_PROTOTYPE_METHOD(t, "end", BunzipEnd);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "init", BunzipInit);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "inflate", BunzipInflate);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "end", BunzipEnd);
target->Set(String::NewSymbol("Bunzip"), t->GetFunction());
}
@@ -896,7 +910,7 @@ class Bunzip : public EventEmitter {
return scope.Close(Undefined());
}
- Bunzip() : EventEmitter(), use_buffers(true), encoding(BINARY) {
+ Bunzip() : ObjectWrap(), use_buffers(true), encoding(BINARY) {
}
~Bunzip() {
@@ -908,6 +922,9 @@ class Bunzip : public EventEmitter {
bool use_buffers;
enum encoding encoding;
};
+
+Persistent<FunctionTemplate> Bunzip::s_ct;
+
#endif//WITH_BZIP
extern "C" {
4 package.json
View
@@ -14,8 +14,8 @@
"type": "git",
"url": "git://github.com/woodya/node-gzbz2.git"
},
- "main": "build/default/gzbz2",
- "directories.lib": "build/default/",
+ "main": "build/Release/gzbz2",
+ "directories.lib": "build/Release/",
"scripts": {
"build": "node-waf configure build",
"test": "node-waf test",
4 wscript
View
@@ -67,5 +67,5 @@ def shutdown(bld):
if lexists('gzbz2.node'):
unlink('gzbz2.node')
elif Options.commands['build']:
- if exists('build/default/gzbz2.node') and not lexists('gzbz2.node'):
- symlink('build/default/gzbz2.node', 'gzbz2.node')
+ if exists('build/Release/gzbz2.node') and not lexists('gzbz2.node'):
+ symlink('build/Release/gzbz2.node', 'gzbz2.node')
Something went wrong with that request. Please try again.