*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.