Skip to content

Commit 0cb3ff6

Browse files
committed
Add runtime support for lambdas on FnPtr
1 parent 6878646 commit 0cb3ff6

3 files changed

Lines changed: 72 additions & 3 deletions

File tree

‎libcc2rs/src/callable.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// Copyright (c) 2022-present INESC-ID.
22
// Distributed under the MIT license that can be found in the LICENSE file.
33

4+
use crate::fn_ptr::FnPtr;
5+
use crate::fn_ptr_arg::FnPtrArg;
6+
47
macro_rules! callable {
58
($name:ident; $($a:ident: $A:ident),*) => {
69
pub trait $name<$($A,)* R> {
@@ -23,6 +26,15 @@ macro_rules! callable {
2326
unsafe { self($($a),*) }
2427
}
2528
}
29+
30+
impl<$($A: FnPtrArg,)* R: FnPtrArg> $name<$($A,)* R>
31+
for FnPtr<fn($($A),*) -> R>
32+
{
33+
#[inline]
34+
fn call(&self, $($a: $A),*) -> R {
35+
self.call($($a),*)
36+
}
37+
}
2638
};
2739
}
2840

‎libcc2rs/src/fn_ptr.rs‎

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
#![allow(private_bounds)]
55

66
use std::any::{Any, TypeId};
7+
use std::cell::{RefCell, UnsafeCell};
78
use std::rc::Rc;
89

9-
use crate::fn_ptr_arg::{ArgList, ArgRepr, FnPtrArg, FnPtrArgs};
10-
use crate::rc::Ptr;
10+
use crate::fn_ptr_arg::{ArgList, ArgRepr, FnPtrArg, FnPtrArgs, record_from_repr};
11+
use crate::rc::{AsPointer, Ptr};
1112
use crate::reinterpret::ByteRepr;
1213
use crate::void::{AnyPtr, ErasedPtr};
1314

@@ -70,6 +71,7 @@ pub struct FnPtr<T: FnSig> {
7071
// The function this pointer was created from, kept type-erased (but
7172
// still callable, through `Adapted`).
7273
original: Option<Rc<dyn Adapted>>,
74+
lambda: Option<Rc<dyn Fn(T::Args) -> T::Ret>>,
7375
}
7476

7577
impl<T: FnSig> FnPtr<T> {
@@ -79,6 +81,7 @@ impl<T: FnSig> FnPtr<T> {
7981
addr: 0,
8082
current: None,
8183
original: None,
84+
lambda: None,
8285
}
8386
}
8487

@@ -93,6 +96,7 @@ impl<T: FnSig> FnPtr<T> {
9396
addr: f.fn_addr(),
9497
current: Some(f),
9598
original: None,
99+
lambda: None,
96100
}
97101
}
98102

@@ -103,6 +107,9 @@ impl<T: FnSig> FnPtr<T> {
103107
if self.is_null() {
104108
panic!("ub: null fn pointer call");
105109
}
110+
if let Some(lambda) = &self.lambda {
111+
return lambda(args);
112+
}
106113
if let Some(f) = self.current {
107114
return f.call_direct(args);
108115
}
@@ -145,10 +152,17 @@ impl<T: FnSig> FnPtr<T> {
145152
self.boxed_original()
146153
};
147154

155+
let lambda: &dyn Any = &self.lambda;
156+
let lambda = lambda
157+
.downcast_ref::<Option<Rc<dyn Fn(U::Args) -> U::Ret>>>()
158+
.cloned()
159+
.flatten();
160+
148161
FnPtr {
149162
addr: self.addr,
150163
current: current_as_u.or(original_as_u),
151164
original,
165+
lambda,
152166
}
153167
}
154168

@@ -175,6 +189,38 @@ macro_rules! impl_fn_ptr_call {
175189
pub fn call(&self $(, $a: $a)*) -> R {
176190
self.call_args(($($a,)*))
177191
}
192+
193+
#[allow(non_snake_case)]
194+
pub fn with_captures<Captures: 'static>(
195+
captures: Captures,
196+
body: fn(Ptr<Captures> $(, $a)*) -> R,
197+
) -> Self {
198+
let captures = Rc::new(RefCell::new(captures));
199+
FnPtr {
200+
addr: body as usize,
201+
current: None,
202+
original: None,
203+
lambda: Some(Rc::new(move |($($a,)*): ($($a,)*)| {
204+
body(captures.as_pointer() $(, $a)*)
205+
})),
206+
}
207+
}
208+
209+
#[allow(non_snake_case)]
210+
pub fn with_captures_unsafe<Captures: 'static>(
211+
captures: Captures,
212+
body: fn(&mut Captures $(, $a)*) -> R,
213+
) -> Self {
214+
let captures = Rc::new(UnsafeCell::new(captures));
215+
FnPtr {
216+
addr: body as usize,
217+
current: None,
218+
original: None,
219+
lambda: Some(Rc::new(move |($($a,)*): ($($a,)*)| {
220+
body(unsafe { &mut *captures.get() } $(, $a)*)
221+
})),
222+
}
223+
}
178224
}
179225
impl_fn_ptr_call!(@peel $($a)*);
180226
};
@@ -191,6 +237,7 @@ impl<T: FnSig> Clone for FnPtr<T> {
191237
addr: self.addr,
192238
current: self.current,
193239
original: self.original.clone(),
240+
lambda: self.lambda.clone(),
194241
}
195242
}
196243
}
@@ -211,6 +258,16 @@ impl<T: FnSig> Eq for FnPtr<T> {}
211258

212259
impl<T: FnSig> ByteRepr for FnPtr<T> {}
213260

261+
impl<T: FnSig> FnPtrArg for FnPtr<T> {
262+
#[inline]
263+
fn to_repr(&self) -> ArgRepr<'_> {
264+
ArgRepr::Record(self)
265+
}
266+
fn from_repr(r: &ArgRepr) -> Self {
267+
record_from_repr(r)
268+
}
269+
}
270+
214271
impl<T: FnSig> ErasedPtr for FnPtr<T> {
215272
fn as_bytes(&self) -> Ptr<u8> {
216273
panic!("byte view not supported on fn pointer");

‎libcc2rs/src/fn_ptr_arg.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl<'a> ArgList<'a> {
221221
}
222222
}
223223

224-
pub(crate) trait FnPtrArgs: Sized {
224+
pub(crate) trait FnPtrArgs: Sized + 'static {
225225
fn to_list(&self) -> ArgList<'_>;
226226
fn from_list(l: &ArgList) -> Self;
227227
}

0 commit comments

Comments
 (0)