From 08e1a1c361dac554906f07fa0880c00d182d04a8 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 13 Jul 2022 12:35:31 +0530 Subject: [PATCH] Add v8::Object `[Get/Set]AlignedPointer[From/In]InternalField` (#1026) --- src/binding.cc | 10 ++++++ src/object.rs | 33 +++++++++++++++++ tests/test_api.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/src/binding.cc b/src/binding.cc index 1ff045b9..934ee6cb 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1165,6 +1165,16 @@ const v8::Value* v8__Object__GetIndex(const v8::Object& self, ptr_to_local(&self)->Get(ptr_to_local(&context), index)); } +void* v8__Object__GetAlignedPointerFromInternalField(const v8::Object& self, + int index) { + return ptr_to_local(&self)->GetAlignedPointerFromInternalField(index); +} + +void v8__Object__SetAlignedPointerInInternalField(const v8::Object& self, + int index, void* value) { + ptr_to_local(&self)->SetAlignedPointerInInternalField(index, value); +} + const v8::Value* v8__Object__GetPrototype(const v8::Object& self) { return local_to_ptr(ptr_to_local(&self)->GetPrototype()); } diff --git a/src/object.rs b/src/object.rs index cd6614da..bf8af59d 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,3 +1,5 @@ +use libc::c_void; + use crate::isolate::Isolate; use crate::support::int; use crate::support::MapFnTo; @@ -120,6 +122,15 @@ extern "C" { this: *const Object, index: int, ) -> *const Value; + fn v8__Object__GetAlignedPointerFromInternalField( + this: *const Object, + index: int, + ) -> *const c_void; + fn v8__Object__SetAlignedPointerInInternalField( + this: *const Object, + index: int, + value: *const c_void, + ); fn v8__Object__SetIntegrityLevel( this: *const Object, context: *const Context, @@ -512,6 +523,28 @@ impl Object { None } + /// Gets a 2-byte-aligned native pointer from an internal field. + /// + /// # Safety + /// This field must have been set by SetAlignedPointerInInternalField, everything else leads to undefined behavior. + pub unsafe fn get_aligned_pointer_from_internal_field( + &self, + index: i32, + ) -> *const c_void { + v8__Object__GetAlignedPointerFromInternalField(self, index) + } + + /// Sets a 2-byte-aligned native pointer in an internal field. + /// To retrieve such a field, GetAlignedPointerFromInternalField must be used. + #[allow(clippy::not_unsafe_ptr_arg_deref)] + pub fn set_aligned_pointer_in_internal_field( + &self, + index: i32, + value: *const c_void, + ) { + unsafe { v8__Object__SetAlignedPointerInInternalField(self, index, value) } + } + /// Sets the integrity level of the object. pub fn set_integrity_level( &self, diff --git a/tests/test_api.rs b/tests/test_api.rs index 11d03e68..eb4b5d95 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -7247,3 +7247,95 @@ fn test_fast_calls_arraybuffer() { eval(scope, source).unwrap(); assert_eq!("fast", unsafe { WHO }); } + +#[test] +fn test_fast_calls_reciever() { + const V8_WRAPPER_TYPE_INDEX: i32 = 0; + const V8_WRAPPER_OBJECT_INDEX: i32 = 1; + + static mut WHO: &str = "none"; + fn fast_fn(recv: v8::Local) -> u32 { + unsafe { + WHO = "fast"; + let embedder_obj = + recv.get_aligned_pointer_from_internal_field(V8_WRAPPER_OBJECT_INDEX); + + let i = *(embedder_obj as *const u32); + assert_eq!(i, 69); + i + } + } + + pub struct FastTest; + impl fast_api::FastFunction for FastTest { + fn args(&self) -> &'static [fast_api::Type] { + &[fast_api::Type::V8Value] + } + + fn return_type(&self) -> fast_api::CType { + fast_api::CType::Uint32 + } + + type Signature = fn(receiver: v8::Local) -> u32; + fn function(&self) -> Self::Signature { + fast_fn + } + } + + fn slow_fn( + scope: &mut v8::HandleScope, + _: v8::FunctionCallbackArguments, + mut rv: v8::ReturnValue, + ) { + unsafe { WHO = "slow" }; + rv.set(v8::Boolean::new(scope, false).into()); + } + + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new( + v8::CreateParams::default().embedder_wrapper_type_info_offsets( + V8_WRAPPER_TYPE_INDEX, + V8_WRAPPER_OBJECT_INDEX, + ), + ); + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let object_template = v8::ObjectTemplate::new(scope); + assert!(object_template + .set_internal_field_count((V8_WRAPPER_OBJECT_INDEX + 1) as usize)); + + let obj = object_template.new_instance(scope).unwrap(); + let embedder_obj = Box::into_raw(Box::new(69u32)); + obj.set_aligned_pointer_in_internal_field( + V8_WRAPPER_OBJECT_INDEX, + embedder_obj as _, + ); + + let template = + v8::FunctionTemplate::builder(slow_fn).build_fast(scope, FastTest); + + let name = v8::String::new(scope, "method").unwrap(); + let value = template.get_function(scope).unwrap(); + obj.set(scope, name.into(), value.into()).unwrap(); + + let obj_str = v8::String::new(scope, "obj").unwrap(); + let global = context.global(scope); + global.set(scope, obj_str.into(), obj.into()).unwrap(); + + let source = r#" + function f() { return obj.method(); } + %PrepareFunctionForOptimization(f); + f(); +"#; + eval(scope, source).unwrap(); + assert_eq!("slow", unsafe { WHO }); + + let source = r#" + %OptimizeFunctionOnNextCall(f); + f(); + "#; + eval(scope, source).unwrap(); + assert_eq!("fast", unsafe { WHO }); +}