Perfect - I think I've got it working now, thanks for all the help!
On Friday, December 13, 2013 4:45:23 PM UTC-8, Nathan Rajlich wrote: > > > On Fri, Dec 13, 2013 at 4:14 PM, AT <[email protected] <javascript:>>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]<javascript:> >> To unsubscribe from this group, send email to >> [email protected] <javascript:> >> 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] <javascript:>. >> 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.
