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}