From a1b989c8421e5b1fa6b2954364b4acc4e80db855 Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Wed, 27 Jul 2022 19:32:21 +0530 Subject: [PATCH] perf(ext/ffi): support Uint8Array in fast calls (#15319) --- ext/ffi/jit_trampoline.rs | 26 ++++++++++++++++++++++---- ext/ffi/lib.rs | 5 ++--- ext/ffi/prelude.h | 6 ++++++ test_ffi/src/lib.rs | 10 ++++++++++ test_ffi/tests/bench.js | 8 ++++++++ 5 files changed, 48 insertions(+), 7 deletions(-) diff --git a/ext/ffi/jit_trampoline.rs b/ext/ffi/jit_trampoline.rs index 6a3efa8764..92e63348d2 100644 --- a/ext/ffi/jit_trampoline.rs +++ b/ext/ffi/jit_trampoline.rs @@ -32,7 +32,8 @@ fn native_arg_to_c(ty: &NativeType) -> &'static str { NativeType::I64 => "int64_t", NativeType::ISize => "intptr_t", NativeType::USize => "uintptr_t", - NativeType::Pointer | NativeType::Function => "void*", + NativeType::Pointer => "struct FastApiTypedArray*", + NativeType::Function => "void*", } } @@ -85,11 +86,15 @@ pub(crate) fn codegen(sym: &crate::Symbol) -> String { c += ") {\n"; // return func(p0, p1, ...); c += " return func("; - for (i, _) in sym.parameter_types.iter().enumerate() { + for (i, ty) in sym.parameter_types.iter().enumerate() { if i > 0 { c += ", "; } - let _ = write!(c, "p{i}"); + if matches!(ty, NativeType::Pointer) { + let _ = write!(c, "p{i}->data"); + } else { + let _ = write!(c, "p{i}"); + } } c += ");\n}\n\n"; c @@ -103,7 +108,6 @@ pub(crate) fn gen_trampoline( // SAFETY: symbol satisfies ABI requirement. unsafe { ctx.add_symbol(cstr!("func"), sym.ptr.0 as *const c_void) }; let c = codegen(&sym); - ctx.compile_string(cstr!(c))?; let alloc = Allocation { addr: ctx.relocate_and_get_symbol(cstr!("func_trampoline"))?, @@ -172,6 +176,20 @@ mod tests { \n return func(p0, p1);\n\ }\n\n", ); + assert_codegen( + codegen(vec![NativeType::Pointer, NativeType::U32], NativeType::U32), + "extern uint32_t func(void* p0, uint32_t p1);\n\n\ + uint32_t func_trampoline(void* recv, struct FastApiTypedArray* p0, uint32_t p1) {\ + \n return func(p0->data, p1);\n\ + }\n\n", + ); + assert_codegen( + codegen(vec![NativeType::Pointer, NativeType::Pointer], NativeType::U32), + "extern uint32_t func(void* p0, void* p1);\n\n\ + uint32_t func_trampoline(void* recv, struct FastApiTypedArray* p0, struct FastApiTypedArray* p1) {\ + \n return func(p0->data, p1->data);\n\ + }\n\n", + ); } #[test] diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs index 4746a52035..05015a45a7 100644 --- a/ext/ffi/lib.rs +++ b/ext/ffi/lib.rs @@ -746,9 +746,8 @@ impl From<&NativeType> for fast_api::Type { NativeType::I64 => fast_api::Type::Int64, NativeType::U64 => fast_api::Type::Uint64, NativeType::ISize => fast_api::Type::Int64, - NativeType::USize | NativeType::Function | NativeType::Pointer => { - fast_api::Type::Uint64 - } + NativeType::USize | NativeType::Function => fast_api::Type::Uint64, + NativeType::Pointer => fast_api::Type::TypedArray(fast_api::CType::Uint8), } } } diff --git a/ext/ffi/prelude.h b/ext/ffi/prelude.h index ed3d14e1a0..89ae162c1d 100644 --- a/ext/ffi/prelude.h +++ b/ext/ffi/prelude.h @@ -17,3 +17,9 @@ typedef unsigned long int uint64_t; /* Types for `void *' pointers. */ typedef long int intptr_t; typedef unsigned long int uintptr_t; + +// https://source.chromium.org/chromium/chromium/src/+/main:v8/include/v8-fast-api-calls.h;l=336 +struct FastApiTypedArray { + uintptr_t length_; + void* data; +}; diff --git a/test_ffi/src/lib.rs b/test_ffi/src/lib.rs index 95b7d900ca..bc89bd66c6 100644 --- a/test_ffi/src/lib.rs +++ b/test_ffi/src/lib.rs @@ -94,6 +94,16 @@ pub extern "C" fn add_f64(a: f64, b: f64) -> f64 { a + b } +#[no_mangle] +unsafe extern "C" fn hash(ptr: *const u8, length: u32) -> u32 { + let buf = std::slice::from_raw_parts(ptr, length as usize); + let mut hash: u32 = 0; + for byte in buf { + hash = hash.wrapping_mul(0x10001000).wrapping_add(*byte as u32); + } + hash +} + #[no_mangle] pub extern "C" fn sleep_blocking(ms: u64) { let duration = Duration::from_millis(ms); diff --git a/test_ffi/tests/bench.js b/test_ffi/tests/bench.js index 8885c7d7e1..da29f482fa 100644 --- a/test_ffi/tests/bench.js +++ b/test_ffi/tests/bench.js @@ -12,6 +12,7 @@ const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`; const dylib = Deno.dlopen(libPath, { "nop": { parameters: [], result: "void" }, "add_u32": { parameters: ["u32", "u32"], result: "u32" }, + "hash": { parameters: ["pointer", "u32"], result: "u32" }, "nop_u8": { parameters: ["u8"], result: "void" }, "nop_i8": { parameters: ["i8"], result: "void" }, "nop_u16": { parameters: ["u16"], result: "void" }, @@ -231,6 +232,13 @@ Deno.bench("add_u32()", () => { add_u32(1, 2); }); +const bytes = new Uint8Array(64); + +const { hash } = dylib.symbols; +Deno.bench("hash()", () => { + hash(bytes, bytes.byteLength); +}); + const { nop_u8 } = dylib.symbols; Deno.bench("nop_u8()", () => { nop_u8(100);