v8/
value_serializer.rs

1use crate::ArrayBuffer;
2use crate::Context;
3use crate::Exception;
4use crate::Global;
5use crate::Isolate;
6use crate::Local;
7use crate::Object;
8use crate::PinScope;
9use crate::SharedArrayBuffer;
10use crate::String;
11use crate::Value;
12use crate::WasmModuleObject;
13use crate::isolate::RealIsolate;
14use crate::scope::CallbackScope;
15use crate::scope::ContextScope;
16use crate::scope::GetIsolate;
17
18use std::alloc::Layout;
19use std::alloc::alloc;
20use std::alloc::dealloc;
21use std::alloc::realloc;
22use std::mem::MaybeUninit;
23use std::pin::pin;
24use std::ptr::addr_of;
25use std::sync::atomic::AtomicUsize;
26
27use crate::support::CxxVTable;
28use crate::support::FieldOffset;
29use crate::support::MaybeBool;
30
31use std::ffi::c_void;
32use std::pin::Pin;
33
34// Must be == sizeof(v8::ValueSerializer::Delegate),
35// see v8__ValueSerializer__Delegate__CONSTRUCT().
36#[repr(C)]
37pub struct CxxValueSerializerDelegate {
38  _cxx_vtable: CxxVTable,
39}
40
41#[unsafe(no_mangle)]
42unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError(
43  this: &CxxValueSerializerDelegate,
44  message: Local<String>,
45) {
46  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
47  let mut isolate =
48    unsafe { Isolate::from_raw_ptr(value_serializer_heap.isolate_ptr) };
49  let scope = unsafe { CallbackScope::new(&mut isolate) };
50  let scope = pin!(scope);
51  let scope = &mut scope.init();
52  let context = Local::new(scope, &value_serializer_heap.context);
53  let mut scope = ContextScope::new(scope, context);
54  value_serializer_heap
55    .value_serializer_impl
56    .throw_data_clone_error(&mut scope, message);
57}
58
59#[unsafe(no_mangle)]
60unsafe extern "C" fn v8__ValueSerializer__Delegate__HasCustomHostObject(
61  this: &CxxValueSerializerDelegate,
62  isolate: *mut RealIsolate,
63) -> bool {
64  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
65  let isolate = unsafe { Isolate::from_raw_ptr(isolate) };
66  value_serializer_heap
67    .value_serializer_impl
68    .has_custom_host_object(&isolate)
69}
70
71#[unsafe(no_mangle)]
72unsafe extern "C" fn v8__ValueSerializer__Delegate__IsHostObject(
73  this: &CxxValueSerializerDelegate,
74  isolate: *mut RealIsolate,
75  object: Local<Object>,
76) -> MaybeBool {
77  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
78  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
79  let scope = unsafe { CallbackScope::new(&mut isolate) };
80  let scope = pin!(scope);
81  let scope = &mut scope.init();
82  let context = Local::new(scope, &value_serializer_heap.context);
83  let mut scope = ContextScope::new(scope, context);
84
85  MaybeBool::from(
86    value_serializer_heap
87      .value_serializer_impl
88      .is_host_object(&mut scope, object),
89  )
90}
91
92#[unsafe(no_mangle)]
93unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject(
94  this: &CxxValueSerializerDelegate,
95  isolate: *mut RealIsolate,
96  object: Local<Object>,
97) -> MaybeBool {
98  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
99  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
100  let scope = unsafe { CallbackScope::new(&mut isolate) };
101  let scope = pin!(scope);
102  let scope = &mut scope.init();
103  let context = Local::new(scope, &value_serializer_heap.context);
104  let mut scope = ContextScope::new(scope, context);
105  let value_serializer_impl =
106    value_serializer_heap.value_serializer_impl.as_ref();
107  MaybeBool::from(value_serializer_impl.write_host_object(
108    &mut scope,
109    object,
110    &value_serializer_heap.cxx_value_serializer,
111  ))
112}
113
114#[unsafe(no_mangle)]
115unsafe extern "C" fn v8__ValueSerializer__Delegate__GetSharedArrayBufferId(
116  this: &CxxValueSerializerDelegate,
117  isolate: *mut RealIsolate,
118  shared_array_buffer: Local<SharedArrayBuffer>,
119  clone_id: *mut u32,
120) -> bool {
121  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
122  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
123  let scope = unsafe { CallbackScope::new(&mut isolate) };
124  let scope = pin!(scope);
125  let scope = &mut scope.init();
126  let context = Local::new(scope, &value_serializer_heap.context);
127  let mut scope = ContextScope::new(scope, context);
128  match value_serializer_heap
129    .value_serializer_impl
130    .get_shared_array_buffer_id(&mut scope, shared_array_buffer)
131  {
132    Some(x) => {
133      unsafe {
134        *clone_id = x;
135      }
136      true
137    }
138    None => false,
139  }
140}
141
142#[unsafe(no_mangle)]
143unsafe extern "C" fn v8__ValueSerializer__Delegate__GetWasmModuleTransferId(
144  this: &CxxValueSerializerDelegate,
145  isolate: *mut RealIsolate,
146  module: Local<WasmModuleObject>,
147  transfer_id: *mut u32,
148) -> bool {
149  let value_serializer_heap = unsafe { ValueSerializerHeap::dispatch(this) };
150  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
151  let scope = unsafe { CallbackScope::new(&mut isolate) };
152  let scope = pin!(scope);
153  let scope = &mut scope.init();
154  let context = Local::new(scope, &value_serializer_heap.context);
155  let scope = &mut ContextScope::new(scope, context);
156  match value_serializer_heap
157    .value_serializer_impl
158    .get_wasm_module_transfer_id(scope, module)
159  {
160    Some(x) => {
161      unsafe {
162        *transfer_id = x;
163      }
164      true
165    }
166    None => false,
167  }
168}
169
170#[unsafe(no_mangle)]
171unsafe extern "C" fn v8__ValueSerializer__Delegate__ReallocateBufferMemory(
172  this: &CxxValueSerializerDelegate,
173  old_buffer: *mut c_void,
174  size: usize,
175  actual_size: *mut usize,
176) -> *mut c_void {
177  let base = unsafe { ValueSerializerHeap::dispatch(this) };
178
179  let buffer_size = base
180    .buffer_size
181    .swap(size, std::sync::atomic::Ordering::Release);
182  let new_buffer = if old_buffer.is_null() {
183    let layout = Layout::from_size_align(size, 1).unwrap();
184    unsafe { alloc(layout) }
185  } else {
186    let old_layout = Layout::from_size_align(buffer_size, 1).unwrap();
187    unsafe { realloc(old_buffer as *mut _, old_layout, size) }
188  };
189
190  unsafe {
191    *actual_size = size;
192  }
193  new_buffer as *mut c_void
194}
195
196#[unsafe(no_mangle)]
197unsafe extern "C" fn v8__ValueSerializer__Delegate__FreeBufferMemory(
198  this: &mut CxxValueSerializerDelegate,
199  buffer: *mut c_void,
200) {
201  let base = unsafe { ValueSerializerHeap::dispatch(this) };
202  if !buffer.is_null() {
203    let layout = Layout::from_size_align(
204      base.buffer_size.load(std::sync::atomic::Ordering::Relaxed),
205      1,
206    )
207    .unwrap();
208    unsafe { dealloc(buffer as *mut _, layout) };
209  };
210}
211
212unsafe extern "C" {
213  fn v8__ValueSerializer__Delegate__CONSTRUCT(
214    buf: *mut MaybeUninit<CxxValueSerializerDelegate>,
215  );
216}
217
218// Must be == sizeof(v8::ValueSerializer), see v8__ValueSerializer__CONSTRUCT().
219#[repr(C)]
220pub struct CxxValueSerializer {
221  _cxx_vtable: CxxVTable,
222}
223
224unsafe extern "C" {
225  fn v8__ValueSerializer__CONSTRUCT(
226    buf: *mut MaybeUninit<CxxValueSerializer>,
227    isolate: *mut RealIsolate,
228    delegate: *mut CxxValueSerializerDelegate,
229  );
230
231  fn v8__ValueSerializer__DESTRUCT(this: *mut CxxValueSerializer);
232
233  fn v8__ValueSerializer__Release(
234    this: *mut CxxValueSerializer,
235    ptr: *mut *mut u8,
236    size: *mut usize,
237  );
238
239  fn v8__ValueSerializer__TransferArrayBuffer(
240    this: *mut CxxValueSerializer,
241    transfer_id: u32,
242    array_buffer: Local<ArrayBuffer>,
243  );
244
245  fn v8__ValueSerializer__WriteHeader(this: *mut CxxValueSerializer);
246  fn v8__ValueSerializer__WriteValue(
247    this: *mut CxxValueSerializer,
248    context: Local<Context>,
249    value: Local<Value>,
250  ) -> MaybeBool;
251  fn v8__ValueSerializer__WriteUint32(
252    this: *mut CxxValueSerializer,
253    value: u32,
254  );
255  fn v8__ValueSerializer__WriteUint64(
256    this: *mut CxxValueSerializer,
257    value: u64,
258  );
259  fn v8__ValueSerializer__WriteDouble(
260    this: *mut CxxValueSerializer,
261    value: f64,
262  );
263  fn v8__ValueSerializer__WriteRawBytes(
264    this: *mut CxxValueSerializer,
265    source: *const c_void,
266    length: usize,
267  );
268  fn v8__ValueSerializer__SetTreatArrayBufferViewsAsHostObjects(
269    this: *mut CxxValueSerializer,
270    mode: bool,
271  );
272}
273
274/// The ValueSerializerImpl trait allows for
275/// custom callback functions used by v8.
276pub trait ValueSerializerImpl {
277  fn throw_data_clone_error<'s>(
278    &self,
279    scope: &mut PinScope<'s, '_>,
280    message: Local<'s, String>,
281  );
282
283  fn has_custom_host_object(&self, _isolate: &Isolate) -> bool {
284    false
285  }
286
287  fn is_host_object<'s>(
288    &self,
289    scope: &mut PinScope<'s, '_>,
290    _object: Local<'s, Object>,
291  ) -> Option<bool> {
292    let msg =
293      String::new(scope, "Deno serializer: is_host_object not implemented")
294        .unwrap();
295    let exc = Exception::error(scope, msg);
296    scope.throw_exception(exc);
297    None
298  }
299
300  fn write_host_object<'s>(
301    &self,
302    scope: &mut PinScope<'s, '_>,
303    _object: Local<'s, Object>,
304    _value_serializer: &dyn ValueSerializerHelper,
305  ) -> Option<bool> {
306    let msg =
307      String::new(scope, "Deno serializer: write_host_object not implemented")
308        .unwrap();
309    let exc = Exception::error(scope, msg);
310    scope.throw_exception(exc);
311    None
312  }
313
314  fn get_shared_array_buffer_id<'s>(
315    &self,
316    _scope: &mut PinScope<'s, '_>,
317    _shared_array_buffer: Local<'s, SharedArrayBuffer>,
318  ) -> Option<u32> {
319    None
320  }
321
322  fn get_wasm_module_transfer_id(
323    &self,
324    scope: &mut PinScope<'_, '_>,
325    _module: Local<WasmModuleObject>,
326  ) -> Option<u32> {
327    let msg = String::new(
328      scope,
329      "Deno serializer: get_wasm_module_transfer_id not implemented",
330    )
331    .unwrap();
332    let exc = Exception::error(scope, msg);
333    scope.throw_exception(exc);
334    None
335  }
336}
337
338/// The ValueSerializerHeap object contains all objects related to serializer.
339/// This object has to be pinned to the heap because of the Cpp pointers that
340/// have to remain valid. Moving this object would result in the Cpp pointer
341/// to the delegate to become invalid and thus causing the delegate callback
342/// to fail. Additionally the serializer and implementation are also pinned
343/// in memory because these have to be accessable from within the delegate
344/// callback methods.
345pub struct ValueSerializerHeap<'a> {
346  value_serializer_impl: Box<dyn ValueSerializerImpl + 'a>,
347  cxx_value_serializer_delegate: CxxValueSerializerDelegate,
348  cxx_value_serializer: CxxValueSerializer,
349  buffer_size: AtomicUsize,
350  context: Global<Context>,
351  isolate_ptr: *mut RealIsolate,
352}
353
354impl ValueSerializerHeap<'_> {
355  fn get_cxx_value_serializer_delegate_offset()
356  -> FieldOffset<CxxValueSerializerDelegate> {
357    let buf = std::mem::MaybeUninit::<Self>::uninit();
358    let delegate =
359      unsafe { addr_of!((*buf.as_ptr()).cxx_value_serializer_delegate) };
360    FieldOffset::from_ptrs(buf.as_ptr(), delegate)
361  }
362
363  /// Starting from 'this' pointer a ValueSerializerHeap ref can be created
364  pub unsafe fn dispatch(
365    value_serializer_delegate: &CxxValueSerializerDelegate,
366  ) -> &Self {
367    unsafe {
368      Self::get_cxx_value_serializer_delegate_offset()
369        .to_embedder::<Self>(value_serializer_delegate)
370    }
371  }
372}
373
374impl Drop for ValueSerializerHeap<'_> {
375  fn drop(&mut self) {
376    unsafe { v8__ValueSerializer__DESTRUCT(&mut self.cxx_value_serializer) };
377  }
378}
379
380fn cast_to_ptr<T>(x: &T) -> *mut T {
381  x as *const T as *mut T
382}
383
384/// Trait used for direct write to the serialization buffer.
385/// Mostly used by the write_host_object callback function in the
386/// ValueSerializerImpl trait to create custom serialization logic.
387pub trait ValueSerializerHelper {
388  fn get_cxx_value_serializer(&self) -> &CxxValueSerializer;
389
390  fn write_header(&self) {
391    unsafe {
392      v8__ValueSerializer__WriteHeader(cast_to_ptr(
393        self.get_cxx_value_serializer(),
394      ));
395    };
396  }
397
398  fn write_value(
399    &self,
400    context: Local<Context>,
401    value: Local<Value>,
402  ) -> Option<bool> {
403    unsafe {
404      v8__ValueSerializer__WriteValue(
405        cast_to_ptr(self.get_cxx_value_serializer()),
406        context,
407        value,
408      )
409    }
410    .into()
411  }
412
413  fn write_uint32(&self, value: u32) {
414    unsafe {
415      v8__ValueSerializer__WriteUint32(
416        cast_to_ptr(self.get_cxx_value_serializer()),
417        value,
418      );
419    };
420  }
421
422  fn write_uint64(&self, value: u64) {
423    unsafe {
424      v8__ValueSerializer__WriteUint64(
425        cast_to_ptr(self.get_cxx_value_serializer()),
426        value,
427      );
428    };
429  }
430
431  fn write_double(&self, value: f64) {
432    unsafe {
433      v8__ValueSerializer__WriteDouble(
434        cast_to_ptr(self.get_cxx_value_serializer()),
435        value,
436      );
437    };
438  }
439
440  fn write_raw_bytes(&self, source: &[u8]) {
441    unsafe {
442      v8__ValueSerializer__WriteRawBytes(
443        cast_to_ptr(self.get_cxx_value_serializer()),
444        source.as_ptr() as *const _,
445        source.len(),
446      );
447    };
448  }
449
450  fn transfer_array_buffer(
451    &self,
452    transfer_id: u32,
453    array_buffer: Local<ArrayBuffer>,
454  ) {
455    unsafe {
456      v8__ValueSerializer__TransferArrayBuffer(
457        cast_to_ptr(self.get_cxx_value_serializer()),
458        transfer_id,
459        array_buffer,
460      );
461    };
462  }
463
464  fn set_treat_array_buffer_views_as_host_objects(&self, mode: bool) {
465    unsafe {
466      v8__ValueSerializer__SetTreatArrayBufferViewsAsHostObjects(
467        cast_to_ptr(self.get_cxx_value_serializer()),
468        mode,
469      );
470    };
471  }
472}
473
474impl ValueSerializerHelper for CxxValueSerializer {
475  fn get_cxx_value_serializer(&self) -> &CxxValueSerializer {
476    self
477  }
478}
479
480impl ValueSerializerHelper for ValueSerializerHeap<'_> {
481  fn get_cxx_value_serializer(&self) -> &CxxValueSerializer {
482    &self.cxx_value_serializer
483  }
484}
485
486impl ValueSerializerHelper for ValueSerializer<'_> {
487  fn get_cxx_value_serializer(&self) -> &CxxValueSerializer {
488    &self.value_serializer_heap.cxx_value_serializer
489  }
490}
491
492pub struct ValueSerializer<'a> {
493  value_serializer_heap: Pin<Box<ValueSerializerHeap<'a>>>,
494  // ValueSerializerHeap is already !Send and !Sync
495  // but this is just making it explicit
496  _phantom: std::marker::PhantomData<*mut ()>,
497}
498
499/// ValueSerializer is a stack object used as entry-point for an owned and
500/// pinned heap object ValueSerializerHeap.
501/// The 'a lifetime is the lifetime of the ValueSerializerImpl implementation.
502/// The 's lifetime is the lifetime of the HandleScope which is used to retrieve
503/// a Local<'s, Context> for the CallbackScopes
504impl<'a> ValueSerializer<'a> {
505  pub fn new<'s, 'i, D: ValueSerializerImpl + 'a>(
506    scope: &PinScope<'s, 'i>,
507    value_serializer_impl: Box<D>,
508  ) -> Self {
509    let context = scope.get_current_context();
510    // create dummy ValueSerializerHeap 'a, and move to heap + pin to address
511    let value_serializer_heap_ptr =
512      Box::into_raw(Box::new(ValueSerializerHeap {
513        value_serializer_impl,
514        cxx_value_serializer: CxxValueSerializer {
515          _cxx_vtable: CxxVTable(std::ptr::null()),
516        },
517        cxx_value_serializer_delegate: CxxValueSerializerDelegate {
518          _cxx_vtable: CxxVTable(std::ptr::null()),
519        },
520        buffer_size: AtomicUsize::new(0),
521        context: Global::new(scope, context),
522        isolate_ptr: scope.get_isolate_ptr(),
523      }));
524
525    unsafe {
526      let delegate_ptr = std::ptr::addr_of_mut!(
527        (*value_serializer_heap_ptr).cxx_value_serializer_delegate
528      );
529      let serializer_ptr = std::ptr::addr_of_mut!(
530        (*value_serializer_heap_ptr).cxx_value_serializer
531      );
532      v8__ValueSerializer__Delegate__CONSTRUCT(
533        delegate_ptr
534          .cast::<std::mem::MaybeUninit<CxxValueSerializerDelegate>>(),
535      );
536
537      v8__ValueSerializer__CONSTRUCT(
538        serializer_ptr.cast::<std::mem::MaybeUninit<CxxValueSerializer>>(),
539        scope.get_isolate_ptr(),
540        delegate_ptr,
541      );
542    };
543
544    // SAFETY: pointer from `Box::into_raw` is valid
545    let value_serializer_heap =
546      Pin::new(unsafe { Box::from_raw(value_serializer_heap_ptr) });
547
548    Self {
549      value_serializer_heap,
550      _phantom: std::marker::PhantomData,
551    }
552  }
553}
554
555impl ValueSerializer<'_> {
556  pub fn release(&self) -> Vec<u8> {
557    unsafe {
558      let mut size: usize = 0;
559      let mut ptr: *mut u8 = &mut 0;
560      v8__ValueSerializer__Release(
561        cast_to_ptr(self.get_cxx_value_serializer()),
562        &mut ptr,
563        &mut size,
564      );
565      let capacity = self
566        .value_serializer_heap
567        .buffer_size
568        .swap(0, std::sync::atomic::Ordering::Relaxed);
569      if ptr.is_null() {
570        return Vec::new();
571      }
572      assert!(size <= capacity);
573      // SAFETY: ptr is non-null, was allocated by us in `v8__ValueSerializer__Delegate__ReallocateBufferMemory`, and
574      // the capacity is correctly updated during reallocation. Size is asserted to be valid above.
575      Vec::from_raw_parts(ptr, size, capacity)
576    }
577  }
578
579  pub fn write_value(
580    &self,
581    context: Local<Context>,
582    value: Local<Value>,
583  ) -> Option<bool> {
584    self.value_serializer_heap.write_value(context, value)
585  }
586}