Skip to content

Conversation

@pkiers
Copy link

@pkiers pkiers commented Jan 27, 2026

Summary

  • Adds CefV8BackingStore class that wraps V8's ArrayBuffer::BackingStore, allowing the backing memory to be allocated on the renderer thread and populated (e.g. memcpy) on a background thread
  • Adds CefV8Value::CreateArrayBufferFromBackingStore() static method to create an ArrayBuffer from a pre-populated backing store in a zero-copy operation
  • Works with V8 sandbox enabled, unlike CreateArrayBuffer (external buffer)

Motivation

Currently with V8 sandbox enabled, CreateArrayBuffer is not supported and CreateArrayBufferWithCopy performs the memcpy on the JS thread. For large buffers this blocks the renderer. This API enables:

  1. Renderer thread: CefV8BackingStore::Create(size) — allocate sandbox-compatible memory
  2. Background thread: write data into Data() pointer — expensive work off JS thread
  3. Renderer thread: CreateArrayBufferFromBackingStore(store) — zero-copy ArrayBuffer creation

API

class CefV8BackingStore : public virtual CefBaseRefCounted {
  static CefRefPtr<CefV8BackingStore> Create(size_t byte_length);
  virtual void* Data() = 0;
  virtual size_t ByteLength() = 0;
  virtual bool IsValid() = 0;
};

// On CefV8Value:
static CefRefPtr<CefV8Value> CreateArrayBufferFromBackingStore(
    CefRefPtr<CefV8BackingStore> backing_store);

Test plan

  • cef_unittests --gtest_filter="V8Test.ArrayBufferBackingStore" — covers creation, data access, zero-copy ArrayBuffer, consumption invalidation, double-use rejection, and neutering
  • Translator tool generates wrappers without errors
  • Verify with V8 sandbox both enabled and disabled

…ingStore()

to allow creating ArrayBuffer backing memory on the renderer thread, populating
it with data on a background thread (avoiding expensive memcpy on the JS
thread), and then creating a zero-copy ArrayBuffer from it.

This is particularly useful when V8 sandbox is enabled, where
CreateArrayBuffer (external buffer) is not supported and
CreateArrayBufferWithCopy performs the memcpy on the JS thread.

Changes:
- Add CefV8BackingStore interface with Create(), Data(), ByteLength(), IsValid()
- Add CefV8Value::CreateArrayBufferFromBackingStore() static factory method
- Add CefV8BackingStoreImpl with thread-safe access and move semantics
- Add V8TEST_ARRAY_BUFFER_BACKING_STORE unit test
Copy link
Collaborator

@magreenblatt magreenblatt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR. Please see comments inline.

- Add byte_length==0 check in CefV8BackingStore::Create()
- Add [[nodiscard]] attribute to TakeBackingStore()
@pkiers
Copy link
Author

pkiers commented Jan 28, 2026

Thanks for the review, comments have been resolved.

I was wondering if I would make getter for CefV8ArrayBuffer to retreive the underlying CefV8BackingStore also. It already has Data getter. What you think?

virtual void ReleaseBuffer(void* buffer) = 0;
};

///
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New classes/methods need to be protected by #if CEF_API_ADDED(CEF_NEXT) with appropriate /*--cef(added=next)--*/ metadata. See https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md#markdown-header-usage-in-pull-requests

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed that

/// Returns a pointer to the allocated memory, or nullptr if the backing
/// store has been consumed or is otherwise invalid. The pointer is safe to
/// read/write from any thread. The caller must ensure all writes are complete
/// before passing this object to CreateArrayBufferFromBackingStore().
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a warning here about not keeping a pointer reference after passing to CreateArrayBufferFromBackingStore?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a warning to the Data() doc comment: "Pointers obtained from this method should not be retained after calling CreateArrayBufferFromBackingStore(), as the memory will then be owned by the ArrayBuffer and subject to V8 garbage collection."

- Wrap CefV8BackingStore class and CreateArrayBufferFromBackingStore with
- Add warning to Data() about not retaining pointer after
CreateArrayBufferFromBackingStore
@nik-sp
Copy link
Collaborator

nik-sp commented Jan 30, 2026

Hey, thanks for the PR!

I have a question about the base::Lock lock_ in CefV8BackingStoreImpl. Could you explain the reasoning behind it?

As I see it, the lock doesn't fully make the class thread-safe. It protects individual method calls, but once Data() returns, the lock is released and the caller holds a raw pointer with no protection. Another thread can then call TakeBackingStore(), leaving the first thread with a dangling pointer.

What do you think about removing the lock and instead documenting that the class is safe to pass between threads, but not to share across threads simultaneously? This seems to match the intended usage pattern:

Renderer thread: Create backing store
       ↓ (pass)
Background thread: Populate via Data()
       ↓ (pass)
Renderer thread: CreateArrayBufferFromBackingStore()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants