v8/
value_deserializer.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 crate::support::CxxVTable;
19use crate::support::FieldOffset;
20use crate::support::MaybeBool;
21
22use std::ffi::c_void;
23use std::mem::MaybeUninit;
24use std::pin::Pin;
25use std::pin::pin;
26use std::ptr::addr_of;
27
28// Must be == sizeof(v8::ValueDeserializer::Delegate),
29// see v8__ValueDeserializer__Delegate__CONSTRUCT().
30#[repr(C)]
31pub struct CxxValueDeserializerDelegate {
32  _cxx_vtable: CxxVTable,
33}
34
35#[unsafe(no_mangle)]
36unsafe extern "C" fn v8__ValueDeserializer__Delegate__ReadHostObject(
37  this: &CxxValueDeserializerDelegate,
38  isolate: *mut RealIsolate,
39) -> *const Object {
40  let value_deserializer_heap =
41    unsafe { ValueDeserializerHeap::dispatch(this) };
42  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
43  let scope = unsafe { CallbackScope::new(&mut isolate) };
44  let scope = pin!(scope);
45  let scope = &mut scope.init();
46  let context = Local::new(scope, &value_deserializer_heap.context);
47  let mut scope = { ContextScope::new(scope, context) };
48
49  match value_deserializer_heap
50    .value_deserializer_impl
51    .read_host_object(
52      &mut scope,
53      &value_deserializer_heap.cxx_value_deserializer,
54    ) {
55    None => std::ptr::null(),
56    Some(x) => x.as_non_null().as_ptr(),
57  }
58}
59
60#[unsafe(no_mangle)]
61unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetSharedArrayBufferFromId(
62  this: &CxxValueDeserializerDelegate,
63  isolate: *mut RealIsolate,
64  transfer_id: u32,
65) -> *const SharedArrayBuffer {
66  let value_deserializer_heap =
67    unsafe { ValueDeserializerHeap::dispatch(this) };
68  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
69  let scope = unsafe { CallbackScope::new(&mut isolate) };
70  let scope = pin!(scope);
71  let scope = &mut scope.init();
72  // let hs = scope;
73  let context = Local::new(scope, &value_deserializer_heap.context);
74  let mut scope = { ContextScope::new(scope, context) };
75
76  match value_deserializer_heap
77    .value_deserializer_impl
78    .get_shared_array_buffer_from_id(&mut scope, transfer_id)
79  {
80    None => std::ptr::null(),
81    Some(x) => x.as_non_null().as_ptr(),
82  }
83}
84
85#[unsafe(no_mangle)]
86unsafe extern "C" fn v8__ValueDeserializer__Delegate__GetWasmModuleFromId(
87  this: &mut CxxValueDeserializerDelegate,
88  isolate: *mut RealIsolate,
89  clone_id: u32,
90) -> *const WasmModuleObject {
91  let value_deserializer_heap =
92    unsafe { ValueDeserializerHeap::dispatch(this) };
93  let mut isolate = unsafe { Isolate::from_raw_ptr(isolate) };
94  let scope = unsafe { CallbackScope::new(&mut isolate) };
95  let scope = pin!(scope);
96  let scope = &mut scope.init();
97  let context = Local::new(scope, &value_deserializer_heap.context);
98  let mut scope = { ContextScope::new(scope, context) };
99
100  match value_deserializer_heap
101    .value_deserializer_impl
102    .get_wasm_module_from_id(&mut scope, clone_id)
103  {
104    None => std::ptr::null(),
105    Some(x) => x.as_non_null().as_ptr(),
106  }
107}
108
109unsafe extern "C" {
110  fn v8__ValueDeserializer__Delegate__CONSTRUCT(
111    buf: *mut MaybeUninit<CxxValueDeserializerDelegate>,
112  );
113}
114
115// Must be == sizeof(v8::ValueDeserializer),
116// see v8__ValueDeserializer__CONSTRUCT().
117#[repr(C)]
118pub struct CxxValueDeserializer {
119  _cxx_vtable: CxxVTable,
120}
121
122unsafe extern "C" {
123  fn v8__ValueDeserializer__CONSTRUCT(
124    buf: *mut MaybeUninit<CxxValueDeserializer>,
125    isolate: *mut RealIsolate,
126    data: *const u8,
127    size: usize,
128    delegate: *mut CxxValueDeserializerDelegate,
129  );
130
131  fn v8__ValueDeserializer__DESTRUCT(this: *mut CxxValueDeserializer);
132
133  fn v8__ValueDeserializer__TransferArrayBuffer(
134    this: *mut CxxValueDeserializer,
135    transfer_id: u32,
136    array_buffer: Local<ArrayBuffer>,
137  );
138
139  fn v8__ValueDeserializer__TransferSharedArrayBuffer(
140    this: *mut CxxValueDeserializer,
141    transfer_id: u32,
142    array_buffer: Local<SharedArrayBuffer>,
143  );
144
145  fn v8__ValueDeserializer__SetSupportsLegacyWireFormat(
146    this: *mut CxxValueDeserializer,
147    supports_legacy_wire_format: bool,
148  );
149
150  fn v8__ValueDeserializer__ReadHeader(
151    this: *mut CxxValueDeserializer,
152    context: Local<Context>,
153  ) -> MaybeBool;
154
155  fn v8__ValueDeserializer__ReadValue(
156    this: *mut CxxValueDeserializer,
157    context: Local<Context>,
158  ) -> *const Value;
159
160  fn v8__ValueDeserializer__ReadUint32(
161    this: *mut CxxValueDeserializer,
162    value: *mut u32,
163  ) -> bool;
164
165  fn v8__ValueDeserializer__ReadUint64(
166    this: *mut CxxValueDeserializer,
167    value: *mut u64,
168  ) -> bool;
169
170  fn v8__ValueDeserializer__ReadDouble(
171    this: *mut CxxValueDeserializer,
172    value: *mut f64,
173  ) -> bool;
174
175  fn v8__ValueDeserializer__ReadRawBytes(
176    this: *mut CxxValueDeserializer,
177    length: usize,
178    data: *mut *const c_void,
179  ) -> bool;
180
181  fn v8__ValueDeserializer__GetWireFormatVersion(
182    this: *mut CxxValueDeserializer,
183  ) -> u32;
184}
185
186/// The ValueDeserializerImpl trait allows for
187/// custom callback functions used by v8.
188pub trait ValueDeserializerImpl {
189  fn read_host_object<'s>(
190    &self,
191    scope: &mut PinScope<'s, '_>,
192    _value_deserializer: &dyn ValueDeserializerHelper,
193  ) -> Option<Local<'s, Object>> {
194    let msg =
195      String::new(scope, "Deno deserializer: read_host_object not implemented")
196        .unwrap();
197    let exc = Exception::error(scope, msg);
198    scope.throw_exception(exc);
199    None
200  }
201
202  fn get_shared_array_buffer_from_id<'s>(
203    &self,
204    scope: &mut PinScope<'s, '_>,
205    _transfer_id: u32,
206  ) -> Option<Local<'s, SharedArrayBuffer>> {
207    let msg = String::new(
208      scope,
209      "Deno deserializer: get_shared_array_buffer_from_id not implemented",
210    )
211    .unwrap();
212    let exc = Exception::error(scope, msg);
213    scope.throw_exception(exc);
214    None
215  }
216
217  fn get_wasm_module_from_id<'s>(
218    &self,
219    scope: &mut PinScope<'s, '_>,
220    _clone_id: u32,
221  ) -> Option<Local<'s, WasmModuleObject>> {
222    let msg = String::new(
223      scope,
224      "Deno deserializer: get_wasm_module_from_id not implemented",
225    )
226    .unwrap();
227    let exc = Exception::error(scope, msg);
228    scope.throw_exception(exc);
229    None
230  }
231}
232
233fn cast_to_ptr<T>(t: &T) -> *mut T {
234  t as *const _ as *mut _
235}
236
237/// The ValueDeserializerHeap object contains all objects related to a
238/// deserializer. This object has to be pinned to the heap because of the Cpp
239/// pointers that have to remain valid. Moving this object would result in the
240/// Cpp pointer to the delegate to become invalid and thus causing the delegate
241/// callback to fail. Additionally the deserializer and implementation are also
242/// pinned in memory because these have to be accessable from within the
243/// delegate callback methods.
244pub struct ValueDeserializerHeap<'a> {
245  value_deserializer_impl: Box<dyn ValueDeserializerImpl + 'a>,
246  cxx_value_deserializer: CxxValueDeserializer,
247  cxx_value_deserializer_delegate: CxxValueDeserializerDelegate,
248  context: Global<Context>,
249}
250
251impl ValueDeserializerHeap<'_> {
252  fn get_cxx_value_deserializer_delegate_offset()
253  -> FieldOffset<CxxValueDeserializerDelegate> {
254    let buf = std::mem::MaybeUninit::<Self>::uninit();
255    let delegate =
256      unsafe { addr_of!((*buf.as_ptr()).cxx_value_deserializer_delegate) };
257    FieldOffset::from_ptrs(buf.as_ptr(), delegate)
258  }
259
260  /// Starting from 'this' pointer a ValueDeserializerHeap ref can be created
261  pub unsafe fn dispatch(
262    value_serializer_delegate: &CxxValueDeserializerDelegate,
263  ) -> &Self {
264    unsafe {
265      Self::get_cxx_value_deserializer_delegate_offset()
266        .to_embedder::<Self>(value_serializer_delegate)
267    }
268  }
269}
270
271impl Drop for ValueDeserializerHeap<'_> {
272  fn drop(&mut self) {
273    unsafe {
274      v8__ValueDeserializer__DESTRUCT(&mut self.cxx_value_deserializer);
275    };
276  }
277}
278
279/// Trait used for direct read from the deserialization buffer.
280/// Mostly used by the read_host_object callback function in the
281/// ValueDeserializerImpl trait to create custom deserialization logic.
282pub trait ValueDeserializerHelper {
283  fn get_cxx_value_deserializer(&self) -> &CxxValueDeserializer;
284
285  fn read_header(&self, context: Local<Context>) -> Option<bool> {
286    unsafe {
287      v8__ValueDeserializer__ReadHeader(
288        cast_to_ptr(self.get_cxx_value_deserializer()),
289        context,
290      )
291    }
292    .into()
293  }
294
295  fn read_value<'s>(
296    &self,
297    context: Local<'s, Context>,
298  ) -> Option<Local<'s, Value>> {
299    unsafe {
300      Local::from_raw(v8__ValueDeserializer__ReadValue(
301        cast_to_ptr(self.get_cxx_value_deserializer()),
302        context,
303      ))
304    }
305  }
306
307  fn read_uint32(&self, value: &mut u32) -> bool {
308    unsafe {
309      v8__ValueDeserializer__ReadUint32(
310        cast_to_ptr(self.get_cxx_value_deserializer()),
311        value,
312      )
313    }
314  }
315
316  fn read_uint64(&self, value: &mut u64) -> bool {
317    unsafe {
318      v8__ValueDeserializer__ReadUint64(
319        cast_to_ptr(self.get_cxx_value_deserializer()),
320        value,
321      )
322    }
323  }
324
325  fn read_double(&self, value: &mut f64) -> bool {
326    unsafe {
327      v8__ValueDeserializer__ReadDouble(
328        cast_to_ptr(self.get_cxx_value_deserializer()),
329        value,
330      )
331    }
332  }
333
334  fn read_raw_bytes(&self, length: usize) -> Option<&[u8]> {
335    let mut data: *const c_void = std::ptr::null_mut();
336    let ok = unsafe {
337      v8__ValueDeserializer__ReadRawBytes(
338        cast_to_ptr(self.get_cxx_value_deserializer()),
339        length,
340        &mut data,
341      )
342    };
343    if ok {
344      assert!(!data.is_null());
345      unsafe { Some(std::slice::from_raw_parts(data as *const u8, length)) }
346    } else {
347      None
348    }
349  }
350
351  fn transfer_array_buffer(
352    &self,
353    transfer_id: u32,
354    array_buffer: Local<ArrayBuffer>,
355  ) {
356    unsafe {
357      v8__ValueDeserializer__TransferArrayBuffer(
358        cast_to_ptr(self.get_cxx_value_deserializer()),
359        transfer_id,
360        array_buffer,
361      );
362    };
363  }
364
365  fn transfer_shared_array_buffer(
366    &self,
367    transfer_id: u32,
368    shared_array_buffer: Local<SharedArrayBuffer>,
369  ) {
370    unsafe {
371      v8__ValueDeserializer__TransferSharedArrayBuffer(
372        cast_to_ptr(self.get_cxx_value_deserializer()),
373        transfer_id,
374        shared_array_buffer,
375      );
376    };
377  }
378
379  fn get_wire_format_version(&self) -> u32 {
380    unsafe {
381      v8__ValueDeserializer__GetWireFormatVersion(cast_to_ptr(
382        self.get_cxx_value_deserializer(),
383      ))
384    }
385  }
386}
387
388impl ValueDeserializerHelper for CxxValueDeserializer {
389  fn get_cxx_value_deserializer(&self) -> &CxxValueDeserializer {
390    self
391  }
392}
393
394impl ValueDeserializerHelper for ValueDeserializerHeap<'_> {
395  fn get_cxx_value_deserializer(&self) -> &CxxValueDeserializer {
396    &self.cxx_value_deserializer
397  }
398}
399
400impl ValueDeserializerHelper for ValueDeserializer<'_> {
401  fn get_cxx_value_deserializer(&self) -> &CxxValueDeserializer {
402    &self.value_deserializer_heap.cxx_value_deserializer
403  }
404}
405
406/// ValueDeserializer is a stack object used as entry-point for an owned and
407/// pinned heap object ValueDeserializerHeap.
408/// The 'a lifetime is the lifetime of the ValueDeserializerImpl implementation.
409/// The 's lifetime is the lifetime of the HandleScope which is used to retrieve
410/// a Local<'s, Context> for the CallbackScopes
411pub struct ValueDeserializer<'a> {
412  value_deserializer_heap: Pin<Box<ValueDeserializerHeap<'a>>>,
413  // ValueDeserializerHeap is already !Send and !Sync
414  // but this is just making it explicit
415  _phantom: std::marker::PhantomData<*mut ()>,
416}
417
418impl<'a> ValueDeserializer<'a> {
419  pub fn new<'s, 'i, D: ValueDeserializerImpl + 'a>(
420    scope: &PinScope<'s, 'i>,
421    value_deserializer_impl: Box<D>,
422    data: &[u8],
423  ) -> Self {
424    let context = scope.get_current_context();
425    // create dummy ValueDeserializerHeap and move to heap + pin to address
426    let value_deserializer_heap_ptr =
427      Box::into_raw(Box::new(ValueDeserializerHeap {
428        value_deserializer_impl,
429        cxx_value_deserializer: CxxValueDeserializer {
430          _cxx_vtable: CxxVTable(std::ptr::null()),
431        },
432        cxx_value_deserializer_delegate: CxxValueDeserializerDelegate {
433          _cxx_vtable: CxxVTable(std::ptr::null()),
434        },
435        context: Global::new(scope, context),
436      }));
437
438    unsafe {
439      let delegate_ptr = std::ptr::addr_of_mut!(
440        (*value_deserializer_heap_ptr).cxx_value_deserializer_delegate
441      );
442      let deserializer_ptr = std::ptr::addr_of_mut!(
443        (*value_deserializer_heap_ptr).cxx_value_deserializer
444      );
445      v8__ValueDeserializer__Delegate__CONSTRUCT(
446        delegate_ptr
447          .cast::<std::mem::MaybeUninit<CxxValueDeserializerDelegate>>(),
448      );
449
450      v8__ValueDeserializer__CONSTRUCT(
451        deserializer_ptr.cast::<std::mem::MaybeUninit<CxxValueDeserializer>>(),
452        scope.get_isolate_ptr(),
453        data.as_ptr(),
454        data.len(),
455        delegate_ptr,
456      );
457    };
458
459    // SAFETY: pointer from Box::into_raw is valid
460    let value_deserializer_heap =
461      Pin::new(unsafe { Box::from_raw(value_deserializer_heap_ptr) });
462
463    ValueDeserializer {
464      value_deserializer_heap,
465      _phantom: std::marker::PhantomData,
466    }
467  }
468}
469
470impl ValueDeserializer<'_> {
471  pub fn set_supports_legacy_wire_format(
472    &self,
473    supports_legacy_wire_format: bool,
474  ) {
475    unsafe {
476      v8__ValueDeserializer__SetSupportsLegacyWireFormat(
477        cast_to_ptr(&self.value_deserializer_heap.cxx_value_deserializer),
478        supports_legacy_wire_format,
479      );
480    }
481  }
482
483  pub fn read_value<'t>(
484    &self,
485    context: Local<'t, Context>,
486  ) -> Option<Local<'t, Value>> {
487    self.value_deserializer_heap.read_value(context)
488  }
489}