Skip to content
File

Blob: src/rust/jsg/ffi.h

cpp347 lines
1// Copyright (c) 2026 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/jsg/modules.capnp.h>
8#include <workerd/jsg/wrappable.h>
9 
10#include <kj-rs/kj-rs.h>
11#include <rust/cxx.h>
12#include <v8.h>
13 
14#include <kj/function.h>
15#include <kj/memory.h>
16#include <kj/refcount.h>
17 
18// Forward declarations needed by v8.rs.h
19namespace workerd::rust::jsg {
20using Isolate = v8::Isolate;
21using FunctionCallbackInfo = v8::FunctionCallbackInfo<v8::Value>;
22struct ModuleRegistry;
23struct Local;
24struct MaybeLocal;
25struct Global;
26struct TracedReference;
27struct Realm;
28struct GcVisitor;
29enum class BackingStoreInitializationMode : ::std::uint8_t;
30enum class ExceptionType : ::std::uint8_t;
31// ModuleType enum is generated by CXX in v8.rs.h - forward declare it here
32enum class ModuleType : ::std::uint8_t;
33using ModuleCallback = ::rust::Fn<Local(Isolate*)>;
34 
35// Mirrors the CXX shared struct defined in v8.rs. Must be kept in sync.
36// The CXX-generated v8.rs.h provides the canonical definition; this is
37// only used when ffi.h is included before v8.rs.h (e.g. from ffi.c++
38// before the CXX bridge is compiled).
39#ifndef CXXBRIDGE1_STRUCT_workerd$rust$jsg$TraitObjectPtr
40#define CXXBRIDGE1_STRUCT_workerd$rust$jsg$TraitObjectPtr
41struct TraitObjectPtr {
42 uintptr_t data_ptr = 0;
43 uintptr_t vtable_ptr = 0;
44 uintptr_t type_id_lo = 0;
45 uintptr_t type_id_hi = 0;
46};
47#endif
48 
49// A Wrappable subclass for Rust objects.
50//
51// Lives on the KJ heap (via kj::Refcounted through Wrappable) and integrates
52// with cppgc via the CppgcShim bridge pattern that Wrappable provides.
53//
54// The data[] field stores a Rust fat pointer (data + vtable) to `dyn GarbageCollected`
55// from a leaked Box<dyn GarbageCollected>. This lets us call back into Rust for tracing
56// and destruction without knowing the concrete type at compile time.
57class Wrappable: public ::workerd::jsg::Wrappable {
58 public:
59 ~Wrappable();
60 void jsgVisitForGc(::workerd::jsg::GcVisitor& visitor) override;
61 kj::StringPtr jsgGetMemoryName() const override;
62 size_t jsgGetMemorySelfSize() const override;
63 
64 // Returns a new kj::Rc reference to this Wrappable.
65 kj::Rc<Wrappable> toRc() {
66 return addRefToThis();
67 }
68 
69 // Rust trait object pointer + TypeId, stored by Ref::new().
70 // Defined as a CXX shared struct in v8.rs; contains data_ptr, vtable_ptr,
71 // type_id_lo, type_id_hi.
72 TraitObjectPtr trait_object = {0, 0, 0, 0};
73};
74 
75struct ResourceDescriptor;
76 
77// Wrappable lifecycle — returns KjRc<Wrappable> to Rust for reference-counted ownership.
78// Ref::clone calls wrappable_add_strong_ref; Ref::drop calls wrappable_remove_strong_ref.
79// wrappable_remove_strong_ref does addRef(+1) + maybeDeferDestruction(-1) = net 0 on kj::Rc;
80// the actual kj::Rc decrement happens when WrappableRc (KjRc<Wrappable>) is dropped.
81kj::Rc<Wrappable> wrappable_new(TraitObjectPtr ptr);
82kj::Rc<Wrappable> wrappable_to_rc(Wrappable& wrappable);
83void wrappable_add_strong_ref(Wrappable& wrappable);
84void wrappable_remove_strong_ref(Wrappable& wrappable, bool is_strong);
85void wrappable_visit_ref(
86 Wrappable& wrappable, uintptr_t* ref_parent, bool* ref_strong, GcVisitor* visitor);
87 
88/// Visit a `v8::Global` field during GC tracing, implementing the same
89/// strong↔traced dual-mode switching as `jsg::Data` / `jsg::V8Ref<T>`.
90///
91/// `global` points to the `ptr` field of `ffi::Global` (the strong handle).
92/// `traced` is the `ffi::TracedReference` slot from `Global<T>` on the Rust side.
93/// Both are mutated in-place by this function.
94void wrappable_visit_global(GcVisitor* visitor, uintptr_t* global, TracedReference& traced);
95 
96/// Resets a `v8::TracedReference`, releasing the weak GC handle.
97/// Must be called when a `Global<T>` is dropped in traced mode to avoid
98/// leaking a live `v8::TracedReference`.
99void traced_reference_reset(TracedReference& traced);
100 
101// Local<T>
102void local_drop(Local value);
103Local local_clone(const Local& value);
104Global local_to_global(Isolate* isolate, Local value);
105Local local_new_number(Isolate* isolate, double value);
106Local local_new_string(Isolate* isolate, ::rust::Str value);
107Local local_new_boolean(Isolate* isolate, bool value);
108Local local_new_object(Isolate* isolate);
109Local local_new_null(Isolate* isolate);
110Local local_new_undefined(Isolate* isolate);
111bool local_eq(const Local& lhs, const Local& rhs);
112bool local_has_value(const Local& val);
113bool local_is_string(const Local& val);
114bool local_is_boolean(const Local& val);
115bool local_is_number(const Local& val);
116bool local_is_null(const Local& val);
117bool local_is_undefined(const Local& val);
118bool local_is_null_or_undefined(const Local& val);
119bool local_is_object(const Local& val);
120bool local_is_native_error(const Local& val);
121bool local_is_array(const Local& val);
122bool local_is_uint8_array(const Local& val);
123bool local_is_uint16_array(const Local& val);
124bool local_is_uint32_array(const Local& val);
125bool local_is_int8_array(const Local& val);
126bool local_is_int16_array(const Local& val);
127bool local_is_int32_array(const Local& val);
128bool local_is_float32_array(const Local& val);
129bool local_is_float64_array(const Local& val);
130bool local_is_bigint64_array(const Local& val);
131bool local_is_biguint64_array(const Local& val);
132bool local_is_float16_array(const Local& val);
133bool local_is_uint8clamped_array(const Local& val);
134bool local_is_array_buffer(const Local& val);
135bool local_is_array_buffer_view(const Local& val);
136bool local_is_shared_array_buffer(const Local& val);
137bool local_is_function(const Local& val);
138bool local_is_symbol(const Local& val);
139bool local_is_name(const Local& val);
140::rust::String local_type_of(Isolate* isolate, const Local& val);
141 
142// Local<String>
143Local local_string_empty(Isolate* isolate);
144int32_t local_string_length(const Local& value);
145bool local_string_is_one_byte(const Local& value);
146bool local_string_contains_only_one_byte(const Local& value);
147size_t local_string_utf8_length(Isolate* isolate, const Local& value);
148void local_string_write_v2(Isolate* isolate,
149 const Local& value,
150 uint32_t offset,
151 uint32_t length,
152 uint16_t* buffer,
153 int32_t flags);
154void local_string_write_one_byte_v2(Isolate* isolate,
155 const Local& value,
156 uint32_t offset,
157 uint32_t length,
158 uint8_t* buffer,
159 int32_t flags);
160size_t local_string_write_utf8_v2(
161 Isolate* isolate, const Local& value, uint8_t* buffer, size_t capacity, int32_t flags);
162bool local_string_equals(const Local& value, const Local& other);
163bool local_string_is_flat(const Local& value);
164Local local_string_concat(Isolate* isolate, Local left, Local right);
165Local local_string_internalize(Isolate* isolate, const Local& value);
166MaybeLocal local_string_new_from_utf8(
167 Isolate* isolate, const uint8_t* data, int32_t length, bool internalized);
168MaybeLocal local_string_new_from_one_byte(
169 Isolate* isolate, const uint8_t* data, int32_t length, bool internalized);
170MaybeLocal local_string_new_from_two_byte(
171 Isolate* isolate, const uint16_t* data, int32_t length, bool internalized);
172bool maybe_local_is_empty(const MaybeLocal& value);
173 
174// Local<Name>
175int32_t local_name_get_identity_hash(const Local& value);
176 
177// Local<Symbol>
178Local local_symbol_new(Isolate* isolate);
179Local local_symbol_new_with_description(Isolate* isolate, Local description);
180MaybeLocal local_symbol_description(Isolate* isolate, const Local& value);
181 
182// Local<Function>
183Local local_function_call(
184 Isolate* isolate, const Local& function, const Local& recv, ::rust::Slice<const Local> args);
185 
186// Local<Object>
187void local_object_set_property(Isolate* isolate, Local& object, ::rust::Str key, Local value);
188bool local_object_has_property(Isolate* isolate, const Local& object, ::rust::Str key);
189kj::Maybe<Local> local_object_get_property(Isolate* isolate, const Local& object, ::rust::Str key);
190 
191// Local<Array>
192Local local_new_array(Isolate* isolate, size_t length);
193uint32_t local_array_length(Isolate* isolate, const Local& array);
194Local local_array_get(Isolate* isolate, const Local& array, uint32_t index);
195void local_array_set(Isolate* isolate, Local& array, uint32_t index, Local value);
196::rust::Vec<Global> local_array_iterate(Isolate* isolate, Local value);
197 
198// Local<TypedArray>
199Local local_new_uint8_array(Isolate* isolate, const uint8_t* data, size_t length);
200Local local_new_uint16_array(Isolate* isolate, const uint16_t* data, size_t length);
201Local local_new_uint32_array(Isolate* isolate, const uint32_t* data, size_t length);
202Local local_new_int8_array(Isolate* isolate, const int8_t* data, size_t length);
203Local local_new_int16_array(Isolate* isolate, const int16_t* data, size_t length);
204Local local_new_int32_array(Isolate* isolate, const int32_t* data, size_t length);
205Local local_new_float32_array(Isolate* isolate, const float* data, size_t length);
206Local local_new_float64_array(Isolate* isolate, const double* data, size_t length);
207Local local_new_bigint64_array(Isolate* isolate, const int64_t* data, size_t length);
208Local local_new_biguint64_array(Isolate* isolate, const uint64_t* data, size_t length);
209size_t local_typed_array_length(Isolate* isolate, const Local& array);
210// Returns a raw pointer to the underlying ArrayBuffer's data (without byte offset).
211// Use local_typed_array_byte_offset to compute the start of this view's data.
212uintptr_t local_typed_array_buffer_data(Isolate* isolate, const Local& array);
213// Returns the byte offset of this TypedArray view within its backing ArrayBuffer.
214size_t local_typed_array_byte_offset(Isolate* isolate, const Local& array);
215// Returns the byte length of the TypedArray.
216size_t local_typed_array_byte_length(Isolate* isolate, const Local& array);
217uint8_t local_uint8_array_get(Isolate* isolate, const Local& array, size_t index);
218uint16_t local_uint16_array_get(Isolate* isolate, const Local& array, size_t index);
219uint32_t local_uint32_array_get(Isolate* isolate, const Local& array, size_t index);
220int8_t local_int8_array_get(Isolate* isolate, const Local& array, size_t index);
221int16_t local_int16_array_get(Isolate* isolate, const Local& array, size_t index);
222int32_t local_int32_array_get(Isolate* isolate, const Local& array, size_t index);
223float local_float32_array_get(Isolate* isolate, const Local& array, size_t index);
224double local_float64_array_get(Isolate* isolate, const Local& array, size_t index);
225int64_t local_bigint64_array_get(Isolate* isolate, const Local& array, size_t index);
226uint64_t local_biguint64_array_get(Isolate* isolate, const Local& array, size_t index);
227uint8_t local_uint8clamped_array_get(Isolate* isolate, const Local& array, size_t index);
228 
229// Local<ArrayBuffer>
230Local local_new_array_buffer(Isolate* isolate, const uint8_t* data, size_t length);
231Local local_new_array_buffer_empty(Isolate* isolate, size_t byte_length);
232kj::Maybe<Local> array_buffer_new_with_mode(
233 Isolate* isolate, size_t byte_length, BackingStoreInitializationMode mode);
234Local array_buffer_from_backing_store(Isolate* isolate, size_t store);
235size_t local_array_buffer_byte_length(Isolate* isolate, const Local& buffer);
236uint8_t* local_array_buffer_data(Isolate* isolate, const Local& buffer);
237size_t local_array_buffer_get_backing_store(Isolate* isolate, const Local& buffer);
238 
239// Local<ArrayBufferView>
240size_t local_array_buffer_view_byte_offset(Isolate* isolate, const Local& view);
241size_t local_array_buffer_view_byte_length(Isolate* isolate, const Local& view);
242uint8_t* local_array_buffer_view_buffer_data(Isolate* isolate, const Local& view);
243Local local_array_buffer_view_get_buffer(Isolate* isolate, const Local& view);
244size_t local_array_buffer_view_element_size(Isolate* isolate, const Local& view);
245bool local_array_buffer_view_is_integer_type(Isolate* isolate, const Local& view);
246 
247// BackingStore
248size_t backing_store_new_resizable(size_t byte_length, size_t max_byte_length);
249void backing_store_drop(size_t ptr);
250uint8_t* backing_store_data(size_t ptr);
251size_t backing_store_byte_length(size_t ptr);
252size_t backing_store_max_byte_length(size_t ptr);
253bool backing_store_is_shared(size_t ptr);
254bool backing_store_is_resizable_by_user_javascript(size_t ptr);
255 
256// Global<T>
257void global_reset(Global& value);
258Global global_clone(Isolate* isolate, const Global& value);
259Local global_to_local(Isolate* isolate, const Global& value);
260 
261// Wrappable - data access
262const TraitObjectPtr& wrappable_get_trait_object(const Wrappable& wrappable);
263void wrappable_clear_trait_object(Wrappable& wrappable);
264kj::uint wrappable_strong_refcount(const Wrappable& wrappable);
265 
266// Wrappers
267Local wrap_resource(Isolate* isolate, kj::Rc<Wrappable> wrappable, const Global& tmpl);
268void wrappable_attach_wrapper(kj::Rc<Wrappable> wrappable, FunctionCallbackInfo& args);
269 
270// Unwrappers
271::rust::String unwrap_string(Isolate* isolate, Local value);
272bool unwrap_boolean(Isolate* isolate, Local value);
273double unwrap_number(Isolate* isolate, Local value);
274kj::Rc<Wrappable> unwrap_resource(Isolate* isolate, Local value);
275::rust::Vec<uint8_t> unwrap_uint8_array(Isolate* isolate, Local value);
276::rust::Vec<uint16_t> unwrap_uint16_array(Isolate* isolate, Local value);
277::rust::Vec<uint32_t> unwrap_uint32_array(Isolate* isolate, Local value);
278::rust::Vec<int8_t> unwrap_int8_array(Isolate* isolate, Local value);
279::rust::Vec<int16_t> unwrap_int16_array(Isolate* isolate, Local value);
280::rust::Vec<int32_t> unwrap_int32_array(Isolate* isolate, Local value);
281::rust::Vec<float> unwrap_float32_array(Isolate* isolate, Local value);
282::rust::Vec<double> unwrap_float64_array(Isolate* isolate, Local value);
283::rust::Vec<int64_t> unwrap_bigint64_array(Isolate* isolate, Local value);
284::rust::Vec<uint64_t> unwrap_biguint64_array(Isolate* isolate, Local value);
285// ArrayBuffer detach/detachable/was-detached
286void local_array_buffer_detach(Isolate* isolate, Local& buffer);
287bool local_array_buffer_was_detached(Isolate* isolate, const Local& buffer);
288bool local_array_buffer_is_detachable(Isolate* isolate, const Local& buffer);
289 
290// Value-level shared check
291bool local_array_buffer_is_shared(const Local& value);
292 
293// FunctionCallbackInfo
294Isolate* fci_get_isolate(FunctionCallbackInfo* args);
295Local fci_get_this(FunctionCallbackInfo* args);
296size_t fci_get_length(FunctionCallbackInfo* args);
297Local fci_get_arg(FunctionCallbackInfo* args, size_t index);
298void fci_set_return_value(FunctionCallbackInfo* args, Local value);
299 
300// Utf8Value — ptr holds a heap-allocated v8::String::Utf8Value*.
301// The complete struct definition is generated by CXX from the shared struct in v8.rs.
302struct Utf8Value;
303 
304// utf8_value_new converts `value` to a UTF-8 string, producing a heap-allocated copy
305// of the UTF-8 bytes that is independent of the V8 heap. The caller must call
306// utf8_value_drop to free it.
307// utf8_value_data returns a pointer into this copy (not into V8 memory); it is valid
308// for the lifetime of the Utf8Value and must not be used after utf8_value_drop.
309// utf8_value_length returns the number of bytes (excluding the null terminator).
310Utf8Value utf8_value_new(Isolate* isolate, Local value);
311void utf8_value_drop(Utf8Value value);
312size_t utf8_value_length(const Utf8Value& value);
313const uint8_t* utf8_value_data(const Utf8Value& value);
314 
315struct ModuleRegistry {
316 virtual ~ModuleRegistry() = default;
317 virtual void addBuiltinModule(
318 ::rust::Str specifier, ModuleCallback moduleCallback, ModuleType moduleType) = 0;
319};
320 
321inline void register_add_builtin_module(ModuleRegistry& registry,
322 ::rust::Str specifier,
323 ModuleCallback callback,
324 ModuleType moduleType) {
325 registry.addBuiltinModule(specifier, kj::mv(callback), moduleType);
326}
327 
328Global create_resource_template(Isolate* isolate, const ResourceDescriptor& descriptor);
329 
330// FunctionTemplate
331Local function_template_get_function(Isolate* isolate, const Global& tmpl);
332 
333// Realm
334Realm* realm_from_isolate(Isolate* isolate);
335 
336// Errors
337Local exception_create(Isolate* isolate, ExceptionType exception_type, ::rust::Str message);
338 
339// Isolate
340void isolate_throw_exception(Isolate* isolate, Local exception);
341void isolate_throw_error(Isolate* isolate, ::rust::Str message);
342void isolate_throw_internal_error(Isolate* isolate, ::rust::Str internalMessage);
343void isolate_terminate_execution(Isolate* isolate);
344bool isolate_is_locked(Isolate* isolate);
345 
346} // namespace workerd::rust::jsg