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, Globals,
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 globals: Globals,
201 offset: usize,
202 call: Call,
203 args: usize,
204 hash: Hash,
205 ) -> Self {
206 Self(FunctionImpl::from_offset(
207 context, unit, globals, offset, call, args, hash,
208 ))
209 }
210
211 /// Create a function pointer from an offset.
212 pub(crate) fn from_vm_closure(
213 context: Arc<RuntimeContext>,
214 unit: Arc<Unit>,
215 globals: Globals,
216 offset: usize,
217 call: Call,
218 args: usize,
219 environment: Box<[Value]>,
220 hash: Hash,
221 ) -> Self {
222 Self(FunctionImpl::from_closure(
223 context,
224 unit,
225 globals,
226 offset,
227 call,
228 args,
229 environment,
230 hash,
231 ))
232 }
233
234 /// Create a function pointer from an offset.
235 pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
236 Self(FunctionImpl::from_unit_struct(rtti))
237 }
238
239 /// Create a function pointer from an offset.
240 pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
241 Self(FunctionImpl::from_tuple_struct(rtti, args))
242 }
243
244 /// Type [Hash][struct@Hash] of the underlying function.
245 ///
246 /// # Examples
247 ///
248 /// The type hash of a top-level function matches what you get out of
249 /// [Hash::type_hash].
250 ///
251 /// ```
252 /// use rune::runtime::Function;
253 /// use rune::sync::Arc;
254 /// use rune::{Hash, Vm};
255 ///
256 /// let mut sources = rune::sources! {
257 /// entry => {
258 /// fn pony() { }
259 ///
260 /// pub fn main() { pony }
261 /// }
262 /// };
263 ///
264 /// let unit = rune::prepare(&mut sources).build()?;
265 /// let unit = Arc::try_new(unit)?;
266 /// let mut vm = Vm::without_runtime(unit)?;
267 ///
268 /// let pony = vm.call(["main"], ())?;
269 /// let pony: Function = rune::from_value(pony)?;
270 ///
271 /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
272 /// # Ok::<_, rune::support::Error>(())
273 /// ```
274 pub fn type_hash(&self) -> Hash {
275 self.0.type_hash()
276 }
277
278 /// Try to convert into a [SyncFunction]. This might not be possible if this
279 /// function is something which is not [Sync], like a closure capturing
280 /// context which is not thread-safe.
281 ///
282 /// # Examples
283 ///
284 /// ```
285 /// use rune::{Hash, Vm};
286 /// use rune::runtime::Function;
287 /// use rune::sync::Arc;
288 ///
289 /// let mut sources = rune::sources! {
290 /// entry => {
291 /// fn pony() { }
292 ///
293 /// pub fn main() { pony }
294 /// }
295 /// };
296 ///
297 /// let unit = rune::prepare(&mut sources).build()?;
298 /// let unit = Arc::try_new(unit)?;
299 /// let mut vm = Vm::without_runtime(unit)?;
300 ///
301 /// let pony = vm.call(["main"], ())?;
302 /// let pony: Function = rune::from_value(pony)?;
303 ///
304 /// // This is fine, since `pony` is a free function.
305 /// let pony = pony.into_sync()?;
306 ///
307 /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
308 /// # Ok::<_, rune::support::Error>(())
309 /// ```
310 ///
311 /// The following *does not* work, because we return a closure which tries
312 /// to make use of a [Generator][crate::runtime::Generator] which is not a
313 /// constant value.
314 ///
315 /// ```
316 /// use rune::runtime::Function;
317 /// use rune::sync::Arc;
318 /// use rune::{Hash, Vm};
319 ///
320 /// let mut sources = rune::sources! {
321 /// entry => {
322 /// fn generator() {
323 /// yield 42;
324 /// }
325 ///
326 /// pub fn main() {
327 /// let g = generator();
328 ///
329 /// move || {
330 /// g.next()
331 /// }
332 /// }
333 /// }
334 /// };
335 ///
336 /// let unit = rune::prepare(&mut sources).build()?;
337 /// let unit = Arc::try_new(unit)?;
338 /// let mut vm = Vm::without_runtime(unit)?;
339 ///
340 /// let closure = vm.call(["main"], ())?;
341 /// let closure: Function = rune::from_value(closure)?;
342 ///
343 /// // This is *not* fine since the returned closure has captured a
344 /// // generator which is not a constant value.
345 /// assert!(closure.into_sync().is_err());
346 /// # Ok::<_, rune::support::Error>(())
347 /// ```
348 pub fn into_sync(self) -> Result<SyncFunction, RuntimeError> {
349 Ok(SyncFunction(self.0.into_sync()?))
350 }
351
352 /// Clone a function.
353 ///
354 /// # Examples
355 ///
356 /// ```rune
357 /// fn function() {
358 /// 42
359 /// }
360 ///
361 /// let a = function;
362 /// let b = a.clone();
363 /// assert_eq!(a(), b());
364 /// ```
365 #[rune::function(keep, protocol = CLONE)]
366 fn clone(&self) -> Result<Function, VmError> {
367 Ok(self.try_clone()?)
368 }
369
370 /// Debug format a function.
371 ///
372 /// # Examples
373 ///
374 /// ```rune
375 /// fn function() {
376 /// 42
377 /// }
378 ///
379 /// println!("{function:?}");
380 /// ``
381 #[rune::function(keep, protocol = DEBUG_FMT)]
382 fn debug_fmt(&self, f: &mut Formatter) -> alloc::Result<()> {
383 write!(f, "{self:?}")
384 }
385}
386
387/// A callable sync function. This currently only supports a subset of values
388/// that are supported by the Vm.
389#[repr(transparent)]
390pub struct SyncFunction(FunctionImpl<ConstValue>);
391
392assert_impl!(SyncFunction: Send + Sync);
393
394impl SyncFunction {
395 /// Perform an asynchronous call over the function which also implements
396 /// [Send].
397 ///
398 /// # Examples
399 ///
400 /// ```
401 /// use rune::runtime::SyncFunction;
402 /// use rune::sync::Arc;
403 /// use rune::{Hash, Vm};
404 ///
405 /// # futures_executor::block_on(async move {
406 /// let mut sources = rune::sources! {
407 /// entry => {
408 /// async fn add(a, b) {
409 /// a + b
410 /// }
411 ///
412 /// pub fn main() { add }
413 /// }
414 /// };
415 ///
416 /// let unit = rune::prepare(&mut sources).build()?;
417 /// let unit = Arc::try_new(unit)?;
418 /// let mut vm = Vm::without_runtime(unit)?;
419 ///
420 /// let add = vm.call(["main"], ())?;
421 /// let add: SyncFunction = rune::from_value(add)?;
422 ///
423 /// let value = add.async_send_call::<u32>((1, 2)).await?;
424 /// assert_eq!(value, 3);
425 /// # Ok::<_, rune::support::Error>(())
426 /// # })?;
427 /// # Ok::<_, rune::support::Error>(())
428 /// ```
429 pub async fn async_send_call<T>(&self, args: impl GuardedArgs + Send) -> Result<T, VmError>
430 where
431 T: Send + FromValue,
432 {
433 self.0.async_send_call(args).await
434 }
435
436 /// Perform a call over the function represented by this function pointer.
437 ///
438 /// # Examples
439 ///
440 /// ```
441 /// use rune::runtime::SyncFunction;
442 /// use rune::sync::Arc;
443 /// use rune::{Hash, Vm};
444 ///
445 /// let mut sources = rune::sources! {
446 /// entry => {
447 /// fn add(a, b) {
448 /// a + b
449 /// }
450 ///
451 /// pub fn main() { add }
452 /// }
453 /// };
454 ///
455 /// let unit = rune::prepare(&mut sources).build()?;
456 /// let unit = Arc::try_new(unit)?;
457 /// let mut vm = Vm::without_runtime(unit)?;
458 ///
459 /// let add = vm.call(["main"], ())?;
460 /// let add: SyncFunction = rune::from_value(add)?;
461 ///
462 /// assert_eq!(add.call::<u32>((1, 2))?, 3);
463 /// # Ok::<_, rune::support::Error>(())
464 /// ```
465 pub fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
466 where
467 T: FromValue,
468 {
469 self.0.call(args)
470 }
471
472 /// Type [Hash][struct@Hash] of the underlying function.
473 ///
474 /// # Examples
475 ///
476 /// The type hash of a top-level function matches what you get out of
477 /// [Hash::type_hash].
478 ///
479 /// ```
480 /// use rune::runtime::SyncFunction;
481 /// use rune::sync::Arc;
482 /// use rune::{Hash, Vm};
483 ///
484 /// let mut sources = rune::sources! {
485 /// entry => {
486 /// fn pony() { }
487 ///
488 /// pub fn main() { pony }
489 /// }
490 /// };
491 ///
492 /// let unit = rune::prepare(&mut sources).build()?;
493 /// let unit = Arc::try_new(unit)?;
494 /// let mut vm = Vm::without_runtime(unit)?;
495 ///
496 /// let pony = vm.call(["main"], ())?;
497 /// let pony: SyncFunction = rune::from_value(pony)?;
498 ///
499 /// assert_eq!(pony.type_hash(), Hash::type_hash(["pony"]));
500 /// # Ok::<_, rune::support::Error>(())
501 /// ```
502 pub fn type_hash(&self) -> Hash {
503 self.0.type_hash()
504 }
505}
506
507impl TryClone for SyncFunction {
508 fn try_clone(&self) -> alloc::Result<Self> {
509 Ok(Self(self.0.try_clone()?))
510 }
511}
512
513/// A stored function, of some specific kind.
514struct FunctionImpl<V>
515where
516 V: FnValue,
517{
518 inner: Inner<V>,
519}
520
521impl<V> TryClone for FunctionImpl<V>
522where
523 V: FnValue,
524{
525 #[inline]
526 fn try_clone(&self) -> alloc::Result<Self> {
527 Ok(Self {
528 inner: self.inner.try_clone()?,
529 })
530 }
531}
532
533impl<V> FunctionImpl<V>
534where
535 V: FnValue,
536 OwnedTuple: TryFrom<Box<[V]>>,
537 VmErrorKind: From<<OwnedTuple as TryFrom<Box<[V]>>>::Error>,
538{
539 fn call<T>(&self, args: impl GuardedArgs) -> Result<T, VmError>
540 where
541 T: FromValue,
542 {
543 let value = match &self.inner {
544 Inner::FnHandler(handler) => {
545 let count = args.count();
546 let size = count.max(1);
547 // Ensure we have space for the return value.
548 let mut stack = Stack::with_capacity(size)?;
549 let _guard = unsafe { args.guarded_into_stack(&mut stack) }?;
550 stack.resize(size)?;
551 handler
552 .handler
553 .call(&mut stack, Address::ZERO, count, Address::ZERO.output())?;
554 stack.at(Address::ZERO).clone()
555 }
556 Inner::FnOffset(fn_offset) => fn_offset.call(args, ())?,
557 Inner::FnClosureOffset(closure) => {
558 let environment = closure.environment.try_clone()?;
559 let environment = OwnedTuple::try_from(environment)?;
560 closure.fn_offset.call(args, (environment,))?
561 }
562 Inner::FnUnitStruct(empty) => {
563 check_args(args.count(), 0)?;
564 Value::empty_struct(empty.rtti.clone())?
565 }
566 Inner::FnTupleStruct(tuple) => {
567 check_args(args.count(), tuple.args)?;
568 // SAFETY: We don't let the guard outlive the value.
569 let (args, _guard) = unsafe { args.guarded_into_vec()? };
570 Value::tuple_struct(tuple.rtti.clone(), args)?
571 }
572 };
573
574 Ok(T::from_value(value)?)
575 }
576
577 fn async_send_call<'a, A, T>(
578 &'a self,
579 args: A,
580 ) -> impl Future<Output = Result<T, VmError>> + Send + 'a
581 where
582 A: 'a + Send + GuardedArgs,
583 T: 'a + Send + FromValue,
584 {
585 let future = async move {
586 let value: Value = self.call(args)?;
587
588 let value = match value.try_borrow_mut::<runtime::Future>()? {
589 Some(future) => future.await?,
590 None => value,
591 };
592
593 Ok(T::from_value(value)?)
594 };
595
596 // Safety: Future is send because there is no way to call this
597 // function in a manner which allows any values from the future
598 // to escape outside of this future, hence it can only be
599 // scheduled by one thread at a time.
600 unsafe { AssertSend::new(future) }
601 }
602
603 /// Call with the given virtual machine. This allows for certain
604 /// optimizations, like avoiding the allocation of a new vm state in case
605 /// the call is internal.
606 ///
607 /// A stop reason will be returned in case the function call results in
608 /// a need to suspend the execution.
609 pub(crate) fn call_with_vm(
610 &self,
611 vm: &mut Vm,
612 addr: Address,
613 args: usize,
614 out: Output,
615 ) -> Result<Option<VmHalt>, VmError> {
616 let reason = match &self.inner {
617 Inner::FnHandler(handler) => {
618 handler.handler.call(vm.stack_mut(), addr, args, out)?;
619 None
620 }
621 Inner::FnOffset(fn_offset) => {
622 if let Some(vm_call) = fn_offset.call_with_vm(vm, addr, args, (), out)? {
623 return Ok(Some(VmHalt::VmCall(vm_call)));
624 }
625
626 None
627 }
628 Inner::FnClosureOffset(closure) => {
629 let environment = closure.environment.try_clone()?;
630 let environment = OwnedTuple::try_from(environment)?;
631
632 if let Some(vm_call) =
633 closure
634 .fn_offset
635 .call_with_vm(vm, addr, args, (environment,), out)?
636 {
637 return Ok(Some(VmHalt::VmCall(vm_call)));
638 }
639
640 None
641 }
642 Inner::FnUnitStruct(empty) => {
643 check_args(args, 0)?;
644 vm.stack_mut()
645 .store(out, || Value::empty_struct(empty.rtti.clone()))?;
646 None
647 }
648 Inner::FnTupleStruct(tuple) => {
649 check_args(args, tuple.args)?;
650
651 let seq = vm.stack().slice_at(addr, args)?;
652 let data = seq.iter().cloned();
653 let value = AnySequence::new(tuple.rtti.clone(), data)?;
654 vm.stack_mut().store(out, value)?;
655 None
656 }
657 };
658
659 Ok(reason)
660 }
661
662 /// Create a function pointer from a handler.
663 pub(crate) fn from_handler(handler: FunctionHandler, hash: Hash) -> Self {
664 Self {
665 inner: Inner::FnHandler(FnHandler { handler, hash }),
666 }
667 }
668
669 /// Create a function pointer from an offset.
670 pub(crate) fn from_offset(
671 context: Arc<RuntimeContext>,
672 unit: Arc<Unit>,
673 globals: V::Globals,
674 offset: usize,
675 call: Call,
676 args: usize,
677 hash: Hash,
678 ) -> Self {
679 Self {
680 inner: Inner::FnOffset(FnOffset {
681 context,
682 unit,
683 globals,
684 offset,
685 call,
686 args,
687 hash,
688 }),
689 }
690 }
691
692 /// Create a function pointer from an offset.
693 pub(crate) fn from_closure(
694 context: Arc<RuntimeContext>,
695 unit: Arc<Unit>,
696 globals: V::Globals,
697 offset: usize,
698 call: Call,
699 args: usize,
700 environment: Box<[V]>,
701 hash: Hash,
702 ) -> Self {
703 Self {
704 inner: Inner::FnClosureOffset(FnClosureOffset {
705 fn_offset: FnOffset {
706 context,
707 unit,
708 globals,
709 offset,
710 call,
711 args,
712 hash,
713 },
714 environment,
715 }),
716 }
717 }
718
719 /// Create a function pointer from an offset.
720 pub(crate) fn from_unit_struct(rtti: Arc<Rtti>) -> Self {
721 Self {
722 inner: Inner::FnUnitStruct(FnUnitStruct { rtti }),
723 }
724 }
725
726 /// Create a function pointer from an offset.
727 pub(crate) fn from_tuple_struct(rtti: Arc<Rtti>, args: usize) -> Self {
728 Self {
729 inner: Inner::FnTupleStruct(FnTupleStruct { rtti, args }),
730 }
731 }
732
733 #[inline]
734 fn type_hash(&self) -> Hash {
735 match &self.inner {
736 Inner::FnHandler(FnHandler { hash, .. }) | Inner::FnOffset(FnOffset { hash, .. }) => {
737 *hash
738 }
739 Inner::FnClosureOffset(fco) => fco.fn_offset.hash,
740 Inner::FnUnitStruct(func) => func.rtti.type_hash(),
741 Inner::FnTupleStruct(func) => func.rtti.type_hash(),
742 }
743 }
744}
745
746impl FunctionImpl<Value> {
747 /// Try to convert into a [SyncFunction].
748 fn into_sync(self) -> Result<FunctionImpl<ConstValue>, RuntimeError> {
749 let inner = match self.inner {
750 Inner::FnClosureOffset(closure) => {
751 let mut env = Vec::try_with_capacity(closure.environment.len())?;
752
753 for value in Vec::from(closure.environment) {
754 env.try_push(FromValue::from_value(value)?)?;
755 }
756
757 Inner::FnClosureOffset(FnClosureOffset {
758 fn_offset: closure.fn_offset.into_sync(),
759 environment: env.try_into_boxed_slice()?,
760 })
761 }
762 Inner::FnHandler(inner) => Inner::FnHandler(inner),
763 Inner::FnOffset(inner) => Inner::FnOffset(inner.into_sync()),
764 Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner),
765 Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner),
766 };
767
768 Ok(FunctionImpl { inner })
769 }
770}
771
772impl fmt::Debug for Function {
773 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
774 match &self.0.inner {
775 Inner::FnHandler(handler) => {
776 write!(f, "native function ({:p})", handler.handler)?;
777 }
778 Inner::FnOffset(offset) => {
779 write!(f, "{} function (at: 0x{:x})", offset.call, offset.offset)?;
780 }
781 Inner::FnClosureOffset(closure) => {
782 write!(
783 f,
784 "closure (at: 0x{:x}, env:{:?})",
785 closure.fn_offset.offset, closure.environment
786 )?;
787 }
788 Inner::FnUnitStruct(empty) => {
789 write!(f, "empty {}", empty.rtti.item)?;
790 }
791 Inner::FnTupleStruct(tuple) => {
792 write!(f, "tuple {}", tuple.rtti.item)?;
793 }
794 }
795
796 Ok(())
797 }
798}
799
800#[derive(Debug)]
801enum Inner<V>
802where
803 V: FnValue,
804{
805 /// A native function handler.
806 /// This is wrapped as an `Arc<dyn FunctionHandler>`.
807 FnHandler(FnHandler),
808 /// The offset to a free function.
809 ///
810 /// This also captures the context and unit it belongs to allow for external
811 /// calls.
812 FnOffset(FnOffset<V>),
813 /// A closure with a captured environment.
814 ///
815 /// This also captures the context and unit it belongs to allow for external
816 /// calls.
817 FnClosureOffset(FnClosureOffset<V>),
818 /// Constructor for a unit struct.
819 FnUnitStruct(FnUnitStruct),
820 /// Constructor for a tuple.
821 FnTupleStruct(FnTupleStruct),
822}
823
824impl<V> TryClone for Inner<V>
825where
826 V: FnValue,
827{
828 fn try_clone(&self) -> alloc::Result<Self> {
829 Ok(match self {
830 Inner::FnHandler(inner) => Inner::FnHandler(inner.clone()),
831 Inner::FnOffset(inner) => Inner::FnOffset(inner.clone()),
832 Inner::FnClosureOffset(inner) => Inner::FnClosureOffset(inner.try_clone()?),
833 Inner::FnUnitStruct(inner) => Inner::FnUnitStruct(inner.clone()),
834 Inner::FnTupleStruct(inner) => Inner::FnTupleStruct(inner.clone()),
835 })
836 }
837}
838
839#[derive(Clone, TryClone)]
840struct FnHandler {
841 /// The function handler.
842 handler: FunctionHandler,
843 /// Hash for the function type
844 hash: Hash,
845}
846
847impl fmt::Debug for FnHandler {
848 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
849 write!(f, "FnHandler")
850 }
851}
852
853/// The kind of value a function closes over, and with it the kind of static
854/// item storage the function is able to carry.
855///
856/// A [`Function`] carries the [`Globals`] of the virtual machine which produced
857/// it, so that calling it from the outside still observes the same statics. A
858/// [`SyncFunction`] can be sent between threads and the storage isn't thread
859/// safe, so it carries nothing.
860pub(crate) trait FnValue: TryClone {
861 /// How static item storage is represented for this kind of function.
862 type Globals: TryClone + Clone;
863
864 /// Materialize the storage a virtual machine should be given.
865 fn globals(globals: &Self::Globals) -> Globals;
866
867 /// Test if the given vm already uses this storage.
868 fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool;
869}
870
871impl FnValue for Value {
872 type Globals = Globals;
873
874 #[inline]
875 fn globals(globals: &Self::Globals) -> Globals {
876 globals.clone()
877 }
878
879 #[inline]
880 fn same_globals(globals: &Self::Globals, vm: &Vm) -> bool {
881 vm.is_same_globals(globals)
882 }
883}
884
885impl FnValue for ConstValue {
886 type Globals = ();
887
888 #[inline]
889 fn globals(_: &Self::Globals) -> Globals {
890 Globals::empty()
891 }
892
893 #[inline]
894 fn same_globals(_: &Self::Globals, vm: &Vm) -> bool {
895 !vm.globals().is_configured()
896 }
897}
898
899struct FnOffset<V>
900where
901 V: FnValue,
902{
903 context: Arc<RuntimeContext>,
904 /// The unit where the function resides.
905 unit: Arc<Unit>,
906 /// The storage for static items declared by the unit.
907 globals: V::Globals,
908 /// The offset of the function.
909 offset: usize,
910 /// The calling convention.
911 call: Call,
912 /// The number of arguments the function takes.
913 args: usize,
914 /// Hash for the function type
915 hash: Hash,
916}
917
918impl<V> Clone for FnOffset<V>
919where
920 V: FnValue,
921{
922 fn clone(&self) -> Self {
923 Self {
924 context: self.context.clone(),
925 unit: self.unit.clone(),
926 globals: self.globals.clone(),
927 offset: self.offset,
928 call: self.call,
929 args: self.args,
930 hash: self.hash,
931 }
932 }
933}
934
935impl<V> TryClone for FnOffset<V>
936where
937 V: FnValue,
938{
939 #[inline]
940 fn try_clone(&self) -> alloc::Result<Self> {
941 Ok(self.clone())
942 }
943}
944
945impl<V> FnOffset<V>
946where
947 V: FnValue,
948{
949 /// Perform a call into the specified offset and return the produced value.
950 #[tracing::instrument(skip_all, fields(args = args.count(), extra = extra.count(), ?self.offset, ?self.call, ?self.args, ?self.hash))]
951 fn call(&self, args: impl GuardedArgs, extra: impl Args) -> Result<Value, VmError> {
952 check_args(args.count().wrapping_add(extra.count()), self.args)?;
953
954 let mut vm = Vm::new(self.context.clone(), self.unit.clone())
955 .with_globals(V::globals(&self.globals));
956
957 vm.set_ip(self.offset);
958 let _guard = unsafe { args.guarded_into_stack(vm.stack_mut())? };
959 extra.into_stack(vm.stack_mut())?;
960
961 self.call.call_with_vm(vm)
962 }
963
964 /// Perform a potentially optimized call into the specified vm.
965 ///
966 /// This will cause a halt in case the vm being called into isn't the same
967 /// as the context and unit of the function.
968 #[tracing::instrument(skip_all, fields(args, extra = extra.count(), keep, ?self.offset, ?self.call, ?self.args, ?self.hash))]
969 fn call_with_vm(
970 &self,
971 vm: &mut Vm,
972 addr: Address,
973 args: usize,
974 extra: impl Args,
975 out: Output,
976 ) -> Result<Option<VmCall>, VmError> {
977 check_args(args.wrapping_add(extra.count()), self.args)?;
978
979 let same_unit = matches!(self.call, Call::Immediate if vm.is_same_unit(&self.unit));
980 let same_context =
981 matches!(self.call, Call::Immediate if vm.is_same_context(&self.context));
982 let same_globals =
983 matches!(self.call, Call::Immediate if V::same_globals(&self.globals, vm));
984
985 vm.push_call_frame(self.offset, addr, args, Isolated::new(!same_context), out)?;
986 extra.into_stack(vm.stack_mut())?;
987
988 // Fast path, just allocate a call frame and keep running.
989 if same_context && same_unit && same_globals {
990 tracing::trace!("same context, unit and globals");
991 return Ok(None);
992 }
993
994 let call = VmCall::new(
995 self.call,
996 (!same_context).then(|| self.context.clone()),
997 (!same_unit).then(|| self.unit.clone()),
998 (!same_globals).then(|| V::globals(&self.globals)),
999 out,
1000 );
1001
1002 Ok(Some(call))
1003 }
1004}
1005
1006impl FnOffset<Value> {
1007 /// Shed the static item storage so that the function can be sent between
1008 /// threads.
1009 ///
1010 /// The storage isn't thread safe, so a [`SyncFunction`] cannot carry it.
1011 /// Reading a static through the resulting function reports that no storage
1012 /// has been configured.
1013 fn into_sync(self) -> FnOffset<ConstValue> {
1014 FnOffset {
1015 context: self.context,
1016 unit: self.unit,
1017 globals: (),
1018 offset: self.offset,
1019 call: self.call,
1020 args: self.args,
1021 hash: self.hash,
1022 }
1023 }
1024}
1025
1026impl<V> fmt::Debug for FnOffset<V>
1027where
1028 V: FnValue,
1029{
1030 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1031 f.debug_struct("FnOffset")
1032 .field("context", &(&self.context as *const _))
1033 .field("unit", &(&self.unit as *const _))
1034 .field("offset", &self.offset)
1035 .field("call", &self.call)
1036 .field("args", &self.args)
1037 .finish()
1038 }
1039}
1040
1041#[derive(Debug)]
1042struct FnClosureOffset<V>
1043where
1044 V: FnValue,
1045{
1046 /// The offset in the associated unit that the function lives.
1047 fn_offset: FnOffset<V>,
1048 /// Captured environment.
1049 environment: Box<[V]>,
1050}
1051
1052impl<V> TryClone for FnClosureOffset<V>
1053where
1054 V: FnValue,
1055{
1056 #[inline]
1057 fn try_clone(&self) -> alloc::Result<Self> {
1058 Ok(Self {
1059 fn_offset: self.fn_offset.clone(),
1060 environment: self.environment.try_clone()?,
1061 })
1062 }
1063}
1064
1065#[derive(Debug, Clone, TryClone)]
1066struct FnUnitStruct {
1067 /// The type of the empty.
1068 rtti: Arc<Rtti>,
1069}
1070
1071#[derive(Debug, Clone, TryClone)]
1072struct FnTupleStruct {
1073 /// The type of the tuple.
1074 rtti: Arc<Rtti>,
1075 /// The number of arguments the tuple takes.
1076 args: usize,
1077}
1078
1079impl FromValue for SyncFunction {
1080 #[inline]
1081 fn from_value(value: Value) -> Result<Self, RuntimeError> {
1082 value.downcast::<Function>()?.into_sync()
1083 }
1084}
1085
1086#[inline]
1087fn check_args(actual: usize, expected: usize) -> Result<(), VmError> {
1088 if actual != expected {
1089 return Err(VmError::new(VmErrorKind::BadArgumentCount {
1090 expected,
1091 actual,
1092 }));
1093 }
1094
1095 Ok(())
1096}