No ability to memcpy into an ArrayBuffer w/o externalizing the data

436 views
Skip to first unread message

Trevor Norris

unread,
May 12, 2014, 6:54:09 PM5/12/14
to v8-u...@googlegroups.com
Just noticed that ArrayBuffer::New(Isolate*, void*, size_t) now always externalizes the data, and from the API there doesn't appear to be a way to retrieve the void* to do any sort of memcpy into an existing ArrayBuffer.

This is presenting a fairly significant setback. As it's proving impossible to hand existing memory over to ArrayBuffer and have the garbage collector free the memory when the life of the ArrayBuffer has expired.

Is there a way to get this done? If not, can it be made possible?

/trev

Dmitry Lomov

unread,
May 15, 2014, 6:34:05 AM5/15/14
to v8-u...@googlegroups.com
Hi Trevor,

Since V8 does not know how the memory backing an ArrayBuffer has been allocated in this case, there is now good way for V8 to free it. 
Just like previously with "external indexed data", the way to do it is to use a weak persistent handle for the ArrayBuffer to get a notification when ArrayBuffer becomes unreachable and then deal with your memory block accordingly.

Dmitry


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

Trevor Norris

unread,
May 15, 2014, 7:16:47 AM5/15/14
to v8-u...@googlegroups.com


On May 15, 2014 3:34 AM, "Dmitry Lomov" <dsl...@chromium.org> wrote:
>
> Hi Trevor,
>
> Since V8 does not know how the memory backing an ArrayBuffer has been allocated in this case, there is now good way for V8 to free it. 

Since the user has to define the ArrayBufferAllocator, V8 isn't in control of how memory is allocated regardless.

Technically using preallocated memory could be hacked in by having the user defined allocator use the user allocated memory instead. Meaning, it's possible but an inappropriate hack of the API. So I'm missing why entrusting the user to only pass in data that's been allocated properly is an issue.

> Just like previously with "external indexed data", the way to do it is to use a weak persistent handle for the ArrayBuffer to get a notification when ArrayBuffer becomes unreachable and then deal with your memory block accordingly.

This removes the performance benefit of using ArrayBuffers. I noticed how much work went in to making ArrayBuffers faster, and I would like to take advantage of this as much as possible.

One additional issue. Say ArrayBuffer is left to allocate the memory correctly. Why is it I can't simply get a pointer back out for a simple operation like memcpy()  without needing to go through all this?

As it stands, the API requires that I either for loop through and copy in values or use a weak persistent handle. Neither of those are particularly appealing.

Can we work out a way to allow the user to get a pointer back from the ArrayBuffer, also have an API sanctioned way of using preallocated memory, without needing to use a weak persistent handle?

Dean McNamee

unread,
Jul 9, 2014, 6:30:33 AM7/9/14
to v8-u...@googlegroups.com
What is the right way to access an ArrayBuffer's memory without
externalizing it? I noticed that the ArrayBufferView objects have the
old API (GetIndexedPropertiesExternalArrayData), because they are
using that mechanism to reference into the ArrayBuffer. However, for
just an ArrayBuffer and not an ArrayBufferView, how can you access the
backing store? From JavaScript you cannot index into an ArrayBuffer
so it makes that HasIndexedPropertiesInExternalArrayData is false.
Currently it seems like the only way is to call Externalize().
Coincidently it doesn't seem valid to do if it is already external, so
not only do you have to track the memory with a weak reference to free
it, you also have to track the Contents / data pointer somewhere to
associate it with the ArrayBuffer?

I would really prefer not to have the manage the memory lifetime, I
just need to peek at the backing store for a second and copy some
things out. I am already doing this for ArrayBufferViews and
everything works well, but I would like to support ArrayBuffers also.
There shouldn't be any worries about moving or GC, since the memory
was allocated with Allocator, it should be safe just to access the
pointer (of course holding the object alive with a handle).

Thanks,

Flying Jester

unread,
Sep 12, 2014, 5:38:53 PM9/12/14
to v8-u...@googlegroups.com


Since V8 does not know how the memory backing an ArrayBuffer has been allocated in this case, there is now good way for V8 to free it.

This doesn't make sense.

A part of v8::ArrayBuffer::Allocator is a Free method. When you pass an allocator to v8::V8::SetArrayBufferAllocator, you are giving V8 all the tools to both allocate and deallocate memory for an ArrayBuffer.

I see absolutely no reason why you can't make the ArrayBuffer take ownership of the memory again when you are done with it. It took ownership when it was created. If it can't take ownership again, this sounds to me like a limitation of it's implementation, not an actual virtue of its design.

Dmitry Lomov

unread,
Sep 18, 2014, 3:00:10 PM9/18/14
to v8-u...@googlegroups.com
On Fri, Sep 12, 2014 at 11:38 PM, Flying Jester <foolki...@gmail.com> wrote:


Since V8 does not know how the memory backing an ArrayBuffer has been allocated in this case, there is now good way for V8 to free it.

This doesn't make sense.

A part of v8::ArrayBuffer::Allocator is a Free method. When you pass an allocator to v8::V8::SetArrayBufferAllocator, you are giving V8 all the tools to both allocate and deallocate memory for an ArrayBuffer.

You can create an ArrayBuffer over external memory (v8::ArrayBuffer::New(v8::Isolate*, void*, size_t)). V8 has no idea how this data has been allocated.

I see absolutely no reason why you can't make the ArrayBuffer take ownership of the memory again when you are done with it. It took ownership when it was created. If it can't take ownership again, this sounds to me like a limitation of it's implementation, not an actual virtue of its design.

I can imagine the API where embedder says to V8: "hey ArrayBuffer I absolutely know what I am doing take ownership of this void*". The problem with that is that people usually don't, they keep the reference to the void* somewhere and later when an ArrayBuffer is garbage-collected it is use-after-free and misery. I do not have a good solution for that yet.

Dmitry


Flying Jester

unread,
Sep 18, 2014, 3:20:39 PM9/18/14
to v8-u...@googlegroups.com
I don't believe you should be able to pass any old pointer into it. I'm saying it would vastly simplify things to be able to re-internalize a previously externalized pointer.

Dmitry Lomov

unread,
Sep 18, 2014, 4:34:39 PM9/18/14
to v8-u...@googlegroups.com
On Thu, Sep 18, 2014 at 9:20 PM, Flying Jester <foolki...@gmail.com> wrote:
I don't believe you should be able to pass any old pointer into it. I'm saying it would vastly simplify things to be able to re-internalize a previously externalized pointer.

How this restriction solves anything?
 

On Thursday, September 18, 2014 11:00:10 AM UTC-8, Dmitry Lomov wrote:


On Fri, Sep 12, 2014 at 11:38 PM, Flying Jester <foolki...@gmail.com> wrote:


Since V8 does not know how the memory backing an ArrayBuffer has been allocated in this case, there is now good way for V8 to free it.

This doesn't make sense.

A part of v8::ArrayBuffer::Allocator is a Free method. When you pass an allocator to v8::V8::SetArrayBufferAllocator, you are giving V8 all the tools to both allocate and deallocate memory for an ArrayBuffer.

You can create an ArrayBuffer over external memory (v8::ArrayBuffer::New(v8::Isolate*, void*, size_t)). V8 has no idea how this data has been allocated.

I see absolutely no reason why you can't make the ArrayBuffer take ownership of the memory again when you are done with it. It took ownership when it was created. If it can't take ownership again, this sounds to me like a limitation of it's implementation, not an actual virtue of its design.

I can imagine the API where embedder says to V8: "hey ArrayBuffer I absolutely know what I am doing take ownership of this void*". The problem with that is that people usually don't, they keep the reference to the void* somewhere and later when an ArrayBuffer is garbage-collected it is use-after-free and misery. I do not have a good solution for that yet.

Dmitry


Flying Jester

unread,
Sep 18, 2014, 4:54:59 PM9/18/14
to v8-u...@googlegroups.com
It would ensure that the V8 has the correct Free method for it.

If you keep a reference to memory after you explicitly give up ownership of its lifetime and it later gets freed, that is not the library's fault.

Dmitry Lomov

unread,
Sep 18, 2014, 5:10:13 PM9/18/14
to v8-u...@googlegroups.com
On Thu, Sep 18, 2014 at 10:54 PM, Flying Jester <foolki...@gmail.com> wrote:
It would ensure that the V8 has the correct Free method for it.
Sure but that was not the primary issue.
 

If you keep a reference to memory after you explicitly give up ownership of its lifetime and it later gets freed, that is not the library's fault.

I wish it weren't :) API design is not a blame game, and this is the point of our disagreement, of course. 

Trevor Norris

unread,
Sep 19, 2014, 5:52:18 PM9/19/14
to v8-u...@googlegroups.com
On Thursday, September 18, 2014 2:10:13 PM UTC-7, Dmitry Lomov wrote:

On Thu, Sep 18, 2014 at 10:54 PM, Flying Jester <foolki...@gmail.com> wrote:

If you keep a reference to memory after you explicitly give up ownership of its lifetime and it later gets freed, that is not the library's fault.

I wish it weren't :) API design is not a blame game, and this is the point of our disagreement, of course.

Originally the ArrayBuffer API did allow the user to pass in and access memory without having to externalize it. That was a huge advantage because of all the performance optimizations that have been done for ArrayBuffers. Unfortunately those are lost once the memory has to be externalized. I hope that part of the initial API is brought back.

Currently there is a way to circumvent part of the API limitation with a (horrible) hack. That is to create a global (well, as far as the v8::Isolate is concerned) void* and then to assign the data you wish to turn into an ArrayBuffer to it just before the call to v8::ArrayBuffer::Allocator::Allocate(). Then inside Allocate() check if the void* == NULL. If not then return that instead. This way I can at least initialize an ArrayBuffer with existing memory.

Though the limitation of not being able to access the data once it's been passed to an ArrayBuffer without needing to externalize it is still a serious bummer.
Reply all
Reply to author
Forward
0 new messages