Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-26 Thread George Corney
*Correction, free(dataPtr) should be replaced with a call to your 
ArrayBufferAllocator's .Free(ptr, length) call

On Friday, February 26, 2016 at 1:22:26 PM UTC, George Corney wrote:
>
> *For the next person trying to do this:*
>
> It turns the approach in the post above doesn't completely work because 
> GetIndexedPropertiesExternalArrayData is only supported on 
> ArrayBufferViews and not ArrayBuffers. My solution now is to grab the 
> Contents::Data() pointer provided when ArrayBuffer::Externalize() is called 
> and store it on the ArrayBuffer in a hidden field (as well as creating a 
> weak persistent handle to free it later). My implementation is provided:
>
> struct WeakCallbackData{
> v8::Persistent* persistent;
> uintptr_t dataPtrValue;
> };
>
> //when we get typed array data we take responsibility for freeing the data
> void ArrayBufferWeakCallback(const v8::WeakCallbackData WeakCallbackData>& info){
> WeakCallbackData* callbackData = info.GetParameter();
> v8::Persistent* persistent = callbackData->persistent;
> void* dataPtr = (void*) info.GetParameter()->dataPtrValue;
>
> Print::Debug("ArrayBufferWeakCallback fired (byte length: %d, dataPtr*: 
> %p)", info.GetValue()->ByteLength(), dataPtr);
>
> //dealloc
> info.GetValue().Clear();
> persistent->Reset();
> delete callbackData;
> free(dataPtr);
> }
>
> void AttachPointerObject(v8::Isolate* isolate, 
> v8::Handle& buffer, void* dataPtr){
> v8::Local ptrObjTmpl = 
> v8::ObjectTemplate::New(isolate);
> ptrObjTmpl->SetInternalFieldCount(1);
> v8::Local ptrObj = ptrObjTmpl->NewInstance();
> ptrObj->SetAlignedPointerInInternalField(0, dataPtr);
> buffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "ptrObj"), ptrObj);
> }
>
> //Public API
>
> const void SafelyExternalizeArrayBuffer(v8::Isolate* isolate, 
> v8::Handle& buffer){
> if(!buffer->IsExternal()){
> v8::ArrayBuffer::Contents contents = buffer->Externalize();
> RegisterExternalData(isolate, buffer, contents.Data());
> }
> }
>
> void RegisterExternalData(v8::Isolate* isolate, 
> v8::Handle& buffer, void* dataPtr){
> Print::Debug("RegisterExternalData (byte length: %d, dataPtr*: %p)", 
> buffer->ByteLength(), dataPtr);
>
> AttachPointerObject(isolate, buffer, dataPtr);
>
> v8::Persistent* persistent = new 
> v8::Persistent();
> persistent->Reset(isolate, buffer);
>
> WeakCallbackData* callbackData = new WeakCallbackData();
> callbackData->persistent = persistent;
> callbackData->dataPtrValue = (uintptr_t)(void *)dataPtr;
>
> persistent->SetWeak(callbackData, 
> ArrayBufferWeakCallback);
> }
>
> const unsigned char* GetArrayBufferBytes(v8::Isolate* isolate, 
> v8::Handle& buffer){
> SafelyExternalizeArrayBuffer(isolate, buffer);
>
> v8::Local v = 
> buffer->GetHiddenValue(v8::String::NewFromUtf8(isolate, "ptrObj"));
>
> if(!v->IsObject()){
> Print::Error("%s: Internal data pointer not found on ArrayBuffer, ensure 
> RegisterExternalData was at initialization", __FUNCTION__);
> return NULL;
> }
>
> v8::Local ptrObj = v8::Local::Cast(v);
> const void* dataPtr = ptrObj->GetAlignedPointerFromInternalField(0);
> const unsigned char* bytePtr = static_cast(dataPtr);
> return bytePtr;
> }
>
>
> const unsigned char* GetArrayBufferViewBytes(v8::Isolate* isolate, 
> v8::Handle& bufferView){
> v8::Local buffer = bufferView->Buffer();
> SafelyExternalizeArrayBuffer(isolate, buffer);
> const void* dataPtr = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast(dataPtr) 
> + bufferView->ByteOffset();
> return bytePtr;
> }
>
>
> (You'll need to replace the Print:: functions with whatever system you're 
> using for logging)
>
> - If the TypedArrays are coming from JS land, you'll only need 
> *GetArrayBufferBytes* and *GetArrayBufferViewBytes* (depending on if 
> you're using an ArrayBufferView or ArrayBuffer) to access the data safely
> - If the TypedArray is created in C++ land and the data buffer is provided 
> to it so it's already external, then you need to use 
> *RegisterExternalData* for to make the ArrayBuffer safe to access with 
> these functions (the buffer will be freed with the WeakCallback)
> - If you want to externalize without accessing the data, you need to use 
> *SafelyExternalizeArrayBuffer* *and not* *ArrayBuffer::Externalize()*
>
>
> All the best,
> George Corney
>
> On Monday, February 22, 2016 at 3:38:08 PM UTC, George Corney wrote:
>>
>> Thanks for the tips
>>
>> I agree regarding upgrading from 3.28, unfortunately for the time being 
>> I'm stuck with it as a consequence of various trade offs (I'm using JXcore 
>> which is built on 3.28 and I can't migrate away because of time constraints)
>>
>> I'm trying the externalize + weak persistent handle method, here's my 
>> code now
>>
>> //weak callback, frees the raw data and handle
>> void ArrayBufferWeakCallback(const v8::WeakCallbackData> v8::Persistent>& info){
>>  Print::Debug("ArrayBufferWeakCallback fired");
>>  void* rawData = info.GetValue()->GetIndexedPropertiesExternalArrayData
>> ()

Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-26 Thread George Corney
*For the next person trying to do this:*

It turns the approach in the post above doesn't completely work because 
GetIndexedPropertiesExternalArrayData is only supported on ArrayBufferViews 
and not ArrayBuffers. My solution now is to grab the Contents::Data() 
pointer provided when ArrayBuffer::Externalize() is called and store it on 
the ArrayBuffer in a hidden field (as well as creating a weak persistent 
handle to free it later). My implementation is provided:

struct WeakCallbackData{
v8::Persistent* persistent;
uintptr_t dataPtrValue;
};

//when we get typed array data we take responsibility for freeing the data
void ArrayBufferWeakCallback(const v8::WeakCallbackData& info){
WeakCallbackData* callbackData = info.GetParameter();
v8::Persistent* persistent = callbackData->persistent;
void* dataPtr = (void*) info.GetParameter()->dataPtrValue;

Print::Debug("ArrayBufferWeakCallback fired (byte length: %d, dataPtr*: 
%p)", info.GetValue()->ByteLength(), dataPtr);

//dealloc
info.GetValue().Clear();
persistent->Reset();
delete callbackData;
free(dataPtr);
}

void AttachPointerObject(v8::Isolate* isolate, v8::Handle& 
buffer, void* dataPtr){
v8::Local ptrObjTmpl = v8::ObjectTemplate::New(isolate);
ptrObjTmpl->SetInternalFieldCount(1);
v8::Local ptrObj = ptrObjTmpl->NewInstance();
ptrObj->SetAlignedPointerInInternalField(0, dataPtr);
buffer->SetHiddenValue(v8::String::NewFromUtf8(isolate, "ptrObj"), ptrObj);
}

//Public API

const void SafelyExternalizeArrayBuffer(v8::Isolate* isolate, 
v8::Handle& buffer){
if(!buffer->IsExternal()){
v8::ArrayBuffer::Contents contents = buffer->Externalize();
RegisterExternalData(isolate, buffer, contents.Data());
}
}

void RegisterExternalData(v8::Isolate* isolate, 
v8::Handle& buffer, void* dataPtr){
Print::Debug("RegisterExternalData (byte length: %d, dataPtr*: %p)", 
buffer->ByteLength(), dataPtr);

AttachPointerObject(isolate, buffer, dataPtr);

v8::Persistent* persistent = new 
v8::Persistent();
persistent->Reset(isolate, buffer);

WeakCallbackData* callbackData = new WeakCallbackData();
callbackData->persistent = persistent;
callbackData->dataPtrValue = (uintptr_t)(void *)dataPtr;

persistent->SetWeak(callbackData, 
ArrayBufferWeakCallback);
}

const unsigned char* GetArrayBufferBytes(v8::Isolate* isolate, 
v8::Handle& buffer){
SafelyExternalizeArrayBuffer(isolate, buffer);

v8::Local v = 
buffer->GetHiddenValue(v8::String::NewFromUtf8(isolate, "ptrObj"));

if(!v->IsObject()){
Print::Error("%s: Internal data pointer not found on ArrayBuffer, ensure 
RegisterExternalData was at initialization", __FUNCTION__);
return NULL;
}

v8::Local ptrObj = v8::Local::Cast(v);
const void* dataPtr = ptrObj->GetAlignedPointerFromInternalField(0);
const unsigned char* bytePtr = static_cast(dataPtr);
return bytePtr;
}


const unsigned char* GetArrayBufferViewBytes(v8::Isolate* isolate, 
v8::Handle& bufferView){
v8::Local buffer = bufferView->Buffer();
SafelyExternalizeArrayBuffer(isolate, buffer);
const void* dataPtr = bufferView->GetIndexedPropertiesExternalArrayData();
const unsigned char* bytePtr = static_cast(dataPtr) + 
bufferView->ByteOffset();
return bytePtr;
}


(You'll need to replace the Print:: functions with whatever system you're 
using for logging)

- If the TypedArrays are coming from JS land, you'll only need 
*GetArrayBufferBytes* and *GetArrayBufferViewBytes* (depending on if you're 
using an ArrayBufferView or ArrayBuffer) to access the data safely
- If the TypedArray is created in C++ land and the data buffer is provided 
to it so it's already external, then you need to use *RegisterExternalData* 
for to make the ArrayBuffer safe to access with these functions (the buffer 
will be freed with the WeakCallback)
- If you want to externalize without accessing the data, you need to use 
*SafelyExternalizeArrayBuffer* *and not* *ArrayBuffer::Externalize()*


All the best,
George Corney

On Monday, February 22, 2016 at 3:38:08 PM UTC, George Corney wrote:
>
> Thanks for the tips
>
> I agree regarding upgrading from 3.28, unfortunately for the time being 
> I'm stuck with it as a consequence of various trade offs (I'm using JXcore 
> which is built on 3.28 and I can't migrate away because of time constraints)
>
> I'm trying the externalize + weak persistent handle method, here's my code 
> now
>
> //weak callback, frees the raw data and handle
> void ArrayBufferWeakCallback(const v8::WeakCallbackData v8::Persistent>& info){
>  Print::Debug("ArrayBufferWeakCallback fired");
>  void* rawData = info.GetValue()->GetIndexedPropertiesExternalArrayData();
>  info.GetValue().Clear();
>  info.GetParameter()->Reset();
>  free(rawData);
>  free(info.GetParameter());
> }
>
>
> //...
>
>
> v8::Local bufferView = dataArg.As >();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
>
> bufferView->Buffer()->Externalize();
>
>
> //create weak persistent handle with callback to above code
> v8::Persistent* persistent = new v8::Persistent ArrayBuf

Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-22 Thread George Corney
Thanks for the tips

I agree regarding upgrading from 3.28, unfortunately for the time being I'm 
stuck with it as a consequence of various trade offs (I'm using JXcore 
which is built on 3.28 and I can't migrate away because of time constraints)

I'm trying the externalize + weak persistent handle method, here's my code 
now

//weak callback, frees the raw data and handle
void ArrayBufferWeakCallback(const v8::WeakCallbackData>& info){
 Print::Debug("ArrayBufferWeakCallback fired");
 void* rawData = info.GetValue()->GetIndexedPropertiesExternalArrayData();
 info.GetValue().Clear();
 info.GetParameter()->Reset();
 free(rawData);
 free(info.GetParameter());
}


//...


v8::Local bufferView = dataArg.As();
size_t byteLength = bufferView->ByteLength();
size_t byteOffset = bufferView->ByteOffset();


bufferView->Buffer()->Externalize();


//create weak persistent handle with callback to above code
v8::Persistent* persistent = new v8::Persistent();
persistent->Reset(isolate, buffer);
persistent->SetWeak>(persistent, 
ArrayBufferWeakCallback);


const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
const unsigned char* bytePtr = static_cast(rawData);


glBufferData(target, byteLength, bytePtr + byteOffset, usage);
REPORT_GL_ERRORS();


The callback seems to fire as expected and there's no segfaults so I think 
this might be the solution! Could you have a quick read to see I'm not 
setting myself up for failure by rolling this approach out across my code?

Many thanks,
George

On Monday, February 22, 2016 at 7:59:15 AM UTC, Jochen Eisinger wrote:
>
> Please note that 3.28 is a really old version of V8 which is full of known 
> issues and no longer maintained.
>
> In general, you'll wait to externalize the buffer and keep a weak 
> persistent handle to the buffer - once the weak callback was triggered, you 
> know that you can free the backing store (if you no longer need it 
> otherwise).
>
> More current versions of V8 also have a method 
> ArrayBufferView::CopyContents that allows you to access the backing store 
> without externalizing the underlying buffer.
>
> On Sun, Feb 21, 2016 at 11:27 PM George Corney  > wrote:
>
>> Hello,
>>
>> I'm working with typed arrays in v8 3.28, I've got a native function that 
>> takes a Float32Array from javascript and passes the float* data off to a gl 
>> call (glBufferData).
>>
>> I discovered that using just
>> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData
>> ();
>> works, but not reliably, the data gets passes to glBufferData correctly 
>> most of the time, but not always! 
>>
>> I've found creating a persistent handle before getting the data pointer, 
>> and then reseting handle after the glBufferData solves the problem, but is 
>> it the right approach? Am I leaking memory / risking sending incorrect data 
>> to glBufferData? Here's the snippet
>>
>> v8::Local bufferView = 
>> dataArg.As();
>> size_t byteLength = bufferView->ByteLength();
>> size_t byteOffset = bufferView->ByteOffset();
>>
>> v8::Persistent persistent;
>> persistent.Reset(__contextORisolate, bufferView->Buffer());
>>
>> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
>> const unsigned char* bytePtr = static_cast(rawData);
>>
>> glBufferData(target, byteLength, bytePtr + byteOffset, usage);
>> REPORT_GL_ERRORS();
>>
>> persistent.Reset();
>>
>>
>> ---
>>
>> If this the wrong approach, I think the next thing is to use 
>> bufferView->Buffer()->Externalize();
>> before getting the data pointer. In this case I'm then responsible for 
>> freeing the data - If this is necessary, could you explain how to do this? 
>> Can it be done without altering the ArrayBufferAllocator? 
>>
>>
>> Many thanks!
>> George Corney
>>
>> -- 
>> -- 
>> v8-users mailing list
>> v8-u...@googlegroups.com 
>> http://groups.google.com/group/v8-users
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "v8-users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to v8-users+u...@googlegroups.com .
>> For more options, visit https://groups.google.com/d/optout.
>>
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread Ben Noordhuis
On Sun, Feb 21, 2016 at 11:27 PM, George Corney  wrote:
> Hello,
>
> I'm working with typed arrays in v8 3.28, I've got a native function that
> takes a Float32Array from javascript and passes the float* data off to a gl
> call (glBufferData).
>
> I discovered that using just
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> works, but not reliably, the data gets passes to glBufferData correctly most
> of the time, but not always!
>
> I've found creating a persistent handle before getting the data pointer, and
> then reseting handle after the glBufferData solves the problem, but is it
> the right approach? Am I leaking memory / risking sending incorrect data to
> glBufferData? Here's the snippet
>
> v8::Local bufferView =
> dataArg.As();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
> v8::Persistent persistent;
> persistent.Reset(__contextORisolate, bufferView->Buffer());
>
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast(rawData);
>
> glBufferData(target, byteLength, bytePtr + byteOffset, usage);
> REPORT_GL_ERRORS();
>
> persistent.Reset();
>
>
> ---
>
> If this the wrong approach, I think the next thing is to use
> bufferView->Buffer()->Externalize();
> before getting the data pointer. In this case I'm then responsible for
> freeing the data - If this is necessary, could you explain how to do this?
> Can it be done without altering the ArrayBufferAllocator?
>
>
> Many thanks!
> George Corney

GetIndexedPropertiesExternalArrayData() is the wrong approach if you
plan on upgrading someday - it was removed in V8 3.29.  In your case,
I'd use GetContents() coupled with a Persistent for
keeping the arraybuffer object alive until you're done with it.

If GetContents() doesn't exist in the version of V8 you're using,
upgrade.  That's a good idea anyway because the 3.28 branch is
retired, the last update was in 2014.

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread Jochen Eisinger
Please note that 3.28 is a really old version of V8 which is full of known
issues and no longer maintained.

In general, you'll wait to externalize the buffer and keep a weak
persistent handle to the buffer - once the weak callback was triggered, you
know that you can free the backing store (if you no longer need it
otherwise).

More current versions of V8 also have a method
ArrayBufferView::CopyContents that allows you to access the backing store
without externalizing the underlying buffer.

On Sun, Feb 21, 2016 at 11:27 PM George Corney  wrote:

> Hello,
>
> I'm working with typed arrays in v8 3.28, I've got a native function that
> takes a Float32Array from javascript and passes the float* data off to a gl
> call (glBufferData).
>
> I discovered that using just
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> works, but not reliably, the data gets passes to glBufferData correctly
> most of the time, but not always!
>
> I've found creating a persistent handle before getting the data pointer,
> and then reseting handle after the glBufferData solves the problem, but is
> it the right approach? Am I leaking memory / risking sending incorrect data
> to glBufferData? Here's the snippet
>
> v8::Local bufferView =
> dataArg.As();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
> v8::Persistent persistent;
> persistent.Reset(__contextORisolate, bufferView->Buffer());
>
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast(rawData);
>
> glBufferData(target, byteLength, bytePtr + byteOffset, usage);
> REPORT_GL_ERRORS();
>
> persistent.Reset();
>
>
> ---
>
> If this the wrong approach, I think the next thing is to use
> bufferView->Buffer()->Externalize();
> before getting the data pointer. In this case I'm then responsible for
> freeing the data - If this is necessary, could you explain how to do this?
> Can it be done without altering the ArrayBufferAllocator?
>
>
> Many thanks!
> George Corney
>
> --
> --
> v8-users mailing list
> v8-users@googlegroups.com
> http://groups.google.com/group/v8-users
> ---
> You received this message because you are subscribed to the Google Groups
> "v8-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to v8-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[v8-users] v8 3.28, getting data from typed arrays, I'm unsure if this approach is correct (and doesn't leak)

2016-02-21 Thread George Corney
Hello,

I'm working with typed arrays in v8 3.28, I've got a native function that 
takes a Float32Array from javascript and passes the float* data off to a gl 
call (glBufferData).

I discovered that using just
const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
works, but not reliably, the data gets passes to glBufferData correctly 
most of the time, but not always! 

I've found creating a persistent handle before getting the data pointer, 
and then reseting handle after the glBufferData solves the problem, but is 
it the right approach? Am I leaking memory / risking sending incorrect data 
to glBufferData? Here's the snippet

v8::Local bufferView = 
dataArg.As();
size_t byteLength = bufferView->ByteLength();
size_t byteOffset = bufferView->ByteOffset();

v8::Persistent persistent;
persistent.Reset(__contextORisolate, bufferView->Buffer());

const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
const unsigned char* bytePtr = static_cast(rawData);

glBufferData(target, byteLength, bytePtr + byteOffset, usage);
REPORT_GL_ERRORS();

persistent.Reset();


---

If this the wrong approach, I think the next thing is to use 
bufferView->Buffer()->Externalize();
before getting the data pointer. In this case I'm then responsible for 
freeing the data - If this is necessary, could you explain how to do this? 
Can it be done without altering the ArrayBufferAllocator? 


Many thanks!
George Corney

-- 
-- 
v8-users mailing list
v8-users@googlegroups.com
http://groups.google.com/group/v8-users
--- 
You received this message because you are subscribed to the Google Groups 
"v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.