mirror of
https://github.com/denoland/deno.git
synced 2024-12-26 09:10:40 -05:00
a2db70a8d0
- [x] `dlfcn.rs` - `dlopen()`-related code. - [x] `turbocall.rs` - Call trampoline JIT compiler. - [x] `repr.rs` - Pointer representation. Home of the UnsafePointerView ops. - [x] `symbol.rs` - Function symbol related code. - [x] `callback.rs` - Home of `Deno.UnsafeCallback` ops. - [x] `ir.rs` - Intermediate representation for values. Home of the `NativeValue` type. - [x] `call.rs` - Generic call ops. Home to everything related to calling FFI symbols. - [x] `static.rs` - static symbol support I find easier to work with this setup, I eventually want to expand TurboCall to unroll type conversion loop in generic calls, generate code for individual symbols (lazy function pointers), etc.
146 lines
5 KiB
Rust
146 lines
5 KiB
Rust
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
|
|
|
use crate::dlfcn::DynamicLibraryResource;
|
|
use crate::symbol::NativeType;
|
|
use crate::MAX_SAFE_INTEGER;
|
|
use crate::MIN_SAFE_INTEGER;
|
|
use deno_core::error::type_error;
|
|
use deno_core::error::AnyError;
|
|
use deno_core::op;
|
|
use deno_core::serde_v8;
|
|
use deno_core::v8;
|
|
use deno_core::ResourceId;
|
|
use std::ptr;
|
|
|
|
#[op(v8)]
|
|
pub fn op_ffi_get_static<'scope>(
|
|
scope: &mut v8::HandleScope<'scope>,
|
|
state: &mut deno_core::OpState,
|
|
rid: ResourceId,
|
|
name: String,
|
|
static_type: NativeType,
|
|
) -> Result<serde_v8::Value<'scope>, AnyError> {
|
|
let resource = state.resource_table.get::<DynamicLibraryResource>(rid)?;
|
|
|
|
let data_ptr = resource.get_static(name)?;
|
|
|
|
Ok(match static_type {
|
|
NativeType::Void => {
|
|
return Err(type_error("Invalid FFI static type 'void'"));
|
|
}
|
|
NativeType::Bool => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const bool) };
|
|
let boolean: v8::Local<v8::Value> =
|
|
v8::Boolean::new(scope, result).into();
|
|
boolean.into()
|
|
}
|
|
NativeType::U8 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u8) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result as u32).into();
|
|
number.into()
|
|
}
|
|
NativeType::I8 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i8) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new(scope, result as i32).into();
|
|
number.into()
|
|
}
|
|
NativeType::U16 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u16) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result as u32).into();
|
|
number.into()
|
|
}
|
|
NativeType::I16 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i16) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new(scope, result as i32).into();
|
|
number.into()
|
|
}
|
|
NativeType::U32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u32) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Integer::new_from_unsigned(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::I32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i32) };
|
|
let number: v8::Local<v8::Value> = v8::Integer::new(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::U64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const u64) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
|
|
v8::BigInt::new_from_u64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::I64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const i64) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as i64
|
|
|| result < MIN_SAFE_INTEGER as i64
|
|
{
|
|
v8::BigInt::new_from_i64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::USize => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const usize) };
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as usize
|
|
{
|
|
v8::BigInt::new_from_u64(scope, result as u64).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::ISize => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const isize) };
|
|
let integer: v8::Local<v8::Value> =
|
|
if !(MIN_SAFE_INTEGER..=MAX_SAFE_INTEGER).contains(&result) {
|
|
v8::BigInt::new_from_i64(scope, result as i64).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
NativeType::F32 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const f32) };
|
|
let number: v8::Local<v8::Value> =
|
|
v8::Number::new(scope, result as f64).into();
|
|
number.into()
|
|
}
|
|
NativeType::F64 => {
|
|
// SAFETY: ptr is user provided
|
|
let result = unsafe { ptr::read_unaligned(data_ptr as *const f64) };
|
|
let number: v8::Local<v8::Value> = v8::Number::new(scope, result).into();
|
|
number.into()
|
|
}
|
|
NativeType::Pointer | NativeType::Function | NativeType::Buffer => {
|
|
let result = data_ptr as u64;
|
|
let integer: v8::Local<v8::Value> = if result > MAX_SAFE_INTEGER as u64 {
|
|
v8::BigInt::new_from_u64(scope, result).into()
|
|
} else {
|
|
v8::Number::new(scope, result as f64).into()
|
|
};
|
|
integer.into()
|
|
}
|
|
})
|
|
}
|