Skip to content

Commit 8815ec1

Browse files
devsnekbartlomieju
andauthored
feat: changes to make DOMException properly serializable (#1220)
denoland/deno#31156 --------- Co-authored-by: Bartek Iwańczuk <[email protected]>
1 parent 3a98951 commit 8815ec1

File tree

3 files changed

+57
-16
lines changed

3 files changed

+57
-16
lines changed

core/01_core.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,8 @@
730730
encode: (text) => op_encode(text),
731731
encodeBinaryString: (buffer) => op_encode_binary_string(buffer),
732732
decode: (buffer) => op_decode(buffer),
733-
structuredClone: (value) => op_structured_clone(value),
733+
structuredClone: (value, deserializers) =>
734+
op_structured_clone(value, deserializers),
734735
serialize: (
735736
value,
736737
options,
@@ -749,6 +750,7 @@
749750
buffer,
750751
options?.hostObjects,
751752
options?.transferredArrayBuffers,
753+
options?.deserializers,
752754
options?.forStorage ?? false,
753755
);
754756
},

core/ops_builtin_v8.rs

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ struct SerializeDeserialize<'a> {
423423
host_objects: Option<v8::Local<'a, v8::Array>>,
424424
error_callback: Option<v8::Local<'a, v8::Function>>,
425425
for_storage: bool,
426-
host_object_brand: Option<v8::Global<v8::Symbol>>,
426+
host_object_brand: Option<v8::Local<'a, v8::Symbol>>,
427+
deserializers: Option<v8::Local<'a, v8::Object>>,
427428
}
428429

429430
impl v8::ValueSerializerImpl for SerializeDeserialize<'_> {
@@ -488,19 +489,16 @@ impl v8::ValueSerializerImpl for SerializeDeserialize<'_> {
488489
}
489490

490491
fn has_custom_host_object(&self, _isolate: &v8::Isolate) -> bool {
491-
true
492+
self.host_object_brand.is_some()
492493
}
493494

494495
fn is_host_object<'s, 'i>(
495496
&self,
496497
scope: &mut v8::PinScope<'s, 'i>,
497498
object: v8::Local<'s, v8::Object>,
498499
) -> Option<bool> {
499-
match &self.host_object_brand {
500-
Some(symbol) => {
501-
let key = v8::Local::new(scope, symbol);
502-
object.has_own_property(scope, key.into())
503-
}
500+
match self.host_object_brand {
501+
Some(symbol) => object.has(scope, symbol.into()),
504502
_ => Some(false),
505503
}
506504
}
@@ -511,6 +509,15 @@ impl v8::ValueSerializerImpl for SerializeDeserialize<'_> {
511509
object: v8::Local<'s, v8::Object>,
512510
value_serializer: &dyn v8::ValueSerializerHelper,
513511
) -> Option<bool> {
512+
if let Some(host_object_brand) = self.host_object_brand {
513+
let value = object.get(scope, host_object_brand.into())?;
514+
if let Ok(func) = value.try_cast::<v8::Function>() {
515+
let result = func.call(scope, object.into(), &[])?;
516+
value_serializer.write_uint32(u32::MAX);
517+
value_serializer.write_value(scope.get_current_context(), result);
518+
return Some(true);
519+
}
520+
}
514521
if let Some(host_objects) = self.host_objects {
515522
for i in 0..host_objects.length() {
516523
let value = host_objects.get_index(scope, i).unwrap();
@@ -570,11 +577,29 @@ impl v8::ValueDeserializerImpl for SerializeDeserialize<'_> {
570577
scope: &mut v8::PinScope<'s, 'i>,
571578
value_deserializer: &dyn v8::ValueDeserializerHelper,
572579
) -> Option<v8::Local<'s, v8::Object>> {
573-
if let Some(host_objects) = self.host_objects {
574-
let mut i = 0;
575-
if !value_deserializer.read_uint32(&mut i) {
576-
return None;
580+
let mut i = 0;
581+
if !value_deserializer.read_uint32(&mut i) {
582+
return None;
583+
}
584+
if i == u32::MAX {
585+
if let Some(deserializers) = self.deserializers
586+
&& let Some(value) =
587+
value_deserializer.read_value(scope.get_current_context())
588+
&& let Some(object) = value.to_object(scope)
589+
{
590+
let key = crate::runtime::v8_static_strings::TYPE
591+
.v8_string(scope)
592+
.unwrap();
593+
let ty = object.get(scope, key.into())?;
594+
let func = deserializers.get(scope, ty)?;
595+
let recv = v8::null(scope).into();
596+
let scope =
597+
std::pin::pin!(v8::AllowJavascriptExecutionScope::new(scope));
598+
let scope = &mut scope.init();
599+
let res = func.cast::<v8::Function>().call(scope, recv, &[value])?;
600+
return res.to_object(scope);
577601
}
602+
} else if let Some(host_objects) = self.host_objects {
578603
let maybe_value = host_objects.get_index(scope, i);
579604
if let Some(value) = maybe_value {
580605
return value.to_object(scope);
@@ -625,13 +650,14 @@ pub fn op_serialize<'s, 'i>(
625650

626651
let key = v8_static_strings::HOST_OBJECT.v8_string(scope).unwrap();
627652
let symbol = v8::Symbol::for_key(scope, key);
628-
let host_object_brand = Some(v8::Global::new(scope, symbol));
653+
let host_object_brand = Some(symbol);
629654

630655
let serialize_deserialize = Box::new(SerializeDeserialize {
631656
host_objects,
632657
error_callback,
633658
for_storage,
634659
host_object_brand,
660+
deserializers: None,
635661
});
636662
let value_serializer = v8::ValueSerializer::new(scope, serialize_deserialize);
637663
value_serializer.write_header();
@@ -692,6 +718,7 @@ pub fn op_deserialize<'s, 'i>(
692718
#[buffer] zero_copy: JsBuffer,
693719
host_objects: Option<v8::Local<'s, v8::Value>>,
694720
transferred_array_buffers: Option<v8::Local<'s, v8::Value>>,
721+
deserializers: Option<v8::Local<'s, v8::Value>>,
695722
for_storage: bool,
696723
) -> Result<v8::Local<'s, v8::Value>, JsErrorBox> {
697724
let host_objects = match host_objects {
@@ -709,12 +736,20 @@ pub fn op_deserialize<'s, 'i>(
709736
}
710737
None => None,
711738
};
739+
let deserializers = match deserializers {
740+
Some(value) => Some(
741+
v8::Local::<v8::Object>::try_from(value)
742+
.map_err(|_| JsErrorBox::type_error("deserializers not an object"))?,
743+
),
744+
None => None,
745+
};
712746

713747
let serialize_deserialize = Box::new(SerializeDeserialize {
714748
host_objects,
715749
error_callback: None,
716750
for_storage,
717751
host_object_brand: None,
752+
deserializers,
718753
});
719754
let value_deserializer =
720755
v8::ValueDeserializer::new(scope, serialize_deserialize, &zero_copy);
@@ -768,16 +803,18 @@ pub fn op_deserialize<'s, 'i>(
768803
pub fn op_structured_clone<'s, 'i>(
769804
scope: &mut v8::PinScope<'s, 'i>,
770805
value: v8::Local<'s, v8::Value>,
806+
deserializers: Option<v8::Local<'s, v8::Object>>,
771807
) -> Result<v8::Local<'s, v8::Value>, JsErrorBox> {
772808
let key = v8_static_strings::HOST_OBJECT.v8_string(scope).unwrap();
773809
let symbol = v8::Symbol::for_key(scope, key);
774-
let host_object_brand = Some(v8::Global::new(scope, symbol));
810+
let host_object_brand = Some(symbol);
775811

776812
let serialize_deserialize = Box::new(SerializeDeserialize {
777813
host_objects: None,
778814
error_callback: None,
779815
for_storage: false,
780-
host_object_brand: host_object_brand.clone(),
816+
host_object_brand,
817+
deserializers: None,
781818
});
782819
let value_serializer = v8::ValueSerializer::new(scope, serialize_deserialize);
783820
value_serializer.write_header();
@@ -802,7 +839,8 @@ pub fn op_structured_clone<'s, 'i>(
802839
host_objects: None,
803840
error_callback: None,
804841
for_storage: false,
805-
host_object_brand: host_object_brand.clone(),
842+
host_object_brand,
843+
deserializers,
806844
});
807845
let value_deserializer =
808846
v8::ValueDeserializer::new(scope, serialize_deserialize, &vector);

core/runtime/v8_static_strings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ v8_static_strings!(
3535
RESOLVE = "resolve",
3636
SET_UP_ASYNC_STUB = "setUpAsyncStub",
3737
STACK = "stack",
38+
TYPE = "type",
3839
URL = "url",
3940
WASM_INSTANCE = "WasmInstance",
4041
WEBASSEMBLY = "WebAssembly",

0 commit comments

Comments
 (0)