From 7dbdc1c481929f64ed5aaa4075eed386a3928592 Mon Sep 17 00:00:00 2001 From: Laurence Rowe Date: Fri, 15 Sep 2023 09:08:07 +0000 Subject: [PATCH 1/3] test embedder host object --- tests/test_api.rs | 84 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/tests/test_api.rs b/tests/test_api.rs index 6b37ad15c3..27ec05fd22 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -7534,12 +7534,18 @@ impl<'a> v8::ValueSerializerImpl for Custom1Value<'a> { fn write_host_object<'s>( &mut self, - _scope: &mut v8::HandleScope<'s>, - _object: v8::Local<'s, v8::Object>, + scope: &mut v8::HandleScope<'s>, + object: v8::Local<'s, v8::Object>, value_serializer: &mut dyn v8::ValueSerializerHelper, ) -> Option { - value_serializer.write_uint64(1); - None + let key = v8::String::new(scope, "hostObject").unwrap(); + let value = object + .get(scope, key.into()) + .unwrap() + .uint32_value(scope) + .unwrap(); + value_serializer.write_uint32(value); + Some(true) } } @@ -7559,12 +7565,18 @@ impl<'a> v8::ValueDeserializerImpl for Custom1Value<'a> { fn read_host_object<'s>( &mut self, - _scope: &mut v8::HandleScope<'s>, + scope: &mut v8::HandleScope<'s>, value_deserializer: &mut dyn v8::ValueDeserializerHelper, ) -> Option> { let mut value = 0; - value_deserializer.read_uint64(&mut value); - None + value_deserializer.read_uint32(&mut value); + let template = v8::ObjectTemplate::new(scope); + template.set_internal_field_count(1); + let host_object = template.new_instance(scope).unwrap(); + let key = v8::String::new(scope, "readHostObject").unwrap(); + let value = v8::Integer::new_from_unsigned(scope, value); + host_object.set(scope, key.into(), value.into()); + Some(host_object) } } @@ -7788,6 +7800,64 @@ fn value_serializer_and_deserializer_array_buffers() { } } +#[test] +fn value_serializer_and_deserializer_embedder_host_object() { + let buffer; + let expected: u32 = 123; + let mut array_buffers = ArrayBuffers::new(); + { + let _setup_guard = setup::parallel_test(); + let isolate = &mut v8::Isolate::new(Default::default()); + + let scope = &mut v8::HandleScope::new(isolate); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let template = v8::ObjectTemplate::new(scope); + template.set_internal_field_count(1); + let host_object = template.new_instance(scope).unwrap(); + let key = v8::String::new(scope, "hostObject").unwrap(); + let value = v8::Integer::new_from_unsigned(scope, expected); + host_object.set(scope, key.into(), value.into()); + + let mut value_serializer = + Custom1Value::serializer(scope, &mut array_buffers); + assert_eq!( + value_serializer.write_value(context, host_object.into()), + Some(true) + ); + + buffer = value_serializer.release(); + } + + { + let _setup_guard = setup::parallel_test(); + let isolate = &mut v8::Isolate::new(Default::default()); + + let scope = &mut v8::HandleScope::new(isolate); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let mut value_deserializer = + Custom1Value::deserializer(scope, &buffer, &mut array_buffers); + let host_object_out = value_deserializer + .read_value(context) + .unwrap() + .to_object(scope) + .unwrap(); + drop(value_deserializer); + let key = v8::String::new(scope, "readHostObject").unwrap(); + let value = host_object_out + .get(scope, key.into()) + .unwrap() + .uint32_value(scope) + .unwrap(); + assert_eq!(value, expected); + } +} + struct Custom2Value {} impl<'a> Custom2Value { From 2545a6159f7ef174538c84c5a0c0e0949222835c Mon Sep 17 00:00:00 2001 From: Laurence Rowe Date: Mon, 18 Sep 2023 22:48:32 +0000 Subject: [PATCH 2/3] feat: Support custom host objects in ValueSerializer See: v8/v8@cf13b9b46572a9824d2d632abdd48c56161ace02 --- src/binding.cc | 17 ++++++ src/value_serializer.rs | 45 ++++++++++++++ tests/test_api.rs | 129 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) diff --git a/src/binding.cc b/src/binding.cc index 6dab984650..1c08904515 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -3178,6 +3178,13 @@ extern "C" { void v8__ValueSerializer__Delegate__ThrowDataCloneError( v8::ValueSerializer::Delegate* self, v8::Local message); +bool v8__ValueSerializer__Delegate__HasCustomHostObject( + v8::ValueSerializer::Delegate* self, v8::Isolate* isolate); + +MaybeBool v8__ValueSerializer__Delegate__IsHostObject( + v8::ValueSerializer::Delegate* self, v8::Isolate* isolate, + v8::Local object); + MaybeBool v8__ValueSerializer__Delegate__WriteHostObject( v8::ValueSerializer::Delegate* self, v8::Isolate* isolate, v8::Local object); @@ -3203,6 +3210,16 @@ struct v8__ValueSerializer__Delegate : public v8::ValueSerializer::Delegate { v8__ValueSerializer__Delegate__ThrowDataCloneError(this, message); } + bool HasCustomHostObject(v8::Isolate* isolate) override { + return v8__ValueSerializer__Delegate__HasCustomHostObject(this, isolate); + } + + v8::Maybe IsHostObject(v8::Isolate* isolate, + v8::Local object) override { + return maybe_bool_to_maybe( + v8__ValueSerializer__Delegate__IsHostObject(this, isolate, object)); + } + v8::Maybe WriteHostObject(v8::Isolate* isolate, v8::Local object) override { return maybe_bool_to_maybe( diff --git a/src/value_serializer.rs b/src/value_serializer.rs index 54a003c981..72e8f0d4b7 100644 --- a/src/value_serializer.rs +++ b/src/value_serializer.rs @@ -45,6 +45,34 @@ pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError( .throw_data_clone_error(scope, message) } +#[no_mangle] +pub unsafe extern "C" fn v8__ValueSerializer__Delegate__HasCustomHostObject( + this: &mut CxxValueSerializerDelegate, + _isolate: *mut Isolate, +) -> bool { + let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this); + let scope = + &mut crate::scope::CallbackScope::new(value_serializer_heap.context); + value_serializer_heap + .value_serializer_impl + .as_mut() + .has_custom_host_object(scope) +} + +#[no_mangle] +pub unsafe extern "C" fn v8__ValueSerializer__Delegate__IsHostObject( + this: &mut CxxValueSerializerDelegate, + _isolate: *mut Isolate, + object: Local, +) -> MaybeBool { + let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this); + let scope = + &mut crate::scope::CallbackScope::new(value_serializer_heap.context); + let value_serializer_impl = + value_serializer_heap.value_serializer_impl.as_mut(); + MaybeBool::from(value_serializer_impl.is_host_object(scope, object)) +} + #[no_mangle] pub unsafe extern "C" fn v8__ValueSerializer__Delegate__WriteHostObject( this: &mut CxxValueSerializerDelegate, @@ -211,6 +239,23 @@ pub trait ValueSerializerImpl { message: Local<'s, String>, ); + fn has_custom_host_object(&mut self, _scope: &mut HandleScope) -> bool { + false + } + + fn is_host_object<'s>( + &mut self, + scope: &mut HandleScope<'s>, + _object: Local<'s, Object>, + ) -> Option { + let msg = + String::new(scope, "Deno serializer: is_host_object not implemented") + .unwrap(); + let exc = Exception::error(scope, msg); + scope.throw_exception(exc); + None + } + fn write_host_object<'s>( &mut self, scope: &mut HandleScope<'s>, diff --git a/tests/test_api.rs b/tests/test_api.rs index 27ec05fd22..8800fb30de 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -7917,6 +7917,135 @@ fn value_serializer_not_implemented() { ); } +struct Custom3Value {} + +impl<'a> Custom3Value { + fn serializer<'s>( + scope: &mut v8::HandleScope<'s>, + ) -> v8::ValueSerializer<'a, 's> { + v8::ValueSerializer::new(scope, Box::new(Self {})) + } + + fn deserializer<'s>( + scope: &mut v8::HandleScope<'s>, + data: &[u8], + ) -> v8::ValueDeserializer<'a, 's> { + v8::ValueDeserializer::new(scope, Box::new(Self {}), data) + } +} + +impl v8::ValueSerializerImpl for Custom3Value { + #[allow(unused_variables)] + fn throw_data_clone_error<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + message: v8::Local<'s, v8::String>, + ) { + let error = v8::Exception::error(scope, message); + scope.throw_exception(error); + } + + fn has_custom_host_object(&mut self, _scope: &mut v8::HandleScope) -> bool { + true + } + + fn is_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + object: v8::Local<'s, v8::Object>, + ) -> Option { + let key = v8::String::new(scope, "hostObject").unwrap(); + object.has_own_property(scope, key.into()) + } + + fn write_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + object: v8::Local<'s, v8::Object>, + value_serializer: &mut dyn v8::ValueSerializerHelper, + ) -> Option { + let key = v8::String::new(scope, "hostObject").unwrap(); + let value = object + .get(scope, key.into()) + .unwrap() + .uint32_value(scope) + .unwrap(); + value_serializer.write_uint32(value); + Some(true) + } +} + +impl v8::ValueDeserializerImpl for Custom3Value { + fn read_host_object<'s>( + &mut self, + scope: &mut v8::HandleScope<'s>, + value_deserializer: &mut dyn v8::ValueDeserializerHelper, + ) -> Option> { + let mut value = 0; + value_deserializer.read_uint32(&mut value); + let host_object = v8::Object::new(scope); + let key = v8::String::new(scope, "readHostObject").unwrap(); + let value = v8::Integer::new_from_unsigned(scope, value); + host_object.set(scope, key.into(), value.into()); + Some(host_object) + } +} + +#[test] +fn value_serializer_and_deserializer_custom_host_object() { + let buffer; + let expected: u32 = 123; + { + let _setup_guard = setup::parallel_test(); + let isolate = &mut v8::Isolate::new(Default::default()); + + let scope = &mut v8::HandleScope::new(isolate); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let host_object = v8::Object::new(scope); + let key = v8::String::new(scope, "hostObject").unwrap(); + let value = v8::Integer::new_from_unsigned(scope, expected); + host_object.set(scope, key.into(), value.into()); + + let mut value_serializer = Custom3Value::serializer(scope); + assert_eq!( + value_serializer.write_value(context, host_object.into()), + Some(true) + ); + + buffer = value_serializer.release(); + } + + { + let _setup_guard = setup::parallel_test(); + let isolate = &mut v8::Isolate::new(Default::default()); + + let scope = &mut v8::HandleScope::new(isolate); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let mut value_deserializer = Custom3Value::deserializer(scope, &buffer); + let host_object_out = value_deserializer + .read_value(context) + .unwrap() + .to_object(scope) + .unwrap(); + drop(value_deserializer); + let key = v8::String::new(scope, "readHostObject").unwrap(); + let has_prop = host_object_out.has_own_property(scope, key.into()).unwrap(); + assert!(has_prop); + let value = host_object_out + .get(scope, key.into()) + .unwrap() + .uint32_value(scope) + .unwrap(); + assert_eq!(value, expected); + } +} + #[test] fn memory_pressure_notification() { let _setup_guard = setup::parallel_test(); From 82b38ed65ea3a5f8f094555c7c66ca137f586d64 Mon Sep 17 00:00:00 2001 From: Laurence Rowe Date: Tue, 7 Nov 2023 00:17:39 -0800 Subject: [PATCH 3/3] has_custom_host_object does not need HandleScope, so just pass Isolate --- src/value_serializer.rs | 8 +++----- tests/test_api.rs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/value_serializer.rs b/src/value_serializer.rs index 72e8f0d4b7..277e6ad07c 100644 --- a/src/value_serializer.rs +++ b/src/value_serializer.rs @@ -48,15 +48,13 @@ pub unsafe extern "C" fn v8__ValueSerializer__Delegate__ThrowDataCloneError( #[no_mangle] pub unsafe extern "C" fn v8__ValueSerializer__Delegate__HasCustomHostObject( this: &mut CxxValueSerializerDelegate, - _isolate: *mut Isolate, + isolate: *mut Isolate, ) -> bool { let value_serializer_heap = ValueSerializerHeap::dispatch_mut(this); - let scope = - &mut crate::scope::CallbackScope::new(value_serializer_heap.context); value_serializer_heap .value_serializer_impl .as_mut() - .has_custom_host_object(scope) + .has_custom_host_object(&mut *isolate) } #[no_mangle] @@ -239,7 +237,7 @@ pub trait ValueSerializerImpl { message: Local<'s, String>, ); - fn has_custom_host_object(&mut self, _scope: &mut HandleScope) -> bool { + fn has_custom_host_object(&mut self, _isolate: &mut Isolate) -> bool { false } diff --git a/tests/test_api.rs b/tests/test_api.rs index 8800fb30de..188970ea0f 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -7945,7 +7945,7 @@ impl v8::ValueSerializerImpl for Custom3Value { scope.throw_exception(error); } - fn has_custom_host_object(&mut self, _scope: &mut v8::HandleScope) -> bool { + fn has_custom_host_object(&mut self, _isolate: &mut v8::Isolate) -> bool { true }