*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<v8::ArrayBuffer>* persistent;
uintptr_t dataPtrValue;
};

//when we get typed array data we take responsibility for freeing the data
void ArrayBufferWeakCallback(const v8::WeakCallbackData<v8::ArrayBuffer, 
WeakCallbackData>& info){
WeakCallbackData* callbackData = info.GetParameter();
v8::Persistent<v8::ArrayBuffer>* 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<v8::ArrayBuffer>& 
buffer, void* dataPtr){
v8::Local<v8::ObjectTemplate> ptrObjTmpl = v8::ObjectTemplate::New(isolate);
ptrObjTmpl->SetInternalFieldCount(1);
v8::Local<v8::Object> 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<v8::ArrayBuffer>& buffer){
if(!buffer->IsExternal()){
v8::ArrayBuffer::Contents contents = buffer->Externalize();
RegisterExternalData(isolate, buffer, contents.Data());
}
}

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

AttachPointerObject(isolate, buffer, dataPtr);

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

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

persistent->SetWeak<WeakCallbackData>(callbackData, 
ArrayBufferWeakCallback);
}

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

v8::Local<v8::Value> 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<v8::Object> ptrObj = v8::Local<v8::Object>::Cast(v);
const void* dataPtr = ptrObj->GetAlignedPointerFromInternalField(0);
const unsigned char* bytePtr = static_cast<const unsigned char*>(dataPtr);
return bytePtr;
}


const unsigned char* GetArrayBufferViewBytes(v8::Isolate* isolate, 
v8::Handle<v8::ArrayBufferView>& bufferView){
v8::Local<v8::ArrayBuffer> buffer = bufferView->Buffer();
SafelyExternalizeArrayBuffer(isolate, buffer);
const void* dataPtr = bufferView->GetIndexedPropertiesExternalArrayData();
const unsigned char* bytePtr = static_cast<const unsigned char*>(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::ArrayBuffer, 
> v8::Persistent<v8::ArrayBuffer>>& info){
>  Print::Debug("ArrayBufferWeakCallback fired");
>  void* rawData = info.GetValue()->GetIndexedPropertiesExternalArrayData();
>  info.GetValue().Clear();
>  info.GetParameter()->Reset();
>  free(rawData);
>  free(info.GetParameter());
> }
>
>
> //...
>
>
> v8::Local<v8::ArrayBufferView> bufferView = dataArg.As<v8::ArrayBufferView
> >();
> size_t byteLength = bufferView->ByteLength();
> size_t byteOffset = bufferView->ByteOffset();
>
>
> bufferView->Buffer()->Externalize();
>
>
> //create weak persistent handle with callback to above code
> v8::Persistent<v8::ArrayBuffer>* persistent = new v8::Persistent<v8::
> ArrayBuffer>();
> persistent->Reset(isolate, buffer);
> persistent->SetWeak<v8::Persistent<v8::ArrayBuffer>>(persistent, 
> ArrayBufferWeakCallback);
>
>
> const void* rawData = bufferView->GetIndexedPropertiesExternalArrayData();
> const unsigned char* bytePtr = static_cast<const unsigned char*>(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 <haxi...@gmail.com> 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<v8::ArrayBufferView> bufferView = 
>>> dataArg.As<v8::ArrayBufferView>();
>>> size_t byteLength = bufferView->ByteLength();
>>> size_t byteOffset = bufferView->ByteOffset();
>>>
>>> v8::Persistent<v8::ArrayBuffer> persistent;
>>> persistent.Reset(__contextORisolate, bufferView->Buffer());
>>>
>>> const void* rawData = 
>>> bufferView->GetIndexedPropertiesExternalArrayData();
>>> const unsigned char* bytePtr = static_cast<const unsigned 
>>> char*>(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.

Reply via email to