rune/runtime/
function.rs

1use core::fmt;
2use core::future::Future;
3
4use crate as rune;
5use crate::alloc::fmt::TryWrite;
6use crate::alloc::prelude::*;
7use crate::alloc::{self, Box, Vec};
8use crate::function;
9use crate::runtime;
10use crate::runtime::vm::Isolated;
11use crate::shared::AssertSend;
12use crate::sync::Arc;
13use crate::{Any, Hash};
14
15use super::{
16    Address, AnySequence, Args, Call, ConstValue, Formatter, FromValue, FunctionHandler,
17    GuardedArgs, Output, OwnedTuple, Rtti, RuntimeContext, RuntimeError, Stack, Unit, Value, Vm,
18    VmCall, VmError, VmErrorKind, VmHalt,
19};
20
21/// The type of a function in Rune.
22///
23/// Functions can be called using call expression syntax, such as `<expr>()`.
24///
25/// There are multiple different kind of things which can be coerced into a
26/// function in Rune:
27/// * Regular functions.
28/// * Closures (which might or might not capture their environment).
29/// * Built-in constructors for tuple types (tuple structs, tuple variants).
30///
31/// # Examples
32///
33/// ```rune
34/// // Captures the constructor for the `Some(<value>)` tuple variant.
35/// let build_some = Some;
36/// assert_eq!(build_some(42), Some(42));
37///
38/// fn build(value) {
39///     Some(value)
40/// }
41///
42/// // Captures the function previously defined.
43/// let build_some = build;
44/// assert_eq!(build_some(42), Some(42));
45/// ```
46#[derive(Any, TryClone)]
47#[repr(transparent)]
48#[rune(item = ::std::ops)]
49pub struct Function(FunctionImpl<Value>);
50
51impl Function {
52    /// Construct a [Function] from a Rust closure.
53    ///
54    /// # Examples
55    ///
56    /// ```
57    /// use rune::{Hash, Vm};
58    /// use rune::runtime::Function;
59    /// use rune::sync::Arc;
60    ///
61    /// let mut sources = rune::sources! {
62    ///     entry => {
63    ///         pub fn main(function) {
64    ///             function(41)
65    ///         }
66    ///     }
67    /// };
68    ///
69    /// let unit = rune::prepare(&mut sources).build()?;
70    /// let unit = Arc::try_new(unit)?;
71    /// let mut vm = Vm::without_runtime(unit)?;
72    ///
73    /// let function = Function::new(|value: u32| value + 1)?;
74    ///
75    /// assert_eq!(function.type_hash(), Hash::EMPTY);
76    ///
77    /// let value = vm.call(["main"], (function,))?;
78    /// let value: u32 = rune::from_value(value)?;
79    /// assert_eq!(value, 42);
80    /// # Ok::<_, rune::support::Error>(())
81    /// ```
82    ///
83    /// Asynchronous functions:
84    ///
85    /// ```
86    /// use rune::{Hash, Vm};
87    /// use rune::runtime::Function;
88    /// use rune::sync::Arc;
89    ///
90    /// # futures_executor::block_on(async move {
91    /// let mut sources = rune::sources! {
92    ///     entry => {
93    ///         pub async fn main(function) {
94    ///             function(41).await
95    ///         }
96    ///     }
97    /// };
98    ///
99    /// let unit = rune::prepare(&mut sources).build()?;
100    /// let unit = Arc::try_new(unit)?;
101    /// let mut vm = Vm::without_runtime(unit)?;
102    ///
103    /// let function = Function::new(|value: u32| async move { value + 1 })?;
104    ///
105    /// assert_eq!(function.type_hash(), Hash::EMPTY);
106    ///
107    /// let value = vm.async_call(["main"], (function,)).await?;
108    /// let value: u32 = rune::from_value(value)?;
109    /// assert_eq!(value, 42);
110    /// # Ok::<_, rune::support::Error>(())
111    /// # })?;
112    /// # Ok::<_, rune::support::Error>(())
113    /// ```
114    pub fn new<F, A, K>(f: F) -> alloc::Result<Self>
115    where
116        F: function::Function<A, K>,
117        K: function::FunctionKind,
118    {
119        Ok(Self(FunctionImpl {
120            inner: Inner::FnHandler(FnHandler {
121                handler: FunctionHandler::new(move |stack, addr, args, output| {
122                    f.call(stack, addr, args, output)
123                })?,
124                hash: Hash::EMPTY,
125            }),
126        }))
127    }
128
129    /// Perform an asynchronous call over the function which also implements
130    /// [Send].
131    pub async fn async_send_call<A, T>(&self, args: A) -> Result<T, VmError>
132    where
133        A: Send + GuardedArgs,
134        T: Send + FromValue,
135    {
136        self.0.async_send_call(args).await
137    }
138
139    /// Perform a call over the function represented by this function pointer.
140    ///
141    /// # Examples
142    ///
143    /// ```
144    /// use rune::{Hash, Vm};
145    /// use rune::runtime::Function;
146    /// use rune::sync::Arc;
147    ///
148    /// let mut sources = rune::sources! {
149    ///     entry => {
150    ///         fn add(a, b) {
151    ///             a + b
152    ///         }
153    ///
154    ///         pub fn main() { add }
155    ///     }
156    /// };
157    ///
158    /// let unit = rune::prepare(&mut sources).build()?;
159    /// let unit = Arc::try_new(unit)?;
160    /// let mut vm = Vm::without_runtime(unit)?;
161    ///
162    /// let value = vm.call(["main"], ())?;
163    ///
164    /// let value: Function = rune::from_value(value)?;
165    /// assert_eq!(value.call::<u32>((1, 2))?, 3);
166    /// # Ok::<_, rune::support::Error>(())
167    /// ```
168    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
169    where
170        T: FromValue,
171    {
172        self.0.call(args)
173    }
174
175    /// Call with the given virtual machine. This allows for certain
176    /// optimizations, like avoiding the allocation of a new vm state in case
177    /// the call is internal.
178    ///
179    /// A stop reason will be returned in case the function call results in
180    /// a need to suspend the execution.
181    pub(crate) fn call_with_vm(
182        &self,
183        vm: &mut Vm,
184        addr: Address,
185        args: usize,
186        out: Output,
187    ) -> Result<Option<VmHalt>, VmError> {
188        self.0.call_with_vm(vm, addr, args, out)
189    }
190
191    /// Create a function pointer from a handler.
192    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
193        Self(FunctionImpl::from_handler(handler, hash))
194    }
195
196    /// Create a function pointer from an offset.
197    pub(crate) fn from_vm_offset(
198        context: Arc<RuntimeContext>,
199        unit: Arc<Unit>,
200        offset: usize,
201        call: Call,
202        args: usize,
203        hash: Hash,
204    ) -> Self {
205        Self(FunctionImpl::from_offset(
206            context, unit, offset, call, args, hash,
207        ))
208    }
209
210    /// Create a function pointer from an offset.
211    pub(crate) fn from_vm_closure(
212        context: Arc<RuntimeContext>,
213        unit: Arc<Unit>,
214        offset: usize,
215        call: Call,
216        args: usize,
217        environment: Box<[Value]>,
218        hash: Hash,
219    ) -> Self {
220        Self(FunctionImpl::from_closure(
221            context,
222            unit,
223            offset,
224            call,
225            args,
226            environment,
227            hash,
228        ))
229    }
230
231    /// Create a function pointer from an offset.
232    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
233        Self(FunctionImpl::from_unit_struct(rtti))
234    }
235
236    /// Create a function pointer from an offset.
237    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
238        Self(FunctionImpl::from_tuple_struct(rtti, args))
239    }
240
241    /// Type [Hash][struct@Hash] of the underlying function.
242    ///
243    /// # Examples
244    ///
245    /// The type hash of a top-level function matches what you get out of
246    /// [Hash::type_hash].
247    ///
248    /// ```
249    /// use rune::runtime::Function;
250    /// use rune::sync::Arc;
251    /// use rune::{Hash, Vm};
252    ///
253    /// let mut sources = rune::sources! {
254    ///     entry => {
255    ///         fn pony() { }
256    ///
257    ///         pub fn main() { pony }
258    ///     }
259    /// };
260    ///
261    /// let unit = rune::prepare(&mut sources).build()?;
262    /// let unit = Arc::try_new(unit)?;
263    /// let mut vm = Vm::without_runtime(unit)?;
264    ///
265    /// let pony = vm.call(["main"], ())?;
266    /// let pony: Function = rune::from_value(pony)?;
267    ///
268    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
269    /// # Ok::<_, rune::support::Error>(())
270    /// ```
271    pub fn type_hash(&self) -> Hash {
272        self.0.type_hash()
273    }
274
275    /// Try to convert into a [SyncFunction]. This might not be possible if this
276    /// function is something which is not [Sync], like a closure capturing
277    /// context which is not thread-safe.
278    ///
279    /// # Examples
280    ///
281    /// ```
282    /// use rune::{Hash, Vm};
283    /// use rune::runtime::Function;
284    /// use rune::sync::Arc;
285    ///
286    /// let mut sources = rune::sources! {
287    ///     entry => {
288    ///         fn pony() { }
289    ///
290    ///         pub fn main() { pony }
291    ///     }
292    /// };
293    ///
294    /// let unit = rune::prepare(&mut sources).build()?;
295    /// let unit = Arc::try_new(unit)?;
296    /// let mut vm = Vm::without_runtime(unit)?;
297    ///
298    /// let pony = vm.call(["main"], ())?;
299    /// let pony: Function = rune::from_value(pony)?;
300    ///
301    /// // This is fine, since `pony` is a free function.
302    /// let pony = pony.into_sync()?;
303    ///
304    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
305    /// # Ok::<_, rune::support::Error>(())
306    /// ```
307    ///
308    /// The following *does not* work, because we return a closure which tries
309    /// to make use of a [Generator][crate::runtime::Generator] which is not a
310    /// constant value.
311    ///
312    /// ```
313    /// use rune::runtime::Function;
314    /// use rune::sync::Arc;
315    /// use rune::{Hash, Vm};
316    ///
317    /// let mut sources = rune::sources! {
318    ///     entry => {
319    ///         fn generator() {
320    ///             yield 42;
321    ///         }
322    ///
323    ///         pub fn main() {
324    ///             let g = generator();
325    ///
326    ///             move || {
327    ///                 g.next()
328    ///             }
329    ///         }
330    ///     }
331    /// };
332    ///
333    /// let unit = rune::prepare(&mut sources).build()?;
334    /// let unit = Arc::try_new(unit)?;
335    /// let mut vm = Vm::without_runtime(unit)?;
336    ///
337    /// let closure = vm.call(["main"], ())?;
338    /// let closure: Function = rune::from_value(closure)?;
339    ///
340    /// // This is *not* fine since the returned closure has captured a
341    /// // generator which is not a constant value.
342    /// assert!(closure.into_sync().is_err());
343    /// # Ok::<_, rune::support::Error>(())
344    /// ```
345    pub fn into_sync(self) -> Result<SyncFunction, RuntimeError> {
346        Ok(SyncFunction(self.0.into_sync()?))
347    }
348
349    /// Clone a function.
350    ///
351    /// # Examples
352    ///
353    /// ```rune
354    /// fn function() {
355    ///     42
356    /// }
357    ///
358    /// let a = function;
359    /// let b = a.clone();
360    /// assert_eq!(a(), b());
361    /// ```
362    #[rune::function(keep, protocol = CLONE)]
363    fn clone(&self) -> Result<Function, VmError> {
364        Ok(self.try_clone()?)
365    }
366
367    /// Debug format a function.
368    ///
369    /// # Examples
370    ///
371    /// ```rune
372    /// fn function() {
373    ///     42
374    /// }
375    ///
376    /// println!("{function:?}");
377    /// ``
378    #[rune::function(keep, protocol = DEBUG_FMT)]
379    fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> {
380        write!(f, "{self:?}")
381    }
382}
383
384/// A callable sync function. This currently only supports a subset of values
385/// that are supported by the Vm.
386#[repr(transparent)]
387pub struct SyncFunction(FunctionImpl<ConstValue>);
388
389assert_impl!(SyncFunction: Send + Sync);
390
391impl SyncFunction {
392    /// Perform an asynchronous call over the function which also implements
393    /// [Send].
394    ///
395    /// # Examples
396    ///
397    /// ```
398    /// use rune::runtime::SyncFunction;
399    /// use rune::sync::Arc;
400    /// use rune::{Hash, Vm};
401    ///
402    /// # futures_executor::block_on(async move {
403    /// let mut sources = rune::sources! {
404    ///     entry => {
405    ///         async fn add(a, b) {
406    ///             a + b
407    ///         }
408    ///
409    ///         pub fn main() { add }
410    ///     }
411    /// };
412    ///
413    /// let unit = rune::prepare(&mut sources).build()?;
414    /// let unit = Arc::try_new(unit)?;
415    /// let mut vm = Vm::without_runtime(unit)?;
416    ///
417    /// let add = vm.call(["main"], ())?;
418    /// let add: SyncFunction = rune::from_value(add)?;
419    ///
420    /// let value = add.async_send_call::<u32>((1, 2)).await?;
421    /// assert_eq!(value, 3);
422    /// # Ok::<_, rune::support::Error>(())
423    /// # })?;
424    /// # Ok::<_, rune::support::Error>(())
425    /// ```
426    pub async fn async_send_call<T>(&self, args: impl GuardedArgs + Send) -> Result<T, VmError>
427    where
428        T: Send + FromValue,
429    {
430        self.0.async_send_call(args).await
431    }
432
433    /// Perform a call over the function represented by this function pointer.
434    ///
435    /// # Examples
436    ///
437    /// ```
438    /// use rune::runtime::SyncFunction;
439    /// use rune::sync::Arc;
440    /// use rune::{Hash, Vm};
441    ///
442    /// let mut sources = rune::sources! {
443    ///     entry => {
444    ///         fn add(a, b) {
445    ///             a + b
446    ///         }
447    ///
448    ///         pub fn main() { add }
449    ///     }
450    /// };
451    ///
452    /// let unit = rune::prepare(&mut sources).build()?;
453    /// let unit = Arc::try_new(unit)?;
454    /// let mut vm = Vm::without_runtime(unit)?;
455    ///
456    /// let add = vm.call(["main"], ())?;
457    /// let add: SyncFunction = rune::from_value(add)?;
458    ///
459    /// assert_eq!(add.call::<u32>((1, 2))?, 3);
460    /// # Ok::<_, rune::support::Error>(())
461    /// ```
462    pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
463    where
464        T: FromValue,
465    {
466        self.0.call(args)
467    }
468
469    /// Type [Hash][struct@Hash] of the underlying function.
470    ///
471    /// # Examples
472    ///
473    /// The type hash of a top-level function matches what you get out of
474    /// [Hash::type_hash].
475    ///
476    /// ```
477    /// use rune::runtime::SyncFunction;
478    /// use rune::sync::Arc;
479    /// use rune::{Hash, Vm};
480    ///
481    /// let mut sources = rune::sources! {
482    ///     entry => {
483    ///         fn pony() { }
484    ///
485    ///         pub fn main() { pony }
486    ///     }
487    /// };
488    ///
489    /// let unit = rune::prepare(&mut sources).build()?;
490    /// let unit = Arc::try_new(unit)?;
491    /// let mut vm = Vm::without_runtime(unit)?;
492    ///
493    /// let pony = vm.call(["main"], ())?;
494    /// let pony: SyncFunction = rune::from_value(pony)?;
495    ///
496    /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
497    /// # Ok::<_, rune::support::Error>(())
498    /// ```
499    pub fn type_hash(&self) -> Hash {
500        self.0.type_hash()
501    }
502}
503
504impl TryClone for SyncFunction {
505    fn try_clone(&self) -> alloc::Result<Self> {
506        Ok(Self(self.0.try_clone()?))
507    }
508}
509
510/// A stored function, of some specific kind.
511struct FunctionImpl<V> {
512    inner: Inner<V>,
513}
514
515impl<V> TryClone for FunctionImpl<V>
516where
517    V: TryClone,
518{
519    #[inline]
520    fn try_clone(&self) -> alloc::Result<Self> {
521        Ok(Self {
522            inner: self.inner.try_clone()?,
523        })
524    }
525}
526
527impl<V> FunctionImpl<V>
528where
529    V: TryClone,
530    OwnedTuple: TryFrom<Box<[V]>>,
531    VmErrorKind: From<<OwnedTuple as TryFrom<Box<[V]>>>::Error>,
532{
533    fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
534    where
535        T: FromValue,
536    {
537        let value = match &self.inner {
538            Inner::FnHandler(handler) => {
539                let count = args.count();
540                let size = count.max(1);
541                // Ensure we have space for the return value.
542                let mut stack = Stack::with_capacity(size)?;
543                let _guard = unsafe { args.guarded_into_stack(&mut stack) }?;
544                stack.resize(size)?;
545                handler
546                    .handler
547                    .call(&mut stack, Address::ZERO, count, Address::ZERO.output())?;
548                stack.at(Address::ZERO).clone()
549            }
550            Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?,
551            Inner::FnClosureOffset(closure) => {
552                let environment = closure.environment.try_clone()?;
553                let environment = OwnedTuple::try_from(environment)?;
554                closure.fn_offset.call(args, (environment,))?
555            }
556            Inner::FnUnitStruct(empty) => {
557                check_args(args.count(), 0)?;
558                Value::empty_struct(empty.rtti.clone())?
559            }
560            Inner::FnTupleStruct(tuple) => {
561                check_args(args.count(), tuple.args)?;
562                // SAFETY: We don't let the guard outlive the value.
563                let (args, _guard) = unsafe { args.guarded_into_vec()? };
564                Value::tuple_struct(tuple.rtti.clone(), args)?
565            }
566        };
567
568        Ok(T::from_value(value)?)
569    }
570
571    fn async_send_call<'a, A, T>(
572        &'a self,
573        args: A,
574    ) -> impl Future<Output = Result<T, VmError>> + Send + 'a
575    where
576        A: 'a + Send + GuardedArgs,
577        T: 'a + Send + FromValue,
578    {
579        let future = async move {
580            let value: Value = self.call(args)?;
581
582            let value = match value.try_borrow_mut::<runtime::Future>()? {
583                Some(future) => future.await?,
584                None => value,
585            };
586
587            Ok(T::from_value(value)?)
588        };
589
590        // Safety: Future is send because there is no way to call this
591        // function in a manner which allows any values from the future
592        // to escape outside of this future, hence it can only be
593        // scheduled by one thread at a time.
594        unsafe { AssertSend::new(future) }
595    }
596
597    /// Call with the given virtual machine. This allows for certain
598    /// optimizations, like avoiding the allocation of a new vm state in case
599    /// the call is internal.
600    ///
601    /// A stop reason will be returned in case the function call results in
602    /// a need to suspend the execution.
603    pub(crate) fn call_with_vm(
604        &self,
605        vm: &mut Vm,
606        addr: Address,
607        args: usize,
608        out: Output,
609    ) -> Result<Option<VmHalt>, VmError> {
610        let reason = match &self.inner {
611            Inner::FnHandler(handler) => {
612                handler.handler.call(vm.stack_mut(), addr, args, out)?;
613                None
614            }
615            Inner::FnOffset(fn_offset) => {
616                if let Some(vm_call) = fn_offset.call_with_vm(vm, addr, args, (), out)? {
617                    return Ok(Some(VmHalt::VmCall(vm_call)));
618                }
619
620                None
621            }
622            Inner::FnClosureOffset(closure) => {
623                let environment = closure.environment.try_clone()?;
624                let environment = OwnedTuple::try_from(environment)?;
625
626                if let Some(vm_call) =
627                    closure
628                        .fn_offset
629                        .call_with_vm(vm, addr, args, (environment,), out)?
630                {
631                    return Ok(Some(VmHalt::VmCall(vm_call)));
632                }
633
634                None
635            }
636            Inner::FnUnitStruct(empty) => {
637                check_args(args, 0)?;
638                vm.stack_mut()
639                    .store(out, || Value::empty_struct(empty.rtti.clone()))?;
640                None
641            }
642            Inner::FnTupleStruct(tuple) => {
643                check_args(args, tuple.args)?;
644
645                let seq = vm.stack().slice_at(addr, args)?;
646                let data = seq.iter().cloned();
647                let value = AnySequence::new(tuple.rtti.clone(), data)?;
648                vm.stack_mut().store(out, value)?;
649                None
650            }
651        };
652
653        Ok(reason)
654    }
655
656    /// Create a function pointer from a handler.
657    pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
658        Self {
659            inner: Inner::FnHandler(FnHandler { handler, hash }),
660        }
661    }
662
663    /// Create a function pointer from an offset.
664    pub(crate) fn from_offset(
665        context: Arc<RuntimeContext>,
666        unit: Arc<Unit>,
667        offset: usize,
668        call: Call,
669        args: usize,
670        hash: Hash,
671    ) -> Self {
672        Self {
673            inner: Inner::FnOffset(FnOffset {
674                context,
675                unit,
676                offset,
677                call,
678                args,
679                hash,
680            }),
681        }
682    }
683
684    /// Create a function pointer from an offset.
685    pub(crate) fn from_closure(
686        context: Arc<RuntimeContext>,
687        unit: Arc<Unit>,
688        offset: usize,
689        call: Call,
690        args: usize,
691        environment: Box<[V]>,
692        hash: Hash,
693    ) -> Self {
694        Self {
695            inner: Inner::FnClosureOffset(FnClosureOffset {
696                fn_offset: FnOffset {
697                    context,
698                    unit,
699                    offset,
700                    call,
701                    args,
702                    hash,
703                },
704                environment,
705            }),
706        }
707    }
708
709    /// Create a function pointer from an offset.
710    pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
711        Self {
712            inner: Inner::FnUnitStruct(FnUnitStruct { rtti }),
713        }
714    }
715
716    /// Create a function pointer from an offset.
717    pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
718        Self {
719            inner: Inner::FnTupleStruct(FnTupleStruct { rtti, args }),
720        }
721    }
722
723    #[inline]
724    fn type_hash(&self) -> Hash {
725        match &self.inner {
726            Inner::FnHandler(FnHandler { hash, .. }) | Inner::FnOffset(FnOffset { hash, .. }) => {
727                *hash
728            }
729            Inner::FnClosureOffset(fco) => fco.fn_offset.hash,
730            Inner::FnUnitStruct(func) => func.rtti.type_hash(),
731            Inner::FnTupleStruct(func) => func.rtti.type_hash(),
732        }
733    }
734}
735
736impl FunctionImpl<Value> {
737    /// Try to convert into a [SyncFunction].
738    fn into_sync(self) -> Result<FunctionImpl<ConstValue>, RuntimeError> {
739        let inner = match self.inner {
740            Inner::FnClosureOffset(closure) => {
741                let mut env = Vec::try_with_capacity(closure.environment.len())?;
742
743                for value in Vec::from(closure.environment) {
744                    env.try_push(FromValue::from_value(value)?)?;
745                }
746
747                Inner::FnClosureOffset(FnClosureOffset {
748                    fn_offset: closure.fn_offset,
749                    environment: env.try_into_boxed_slice()?,
750                })
751            }
752            Inner::FnHandler(inner) => Inner::FnHandler(inner),
753            Inner::FnOffset(inner) => Inner::FnOffset(inner),
754            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner),
755            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner),
756        };
757
758        Ok(FunctionImpl { inner })
759    }
760}
761
762impl fmt::Debug for Function {
763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764        match &self.0.inner {
765            Inner::FnHandler(handler) => {
766                write!(f, "native function ({:p})", handler.handler)?;
767            }
768            Inner::FnOffset(offset) => {
769                write!(f, "{} function (at: 0x{:x})", offset.call, offset.offset)?;
770            }
771            Inner::FnClosureOffset(closure) => {
772                write!(
773                    f,
774                    "closure (at: 0x{:x}, env:{:?})",
775                    closure.fn_offset.offset, closure.environment
776                )?;
777            }
778            Inner::FnUnitStruct(empty) => {
779                write!(f, "empty {}", empty.rtti.item)?;
780            }
781            Inner::FnTupleStruct(tuple) => {
782                write!(f, "tuple {}", tuple.rtti.item)?;
783            }
784        }
785
786        Ok(())
787    }
788}
789
790#[derive(Debug)]
791enum Inner<V> {
792    /// A native function handler.
793    /// This is wrapped as an `Arc<dyn FunctionHandler>`.
794    FnHandler(FnHandler),
795    /// The offset to a free function.
796    ///
797    /// This also captures the context and unit it belongs to allow for external
798    /// calls.
799    FnOffset(FnOffset),
800    /// A closure with a captured environment.
801    ///
802    /// This also captures the context and unit it belongs to allow for external
803    /// calls.
804    FnClosureOffset(FnClosureOffset<V>),
805    /// Constructor for a unit struct.
806    FnUnitStruct(FnUnitStruct),
807    /// Constructor for a tuple.
808    FnTupleStruct(FnTupleStruct),
809}
810
811impl<V> TryClone for Inner<V>
812where
813    V: TryClone,
814{
815    fn try_clone(&self) -> alloc::Result<Self> {
816        Ok(match self {
817            Inner::FnHandler(inner) => Inner::FnHandler(inner.clone()),
818            Inner::FnOffset(inner) => Inner::FnOffset(inner.clone()),
819            Inner::FnClosureOffset(inner) => Inner::FnClosureOffset(inner.try_clone()?),
820            Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner.clone()),
821            Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner.clone()),
822        })
823    }
824}
825
826#[derive(Clone, TryClone)]
827struct FnHandler {
828    /// The function handler.
829    handler: FunctionHandler,
830    /// Hash for the function type
831    hash: Hash,
832}
833
834impl fmt::Debug for FnHandler {
835    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
836        write!(f, "FnHandler")
837    }
838}
839
840#[derive(Clone, TryClone)]
841struct FnOffset {
842    context: Arc<RuntimeContext>,
843    /// The unit where the function resides.
844    unit: Arc<Unit>,
845    /// The offset of the function.
846    offset: usize,
847    /// The calling convention.
848    call: Call,
849    /// The number of arguments the function takes.
850    args: usize,
851    /// Hash for the function type
852    hash: Hash,
853}
854
855impl FnOffset {
856    /// Perform a call into the specified offset and return the produced value.
857    #[tracing::instrument(skip_all, fields(args = args.count(), extra = extra.count(), ?self.offset, ?self.call, ?self.args, ?self.hash))]
858    fn call(&self, args: impl GuardedArgs, extra: impl Args) -> Result<Value, VmError> {
859        check_args(args.count().wrapping_add(extra.count()), self.args)?;
860
861        let mut vm = Vm::new(self.context.clone(), self.unit.clone());
862
863        vm.set_ip(self.offset);
864        let _guard = unsafe { args.guarded_into_stack(vm.stack_mut())? };
865        extra.into_stack(vm.stack_mut())?;
866
867        self.call.call_with_vm(vm)
868    }
869
870    /// Perform a potentially optimized call into the specified vm.
871    ///
872    /// This will cause a halt in case the vm being called into isn't the same
873    /// as the context and unit of the function.
874    #[tracing::instrument(skip_all, fields(args, extra = extra.count(), keep, ?self.offset, ?self.call, ?self.args, ?self.hash))]
875    fn call_with_vm(
876        &self,
877        vm: &mut Vm,
878        addr: Address,
879        args: usize,
880        extra: impl Args,
881        out: Output,
882    ) -> Result<Option<VmCall>, VmError> {
883        check_args(args.wrapping_add(extra.count()), self.args)?;
884
885        let same_unit = matches!(self.call, Call::Immediate if vm.is_same_unit(&self.unit));
886        let same_context =
887            matches!(self.call, Call::Immediate if vm.is_same_context(&self.context));
888
889        vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)?;
890        extra.into_stack(vm.stack_mut())?;
891
892        // Fast path, just allocate a call frame and keep running.
893        if same_context && same_unit {
894            tracing::trace!("same context and unit");
895            return Ok(None);
896        }
897
898        let call = VmCall::new(
899            self.call,
900            (!same_context).then(|| self.context.clone()),
901            (!same_unit).then(|| self.unit.clone()),
902            out,
903        );
904
905        Ok(Some(call))
906    }
907}
908
909impl fmt::Debug for FnOffset {
910    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911        f.debug_struct("FnOffset")
912            .field("context", &(&self.context as *const _))
913            .field("unit", &(&self.unit as *const _))
914            .field("offset", &self.offset)
915            .field("call", &self.call)
916            .field("args", &self.args)
917            .finish()
918    }
919}
920
921#[derive(Debug)]
922struct FnClosureOffset<V> {
923    /// The offset in the associated unit that the function lives.
924    fn_offset: FnOffset,
925    /// Captured environment.
926    environment: Box<[V]>,
927}
928
929impl<V> TryClone for FnClosureOffset<V>
930where
931    V: TryClone,
932{
933    #[inline]
934    fn try_clone(&self) -> alloc::Result<Self> {
935        Ok(Self {
936            fn_offset: self.fn_offset.clone(),
937            environment: self.environment.try_clone()?,
938        })
939    }
940}
941
942#[derive(Debug, Clone, TryClone)]
943struct FnUnitStruct {
944    /// The type of the empty.
945    rtti: Arc<Rtti>,
946}
947
948#[derive(Debug, Clone, TryClone)]
949struct FnTupleStruct {
950    /// The type of the tuple.
951    rtti: Arc<Rtti>,
952    /// The number of arguments the tuple takes.
953    args: usize,
954}
955
956impl FromValue for SyncFunction {
957    #[inline]
958    fn from_value(value: Value) -> Result<Self, RuntimeError> {
959        value.downcast::<Function>()?.into_sync()
960    }
961}
962
963#[inline]
964fn check_args(actual: usize, expected: usize) -> Result<(), VmError> {
965    if actual != expected {
966        return Err(VmError::new(VmErrorKind::BadArgumentCount {
967            expected,
968            actual,
969        }));
970    }
971
972    Ok(())
973}