Skip to content
File

Blob: src/workerd/jsg/fast-api.h

cpp111 lines
1#pragma once
2 
3// Fast API implementation for workerd
4//
5// This file provides utilities to support V8 Fast API Calls, which allow optimized
6// method calls from JavaScript to C++ without going through the V8 API. Fast API
7// Calls perform type checks in the compiler instead of on the embedder side and
8// are subject to strict limitations - they cannot allocate on the JS heap or
9// trigger JS execution.
10//
11// The implementation provides concepts and helpers to determine which types and methods
12// are compatible with Fast API, handling both primitive types that can be passed directly
13// and wrapped objects that require conversion between JavaScript and C++.
14//
15// We don't add FastOneByteString because any GC call before FastOneByteString being copied
16// will corrupt the string data and cause catastrophic failures with almost zero stack trace.
17// For more information, see https://github.com/cloudflare/workerd/pull/4625.
18 
19#include <v8-fast-api-calls.h>
20#include <v8-local-handle.h>
21#include <v8-value.h>
22 
23#include <kj/async.h>
24#include <kj/common.h>
25#include <kj/string.h>
26 
27namespace workerd::jsg {
28 
29class DOMString;
30class USVString;
31class Lock;
32template <typename T>
33class Promise;
34 
35template <typename T>
36constexpr bool isFunctionCallbackInfo = false;
37 
38template <typename T>
39constexpr bool isFunctionCallbackInfo<v8::FunctionCallbackInfo<T>> = true;
40 
41template <typename T>
42constexpr bool isKjPromise = false;
43 
44template <typename T>
45constexpr bool isKjPromise<kj::Promise<T>> = true;
46 
47template <typename T>
48constexpr bool isJsgPromise = false;
49 
50template <typename T>
51constexpr bool isJsgPromise<jsg::Promise<T>> = true;
52 
53// These types are passed by fast api as is and do not require wrapping/unwrapping.
54template <typename T>
55concept FastApiPrimitive = kj::isSameType<T, void>() || kj::isSameType<T, bool>() ||
56 kj::isSameType<T, int32_t>() || kj::isSameType<T, int64_t>() || kj::isSameType<T, uint32_t>() ||
57 kj::isSameType<T, uint64_t>() || kj::isSameType<T, float>() || kj::isSameType<T, double>();
58 
59// Helper to determine if a type can be used as a parameter in V8 Fast API
60template <typename T>
61concept FastApiParam = !isFunctionCallbackInfo<kj::RemoveConst<kj::Decay<T>>> &&
62 !isKjPromise<kj::RemoveConst<kj::Decay<T>>> && !isJsgPromise<kj::RemoveConst<kj::Decay<T>>>;
63 
64// Helper to determine if a type can be used as a return value in a V8 Fast API
65template <typename T>
66concept FastApiReturnParam = FastApiPrimitive<T>;
67 
68// Helper to determine if a method can be used with V8 fast API
69template <typename Ret, typename... Args>
70concept FastApiMethod = FastApiReturnParam<Ret> && (FastApiParam<Args> && ...);
71 
72// Helper to determine if a method pointer type is compatible with Fast API
73template <typename Method>
74constexpr bool isFastApiCompatible = false;
75 
76// Specialization for non-static member functions
77template <typename Class, typename Ret, typename... Args>
78constexpr bool isFastApiCompatible<Ret (Class::*)(Args...)> = FastApiMethod<Ret, Args...>;
79 
80// Specialization for const non-static member functions
81template <typename Class, typename Ret, typename... Args>
82constexpr bool isFastApiCompatible<Ret (Class::*)(Args...) const> = FastApiMethod<Ret, Args...>;
83 
84template <typename Class, typename Ret, typename... Args>
85constexpr bool isFastApiCompatible<Ret (Class::*)(jsg::Lock&, Args...)> =
86 FastApiMethod<Ret, Args...>;
87 
88template <typename Class, typename Ret, typename... Args>
89constexpr bool isFastApiCompatible<Ret (Class::*)(jsg::Lock&, Args...) const> =
90 FastApiMethod<Ret, Args...>;
91 
92// Specialization for static functions
93template <typename Ret, typename... Args>
94constexpr bool isFastApiCompatible<Ret(Args...)> = FastApiMethod<Ret, Args...>;
95 
96template <typename Ret, typename... Args>
97constexpr bool isFastApiCompatible<Ret(jsg::Lock&, Args...)> = FastApiMethod<Ret, Args...>;
98 
99template <typename T>
100struct FastApiJSGToV8 {
101 using value = v8::Local<v8::Value>;
102};
103 
104template <typename T>
105 requires FastApiPrimitive<kj::RemoveConst<kj::Decay<T>>>
106struct FastApiJSGToV8<T> {
107 using value = kj::RemoveConst<kj::Decay<T>>;
108};
109 
110} // namespace workerd::jsg