On Fri, Dec 13, 2013 at 4:14 PM, AT <[email protected]> wrote: > Thanks Nate - doesn't that still have the issue as above though, where the > user can do this: > > var object = new MyObject(); > var myData = object.myData(); > object = null; > > And now `object` will get GC-ed, and that pointer will no longer be valid, > so if the user tries to access myData the program will segfault? >
I'd suggest having the myData() function attach a reference to "object" onto the Buffer instance before returning it to the user. (i.e. `buf._obj = this;`). That way, you know "object" won't be GC'd until after the Buffer instance is also eligible for GC. > Also, this is creating a persistent handle every single time someone calls > object.myData(); - what is the right way to make sure those get cleaned up? > I have no way of knowing when the user will throw away their reference to > myData > Under the hood, creating C++ Buffer objects creates a Persistent "weak" handle. This means that you don't need to worry about *when* the object gets GC'd, but you can be confident that the provided callback function will be invoked after there are no more JS references to the Buffer, so you should clean up any created C++ data at that point. > On Thursday, December 12, 2013 9:51:44 PM UTC-8, Nathan Rajlich wrote: > >> Sounds to me like you want the Buffer to use an existing external pointer >> without copying the data. i.e. *use* the existing pointer. This is possible >> by passing a "weak callback function" as the third argument to >> Buffer::New(). For an example, see here: https://github.com/ >> TooTallNate/ref/blob/44665a4e99d721910d29bbecc1f45b >> 3b1ef7fb14/src/binding.cc#L101-L120<https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2FTooTallNate%2Fref%2Fblob%2F44665a4e99d721910d29bbecc1f45b3b1ef7fb14%2Fsrc%2Fbinding.cc%23L101-L120&sa=D&sntz=1&usg=AFQjCNEpv9tX0bXNjZbmu26yKcdOX21Jaw> >> >> >> On Thu, Dec 12, 2013 at 8:18 PM, AT <[email protected]> wrote: >> >>> Thanks Andrew! That is all very helpful. I'm still having a little bit >>> of trouble on the buffers. The object that I'm wrapping has a field on it >>> which is a std::vector<uint8_t>, and a method which returns that vector to >>> me. This is one of the methods that I'm exposing to JS, and I would like it >>> to return a Buffer, which I'm doing like this simplified example (in >>> v0.10.23): >>> >>> v8::HandleScope scope; >>> MyObject* object = node::ObjectWrap::Unwrap<MyObject>(args.This()); >>> std::vector<uint8_t> my_data = object->my_data(); >>> v8::Handle<v8::Object> buffer = >>> node::Buffer::New(reinterpret_cast<char*>(my_data.data()), >>> my_data.size()).handle_; >>> return scope.Close(buffer); >>> >>> However when I do this I'm actually getting a SlowBuffer. In >>> node_buffer.h it says I can construct a fast buffer by invoking New with a >>> v8::Handle<v8::String>, but I believe this would mean copying over the >>> data? Is that the only way to construct a fast (sliced) buffer? >>> >>> Also this is returning a persistent handle, and I don't think I fully >>> understand how to make sure those get cleaned up correctly - I just want >>> the data to get collected when the user decides to throw away the reference >>> to the buffer returned to them in javascript. Does that mean I have to make >>> the reference weak, and supply a callback to be invoked when only weak >>> references are held to the object? If that's the case, then it seems like I >>> actually need to delete (in the C++ sense) the backing node::Buffer*, but >>> since the callback only provides the char* data pointed at, I can't do that? >>> >>> Last but not least - if the user does this in JS: >>> var object = new MyObject(); >>> var myData = object.myData(); >>> object = null; >>> >>> Then object is eligible to get garbage collected, but myData has a >>> pointer into data held by object. Does this mean, again, that I have to >>> make a copy of the data every time someone calls myData()? Is there a more >>> efficient method (shared pointers? something else?) >>> >>> Sorry if some of that doesn't make sense - I'm having a hard time >>> figuring out the proper way to do this. >>> >>> Thanks! >>> >>> >>> On Thursday, December 12, 2013 9:43:29 AM UTC-8, Andrew Kelley wrote: >>>> >>>> I can't answer all of your questions but I can help with a couple: >>>> >>>> 2. setInternalFieldCount. See this page of v8 docs: >>>> http://izs.me/v8-docs/classv8_1_1Object.html#a94e24494 >>>> 687ea499471d41e914eeb90d >>>> >>>> My understanding of this is that you setInternalFieldCount to some >>>> integer (such as 3) and then you have that many slots with which to put >>>> stuff in. You can then use SetInternalField(0, someValue) and >>>> GetInternalField(0) where 0 is the index of the internal field. I think >>>> that the node::ObjectWrap helper thing uses internal field index 0 under >>>> the covers. So the fact that you have to setInternalFieldCount even though >>>> you never use it is a leaky abstraction. I could be wrong; I haven't >>>> actually looked at the node objectwrap code. >>>> >>>> >>>> 3. buffers. >>>> >>>> Here's a chat log of trevnorris helping me out with buffers: >>>> https://gist.github.com/superjoe30/7198261 >>>> >>>> 4. packaging >>>> >>>> It's generally considered convenient to bundle C library dependencies >>>> with your node module. So you'd compile your depending library along with >>>> your wrapper code all together, that way the user of your module does not >>>> actually need that library installed on their system. This is not required >>>> however, and if the dependency is huge and heavy it would probably make >>>> more sense to depend on it dynamically instead of bundling it. >>>> >>>> 5. general tips >>>> >>>> Look at existing node addons for reference. TooTallNate specifically >>>> has a bunch of good examples available on github to look at. >>>> For what it's worth here's a module I made: https://github.com/super >>>> joe30/node-groove >>>> It should by no means be taken as a perfect example; it's the first and >>>> only addon I've made, but maybe it can help anyway. >>>> >>>> good luck! >>>> >>>> On Tuesday, December 10, 2013 5:39:59 PM UTC-5, AT wrote: >>>>> >>>>> Hey all, >>>>> >>>>> I'm just starting to write my first C++ addon for node and I'm finding >>>>> that the documentation can be a little sparse at times. I had a few >>>>> beginner questions for you all, in no particular order: >>>>> >>>>> 1) v8::Signatures - It seems like they're supposed to validate that >>>>> functions are invoked on objects which can respond to that function, in >>>>> case people use call/apply. A common pattern in the node code is to use >>>>> NODE_SET_PROTOTYPE_METHOD macro to automatically use the correct >>>>> signature, >>>>> but it generates multiple signature objects that I believe are all >>>>> identical, since they're based only on the template being supplied. So, >>>>> instead of doing: >>>>> >>>>> NODE_SET_PROTOTYPE_METHOD(tpl, "function1", Function1) >>>>> NODE_SET_PROTOTYPE_METHOD(tpl, "function2", Function2) >>>>> NODE_SET_PROTOTYPE_METHOD(tpl, "function3", Function3) >>>>> >>>>> I could do: >>>>> >>>>> v8::Local<v8::Signature> signature = v8::Signature::New(tpl); >>>>> tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("function1"), >>>>> v8::FunctionTemplate::New(Function1, v8::Handle<v8::Value>(), >>>>> signature)); >>>>> tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("function2"), >>>>> v8::FunctionTemplate::New(Function2, v8::Handle<v8::Value>(), >>>>> signature)); >>>>> tpl->PrototypeTemplate()->Set(v8::String::NewSymbol("function3"), >>>>> v8::FunctionTemplate::New(Function3, v8::Handle<v8::Value>(), >>>>> signature)); >>>>> >>>>> Is it correct to reuse the signature like this? Is it not worth doing >>>>> so because of the extra verbosity? >>>>> >>>>> Also, what is the second parameter (`data`) passed in to >>>>> FunctionTemplate::New? I took a look at v8.h but it was not described. >>>>> >>>>> 2) SetInternalFieldCount. I took at look at the following: >>>>> http://stackoverflow.com/questions/16600735/what-is-an-inter >>>>> nal-field-count-and-what-is-setinternalfieldcount-used-for >>>>> https://groups.google.com/forum/#!searchin/v8-users/SetInter >>>>> nalFieldCount/v8-users/2LyzMXilUiM/OVQpWehDm9MJ >>>>> >>>>> and I still don't fully understand this. It seems like >>>>> SetInternalField lets me associate arbitrary C++ objects with my JS >>>>> objects, and SetInternalFieldCount just makes space for that many (void >>>>> *)'s, but I don't think I understand the use case for this. In the node >>>>> examples here: >>>>> http://nodejs.org/api/addons.html >>>>> >>>>> they call SetInternalFieldCount even though they don't set any >>>>> internal fields. Indeed, when I run some of my own code and omit the >>>>> SetInternalFieldCount(1) call, I get the following: >>>>> .node-gyp/0.10.16/src/node_object_wrap.h:71: void >>>>> node::ObjectWrap::Wrap(v8::Handle<v8::Object>): Assertion >>>>> `handle->InternalFieldCount() >0 ' failed. >>>>> >>>>> Why does this need to be a minimum of 1 if I have no internal fields? >>>>> If I want to implement my own JS objects it seems cleaner to me to have my >>>>> class which inherits from node::ObjectWrap to just have the necessary >>>>> members on it there, instead of having them set as internal fields? >>>>> >>>>> 3) Buffers. >>>>> >>>>> The first result on google for making a Node buffer in C++ land is the >>>>> following: >>>>> http://www.samcday.com.au/blog/2011/03/03/creating-a-proper- >>>>> buffer-in-a-node-c-addon/ >>>>> >>>>> This post is from 2011 - is it still accurate? Looking through the >>>>> Node source it seems that the structure is still the same as described in >>>>> the article (slow buffer implemented in node_buffers.h, regular buffer >>>>> implemented in JS land via buffer.js), but it seems so hacky to construct >>>>> buffers this way. What if someone changes the global Buffer? >>>>> >>>>> One of the comments an the article alludes to Buffer::MakeFastBuffer() >>>>> but I don't see this function in master. What I do see is SetupBufferJS: >>>>> https://github.com/joyent/node/blob/master/src/node_buffer.cc#L598 >>>>> which looks like it takes a C++ land buffer and makes it more >>>>> "node-like", but the methods it adds are different than the plain Buffer >>>>> interface provided in buffer.js, so I don't think that's what I want >>>>> either. >>>>> >>>>> 4) Packaging >>>>> >>>>> What are the packaging conventions / how do I ship my addon which >>>>> depends on other libraries being present. >>>>> >>>>> For users who want to build from source: >>>>> >>>>> Should my library include the source of my dependency, and its >>>>> dependencies, and so on, so that users who try to compile will get the >>>>> versions that I'm building against? >>>>> >>>>> Should my library include none of my dependencies, and just include >>>>> instructions (before running node-gyp, install xxx >= 1.0.0, install yyy >>>>> <= >>>>> 1.5.0, etc) >>>>> >>>>> For users who want to install from npm: >>>>> >>>>> Should my addon include pre-built binaries for the platforms that I >>>>> plan on supporting? >>>>> >>>>> Should it just give instructions (have the following libs available, >>>>> etc), and I can dynamically load those libraries? >>>>> >>>>> Sorry for the lengthy post - thanks in advance for all the help! >>>>> >>>> -- >>> -- >>> Job Board: http://jobs.nodejs.org/ >>> Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List- >>> Posting-Guidelines >>> You received this message because you are subscribed to the Google >>> Groups "nodejs" group. >>> To post to this group, send email to [email protected] >>> >>> To unsubscribe from this group, send email to >>> [email protected] >>> >>> For more options, visit this group at >>> http://groups.google.com/group/nodejs?hl=en?hl=en >>> >>> --- >>> You received this message because you are subscribed to the Google >>> Groups "nodejs" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> >>> For more options, visit https://groups.google.com/groups/opt_out. >>> >> >> -- > -- > Job Board: http://jobs.nodejs.org/ > Posting guidelines: > https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines > You received this message because you are subscribed to the Google > Groups "nodejs" group. > To post to this group, send email to [email protected] > To unsubscribe from this group, send email to > [email protected] > For more options, visit this group at > http://groups.google.com/group/nodejs?hl=en?hl=en > > --- > You received this message because you are subscribed to the Google Groups > "nodejs" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/groups/opt_out. > -- -- Job Board: http://jobs.nodejs.org/ Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines You received this message because you are subscribed to the Google Groups "nodejs" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/nodejs?hl=en?hl=en --- You received this message because you are subscribed to the Google Groups "nodejs" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
