summaryrefslogtreecommitdiff
path: root/ext/ffi/lib.rs
diff options
context:
space:
mode:
authorAapo Alasuutari <aapo.alasuutari@gmail.com>2022-02-18 14:21:19 +0200
committerGitHub <noreply@github.com>2022-02-18 17:51:19 +0530
commitb1a6555c0502196174bed1454e446717daf52f12 (patch)
tree3e0c74d87a63044090564638dee0af22f4e2ca10 /ext/ffi/lib.rs
parent4a144c7d6e55a5e047080cb1e2377b70657f1809 (diff)
feat(ext/ffi): Support read only global statics (#13662)
Diffstat (limited to 'ext/ffi/lib.rs')
-rw-r--r--ext/ffi/lib.rs110
1 files changed, 107 insertions, 3 deletions
diff --git a/ext/ffi/lib.rs b/ext/ffi/lib.rs
index 3075684d8..f2e7bb175 100644
--- a/ext/ffi/lib.rs
+++ b/ext/ffi/lib.rs
@@ -118,6 +118,19 @@ impl DynamicLibraryResource {
Ok(())
}
+
+ fn get_static(&self, symbol: String) -> Result<*const c_void, AnyError> {
+ // By default, Err returned by this function does not tell
+ // which symbol wasn't exported. So we'll modify the error
+ // message to include the name of symbol.
+ match unsafe { self.lib.symbol::<*const c_void>(&symbol) } {
+ Ok(value) => Ok(Ok(value)),
+ Err(err) => Err(generic_error(format!(
+ "Failed to register symbol {}: {}",
+ symbol, err
+ ))),
+ }?
+ }
}
pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
@@ -128,6 +141,7 @@ pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
))
.ops(vec![
("op_ffi_load", op_sync(op_ffi_load::<P>)),
+ ("op_ffi_get_static", op_sync(op_ffi_get_static)),
("op_ffi_call", op_sync(op_ffi_call)),
("op_ffi_call_nonblocking", op_async(op_ffi_call_nonblocking)),
("op_ffi_call_ptr", op_sync(op_ffi_call_ptr)),
@@ -351,10 +365,28 @@ struct ForeignFunction {
result: NativeType,
}
+// ForeignStatic's name and type fields are read and used by
+// serde_v8 to determine which variant a ForeignSymbol is.
+// They are not used beyond that and are thus marked with underscores.
+#[derive(Deserialize, Debug)]
+struct ForeignStatic {
+ #[serde(rename(deserialize = "name"))]
+ _name: Option<String>,
+ #[serde(rename(deserialize = "type"))]
+ _type: String,
+}
+
+#[derive(Deserialize, Debug)]
+#[serde(untagged)]
+enum ForeignSymbol {
+ ForeignFunction(ForeignFunction),
+ ForeignStatic(ForeignStatic),
+}
+
#[derive(Deserialize, Debug)]
struct FfiLoadArgs {
path: String,
- symbols: HashMap<String, ForeignFunction>,
+ symbols: HashMap<String, ForeignSymbol>,
}
// `path` is only used on Windows.
@@ -458,8 +490,15 @@ where
symbols: HashMap::new(),
};
- for (symbol, foreign_fn) in args.symbols {
- resource.register(symbol, foreign_fn)?;
+ for (symbol, foreign_symbol) in args.symbols {
+ match foreign_symbol {
+ ForeignSymbol::ForeignStatic(_) => {
+ // No-op: Statics will be handled separately and are not part of the Rust-side resource.
+ }
+ ForeignSymbol::ForeignFunction(foreign_fn) => {
+ resource.register(symbol, foreign_fn)?;
+ }
+ }
}
Ok(state.resource_table.add(resource))
@@ -631,6 +670,71 @@ async fn op_ffi_call_ptr_nonblocking(
.unwrap()
}
+#[derive(Deserialize)]
+#[serde(rename_all = "camelCase")]
+struct FfiGetArgs {
+ rid: ResourceId,
+ name: String,
+ r#type: NativeType,
+}
+
+fn op_ffi_get_static(
+ state: &mut deno_core::OpState,
+ args: FfiGetArgs,
+ _: (),
+) -> Result<Value, AnyError> {
+ let resource = state
+ .resource_table
+ .get::<DynamicLibraryResource>(args.rid)?;
+
+ let data_ptr = resource.get_static(args.name)? as *const u8;
+
+ Ok(match args.r#type {
+ NativeType::Void => {
+ unreachable!();
+ }
+ NativeType::U8 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const u8) })
+ }
+ NativeType::I8 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const i8) })
+ }
+ NativeType::U16 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const u16) })
+ }
+ NativeType::I16 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const i16) })
+ }
+ NativeType::U32 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const u32) })
+ }
+ NativeType::I32 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const i32) })
+ }
+ NativeType::U64 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const u64) })
+ }
+ NativeType::I64 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const i64) })
+ }
+ NativeType::USize => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const usize) })
+ }
+ NativeType::ISize => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const isize) })
+ }
+ NativeType::F32 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const f32) })
+ }
+ NativeType::F64 => {
+ json!(unsafe { ptr::read_unaligned(data_ptr as *const f64) })
+ }
+ NativeType::Pointer => {
+ json!(U32x2::from(data_ptr as *const u8 as u64))
+ }
+ })
+}
+
fn op_ffi_call(
state: &mut deno_core::OpState,
args: FfiCallArgs,