File
Blob: src/workerd/jsg/fast-api.h
| 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 | |
| 27 | namespace workerd::jsg { |
| 28 | |
| 29 | class DOMString; |
| 30 | class USVString; |
| 31 | class Lock; |
| 32 | template <typename T> |
| 33 | class Promise; |
| 34 | |
| 35 | template <typename T> |
| 36 | constexpr bool isFunctionCallbackInfo = false; |
| 37 | |
| 38 | template <typename T> |
| 39 | constexpr bool isFunctionCallbackInfo<v8::FunctionCallbackInfo<T>> = true; |
| 40 | |
| 41 | template <typename T> |
| 42 | constexpr bool isKjPromise = false; |
| 43 | |
| 44 | template <typename T> |
| 45 | constexpr bool isKjPromise<kj::Promise<T>> = true; |
| 46 | |
| 47 | template <typename T> |
| 48 | constexpr bool isJsgPromise = false; |
| 49 | |
| 50 | template <typename T> |
| 51 | constexpr bool isJsgPromise<jsg::Promise<T>> = true; |
| 52 | |
| 53 | // These types are passed by fast api as is and do not require wrapping/unwrapping. |
| 54 | template <typename T> |
| 55 | concept 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 |
| 60 | template <typename T> |
| 61 | concept 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 |
| 65 | template <typename T> |
| 66 | concept FastApiReturnParam = FastApiPrimitive<T>; |
| 67 | |
| 68 | // Helper to determine if a method can be used with V8 fast API |
| 69 | template <typename Ret, typename... Args> |
| 70 | concept FastApiMethod = FastApiReturnParam<Ret> && (FastApiParam<Args> && ...); |
| 71 | |
| 72 | // Helper to determine if a method pointer type is compatible with Fast API |
| 73 | template <typename Method> |
| 74 | constexpr bool isFastApiCompatible = false; |
| 75 | |
| 76 | // Specialization for non-static member functions |
| 77 | template <typename Class, typename Ret, typename... Args> |
| 78 | constexpr bool isFastApiCompatible<Ret (Class::*)(Args...)> = FastApiMethod<Ret, Args...>; |
| 79 | |
| 80 | // Specialization for const non-static member functions |
| 81 | template <typename Class, typename Ret, typename... Args> |
| 82 | constexpr bool isFastApiCompatible<Ret (Class::*)(Args...) const> = FastApiMethod<Ret, Args...>; |
| 83 | |
| 84 | template <typename Class, typename Ret, typename... Args> |
| 85 | constexpr bool isFastApiCompatible<Ret (Class::*)(jsg::Lock&, Args...)> = |
| 86 | FastApiMethod<Ret, Args...>; |
| 87 | |
| 88 | template <typename Class, typename Ret, typename... Args> |
| 89 | constexpr bool isFastApiCompatible<Ret (Class::*)(jsg::Lock&, Args...) const> = |
| 90 | FastApiMethod<Ret, Args...>; |
| 91 | |
| 92 | // Specialization for static functions |
| 93 | template <typename Ret, typename... Args> |
| 94 | constexpr bool isFastApiCompatible<Ret(Args...)> = FastApiMethod<Ret, Args...>; |
| 95 | |
| 96 | template <typename Ret, typename... Args> |
| 97 | constexpr bool isFastApiCompatible<Ret(jsg::Lock&, Args...)> = FastApiMethod<Ret, Args...>; |
| 98 | |
| 99 | template <typename T> |
| 100 | struct FastApiJSGToV8 { |
| 101 | using value = v8::Local<v8::Value>; |
| 102 | }; |
| 103 | |
| 104 | template <typename T> |
| 105 | requires FastApiPrimitive<kj::RemoveConst<kj::Decay<T>>> |
| 106 | struct FastApiJSGToV8<T> { |
| 107 | using value = kj::RemoveConst<kj::Decay<T>>; |
| 108 | }; |
| 109 | |
| 110 | } // namespace workerd::jsg |