From 82655b928500ca7a9762617b1c61f80fd122ccbd Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Tue, 21 Jun 2022 06:46:59 +0300 Subject: [PATCH] perf(ext/ffi): Optimize FFI Rust side type checks (#14923) --- ext/ffi/lib.rs | 121 ++++++++++++++++------------ test_ffi/tests/integration_tests.rs | 1 + test_ffi/tests/test.js | 3 + 3 files changed, 72 insertions(+), 53 deletions(-) diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index f380546b0d..6c7f3375f9 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -627,47 +627,47 @@ where ffi_args.push(NativeValue { i32_value: value }); } NativeType::U64 => { - let value: u64 = if value.is_big_int() { - let value = v8::Local::::try_from(value)?; - value.u64_value().0 - } else { - value.integer_value(scope).ok_or_else(|| { - type_error("Invalid FFI u64 type, expected number") - })? as u64 - }; + let value: u64 = + if let Ok(value) = v8::Local::::try_from(value) { + value.u64_value().0 + } else { + value.integer_value(scope).ok_or_else(|| { + type_error("Invalid FFI u64 type, expected number") + })? as u64 + }; ffi_args.push(NativeValue { u64_value: value }); } NativeType::I64 => { - let value: i64 = if value.is_big_int() { - let value = v8::Local::::try_from(value)?; - value.i64_value().0 - } else { - value.integer_value(scope).ok_or_else(|| { - type_error("Invalid FFI i64 type, expected number") - })? as i64 - }; + let value: i64 = + if let Ok(value) = v8::Local::::try_from(value) { + value.i64_value().0 + } else { + value.integer_value(scope).ok_or_else(|| { + type_error("Invalid FFI i64 type, expected number") + })? as i64 + }; ffi_args.push(NativeValue { i64_value: value }); } NativeType::USize => { - let value: usize = if value.is_big_int() { - let value = v8::Local::::try_from(value)?; - value.u64_value().0 as usize - } else { - value.integer_value(scope).ok_or_else(|| { - type_error("Invalid FFI usize type, expected number") - })? as usize - }; + let value: usize = + if let Ok(value) = v8::Local::::try_from(value) { + value.u64_value().0 as usize + } else { + value.integer_value(scope).ok_or_else(|| { + type_error("Invalid FFI usize type, expected number") + })? as usize + }; ffi_args.push(NativeValue { usize_value: value }); } NativeType::ISize => { - let value: isize = if value.is_big_int() { - let value = v8::Local::::try_from(value)?; - value.i64_value().0 as isize - } else { - value.integer_value(scope).ok_or_else(|| { - type_error("Invalid FFI isize type, expected number") - })? as isize - }; + let value: isize = + if let Ok(value) = v8::Local::::try_from(value) { + value.i64_value().0 as isize + } else { + value.integer_value(scope).ok_or_else(|| { + type_error("Invalid FFI isize type, expected number") + })? as isize + }; ffi_args.push(NativeValue { isize_value: value }); } NativeType::F32 => { @@ -688,16 +688,28 @@ where if value.is_null() { let value: *const u8 = ptr::null(); ffi_args.push(NativeValue { pointer: value }) - } else if value.is_big_int() { - let value = v8::Local::::try_from(value).unwrap(); + } else if let Ok(value) = v8::Local::::try_from(value) { let value = value.u64_value().0 as *const u8; ffi_args.push(NativeValue { pointer: value }); - } else if value.is_array_buffer() || value.is_array_buffer_view() { - let value: ZeroCopyBuf = serde_v8::from_v8(scope, value)?; - let value: &[u8] = &value[..]; - ffi_args.push(NativeValue { - pointer: value.as_ptr(), - }); + } else if let Ok(value) = + v8::Local::::try_from(value) + { + let byte_offset = value.byte_offset(); + let backing_store = value + .buffer(scope) + .ok_or_else(|| { + type_error( + "Invalid FFI ArrayBufferView, expected data in the buffer", + ) + })? + .get_backing_store(); + let pointer = &backing_store[byte_offset] as *const _ as *const u8; + ffi_args.push(NativeValue { pointer }); + } else if let Ok(value) = v8::Local::::try_from(value) + { + let backing_store = value.get_backing_store(); + let pointer = &backing_store as *const _ as *const u8; + ffi_args.push(NativeValue { pointer }); } else { return Err(type_error("Invalid FFI pointer type, expected null, BigInt, ArrayBuffer, or ArrayBufferView")); } @@ -706,8 +718,7 @@ where if value.is_null() { let value: *const u8 = ptr::null(); ffi_args.push(NativeValue { pointer: value }) - } else if value.is_big_int() { - let value = v8::Local::::try_from(value).unwrap(); + } else if let Ok(value) = v8::Local::::try_from(value) { let value = value.u64_value().0 as *const u8; ffi_args.push(NativeValue { pointer: value }); } else { @@ -969,13 +980,19 @@ unsafe extern "C" fn deno_ffi_callback( .expect("Unable to deserialize result parameter."); } FFI_TYPE_POINTER | FFI_TYPE_STRUCT => { - if value.is_array_buffer() | value.is_array_buffer_view() { - let value: ZeroCopyBuf = serde_v8::from_v8(&mut scope, value) - .expect("Unable to deserialize result parameter."); - let value: &[u8] = &value[..]; - *(result as *mut *const u8) = value.as_ptr(); - } else if value.is_big_int() { - let value = v8::Local::::try_from(value).unwrap(); + if let Ok(value) = v8::Local::::try_from(value) { + let byte_offset = value.byte_offset(); + let backing_store = value + .buffer(&mut scope) + .expect("Unable to deserialize result parameter.") + .get_backing_store(); + let pointer = &backing_store[byte_offset] as *const _ as *const u8; + *(result as *mut *const u8) = pointer; + } else if let Ok(value) = v8::Local::::try_from(value) { + let backing_store = value.get_backing_store(); + let pointer = &backing_store as *const _ as *const u8; + *(result as *mut *const u8) = pointer; + } else if let Ok(value) = v8::Local::::try_from(value) { *(result as *mut u64) = value.u64_value().0; } else if value.is_null() { *(result as *mut *const c_void) = ptr::null(); @@ -1018,8 +1035,7 @@ unsafe extern "C" fn deno_ffi_callback( .expect("Unable to deserialize result parameter."); } FFI_TYPE_SINT64 => { - if value.is_big_int() { - let value = v8::Local::::try_from(value).unwrap(); + if let Ok(value) = v8::Local::::try_from(value) { *(result as *mut i64) = value.i64_value().0; } else { *(result as *mut i64) = value @@ -1029,8 +1045,7 @@ unsafe extern "C" fn deno_ffi_callback( } } FFI_TYPE_UINT64 => { - if value.is_big_int() { - let value = v8::Local::::try_from(value).unwrap(); + if let Ok(value) = v8::Local::::try_from(value) { *(result as *mut u64) = value.u64_value().0; } else { *(result as *mut u64) = value diff --git a/test_ffi/tests/integration_tests.rs b/test_ffi/tests/integration_tests.rs index 93f3687871..77bcc758e3 100644 --- a/test_ffi/tests/integration_tests.rs +++ b/test_ffi/tests/integration_tests.rs @@ -45,6 +45,7 @@ fn basic() { let expected = "\ something\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ + [4, 5, 6]\n\ [1, 2, 3, 4, 5, 6, 7, 8] [9, 10]\n\ [1, 2, 3, 4, 5, 6, 7, 8]\n\ [ 1, 2, 3, 4, 5, 6 ]\n\ diff --git a/test_ffi/tests/test.js b/test_ffi/tests/test.js index 8190b3c8e2..ab31dcb836 100644 --- a/test_ffi/tests/test.js +++ b/test_ffi/tests/test.js @@ -174,6 +174,9 @@ dylib.symbols.printSomething(); const buffer = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]); const buffer2 = new Uint8Array([9, 10]); dylib.symbols.print_buffer(buffer, buffer.length); +// Test subarrays +const subarray = buffer.subarray(3); +dylib.symbols.print_buffer(subarray, subarray.length - 2); dylib.symbols.print_buffer2(buffer, buffer.length, buffer2, buffer2.length); const ptr0 = dylib.symbols.return_buffer(); dylib.symbols.print_buffer(ptr0, 8);