Skip to content

fix: handle all values for buffers in turbocall codegen #28170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cli/lib/util/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ pub fn init<
.filter_module("opentelemetry_sdk", log::LevelFilter::Off)
// for deno_compile, this is too verbose
.filter_module("editpe", log::LevelFilter::Error)
// too verbose
.filter_module("cranelift_codegen", log::LevelFilter::Off)
.format(|buf, record| {
let mut target = record.target().to_string();
if let Some(line_no) = record.line() {
Expand Down
2 changes: 1 addition & 1 deletion ext/ffi/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ where
ffi_args.push(ffi_parse_f64_arg(value)?);
}
NativeType::Buffer => {
ffi_args.push(ffi_parse_buffer_arg(scope, value)?);
ffi_args.push(ffi_parse_buffer_arg(value)?);
}
NativeType::Struct(_) => {
ffi_args.push(ffi_parse_struct_arg(scope, value)?);
Expand Down
14 changes: 11 additions & 3 deletions ext/ffi/dlfcn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ where

let func_key = v8::String::new(scope, &symbol_key).unwrap();
let sym = Box::new(Symbol {
name: symbol_key.clone(),
cif,
ptr,
parameter_types: foreign_fn.parameters,
Expand Down Expand Up @@ -259,9 +260,16 @@ fn make_sync_fn<'s>(
symbol: Box<Symbol>,
) -> v8::Local<'s, v8::Function> {
let turbocall = if turbocall::is_compatible(&symbol) {
let trampoline = turbocall::compile_trampoline(&symbol);
let turbocall = turbocall::make_template(&symbol, trampoline);
Some(turbocall)
match turbocall::compile_trampoline(&symbol) {
Ok(trampoline) => {
let turbocall = turbocall::make_template(&symbol, trampoline);
Some(turbocall)
}
Err(e) => {
log::warn!("Failed to compile FFI turbocall: {e}");
None
}
}
} else {
None
};
Expand Down
54 changes: 31 additions & 23 deletions ext/ffi/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,39 +350,47 @@ pub fn ffi_parse_pointer_arg(
}

#[inline]
pub fn ffi_parse_buffer_arg(
scope: &mut v8::HandleScope,
pub fn parse_buffer_arg(
arg: v8::Local<v8::Value>,
) -> Result<NativeValue, IRError> {
) -> Result<*mut c_void, IRError> {
// Order of checking:
// 1. ArrayBuffer: Fairly common and not supported by Fast API, optimise this case.
// 2. ArrayBufferView: Common and supported by Fast API
// 5. Null: Very uncommon / can be represented by a 0.

let pointer = if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(arg) {
if let Some(non_null) = value.data() {
non_null.as_ptr()
} else {
ptr::null_mut()
}
if let Ok(value) = v8::Local::<v8::ArrayBuffer>::try_from(arg) {
Ok(value.data().map(|p| p.as_ptr()).unwrap_or(ptr::null_mut()))
} else if let Ok(value) = v8::Local::<v8::ArrayBufferView>::try_from(arg) {
let byte_offset = value.byte_offset();
let pointer = value
.buffer(scope)
.ok_or(IRError::InvalidArrayBufferView)?
.data();
if let Some(non_null) = pointer {
// SAFETY: Pointer is non-null, and V8 guarantees that the byte_offset
// is within the buffer backing store.
unsafe { non_null.as_ptr().add(byte_offset) }
const {
// We don't keep `buffer` around when this function returns,
// so assert that it will be unused.
assert!(deno_core::v8::TYPED_ARRAY_MAX_SIZE_IN_HEAP == 0);
}
let mut buffer = [0; deno_core::v8::TYPED_ARRAY_MAX_SIZE_IN_HEAP];
// SAFETY: `buffer` is unused due to above, returned pointer is not
// dereferenced by rust code, and we keep it alive at least as long
// as the turbocall.
let (ptr, len) = unsafe { value.get_contents_raw_parts(&mut buffer) };
if ptr == buffer.as_mut_ptr() {
// Empty TypedArray instances can hit this path because their base pointer
// isn't cleared properly: https://issues.chromium.org/issues/40643872
debug_assert_eq!(len, 0);
Ok(ptr::null_mut())
} else {
ptr::null_mut()
Ok(ptr as _)
}
} else if arg.is_null() {
ptr::null_mut()
Ok(ptr::null_mut())
} else {
return Err(IRError::InvalidBufferType);
};
Err(IRError::InvalidBufferType)
}
}

#[inline]
pub fn ffi_parse_buffer_arg(
arg: v8::Local<v8::Value>,
) -> Result<NativeValue, IRError> {
let pointer = parse_buffer_arg(arg)?;
Ok(NativeValue { pointer })
}

Expand Down Expand Up @@ -493,7 +501,7 @@ where
ffi_args.push(ffi_parse_f64_arg(value)?);
}
NativeType::Buffer => {
ffi_args.push(ffi_parse_buffer_arg(scope, value)?);
ffi_args.push(ffi_parse_buffer_arg(value)?);
}
NativeType::Struct(_) => {
ffi_args.push(ffi_parse_struct_arg(scope, value)?);
Expand Down
1 change: 1 addition & 0 deletions ext/ffi/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl TryFrom<NativeType> for libffi::middle::Type {

#[derive(Clone)]
pub struct Symbol {
pub name: String,
pub cif: libffi::middle::Cif,
pub ptr: libffi::middle::CodePtr,
pub parameter_types: Vec<NativeType>,
Expand Down
Loading