Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::RwLock;
4use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
5use anyhow::{Result, anyhow};
6use cranelift::prelude::AbiParam;
7use cranelift_module::{Linkage, Module};
8use dynamic::{Dynamic, Type};
9use parser::{BinaryOp, Expr, ExprKind, Span};
10use rand::RngExt;
11use std::borrow::Cow;
12use std::collections::BTreeMap;
13use std::fmt::Write as _;
14use std::sync::Weak;
15
16#[derive(Clone, Debug)]
17pub struct ZustCallback {
18    pub fn_ptr: usize,
19    pub ret_ty: Type,
20    pub explicit_arg_len: usize,
21    pub captures: Vec<Dynamic>,
22}
23
24impl ZustCallback {
25    pub fn new(fn_ptr: usize, ret_ty: Type, captures: Vec<Dynamic>) -> Self {
26        Self { fn_ptr, ret_ty, explicit_arg_len: usize::MAX, captures }
27    }
28
29    pub fn new_with_arg_len(fn_ptr: usize, ret_ty: Type, explicit_arg_len: usize, captures: Vec<Dynamic>) -> Self {
30        Self { fn_ptr, ret_ty, explicit_arg_len, captures }
31    }
32
33    pub fn call0(&self) -> Result<Dynamic> {
34        if matches!(self.explicit_arg_len, usize::MAX | 0) {
35            return self.call_with_arg_ptrs(&[]);
36        }
37        self.call(Vec::new())
38    }
39
40    pub fn call1(&self, arg: Dynamic) -> Result<Dynamic> {
41        match self.explicit_arg_len {
42            0 => self.call0(),
43            usize::MAX | 1 => {
44                let mut ptrs = Vec::with_capacity(1 + self.captures.len());
45                ptrs.push(&arg as *const Dynamic);
46                self.call_with_arg_ptrs(&ptrs)
47            }
48            _ => self.call(vec![arg]),
49        }
50    }
51
52    pub fn call(&self, mut args: Vec<Dynamic>) -> Result<Dynamic> {
53        if self.explicit_arg_len != usize::MAX {
54            args.truncate(self.explicit_arg_len);
55            while args.len() < self.explicit_arg_len {
56                args.push(Dynamic::Null);
57            }
58        }
59        let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg as *const Dynamic).collect();
60        self.call_with_arg_ptrs(&ptrs)
61    }
62
63    fn call_with_arg_ptrs(&self, args: &[*const Dynamic]) -> Result<Dynamic> {
64        let mut ptrs = Vec::with_capacity(args.len() + self.captures.len());
65        ptrs.extend_from_slice(args);
66        ptrs.extend(self.captures.iter().map(|value| value as *const Dynamic));
67        call_jit_isolated(|| unsafe { call_callback(self.fn_ptr as *const u8, &self.ret_ty, &ptrs) })
68    }
69}
70
71extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
72    //在堆上分配内存 复制 addr 到内存中
73    unsafe {
74        let cloned_value = (*addr).deep_clone();
75        alloc_dynamic(cloned_value)
76    }
77}
78
79extern "C" fn any_null() -> *const Dynamic {
80    //在堆上分配内存 复制 addr 到内存中
81    alloc_dynamic(Dynamic::Null)
82}
83
84extern "C" fn print(addr: *const Dynamic) {
85    if !addr.is_null() {
86        unsafe {
87            println!("{}", (*addr).to_string());
88        }
89    }
90}
91
92extern "C" fn sqrt(value: f64) -> f64 {
93    value.sqrt()
94}
95
96extern "C" fn log_any(addr: *const Dynamic) {
97    if addr.is_null() {
98        log::debug!("{:?}", Dynamic::Null);
99    } else {
100        log::debug!("{:?}", unsafe { &*addr });
101    }
102}
103
104extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
105    !addr.is_null() && unsafe { (*addr).is_map() }
106}
107
108extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
109    !addr.is_null() && unsafe { (*addr).is_list() }
110}
111
112extern "C" fn any_is_string(addr: *const Dynamic) -> bool {
113    !addr.is_null() && unsafe { (*addr).is_str() }
114}
115
116extern "C" fn any_is_null(addr: *const Dynamic) -> bool {
117    addr.is_null() || unsafe { (*addr).is_null() }
118}
119
120extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
121    if !start.is_null() && !stop.is_null() {
122        let mut rng = rand::rng();
123        unsafe {
124            if (&*start).is_int() {
125                let start = (*start).as_int().unwrap_or(0);
126                let stop = (*stop).as_int().unwrap_or(100);
127                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
128            } else if (&*start).is_f32() || (&*start).is_f64() {
129                let start = (*start).as_float().unwrap_or(0.0);
130                let stop = (*stop).as_float().unwrap_or(1.0);
131                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
132            }
133        }
134    }
135    alloc_dynamic(Dynamic::Null)
136}
137
138extern "C" fn uuid() -> *const Dynamic {
139    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
140}
141
142pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
143    let size = size.max(0) as usize;
144    let ptr = alloc_struct_bytes(size);
145    unsafe {
146        std::ptr::write_bytes(ptr, 0, size);
147    }
148    ptr
149}
150
151pub(crate) extern "C" fn repeat_fill(dst: *mut u8, pattern: u64, width: i64, len: i64) {
152    if dst.is_null() || width <= 0 || len <= 0 {
153        return;
154    }
155    let width = width as usize;
156    let len = len as usize;
157    let bytes = pattern.to_le_bytes();
158    unsafe {
159        if width == 1 {
160            std::ptr::write_bytes(dst, bytes[0], len);
161            return;
162        }
163        if !matches!(width, 2 | 4 | 8) {
164            return;
165        }
166        for idx in 0..len {
167            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst.add(idx * width), width);
168        }
169    }
170}
171
172pub(crate) extern "C" fn strcat(left: *const Dynamic, right: *const Dynamic) -> *const Dynamic {
173    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
174    let right = if right.is_null() { "" } else { unsafe { (&*right).as_str() } };
175    let mut out = String::with_capacity(left.len() + right.len());
176    out.push_str(left);
177    out.push_str(right);
178    alloc_dynamic(Dynamic::StringBuf(out))
179}
180
181pub(crate) extern "C" fn strcat_i64(left: *const Dynamic, right: i64) -> *const Dynamic {
182    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
183    let mut out = String::with_capacity(left.len() + 20);
184    out.push_str(left);
185    let _ = write!(&mut out, "{right}");
186    alloc_dynamic(Dynamic::StringBuf(out))
187}
188
189pub(crate) extern "C" fn strcat_assign(left: *mut Dynamic, right: *const Dynamic) -> *const Dynamic {
190    if left.is_null() {
191        return strcat(left, right);
192    }
193    let suffix = if right.is_null() {
194        Cow::Borrowed("")
195    } else if std::ptr::eq(left as *const Dynamic, right) {
196        Cow::Owned(unsafe { (&*right).to_string() })
197    } else {
198        let right = unsafe { &*right };
199        if right.is_str() { Cow::Borrowed(right.as_str()) } else { Cow::Owned(right.to_string()) }
200    };
201    unsafe {
202        match &mut *left {
203            Dynamic::StringBuf(text) => text.push_str(suffix.as_ref()),
204            Dynamic::String(text) => {
205                let mut out = String::with_capacity(text.len() + suffix.len());
206                out.push_str(text.as_str());
207                out.push_str(suffix.as_ref());
208                *left = Dynamic::StringBuf(out);
209            }
210            value => {
211                let prefix = value.to_string();
212                let mut out = String::with_capacity(prefix.len() + suffix.len());
213                out.push_str(&prefix);
214                out.push_str(suffix.as_ref());
215                *value = Dynamic::StringBuf(out);
216            }
217        }
218    }
219    left
220}
221
222pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
223    let ty = unsafe { (&*(ty as *const Type)).clone() };
224    alloc_dynamic(Dynamic::owned_struct_from_ptr(addr as usize, ty))
225}
226
227pub(crate) extern "C" fn array_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
228    if addr == 0 || ty == 0 {
229        return alloc_dynamic(Dynamic::Null);
230    }
231    let ty = unsafe { &*(ty as *const Type) };
232    alloc_dynamic(dynamic_from_ptr(addr as *const u8, ty))
233}
234
235pub(crate) extern "C" fn array_to_ptr(dst: *mut u8, value: *const Dynamic, ty: i64) {
236    if dst.is_null() || value.is_null() || ty == 0 {
237        return;
238    }
239    let ty = unsafe { &*(ty as *const Type) };
240    write_dynamic_to_ptr(dst, unsafe { &*value }, ty);
241}
242
243fn dynamic_from_ptr(addr: *const u8, ty: &Type) -> Dynamic {
244    if addr.is_null() {
245        return Dynamic::Null;
246    }
247    match ty {
248        Type::Bool => Dynamic::Bool(unsafe { std::ptr::read_unaligned(addr) } != 0),
249        Type::I8 => Dynamic::I8(unsafe { std::ptr::read_unaligned(addr as *const i8) }),
250        Type::U8 => Dynamic::U8(unsafe { std::ptr::read_unaligned(addr) }),
251        Type::I16 => Dynamic::I16(unsafe { std::ptr::read_unaligned(addr as *const i16) }),
252        Type::U16 => Dynamic::U16(unsafe { std::ptr::read_unaligned(addr as *const u16) }),
253        Type::I32 => Dynamic::I32(unsafe { std::ptr::read_unaligned(addr as *const i32) }),
254        Type::U32 => Dynamic::U32(unsafe { std::ptr::read_unaligned(addr as *const u32) }),
255        Type::I64 => Dynamic::I64(unsafe { std::ptr::read_unaligned(addr as *const i64) }),
256        Type::U64 => Dynamic::U64(unsafe { std::ptr::read_unaligned(addr as *const u64) }),
257        Type::F32 => Dynamic::F32(unsafe { std::ptr::read_unaligned(addr as *const f32) }),
258        Type::F64 => Dynamic::F64(unsafe { std::ptr::read_unaligned(addr as *const f64) }),
259        Type::Array(elem_ty, len) => {
260            let width = elem_ty.storage_width() as usize;
261            let values = (0..*len as usize).map(|idx| unsafe { dynamic_from_ptr(addr.add(idx * width), elem_ty) }).collect();
262            Dynamic::list(values)
263        }
264        Type::Struct { fields, .. } => {
265            let mut map = BTreeMap::new();
266            let (_, offsets) = Type::struct_layout(fields);
267            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
268                let value = unsafe { dynamic_from_ptr(addr.add(offset as usize), field_ty) };
269                map.insert(name.clone(), value);
270            }
271            Dynamic::map(map)
272        }
273        _ => {
274            let ptr = unsafe { std::ptr::read_unaligned(addr as *const *const Dynamic) };
275            if ptr.is_null() { Dynamic::Null } else { unsafe { (&*ptr).deep_clone() } }
276        }
277    }
278}
279
280fn write_dynamic_to_ptr(dst: *mut u8, value: &Dynamic, ty: &Type) {
281    if dst.is_null() {
282        return;
283    }
284    match ty {
285        Type::Bool => unsafe { std::ptr::write_unaligned(dst, if value.is_true() { 1 } else { 0 }) },
286        Type::I8 => unsafe { std::ptr::write_unaligned(dst as *mut i8, value.clone().try_into().unwrap_or_default()) },
287        Type::U8 => unsafe { std::ptr::write_unaligned(dst, value.clone().try_into().unwrap_or_default()) },
288        Type::I16 => unsafe { std::ptr::write_unaligned(dst as *mut i16, value.clone().try_into().unwrap_or_default()) },
289        Type::U16 => unsafe { std::ptr::write_unaligned(dst as *mut u16, value.clone().try_into().unwrap_or_default()) },
290        Type::I32 => unsafe { std::ptr::write_unaligned(dst as *mut i32, value.clone().try_into().unwrap_or_default()) },
291        Type::U32 => unsafe { std::ptr::write_unaligned(dst as *mut u32, value.clone().try_into().unwrap_or_default()) },
292        Type::I64 => unsafe { std::ptr::write_unaligned(dst as *mut i64, value.clone().try_into().unwrap_or_default()) },
293        Type::U64 => unsafe { std::ptr::write_unaligned(dst as *mut u64, value.clone().try_into().unwrap_or_default()) },
294        Type::F32 => unsafe { std::ptr::write_unaligned(dst as *mut f32, f32::try_from(value.clone()).unwrap_or_default()) },
295        Type::F64 => unsafe { std::ptr::write_unaligned(dst as *mut f64, value.clone().try_into().unwrap_or_default()) },
296        Type::Array(elem_ty, len) => {
297            let width = elem_ty.storage_width() as usize;
298            for idx in 0..*len as usize {
299                let item = value.get_idx(idx).unwrap_or(Dynamic::Null);
300                unsafe { write_dynamic_to_ptr(dst.add(idx * width), &item, elem_ty) };
301            }
302        }
303        Type::Struct { fields, .. } => {
304            let (_, offsets) = Type::struct_layout(fields);
305            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
306                let item = value.get_dynamic(name.as_str()).unwrap_or(Dynamic::Null);
307                unsafe { write_dynamic_to_ptr(dst.add(offset as usize), &item, field_ty) };
308            }
309        }
310        _ => {
311            let ptr = alloc_dynamic(value.deep_clone());
312            unsafe { std::ptr::write_unaligned(dst as *mut usize, ptr as usize) };
313        }
314    }
315}
316
317pub(crate) extern "C" fn import_with_vm(context: *const Weak<RwLock<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
318    if addr.is_null() || path.is_null() {
319        return false;
320    }
321    super::with_vm_context(context, |jit| {
322        let name = unsafe { &*addr }.as_str();
323        let path = unsafe { &*path }.as_str();
324        jit.import(name, path)
325    })
326    .map_err(|e| log::error!("import failed: {e:#}"))
327    .is_ok()
328}
329
330pub(crate) extern "C" fn spawn_with_vm(context: *const Weak<RwLock<JITRunTime>>, fn_name: *const Dynamic, args: *const Dynamic) -> bool {
331    if context.is_null() || fn_name.is_null() {
332        return false;
333    }
334    let fn_name = unsafe { (&*fn_name).as_str().to_string() };
335    if fn_name.is_empty() {
336        return false;
337    }
338    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
339    let context = unsafe { (&*context).clone() };
340    std::thread::Builder::new()
341        .name(format!("zust:{fn_name}"))
342        .spawn(move || {
343            if let Err(err) = spawn_run(context, fn_name.as_str(), args) {
344                log::error!("spawn {fn_name} failed: {err:?}");
345            }
346        })
347        .is_ok()
348}
349
350fn spawn_args(args: Dynamic) -> Vec<Dynamic> {
351    match args {
352        Dynamic::Null => Vec::new(),
353        Dynamic::List(values) => values.read().iter().map(Dynamic::deep_clone).collect(),
354        value => vec![value],
355    }
356}
357
358fn spawn_run(context: Weak<RwLock<JITRunTime>>, fn_name: &str, args: Dynamic) -> Result<()> {
359    let args = spawn_args(args);
360    if args.len() > 16 {
361        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
362    }
363    let arg_tys = vec![Type::Any; args.len()];
364    let (ptr, ret_ty) = super::with_vm_context(&context as *const Weak<RwLock<JITRunTime>>, |vm| vm.jit.write().get_fn_ptr(fn_name, &arg_tys))?;
365    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
366    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
367    call_jit_isolated(|| unsafe { call_spawned(ptr, &ret_ty, &ptrs) })
368}
369
370pub(crate) extern "C" fn spawn_ptr(fn_ptr: i64, ret_ty: i64, args: *const Dynamic) -> bool {
371    if fn_ptr == 0 || ret_ty == 0 {
372        return false;
373    }
374    let fn_ptr = fn_ptr as usize;
375    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
376    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
377    std::thread::Builder::new()
378        .name("zust:closure".to_string())
379        .spawn(move || {
380            if let Err(err) = spawn_run_ptr(fn_ptr, ret_ty, args) {
381                log::error!("spawn closure failed: {err:?}");
382            }
383        })
384        .is_ok()
385}
386
387pub(crate) extern "C" fn callback_new(fn_ptr: i64, ret_ty: i64, explicit_arg_len: i64, captures: *const Dynamic) -> *const Dynamic {
388    if fn_ptr == 0 || ret_ty == 0 {
389        return alloc_dynamic(Dynamic::Null);
390    }
391    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
392    let explicit_arg_len = usize::try_from(explicit_arg_len).unwrap_or(usize::MAX);
393    let captures = if captures.is_null() {
394        Vec::new()
395    } else {
396        // 闭包捕获按引用共享:浅 clone 只复制 Arc 句柄,多个闭包捕获同一个
397        // Map/List 时读写同一份数据(spawn 跨线程才需要 deep_clone 隔离)。
398        match unsafe { &*captures } {
399            Dynamic::List(values) => values.read().to_vec(),
400            value => vec![value.clone()],
401        }
402    };
403    alloc_dynamic(Dynamic::custom(ZustCallback::new_with_arg_len(fn_ptr as usize, ret_ty, explicit_arg_len, captures)))
404}
405
406fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
407    let args = spawn_args(args);
408    if args.len() > 16 {
409        anyhow::bail!("spawn supports at most 16 args, got {}", args.len());
410    }
411    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
412    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
413    call_jit_isolated(|| unsafe { call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs) })
414}
415
416/// 脚本执行的隔离边界。
417///
418/// JIT 代码无法返回 `Result`,运行期错误(整数除零等)通过 [`dynamic`] 的线程
419/// 局部 fault 标志上报(由 `__vm_arith_fault` 与 `Dynamic` 的除法守卫设置)。这里
420/// 在调用前清掉陈旧标志,调用后读取它,把"脚本出错"降级为一次失败的 `Result`,
421/// 而不是让进程崩溃。`catch_unwind` 额外兜住宿主侧 Rust 代码(参数编组、返回值
422/// 取出)的 panic。
423///
424/// 注意:若 panic 发生在 JIT 的 `extern "C"` 帧之内再向外穿越,Rust 默认会 abort,
425/// `catch_unwind` 无法拦截——这类路径靠的是各 native 助手不 panic(除零已改为置
426/// fault 标志)。
427pub(crate) fn call_jit_isolated<T>(f: impl FnOnce() -> Result<T>) -> Result<T> {
428    let _ = dynamic::take_fault();
429    let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(f));
430    match outcome {
431        Ok(inner) => match dynamic::take_fault() {
432            Some(reason) => Err(anyhow!("脚本运行期错误: {}", reason)),
433            None => inner,
434        },
435        Err(_) => Err(anyhow!("脚本执行 panic,已隔离")),
436    }
437}
438
439unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
440    macro_rules! callback_arg_ty {
441        ($arg:ident) => {
442            *const Dynamic
443        };
444    }
445
446    macro_rules! callback_args {
447        ($body:ident $(, $extra:tt)*) => {
448            match args {
449                [] => $body!($($extra),*;),
450                [a] => $body!($($extra),*; a),
451                [a, b] => $body!($($extra),*; a, b),
452                [a, b, c] => $body!($($extra),*; a, b, c),
453                [a, b, c, d] => $body!($($extra),*; a, b, c, d),
454                [a, b, c, d, e] => $body!($($extra),*; a, b, c, d, e),
455                [a, b, c, d, e, f] => $body!($($extra),*; a, b, c, d, e, f),
456                [a, b, c, d, e, f, g] => $body!($($extra),*; a, b, c, d, e, f, g),
457                [a, b, c, d, e, f, g, h] => $body!($($extra),*; a, b, c, d, e, f, g, h),
458                [a, b, c, d, e, f, g, h, i] => $body!($($extra),*; a, b, c, d, e, f, g, h, i),
459                [a, b, c, d, e, f, g, h, i, j] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j),
460                [a, b, c, d, e, f, g, h, i, j, k] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k),
461                [a, b, c, d, e, f, g, h, i, j, k, l] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l),
462                [a, b, c, d, e, f, g, h, i, j, k, l, m] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m),
463                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n),
464                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o),
465                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p),
466                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q),
467                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r),
468                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s),
469                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t),
470                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u),
471                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v),
472                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w),
473                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x),
474                _ => anyhow::bail!("callback supports at most 24 args including captures, got {}", args.len()),
475            }
476        };
477    }
478
479    macro_rules! call_void_body {
480        (; $($arg:ident),*) => {{
481            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) = unsafe { std::mem::transmute(ptr) };
482            fn_ptr($(*$arg),*)
483        }};
484    }
485
486    macro_rules! call_void {
487        () => {
488            callback_args!(call_void_body)
489        };
490    }
491
492    macro_rules! call_ret_body {
493        ($ret:ty, $dynamic:expr; $($arg:ident),*) => {{
494            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) -> $ret = unsafe { std::mem::transmute(ptr) };
495            $dynamic(fn_ptr($(*$arg),*))
496        }};
497    }
498
499    macro_rules! call_ret {
500        ($ret:ty, $dynamic:expr) => {{ callback_args!(call_ret_body, $ret, $dynamic) }};
501    }
502
503    if ret_ty.is_void() {
504        call_void!();
505        Ok(Dynamic::Null)
506    } else if ret_ty.is_bool() {
507        call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
508    } else if ret_ty.is_float() {
509        if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
510    } else if ret_ty.is_int() || ret_ty.is_uint() {
511        match ret_ty {
512            Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
513            Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
514            Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
515            Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
516            Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
517            Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
518            Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
519            Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
520            _ => unreachable!(),
521        }
522    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
523        log::warn!("callback returns {ret_ty:?} — not supported, discarding");
524        call_ret!(*const u8, |_| Ok(Dynamic::Null))
525    } else {
526        call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
527    }
528}
529
530unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
531    macro_rules! call_void {
532        () => {
533            match args {
534                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
535                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
536                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
537                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
538                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
539                [a, b, c, d, e] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e) },
540                [a, b, c, d, e, f] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f) },
541                [a, b, c, d, e, f, g] => unsafe {
542                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d, *e, *f, *g)
543                },
544                [a, b, c, d, e, f, g, h] => unsafe {
545                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
546                        *a, *b, *c, *d, *e, *f, *g, *h,
547                    )
548                },
549                [a, b, c, d, e, f, g, h, i] => unsafe {
550                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
551                        *a, *b, *c, *d, *e, *f, *g, *h, *i,
552                    )
553                },
554                [a, b, c, d, e, f, g, h, i, j] => unsafe {
555                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(
556                        ptr,
557                    )(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j)
558                },
559                [a, b, c, d, e, f, g, h, i, j, k] => unsafe {
560                    std::mem::transmute::<
561                        _,
562                        extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic),
563                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k)
564                },
565                [a, b, c, d, e, f, g, h, i, j, k, l] => unsafe {
566                    std::mem::transmute::<
567                        _,
568                        extern "C" fn(
569                            *const Dynamic,
570                            *const Dynamic,
571                            *const Dynamic,
572                            *const Dynamic,
573                            *const Dynamic,
574                            *const Dynamic,
575                            *const Dynamic,
576                            *const Dynamic,
577                            *const Dynamic,
578                            *const Dynamic,
579                            *const Dynamic,
580                            *const Dynamic,
581                        ),
582                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l)
583                },
584                [a, b, c, d, e, f, g, h, i, j, k, l, m] => unsafe {
585                    std::mem::transmute::<
586                        _,
587                        extern "C" fn(
588                            *const Dynamic,
589                            *const Dynamic,
590                            *const Dynamic,
591                            *const Dynamic,
592                            *const Dynamic,
593                            *const Dynamic,
594                            *const Dynamic,
595                            *const Dynamic,
596                            *const Dynamic,
597                            *const Dynamic,
598                            *const Dynamic,
599                            *const Dynamic,
600                            *const Dynamic,
601                        ),
602                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m)
603                },
604                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => unsafe {
605                    std::mem::transmute::<
606                        _,
607                        extern "C" fn(
608                            *const Dynamic,
609                            *const Dynamic,
610                            *const Dynamic,
611                            *const Dynamic,
612                            *const Dynamic,
613                            *const Dynamic,
614                            *const Dynamic,
615                            *const Dynamic,
616                            *const Dynamic,
617                            *const Dynamic,
618                            *const Dynamic,
619                            *const Dynamic,
620                            *const Dynamic,
621                            *const Dynamic,
622                        ),
623                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n)
624                },
625                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => unsafe {
626                    std::mem::transmute::<
627                        _,
628                        extern "C" fn(
629                            *const Dynamic,
630                            *const Dynamic,
631                            *const Dynamic,
632                            *const Dynamic,
633                            *const Dynamic,
634                            *const Dynamic,
635                            *const Dynamic,
636                            *const Dynamic,
637                            *const Dynamic,
638                            *const Dynamic,
639                            *const Dynamic,
640                            *const Dynamic,
641                            *const Dynamic,
642                            *const Dynamic,
643                            *const Dynamic,
644                        ),
645                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o)
646                },
647                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => unsafe {
648                    std::mem::transmute::<
649                        _,
650                        extern "C" fn(
651                            *const Dynamic,
652                            *const Dynamic,
653                            *const Dynamic,
654                            *const Dynamic,
655                            *const Dynamic,
656                            *const Dynamic,
657                            *const Dynamic,
658                            *const Dynamic,
659                            *const Dynamic,
660                            *const Dynamic,
661                            *const Dynamic,
662                            *const Dynamic,
663                            *const Dynamic,
664                            *const Dynamic,
665                            *const Dynamic,
666                            *const Dynamic,
667                        ),
668                    >(ptr)(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p)
669                },
670                _ => unreachable!(),
671            }
672        };
673    }
674
675    if ret_ty.is_void() {
676        call_void!();
677        return Ok(());
678    }
679
680    macro_rules! call_ret {
681        ($ret:ty, $drop_result:expr) => {
682            match args {
683                [] => {
684                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
685                    $drop_result(fn_ptr());
686                }
687                [a] => {
688                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
689                    $drop_result(fn_ptr(*a));
690                }
691                [a, b] => {
692                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
693                    $drop_result(fn_ptr(*a, *b));
694                }
695                [a, b, c] => {
696                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
697                    $drop_result(fn_ptr(*a, *b, *c));
698                }
699                [a, b, c, d] => {
700                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
701                    $drop_result(fn_ptr(*a, *b, *c, *d));
702                }
703                [a, b, c, d, e] => {
704                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
705                    $drop_result(fn_ptr(*a, *b, *c, *d, *e));
706                }
707                [a, b, c, d, e, f] => {
708                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
709                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
710                }
711                [a, b, c, d, e, f, g] => {
712                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
713                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
714                }
715                [a, b, c, d, e, f, g, h] => {
716                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
717                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
718                }
719                [a, b, c, d, e, f, g, h, i] => {
720                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret =
721                        unsafe { std::mem::transmute(ptr) };
722                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i));
723                }
724                [a, b, c, d, e, f, g, h, i, j] => {
725                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret =
726                        unsafe { std::mem::transmute(ptr) };
727                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j));
728                }
729                [a, b, c, d, e, f, g, h, i, j, k] => {
730                    let fn_ptr: extern "C" fn(
731                        *const Dynamic,
732                        *const Dynamic,
733                        *const Dynamic,
734                        *const Dynamic,
735                        *const Dynamic,
736                        *const Dynamic,
737                        *const Dynamic,
738                        *const Dynamic,
739                        *const Dynamic,
740                        *const Dynamic,
741                        *const Dynamic,
742                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
743                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k));
744                }
745                [a, b, c, d, e, f, g, h, i, j, k, l] => {
746                    let fn_ptr: extern "C" fn(
747                        *const Dynamic,
748                        *const Dynamic,
749                        *const Dynamic,
750                        *const Dynamic,
751                        *const Dynamic,
752                        *const Dynamic,
753                        *const Dynamic,
754                        *const Dynamic,
755                        *const Dynamic,
756                        *const Dynamic,
757                        *const Dynamic,
758                        *const Dynamic,
759                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
760                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l));
761                }
762                [a, b, c, d, e, f, g, h, i, j, k, l, m] => {
763                    let fn_ptr: extern "C" fn(
764                        *const Dynamic,
765                        *const Dynamic,
766                        *const Dynamic,
767                        *const Dynamic,
768                        *const Dynamic,
769                        *const Dynamic,
770                        *const Dynamic,
771                        *const Dynamic,
772                        *const Dynamic,
773                        *const Dynamic,
774                        *const Dynamic,
775                        *const Dynamic,
776                        *const Dynamic,
777                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
778                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m));
779                }
780                [a, b, c, d, e, f, g, h, i, j, k, l, m, n] => {
781                    let fn_ptr: extern "C" fn(
782                        *const Dynamic,
783                        *const Dynamic,
784                        *const Dynamic,
785                        *const Dynamic,
786                        *const Dynamic,
787                        *const Dynamic,
788                        *const Dynamic,
789                        *const Dynamic,
790                        *const Dynamic,
791                        *const Dynamic,
792                        *const Dynamic,
793                        *const Dynamic,
794                        *const Dynamic,
795                        *const Dynamic,
796                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
797                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n));
798                }
799                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] => {
800                    let fn_ptr: extern "C" fn(
801                        *const Dynamic,
802                        *const Dynamic,
803                        *const Dynamic,
804                        *const Dynamic,
805                        *const Dynamic,
806                        *const Dynamic,
807                        *const Dynamic,
808                        *const Dynamic,
809                        *const Dynamic,
810                        *const Dynamic,
811                        *const Dynamic,
812                        *const Dynamic,
813                        *const Dynamic,
814                        *const Dynamic,
815                        *const Dynamic,
816                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
817                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o));
818                }
819                [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] => {
820                    let fn_ptr: extern "C" fn(
821                        *const Dynamic,
822                        *const Dynamic,
823                        *const Dynamic,
824                        *const Dynamic,
825                        *const Dynamic,
826                        *const Dynamic,
827                        *const Dynamic,
828                        *const Dynamic,
829                        *const Dynamic,
830                        *const Dynamic,
831                        *const Dynamic,
832                        *const Dynamic,
833                        *const Dynamic,
834                        *const Dynamic,
835                        *const Dynamic,
836                        *const Dynamic,
837                    ) -> $ret = unsafe { std::mem::transmute(ptr) };
838                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h, *i, *j, *k, *l, *m, *n, *o, *p));
839                }
840                _ => unreachable!(),
841            }
842        };
843    }
844
845    if ret_ty.is_bool() {
846        call_ret!(bool, |_| {});
847    } else if ret_ty.is_float() {
848        if ret_ty.is_f64() {
849            call_ret!(f64, |_| {});
850        } else {
851            call_ret!(f32, |_| {});
852        }
853    } else if ret_ty.is_int() || ret_ty.is_uint() {
854        match ret_ty {
855            Type::I8 => call_ret!(i8, |_| {}),
856            Type::U8 => call_ret!(u8, |_| {}),
857            Type::I16 => call_ret!(i16, |_| {}),
858            Type::U16 => call_ret!(u16, |_| {}),
859            Type::I32 => call_ret!(i32, |_| {}),
860            Type::U32 => call_ret!(u32, |_| {}),
861            Type::I64 => call_ret!(i64, |_| {}),
862            Type::U64 => call_ret!(u64, |_| {}),
863            _ => unreachable!(),
864        }
865    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
866        log::warn!("spawned fn returns {ret_ty:?} — not supported, discarding");
867        call_ret!(*const u8, |_| {});
868    } else {
869        call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
870    }
871    Ok(())
872}
873
874extern "C" fn any_len(addr: *const Dynamic) -> i64 {
875    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
876}
877
878extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
879    if addr.is_null() {
880        return alloc_dynamic(Dynamic::list(Vec::new()));
881    }
882    let keys = match unsafe { &*addr } {
883        Dynamic::Map(map) => map.read().keys().map(|key| Dynamic::from(key.as_str())).collect(),
884        _ => Vec::new(),
885    };
886    alloc_dynamic(Dynamic::list(keys))
887}
888
889extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
890    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
891}
892
893extern "C" fn any_next(addr: *const Dynamic) -> *const Dynamic {
894    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next().unwrap_or(Dynamic::Null) }) }
895}
896
897extern "C" fn any_next_pair(addr: *const Dynamic) -> *const Dynamic {
898    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (&mut *(addr as *mut Dynamic)).next_pair().unwrap_or(Dynamic::Null) }) }
899}
900
901extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
902    if !addr.is_null() && !value.is_null() {
903        unsafe {
904            (&mut *addr).push_dynamic((&*value).clone());
905        }
906    }
907}
908
909extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
910    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
911}
912
913extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
914    if addr.is_null() || key.is_null() {
915        any_null()
916    } else {
917        let key: &str = unsafe { &*key }.as_str();
918        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
919    }
920}
921
922extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
923    if addr.is_null() || key.is_null() {
924        any_null()
925    } else {
926        let key: &str = unsafe { &*key }.as_str();
927        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
928    }
929}
930
931extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
932    if addr.is_null() || key.is_null() {
933        false
934    } else {
935        let key: &str = unsafe { &*key }.as_str();
936        unsafe { (*addr).contains(key) }
937    }
938}
939
940extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
941    if addr.is_null() || prefix.is_null() {
942        false
943    } else {
944        let prefix: &str = unsafe { &*prefix }.as_str();
945        unsafe { (*addr).starts_with(prefix) }
946    }
947}
948
949extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
950    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
951}
952
953macro_rules! myvec_list_native {
954    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
955        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
956            if addr.is_null() {
957                return;
958            }
959            unsafe {
960                match &mut *addr {
961                    Dynamic::$vec(values) => values.push(value),
962                    list => {
963                        list.push_dynamic(Dynamic::$dynamic(value));
964                    }
965                }
966            }
967        }
968
969        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
970            if addr.is_null() {
971                return <$ty>::default();
972            }
973            let Ok(idx) = usize::try_from(idx) else {
974                return <$ty>::default();
975            };
976            unsafe {
977                match &*addr {
978                    Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
979                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
980                }
981            }
982        }
983
984        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
985            if addr.is_null() {
986                return;
987            }
988            let Ok(idx) = usize::try_from(idx) else {
989                return;
990            };
991            unsafe {
992                match &mut *addr {
993                    Dynamic::$vec(values) => values.set(idx, value),
994                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
995                }
996            }
997        }
998    };
999}
1000
1001macro_rules! stdvec_list_native {
1002    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
1003        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
1004            if addr.is_null() {
1005                return;
1006            }
1007            unsafe {
1008                match &mut *addr {
1009                    Dynamic::$vec(values) => values.push(value),
1010                    list => {
1011                        list.push_dynamic(Dynamic::$dynamic(value));
1012                    }
1013                }
1014            }
1015        }
1016
1017        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
1018            if addr.is_null() {
1019                return <$ty>::default();
1020            }
1021            let Ok(idx) = usize::try_from(idx) else {
1022                return <$ty>::default();
1023            };
1024            unsafe {
1025                match &*addr {
1026                    Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
1027                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
1028                }
1029            }
1030        }
1031
1032        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
1033            if addr.is_null() {
1034                return;
1035            }
1036            let Ok(idx) = usize::try_from(idx) else {
1037                return;
1038            };
1039            unsafe {
1040                match &mut *addr {
1041                    Dynamic::$vec(values) => {
1042                        if let Some(slot) = values.get_mut(idx) {
1043                            *slot = value;
1044                        }
1045                    }
1046                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
1047                }
1048            }
1049        }
1050    };
1051}
1052
1053myvec_list_native!(list_i8_push, list_i8_get_idx, list_i8_set_idx, VecI8, I8, i8, |value: Dynamic| value.as_int().map(|value| value as i8));
1054myvec_list_native!(list_u16_push, list_u16_get_idx, list_u16_set_idx, VecU16, U16, u16, |value: Dynamic| value.as_uint().map(|value| value as u16));
1055myvec_list_native!(list_i16_push, list_i16_get_idx, list_i16_set_idx, VecI16, I16, i16, |value: Dynamic| value.as_int().map(|value| value as i16));
1056myvec_list_native!(list_u32_push, list_u32_get_idx, list_u32_set_idx, VecU32, U32, u32, |value: Dynamic| value.as_uint().map(|value| value as u32));
1057myvec_list_native!(list_i32_push, list_i32_get_idx, list_i32_set_idx, VecI32, I32, i32, |value: Dynamic| value.as_int().map(|value| value as i32));
1058myvec_list_native!(list_f32_push, list_f32_get_idx, list_f32_set_idx, VecF32, F32, f32, |value: Dynamic| value.as_float().map(|value| value as f32));
1059stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, |value: Dynamic| value.as_uint());
1060stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, |value: Dynamic| value.as_int());
1061stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
1062
1063extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
1064    if !addr.is_null() {
1065        unsafe {
1066            (&mut *addr).push_dynamic(Dynamic::Bool(value));
1067        }
1068    }
1069}
1070
1071extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
1072    if addr.is_null() {
1073        return false;
1074    }
1075    let Ok(idx) = usize::try_from(idx) else {
1076        return false;
1077    };
1078    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_bool()).unwrap_or(false) }
1079}
1080
1081extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
1082    if addr.is_null() {
1083        return;
1084    }
1085    let Ok(idx) = usize::try_from(idx) else {
1086        return;
1087    };
1088    unsafe {
1089        (&mut *addr).set_idx(idx, Dynamic::Bool(value));
1090    }
1091}
1092
1093extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
1094    if !addr.is_null() {
1095        unsafe {
1096            (&mut *addr).push_dynamic(Dynamic::U8(value));
1097        }
1098    }
1099}
1100
1101extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
1102    if addr.is_null() {
1103        return 0;
1104    }
1105    let Ok(idx) = usize::try_from(idx) else {
1106        return 0;
1107    };
1108    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_uint()).map(|value| value as u8).unwrap_or(0) }
1109}
1110
1111extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
1112    if addr.is_null() {
1113        return;
1114    }
1115    let Ok(idx) = usize::try_from(idx) else {
1116        return;
1117    };
1118    unsafe {
1119        (&mut *addr).set_idx(idx, Dynamic::U8(value));
1120    }
1121}
1122
1123extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
1124    if addr.is_null() || value.is_null() {
1125        return;
1126    }
1127    unsafe {
1128        (&mut *addr).push_dynamic((&*value).clone());
1129    }
1130}
1131
1132extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
1133    if addr.is_null() {
1134        return any_null();
1135    };
1136    let Ok(idx) = usize::try_from(idx) else {
1137        return any_null();
1138    };
1139    if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
1140}
1141
1142extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
1143    if addr.is_null() || value.is_null() {
1144        return;
1145    }
1146    let Ok(idx) = usize::try_from(idx) else {
1147        return;
1148    };
1149    unsafe {
1150        (&mut *addr).set_idx(idx, (&*value).clone());
1151    }
1152}
1153
1154extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
1155    if addr.is_null() {
1156        return any_null();
1157    }
1158
1159    let value = unsafe { &*addr };
1160    let len = value.len() as i64;
1161    let start = start.clamp(0, len) as usize;
1162    let mut stop = if stop.is_null() {
1163        len
1164    } else {
1165        let raw = unsafe { &*stop };
1166        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
1167    };
1168    if inclusive && stop < len {
1169        stop += 1;
1170    }
1171    let stop = stop.clamp(start as i64, len) as usize;
1172
1173    let sliced = if value.is_str() {
1174        Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
1175    } else {
1176        match value {
1177            Dynamic::List(list) => Dynamic::list(list.read()[start..stop].to_vec()),
1178            _ => Dynamic::Null,
1179        }
1180    };
1181    alloc_dynamic(sliced)
1182}
1183
1184extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
1185    if addr.is_null() || key.is_null() {
1186        return;
1187    }
1188    let key: &str = unsafe { &*key }.as_str();
1189    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
1190}
1191
1192extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
1193    if addr.is_null() {
1194        return;
1195    }
1196    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
1197}
1198
1199extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
1200    alloc_dynamic(Dynamic::I64(v))
1201}
1202
1203extern "C" fn any_from_u64(v: u64) -> *const Dynamic {
1204    alloc_dynamic(Dynamic::U64(v))
1205}
1206
1207extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
1208    alloc_dynamic(Dynamic::Bool(v))
1209}
1210
1211extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
1212    if addr.is_null() {
1213        return 0;
1214    }
1215    unsafe {
1216        let value = &*addr;
1217        value
1218            .as_int()
1219            .or_else(|| value.as_float().map(|value| value as i64))
1220            .or_else(|| {
1221                let text = value.as_str();
1222                let text = text.trim();
1223                if text.is_empty() { None } else { text.parse::<i64>().ok().or_else(|| text.parse::<f64>().ok().map(|value| value as i64)) }
1224            })
1225            .unwrap_or(0)
1226    }
1227}
1228
1229extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
1230    if addr.is_null() {
1231        return false;
1232    }
1233    unsafe {
1234        let value = &*addr;
1235        if let Some(v) = value.as_bool() {
1236            v
1237        } else if let Some(v) = value.as_int() {
1238            v != 0
1239        } else if let Some(v) = value.as_float() {
1240            v != 0.0
1241        } else {
1242            !value.is_null()
1243        }
1244    }
1245}
1246
1247extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
1248    alloc_dynamic(Dynamic::F64(v))
1249}
1250
1251extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
1252    if addr.is_null() || s.is_null() {
1253        return any_null();
1254    }
1255    let s: &str = unsafe { &*s }.as_str();
1256    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
1257}
1258
1259extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
1260    if addr.is_null() {
1261        return 0.0;
1262    }
1263    unsafe {
1264        let value = &*addr;
1265        value.as_float().or_else(|| value.as_str().trim().parse::<f64>().ok()).unwrap_or(0.0)
1266    }
1267}
1268
1269extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
1270    if addr.is_null() {
1271        return alloc_dynamic(Dynamic::from(""));
1272    }
1273    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
1274}
1275
1276extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
1277    if left.is_null() {
1278        if right.is_null() {
1279            return any_null();
1280        }
1281        return alloc_dynamic(unsafe { (&*right).clone() });
1282    }
1283    if right.is_null() {
1284        return alloc_dynamic(unsafe { (&*left).clone() });
1285    }
1286    let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1287    if op == BinaryOp::Add {
1288        let (left_value, right_value) = unsafe { (&*left, &*right) };
1289        if left_value.is_str() || right_value.is_str() {
1290            return alloc_dynamic(left_value.clone() + right_value.clone());
1291        }
1292    }
1293    unsafe {
1294        let expr = Expr::new(
1295            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
1296            Span::default(),
1297        );
1298        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
1299    }
1300}
1301
1302extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> bool {
1303    let op = BinaryOp::try_from(op).unwrap_or(BinaryOp::Unknow);
1304    unsafe {
1305        let expr = Expr::new(
1306            ExprKind::Binary { left: Box::new(Expr::new(ExprKind::Value((&*left).clone()), Span::default())), op, right: Box::new(Expr::new(ExprKind::Value((&*right).clone()), Span::default())) },
1307            Span::default(),
1308        );
1309        expr.compact().and_then(|r| r.as_bool()).unwrap_or(false)
1310    }
1311}
1312
1313pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
1314    ("print", &[Type::Any], Type::Void, print as *const u8),
1315    ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
1316    ("log", &[Type::Any], Type::Void, log_any as *const u8),
1317    ("uuid", &[], Type::Any, uuid as *const u8),
1318    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
1319];
1320
1321pub const ANY: [(&str, &[Type], Type, *const u8); 69] = [
1322    ("Any::null", &[], Type::Any, any_null as *const u8),
1323    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
1324    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1325    ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1326    ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1327    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1328    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1329    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1330    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1331    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1332    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1333    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1334    ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1335    ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1336    ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1337    ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1338    ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1339    ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1340    ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1341    ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1342    ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1343    ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1344    ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1345    ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1346    ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1347    ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1348    ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1349    ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1350    ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1351    ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1352    ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1353    ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1354    ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1355    ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1356    ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1357    ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1358    ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1359    ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1360    ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1361    ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1362    ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1363    ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1364    ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1365    ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1366    ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1367    ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1368    ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1369    ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1370    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1371    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1372    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1373    ("Any::get", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1374    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1375    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1376    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1377    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1378    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1379    ("Any::from_u64", &[Type::U64], Type::Any, any_from_u64 as *const u8),
1380    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1381    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1382    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1383    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1384    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1385    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1386    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1387    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1388    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1389    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1390    ("Any::next_pair", &[Type::Any], Type::Any, any_next_pair as *const u8),
1391];
1392
1393use std::rc::Rc;
1394impl JITRunTime {
1395    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1396        self.native_symbols.write().insert(full_name.to_string(), fn_ptr as usize);
1397        self.add_native(full_name, name, arg_tys, ret_ty)
1398    }
1399
1400    pub(crate) fn add_context_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1401        self.native_symbols.write().insert(full_name.to_string(), fn_ptr as usize);
1402        self.add_context_native(full_name, name, arg_tys, ret_ty)
1403    }
1404
1405    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1406        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1407        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1408        let sig = self.get_sig(arg_tys, ret_ty)?;
1409        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1410        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1411        Ok(id)
1412    }
1413
1414    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1415        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1416        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1417        let mut sig = self.module.make_signature();
1418        sig.params.push(AbiParam::new(crate::ptr_type()));
1419        for arg in arg_tys.iter() {
1420            sig.params.push(AbiParam::new(crate::get_type(arg)?));
1421        }
1422        if !ret_ty.is_void() {
1423            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1424        }
1425        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1426        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1427        Ok(id)
1428    }
1429}