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.

Reply via email to