1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Defines WasmEdge CallingFrame.

use crate::{
    executor::InnerExecutor,
    ffi,
    instance::{memory::InnerMemory, module::InnerInstance},
    Executor, Instance, Memory,
};
use parking_lot::Mutex;
use std::sync::Arc;

/// Represents a calling frame on top of stack.
#[derive(Debug)]
pub struct CallingFrame {
    pub(crate) inner: InnerCallingFrame,
}
impl Drop for CallingFrame {
    fn drop(&mut self) {
        if !self.inner.0.is_null() {
            self.inner.0 = std::ptr::null();
        }
    }
}
impl CallingFrame {
    /// Creates a CallingFrame instance.
    pub(crate) fn create(ctx: *const ffi::WasmEdge_CallingFrameContext) -> Self {
        Self {
            inner: InnerCallingFrame(ctx),
        }
    }

    /// Returns the [executor instance](crate::Executor) from this calling frame.
    pub fn executor_mut(&self) -> Option<Executor> {
        let ctx = unsafe { ffi::WasmEdge_CallingFrameGetExecutor(self.inner.0) };

        match ctx.is_null() {
            false => Some(Executor {
                inner: std::sync::Arc::new(InnerExecutor(ctx)),
                registered: true,
            }),
            true => None,
        }
    }

    /// Returns the [module instance](crate::Instance) in this calling frame.
    ///
    /// If the executing function instance is a host function and not added into any module instance, then returns `None`.
    ///
    /// When a wasm function is executing and trying to call a host function inside, a frame with the module
    /// instance the wasm function belongs to will be pushed onto the stack. And therefore the calling frame
    /// context will record that module instance.
    ///
    pub fn module_instance(&self) -> Option<Instance> {
        let ctx = unsafe { ffi::WasmEdge_CallingFrameGetModuleInstance(self.inner.0) };

        match ctx.is_null() {
            false => Some(Instance {
                inner: Arc::new(Mutex::new(InnerInstance(ctx as *mut _))),
                registered: true,
            }),
            true => None,
        }
    }

    /// Returns the [memory instance](crate::Memory) by the given index from the module instance of the current
    /// calling frame. If the memory instance is not found, returns `None`.
    ///
    /// By default, a WASM module has only one memory instance after instantiation. Therefore, users can pass in `0` as
    /// the index to get the memory instance in host function body. When the [MultiMemories](crate::Config::multi_memories)
    /// config option is enabled, there would be more than one memory instances in the wasm module. Users can retrieve
    /// the target memory instance by specifying the index of the memory instance in the wasm module instance.
    ///
    /// # Arguments
    ///
    /// * idx - The index of the memory instance.
    ///
    pub fn memory_mut(&self, idx: u32) -> Option<Memory> {
        let ctx = unsafe { ffi::WasmEdge_CallingFrameGetMemoryInstance(self.inner.0, idx) };

        match ctx.is_null() {
            false => Some(Memory {
                inner: std::sync::Arc::new(Mutex::new(InnerMemory(ctx))),
                registered: true,
            }),
            true => None,
        }
    }

    /// Provides a raw pointer to the inner CallingFrame context.
    #[cfg(feature = "ffi")]
    #[cfg_attr(docsrs, doc(cfg(feature = "ffi")))]
    pub fn as_ptr(&self) -> *const ffi::WasmEdge_CallingFrameContext {
        self.inner.0 as *const _
    }
}

#[derive(Debug)]
pub(crate) struct InnerCallingFrame(pub(crate) *const ffi::WasmEdge_CallingFrameContext);
unsafe impl Send for InnerCallingFrame {}
unsafe impl Sync for InnerCallingFrame {}