Questions about the state of v8 fast API

186 views
Skip to first unread message

Yagiz Nizipli

unread,
Apr 24, 2025, 4:17:47 PMApr 24
to v8-dev
We are actively investigating/working on adding V8 Fast API support for Cloudflare Workers. While looking at the v8-fast-api-calls.h file (ref: https://github.com/v8/v8/blob/main/include/v8-fast-api-calls.h) , I realized that some of the documentation referencing the limitations are not correct and up to date.

I'm more than happy to update the header file to reflect the current state of the implementation, but first,  I'd like to ask couple of questions to understand the implementation better. 

- Is V8 Fast API considered unstable?
- Since V8 fast api can now allocate, trigger JS and GC, which limitations still apply? Looking at line 24, I believe these comments are not valid.
- What is the heuristics of CFunction overloads? In an example where a function has a required and an optional parameter, is it sufficient to add 2 functions,  method(a) and method(a, b)? What is the behavior if the user calls this method with 3 arguments? Would it trigger method(a,b)? Is the order MemorySpan CFunctions make a difference? Since v8::Local<Value> is supported, it seems we can get away with a CFunction that has a second parameter of v8::Local<Value> for the optional parameter.
- Since v8 fast api supports v8::Local<v8::Value> now, is there any particular reason for using FastOneByteString over v8 local value for one byte strings?
- By looking at the documentation, the only limitations I could think of are the ones related to the return type of CFunction, which doesn't allow returning objects/values/strings. What are the actual limitations of V8 fast api?

Thank you for your help.

Andreas Haas

unread,
Apr 28, 2025, 2:48:28 AMApr 28
to v8-...@googlegroups.com
Hi,

I would say the V8 Fast API is still considered unstable. Since many limitations were removed, not only the documentation but also the APIs are out-dated and would benefit from cleanup. However, since old APIs have to be deprecated before they can be changed, this takes some time.

When it comes to arguments, there are some subtle limitations left, see [1], but those are platform-specific. Mostly all limitations should be gone. I will go over the documentation and update it. When it comes to return values, then indeed, as you noted, objects and strings cannot be returned, only integers, floats, and void.

The heuristics of CFunction overloads depends now only on the number of arguments. If an API function is called in JavaScript with n parameters, then it will call the C++ function which expects n parameters. If no such C++ exists, then no fast call is happening. If the API has overloads or optional parameters, then this has to be resolved by the C++ functions. There should not be two CFunctions with the same number of arguments, although I'm not sure if we are checking for that.

Unfortunately, `FastOneByteString` is faster than what you can achieve with a `v8::Local<v8::Value>` parameter, when you use `FastOneByteString`, you should not trigger a GC.

Cheers, Andreas


--
--
v8-dev mailing list
v8-...@googlegroups.com
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-dev+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/v8-dev/08d9e03f-9db2-47c9-98ce-72c464c72475n%40googlegroups.com.


--

Andreas Haas

Software Engineer

ah...@google.com


Google Germany GmbH

Erika-Mann-Straße 33

80636 München


Geschäftsführer: Paul Manicle, Liana Sebastian

Registergericht und -nummer: Hamburg, HRB 86891

Sitz der Gesellschaft: Hamburg


Diese E-Mail ist vertraulich. Falls Sie diese fälschlicherweise erhalten haben sollten, leiten Sie diese bitte nicht an jemand anderes weiter, löschen Sie alle Kopien und Anhänge davon und lassen Sie mich bitte wissen, dass die E-Mail an die falsche Person gesendet wurde.

    

This e-mail is confidential. If you received this communication by mistake, please don't forward it to anyone else, please erase all copies and attachments, and please let me know that it has gone to the wrong person.


Aapo Alasuutari

unread,
Apr 28, 2025, 4:50:32 AMApr 28
to v8-dev
Don't forget about pointers! Those can be returned as well :)

Yagiz Nizipli

unread,
Apr 28, 2025, 1:41:03 PMApr 28
to v8-dev
What's the use case of returning a pointer from a v8 fast api?

Aapo Alasuutari

unread,
Apr 29, 2025, 7:37:00 AMApr 29
to v8-dev
It's a highly useful feature for doing FFI in JavaScript. Deno's FFI API relies on it heavily, as it enables passing opaque pointers through JavaScript without resorting to weird zero-sized ArrayBuffer workarounds, which I believe is the go-to method for doing this in the Node Addon / N-API world.

TypedArrays used to be fully supported in Fast API, at which time zero-sized ArrayBuffers could've been used at mostly equal performance as the External pointer objects, but there were some unfortunate bugs around that (like zero-sized AB/TAs always giving a null pointer in Fast API, or inline-created zero-size TAs giving a bogus pointer in Fast API; the first has been fixed, the second hasn't IIRC) and nowadays the TA support has been deprecated entirely. As a result, the only way to pass opaque pointers through Fast API without needing dedicated wrap and unwrap code on entry and exit from V8 is using the External pointers.

Hope this answers your question.
-Aapo

Erik Corry

unread,
Apr 29, 2025, 8:40:11 AMApr 29
to v8-...@googlegroups.com
Since JS doesn't have 64 ints, what does the pointer turn into on the JS side?

Aapo Alasuutari

unread,
Apr 29, 2025, 9:21:12 AMApr 29
to v8-dev
It becomes a v8::External which is an entirely immutable object with no properties and no prototype; from JS point of view it's a object that cannot be interacted with aside from doing equality comparisons.

The engine side of course can use that object to track down the actual pointer value (which I believe is stored either in the object directly or in the External Pointer Table, depending on build flags).

-Aapo

James Snell

unread,
Apr 29, 2025, 9:32:39 AMApr 29
to v8-...@googlegroups.com
In workers we don't have a lot of use for Externals but we do extensively use c++ API objects that are wrapped by JS objects (defined by Function templates). Is there a roadmap for fast API to expand the return value types? Could their potentially be a path for returning pointers to API objects that are wrapped by their associated function templates rather than External?

- James M Snell
  he/him
  https://bsky.app/profile/jasnell.me

Andreas Haas

unread,
Apr 29, 2025, 1:07:15 PMApr 29
to v8-...@googlegroups.com
When the C++ function returns a pointer, the generated code wraps it in a JavaScript `External` object. In JavaScript it would be an opaque object, but when it gets passed back to C++ the pointer can be extracted again.

Andreas Haas

unread,
Apr 29, 2025, 1:07:15 PMApr 29
to v8-...@googlegroups.com
It would probably be better to support `Local<Value>` returns, and then let the embedder allocate the `External` in the API function instead of in generated code. When the embedder allocates the `External`, it could set the correct type, and thereby use the type checking of the V8 sandbox better. However, returning `Local<Value>` is not a priority at the moment, and the support for returning pointers over the fast API does not cause side effects, really, so I think this will not change anytime soon.

Cheers, Andreas

On Tue, Apr 29, 2025 at 1:37 PM Aapo Alasuutari <aapo.al...@gmail.com> wrote:

Andreas Haas

unread,
Apr 29, 2025, 1:07:15 PMApr 29
to v8-...@googlegroups.com
The pointer turns into a JS object, which is a wrapper around the pointer. The pointer is not visible from JS, but it can be unwrapped in C++.

Andreas Haas

unread,
May 1, 2025, 2:00:17 PMMay 1
to v8-...@googlegroups.com
There is no roadmap at the moment for the fast API to expand the return type values.

When I think about it, there is a fundamental problem with returns of type `Local<Value>`. A `Local<Value>` is allocated in a `HandleScope`. The `HandleScope` would be opened at the beginning of the C++ function, and closed in its epilogue. After the `HandleScope` is closed, all `Local<Value>`s are deallocated again and can therefore not be returned anymore. Within V8 the function would just return the `Value` instead, but for the embedder it is not possible to extract the `Value` from a `Local<Value>`.

There exist workarounds for this problem, but these add overhead, and with that overhead, fast API calls may already not be faster anymore than fast API calls.

Cheers, Andreas

Yagiz Nizipli

unread,
May 3, 2025, 4:19:37 PMMay 3
to v8-dev
I've created a separate discussion around a regression caused by a v8 fast api path on node.js - https://groups.google.com/g/v8-dev/c/x2Fs6do0jDA.
Reply all
Reply to author
Forward
0 new messages