Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::memory::{alloc_dynamic, alloc_struct_bytes, take_dynamic_return};
4use anyhow::Result;
5use cranelift::prelude::AbiParam;
6use cranelift_module::{Linkage, Module};
7use dynamic::{Dynamic, Type};
8use parser::{BinaryOp, Expr, ExprKind, Span};
9use rand::RngExt;
10use std::borrow::Cow;
11use std::collections::BTreeMap;
12use std::fmt::Write as _;
13use std::sync::{Mutex, Weak};
14
15#[derive(Clone, Debug)]
16pub struct ZustCallback {
17    pub fn_ptr: usize,
18    pub ret_ty: Type,
19    pub captures: Vec<Dynamic>,
20}
21
22impl ZustCallback {
23    pub fn new(fn_ptr: usize, ret_ty: Type, captures: Vec<Dynamic>) -> Self {
24        Self { fn_ptr, ret_ty, captures }
25    }
26
27    pub fn call0(&self) -> Result<Dynamic> {
28        self.call(Vec::new())
29    }
30
31    pub fn call1(&self, arg: Dynamic) -> Result<Dynamic> {
32        self.call(vec![arg])
33    }
34
35    pub fn call(&self, mut args: Vec<Dynamic>) -> Result<Dynamic> {
36        args.extend(self.captures.iter().map(|value| value.deep_clone()));
37        let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
38        let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
39        unsafe { call_callback(self.fn_ptr as *const u8, &self.ret_ty, &ptrs) }
40    }
41}
42
43extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
44    //在堆上分配内存 复制 addr 到内存中
45    unsafe {
46        let cloned_value = (*addr).deep_clone();
47        alloc_dynamic(cloned_value)
48    }
49}
50
51extern "C" fn any_null() -> *const Dynamic {
52    //在堆上分配内存 复制 addr 到内存中
53    alloc_dynamic(Dynamic::Null)
54}
55
56extern "C" fn print(addr: *const Dynamic) {
57    if !addr.is_null() {
58        unsafe {
59            println!("{}", (*addr).to_string());
60        }
61    }
62}
63
64extern "C" fn sqrt(value: f64) -> f64 {
65    value.sqrt()
66}
67
68extern "C" fn log_any(addr: *const Dynamic) {
69    if addr.is_null() {
70        log::info!("{:?}", Dynamic::Null);
71    } else {
72        log::info!("{:?}", unsafe { &*addr });
73    }
74}
75
76extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
77    !addr.is_null() && unsafe { (*addr).is_map() }
78}
79
80extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
81    !addr.is_null() && unsafe { (*addr).is_list() }
82}
83
84extern "C" fn any_is_string(addr: *const Dynamic) -> bool {
85    !addr.is_null() && unsafe { (*addr).is_str() }
86}
87
88extern "C" fn any_is_null(addr: *const Dynamic) -> bool {
89    addr.is_null() || unsafe { (*addr).is_null() }
90}
91
92extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
93    if !start.is_null() && !stop.is_null() {
94        let mut rng = rand::rng();
95        unsafe {
96            if (&*start).is_int() {
97                let start = (*start).as_int().unwrap_or(0);
98                let stop = (*stop).as_int().unwrap_or(100);
99                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
100            } else if (&*start).is_f32() || (&*start).is_f64() {
101                let start = (*start).as_float().unwrap_or(0.0);
102                let stop = (*stop).as_float().unwrap_or(1.0);
103                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
104            }
105        }
106    }
107    alloc_dynamic(Dynamic::Null)
108}
109
110extern "C" fn uuid() -> *const Dynamic {
111    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
112}
113
114pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
115    let size = size.max(0) as usize;
116    let ptr = alloc_struct_bytes(size);
117    unsafe {
118        std::ptr::write_bytes(ptr, 0, size);
119    }
120    ptr
121}
122
123pub(crate) extern "C" fn repeat_fill(dst: *mut u8, pattern: u64, width: i64, len: i64) {
124    if dst.is_null() || width <= 0 || len <= 0 {
125        return;
126    }
127    let width = width as usize;
128    let len = len as usize;
129    let bytes = pattern.to_le_bytes();
130    unsafe {
131        if width == 1 {
132            std::ptr::write_bytes(dst, bytes[0], len);
133            return;
134        }
135        if !matches!(width, 2 | 4 | 8) {
136            return;
137        }
138        for idx in 0..len {
139            std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst.add(idx * width), width);
140        }
141    }
142}
143
144pub(crate) extern "C" fn strcat(left: *const Dynamic, right: *const Dynamic) -> *const Dynamic {
145    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
146    let right = if right.is_null() { "" } else { unsafe { (&*right).as_str() } };
147    let mut out = String::with_capacity(left.len() + right.len());
148    out.push_str(left);
149    out.push_str(right);
150    alloc_dynamic(Dynamic::StringBuf(out))
151}
152
153pub(crate) extern "C" fn strcat_i64(left: *const Dynamic, right: i64) -> *const Dynamic {
154    let left = if left.is_null() { "" } else { unsafe { (&*left).as_str() } };
155    let mut out = String::with_capacity(left.len() + 20);
156    out.push_str(left);
157    let _ = write!(&mut out, "{right}");
158    alloc_dynamic(Dynamic::StringBuf(out))
159}
160
161pub(crate) extern "C" fn strcat_assign(left: *mut Dynamic, right: *const Dynamic) -> *const Dynamic {
162    if left.is_null() {
163        return strcat(left, right);
164    }
165    let suffix = if right.is_null() {
166        Cow::Borrowed("")
167    } else if std::ptr::eq(left as *const Dynamic, right) {
168        Cow::Owned(unsafe { (&*right).to_string() })
169    } else {
170        let right = unsafe { &*right };
171        if right.is_str() { Cow::Borrowed(right.as_str()) } else { Cow::Owned(right.to_string()) }
172    };
173    unsafe {
174        match &mut *left {
175            Dynamic::StringBuf(text) => text.push_str(suffix.as_ref()),
176            Dynamic::String(text) => {
177                let mut out = String::with_capacity(text.len() + suffix.len());
178                out.push_str(text.as_str());
179                out.push_str(suffix.as_ref());
180                *left = Dynamic::StringBuf(out);
181            }
182            value => {
183                let prefix = value.to_string();
184                let mut out = String::with_capacity(prefix.len() + suffix.len());
185                out.push_str(&prefix);
186                out.push_str(suffix.as_ref());
187                *value = Dynamic::StringBuf(out);
188            }
189        }
190    }
191    left
192}
193
194pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
195    let ty = unsafe { (&*(ty as *const Type)).clone() };
196    alloc_dynamic(Dynamic::Struct { addr: addr as usize, ty })
197}
198
199pub(crate) extern "C" fn array_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
200    if addr == 0 || ty == 0 {
201        return alloc_dynamic(Dynamic::Null);
202    }
203    let ty = unsafe { &*(ty as *const Type) };
204    alloc_dynamic(dynamic_from_ptr(addr as *const u8, ty))
205}
206
207pub(crate) extern "C" fn array_to_ptr(dst: *mut u8, value: *const Dynamic, ty: i64) {
208    if dst.is_null() || value.is_null() || ty == 0 {
209        return;
210    }
211    let ty = unsafe { &*(ty as *const Type) };
212    write_dynamic_to_ptr(dst, unsafe { &*value }, ty);
213}
214
215fn dynamic_from_ptr(addr: *const u8, ty: &Type) -> Dynamic {
216    if addr.is_null() {
217        return Dynamic::Null;
218    }
219    match ty {
220        Type::Bool => Dynamic::Bool(unsafe { std::ptr::read_unaligned(addr) } != 0),
221        Type::I8 => Dynamic::I8(unsafe { std::ptr::read_unaligned(addr as *const i8) }),
222        Type::U8 => Dynamic::U8(unsafe { std::ptr::read_unaligned(addr) }),
223        Type::I16 => Dynamic::I16(unsafe { std::ptr::read_unaligned(addr as *const i16) }),
224        Type::U16 => Dynamic::U16(unsafe { std::ptr::read_unaligned(addr as *const u16) }),
225        Type::I32 => Dynamic::I32(unsafe { std::ptr::read_unaligned(addr as *const i32) }),
226        Type::U32 => Dynamic::U32(unsafe { std::ptr::read_unaligned(addr as *const u32) }),
227        Type::I64 => Dynamic::I64(unsafe { std::ptr::read_unaligned(addr as *const i64) }),
228        Type::U64 => Dynamic::U64(unsafe { std::ptr::read_unaligned(addr as *const u64) }),
229        Type::F32 => Dynamic::F32(unsafe { std::ptr::read_unaligned(addr as *const f32) }),
230        Type::F64 => Dynamic::F64(unsafe { std::ptr::read_unaligned(addr as *const f64) }),
231        Type::Array(elem_ty, len) => {
232            let width = elem_ty.storage_width() as usize;
233            let values = (0..*len as usize).map(|idx| unsafe { dynamic_from_ptr(addr.add(idx * width), elem_ty) }).collect();
234            Dynamic::list(values)
235        }
236        Type::Struct { fields, .. } => {
237            let mut map = BTreeMap::new();
238            let (_, offsets) = Type::struct_layout(fields);
239            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
240                let value = unsafe { dynamic_from_ptr(addr.add(offset as usize), field_ty) };
241                map.insert(name.clone(), value);
242            }
243            Dynamic::map(map)
244        }
245        _ => {
246            let ptr = unsafe { std::ptr::read_unaligned(addr as *const *const Dynamic) };
247            if ptr.is_null() { Dynamic::Null } else { unsafe { (&*ptr).deep_clone() } }
248        }
249    }
250}
251
252fn write_dynamic_to_ptr(dst: *mut u8, value: &Dynamic, ty: &Type) {
253    if dst.is_null() {
254        return;
255    }
256    match ty {
257        Type::Bool => unsafe { std::ptr::write_unaligned(dst, if value.is_true() { 1 } else { 0 }) },
258        Type::I8 => unsafe { std::ptr::write_unaligned(dst as *mut i8, value.clone().try_into().unwrap_or_default()) },
259        Type::U8 => unsafe { std::ptr::write_unaligned(dst, value.clone().try_into().unwrap_or_default()) },
260        Type::I16 => unsafe { std::ptr::write_unaligned(dst as *mut i16, value.clone().try_into().unwrap_or_default()) },
261        Type::U16 => unsafe { std::ptr::write_unaligned(dst as *mut u16, value.clone().try_into().unwrap_or_default()) },
262        Type::I32 => unsafe { std::ptr::write_unaligned(dst as *mut i32, value.clone().try_into().unwrap_or_default()) },
263        Type::U32 => unsafe { std::ptr::write_unaligned(dst as *mut u32, value.clone().try_into().unwrap_or_default()) },
264        Type::I64 => unsafe { std::ptr::write_unaligned(dst as *mut i64, value.clone().try_into().unwrap_or_default()) },
265        Type::U64 => unsafe { std::ptr::write_unaligned(dst as *mut u64, value.clone().try_into().unwrap_or_default()) },
266        Type::F32 => unsafe { std::ptr::write_unaligned(dst as *mut f32, f32::try_from(value.clone()).unwrap_or_default()) },
267        Type::F64 => unsafe { std::ptr::write_unaligned(dst as *mut f64, value.clone().try_into().unwrap_or_default()) },
268        Type::Array(elem_ty, len) => {
269            let width = elem_ty.storage_width() as usize;
270            for idx in 0..*len as usize {
271                let item = value.get_idx(idx).unwrap_or(Dynamic::Null);
272                unsafe { write_dynamic_to_ptr(dst.add(idx * width), &item, elem_ty) };
273            }
274        }
275        Type::Struct { fields, .. } => {
276            let (_, offsets) = Type::struct_layout(fields);
277            for ((name, field_ty), offset) in fields.iter().zip(offsets) {
278                let item = value.get_dynamic(name.as_str()).unwrap_or(Dynamic::Null);
279                unsafe { write_dynamic_to_ptr(dst.add(offset as usize), &item, field_ty) };
280            }
281        }
282        _ => {
283            let ptr = alloc_dynamic(value.deep_clone());
284            unsafe { std::ptr::write_unaligned(dst as *mut usize, ptr as usize) };
285        }
286    }
287}
288
289pub(crate) extern "C" fn import_with_vm(context: *const Weak<Mutex<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
290    if addr.is_null() || path.is_null() {
291        return false;
292    }
293    super::with_vm_context(context, |vm| vm.import(unsafe { &*addr }.as_str(), unsafe { &*path }.as_str())).map_err(|e| println!("import {:?}", e)).is_ok()
294}
295
296pub(crate) extern "C" fn spawn_with_vm(context: *const Weak<Mutex<JITRunTime>>, fn_name: *const Dynamic, args: *const Dynamic) -> bool {
297    if context.is_null() || fn_name.is_null() {
298        return false;
299    }
300    let fn_name = unsafe { (&*fn_name).as_str().to_string() };
301    if fn_name.is_empty() {
302        return false;
303    }
304    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
305    let context = unsafe { (&*context).clone() };
306    std::thread::Builder::new()
307        .name(format!("zust:{fn_name}"))
308        .spawn(move || {
309            if let Err(err) = spawn_run(context, fn_name.as_str(), args) {
310                log::error!("spawn {fn_name} failed: {err:?}");
311            }
312        })
313        .is_ok()
314}
315
316fn spawn_args(args: Dynamic) -> Vec<Dynamic> {
317    match args {
318        Dynamic::Null => Vec::new(),
319        Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
320        value => vec![value],
321    }
322}
323
324fn spawn_run(context: Weak<Mutex<JITRunTime>>, fn_name: &str, args: Dynamic) -> Result<()> {
325    let args = spawn_args(args);
326    if args.len() > 8 {
327        anyhow::bail!("spawn supports at most 8 args, got {}", args.len());
328    }
329    let arg_tys = vec![Type::Any; args.len()];
330    let (ptr, ret_ty) = super::with_vm_context(&context as *const Weak<Mutex<JITRunTime>>, |vm| vm.get_fn_ptr(fn_name, &arg_tys))?;
331    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
332    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
333    unsafe {
334        call_spawned(ptr, &ret_ty, &ptrs)?;
335    }
336    Ok(())
337}
338
339pub(crate) extern "C" fn spawn_ptr(fn_ptr: i64, ret_ty: i64, args: *const Dynamic) -> bool {
340    if fn_ptr == 0 || ret_ty == 0 {
341        return false;
342    }
343    let fn_ptr = fn_ptr as usize;
344    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
345    let args = if args.is_null() { Dynamic::Null } else { unsafe { (&*args).deep_clone() } };
346    std::thread::Builder::new()
347        .name("zust:closure".to_string())
348        .spawn(move || {
349            if let Err(err) = spawn_run_ptr(fn_ptr, ret_ty, args) {
350                log::error!("spawn closure failed: {err:?}");
351            }
352        })
353        .is_ok()
354}
355
356pub(crate) extern "C" fn callback_new(fn_ptr: i64, ret_ty: i64, captures: *const Dynamic) -> *const Dynamic {
357    if fn_ptr == 0 || ret_ty == 0 {
358        return alloc_dynamic(Dynamic::Null);
359    }
360    let ret_ty = unsafe { (&*(ret_ty as *const Type)).clone() };
361    let captures = if captures.is_null() {
362        Vec::new()
363    } else {
364        match unsafe { &*captures } {
365            Dynamic::List(values) => values.read().unwrap().iter().map(Dynamic::deep_clone).collect(),
366            value => vec![value.deep_clone()],
367        }
368    };
369    alloc_dynamic(Dynamic::custom(ZustCallback::new(fn_ptr as usize, ret_ty, captures)))
370}
371
372fn spawn_run_ptr(fn_ptr: usize, ret_ty: Type, args: Dynamic) -> Result<()> {
373    let args = spawn_args(args);
374    if args.len() > 8 {
375        anyhow::bail!("spawn supports at most 8 args, got {}", args.len());
376    }
377    let args: Vec<Box<Dynamic>> = args.into_iter().map(Box::new).collect();
378    let ptrs: Vec<*const Dynamic> = args.iter().map(|arg| arg.as_ref() as *const Dynamic).collect();
379    unsafe {
380        call_spawned(fn_ptr as *const u8, &ret_ty, &ptrs)?;
381    }
382    Ok(())
383}
384
385unsafe fn call_callback(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<Dynamic> {
386    macro_rules! callback_arg_ty {
387        ($arg:ident) => {
388            *const Dynamic
389        };
390    }
391
392    macro_rules! callback_args {
393        ($body:ident $(, $extra:tt)*) => {
394            match args {
395                [] => $body!($($extra),*;),
396                [a] => $body!($($extra),*; a),
397                [a, b] => $body!($($extra),*; a, b),
398                [a, b, c] => $body!($($extra),*; a, b, c),
399                [a, b, c, d] => $body!($($extra),*; a, b, c, d),
400                [a, b, c, d, e] => $body!($($extra),*; a, b, c, d, e),
401                [a, b, c, d, e, f] => $body!($($extra),*; a, b, c, d, e, f),
402                [a, b, c, d, e, f, g] => $body!($($extra),*; a, b, c, d, e, f, g),
403                [a, b, c, d, e, f, g, h] => $body!($($extra),*; a, b, c, d, e, f, g, h),
404                [a, b, c, d, e, f, g, h, i] => $body!($($extra),*; a, b, c, d, e, f, g, h, i),
405                [a, b, c, d, e, f, g, h, i, j] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j),
406                [a, b, c, d, e, f, g, h, i, j, k] => $body!($($extra),*; a, b, c, d, e, f, g, h, i, j, k),
407                [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),
408                [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),
409                [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),
410                [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),
411                [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),
412                _ => anyhow::bail!("callback supports at most 16 args including captures, got {}", args.len()),
413            }
414        };
415    }
416
417    macro_rules! call_void_body {
418        (; $($arg:ident),*) => {{
419            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) = unsafe { std::mem::transmute(ptr) };
420            fn_ptr($(*$arg),*)
421        }};
422    }
423
424    macro_rules! call_void {
425        () => {
426            callback_args!(call_void_body)
427        };
428    }
429
430    macro_rules! call_ret_body {
431        ($ret:ty, $dynamic:expr; $($arg:ident),*) => {{
432            let fn_ptr: extern "C" fn($(callback_arg_ty!($arg)),*) -> $ret = unsafe { std::mem::transmute(ptr) };
433            $dynamic(fn_ptr($(*$arg),*))
434        }};
435    }
436
437    macro_rules! call_ret {
438        ($ret:ty, $dynamic:expr) => {{ callback_args!(call_ret_body, $ret, $dynamic) }};
439    }
440
441    if ret_ty.is_void() {
442        call_void!();
443        Ok(Dynamic::Null)
444    } else if ret_ty.is_bool() {
445        call_ret!(bool, |value| Ok(Dynamic::Bool(value)))
446    } else if ret_ty.is_float() {
447        if ret_ty.is_f64() { call_ret!(f64, |value| Ok(Dynamic::F64(value))) } else { call_ret!(f32, |value| Ok(Dynamic::F32(value))) }
448    } else if ret_ty.is_int() || ret_ty.is_uint() {
449        match ret_ty {
450            Type::I8 => call_ret!(i8, |value| Ok(Dynamic::I8(value))),
451            Type::U8 => call_ret!(u8, |value| Ok(Dynamic::U8(value))),
452            Type::I16 => call_ret!(i16, |value| Ok(Dynamic::I16(value))),
453            Type::U16 => call_ret!(u16, |value| Ok(Dynamic::U16(value))),
454            Type::I32 => call_ret!(i32, |value| Ok(Dynamic::I32(value))),
455            Type::U32 => call_ret!(u32, |value| Ok(Dynamic::U32(value))),
456            Type::I64 => call_ret!(i64, |value| Ok(Dynamic::I64(value))),
457            Type::U64 => call_ret!(u64, |value| Ok(Dynamic::U64(value))),
458            _ => unreachable!(),
459        }
460    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
461        call_ret!(*const u8, |_| Ok(Dynamic::Null))
462    } else {
463        call_ret!(*const Dynamic, |ptr| unsafe { Ok((*take_dynamic_return(ptr)).deep_clone()) })
464    }
465}
466
467unsafe fn call_spawned(ptr: *const u8, ret_ty: &Type, args: &[*const Dynamic]) -> Result<()> {
468    macro_rules! call_void {
469        () => {
470            match args {
471                [] => unsafe { std::mem::transmute::<_, extern "C" fn()>(ptr)() },
472                [a] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic)>(ptr)(*a) },
473                [a, b] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic)>(ptr)(*a, *b) },
474                [a, b, c] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c) },
475                [a, b, c, d] => unsafe { std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(*a, *b, *c, *d) },
476                [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) },
477                [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) },
478                [a, b, c, d, e, f, g] => unsafe {
479                    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)
480                },
481                [a, b, c, d, e, f, g, h] => unsafe {
482                    std::mem::transmute::<_, extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic)>(ptr)(
483                        *a, *b, *c, *d, *e, *f, *g, *h,
484                    )
485                },
486                _ => unreachable!(),
487            }
488        };
489    }
490
491    if ret_ty.is_void() {
492        call_void!();
493        return Ok(());
494    }
495
496    macro_rules! call_ret {
497        ($ret:ty, $drop_result:expr) => {
498            match args {
499                [] => {
500                    let fn_ptr: extern "C" fn() -> $ret = unsafe { std::mem::transmute(ptr) };
501                    $drop_result(fn_ptr());
502                }
503                [a] => {
504                    let fn_ptr: extern "C" fn(*const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
505                    $drop_result(fn_ptr(*a));
506                }
507                [a, b] => {
508                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
509                    $drop_result(fn_ptr(*a, *b));
510                }
511                [a, b, c] => {
512                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
513                    $drop_result(fn_ptr(*a, *b, *c));
514                }
515                [a, b, c, d] => {
516                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
517                    $drop_result(fn_ptr(*a, *b, *c, *d));
518                }
519                [a, b, c, d, e] => {
520                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
521                    $drop_result(fn_ptr(*a, *b, *c, *d, *e));
522                }
523                [a, b, c, d, e, f] => {
524                    let fn_ptr: extern "C" fn(*const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic, *const Dynamic) -> $ret = unsafe { std::mem::transmute(ptr) };
525                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f));
526                }
527                [a, b, c, d, e, f, g] => {
528                    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) };
529                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g));
530                }
531                [a, b, c, d, e, f, g, h] => {
532                    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) };
533                    $drop_result(fn_ptr(*a, *b, *c, *d, *e, *f, *g, *h));
534                }
535                _ => unreachable!(),
536            }
537        };
538    }
539
540    if ret_ty.is_bool() {
541        call_ret!(bool, |_| {});
542    } else if ret_ty.is_float() {
543        if ret_ty.is_f64() {
544            call_ret!(f64, |_| {});
545        } else {
546            call_ret!(f32, |_| {});
547        }
548    } else if ret_ty.is_int() || ret_ty.is_uint() {
549        match ret_ty {
550            Type::I8 => call_ret!(i8, |_| {}),
551            Type::U8 => call_ret!(u8, |_| {}),
552            Type::I16 => call_ret!(i16, |_| {}),
553            Type::U16 => call_ret!(u16, |_| {}),
554            Type::I32 => call_ret!(i32, |_| {}),
555            Type::U32 => call_ret!(u32, |_| {}),
556            Type::I64 => call_ret!(i64, |_| {}),
557            Type::U64 => call_ret!(u64, |_| {}),
558            _ => unreachable!(),
559        }
560    } else if ret_ty.is_struct() || ret_ty.is_array() || ret_ty.is_vec() {
561        call_ret!(*const u8, |_| {});
562    } else {
563        call_ret!(*const Dynamic, |ptr| drop(unsafe { take_dynamic_return(ptr) }));
564    }
565    Ok(())
566}
567
568extern "C" fn any_len(addr: *const Dynamic) -> i64 {
569    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
570}
571
572extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
573    if addr.is_null() {
574        return alloc_dynamic(Dynamic::list(Vec::new()));
575    }
576    let keys = match unsafe { &*addr } {
577        Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
578        _ => Vec::new(),
579    };
580    alloc_dynamic(Dynamic::list(keys))
581}
582
583extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
584    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
585}
586
587extern "C" fn any_next(addr: *mut Dynamic) -> *const Dynamic {
588    alloc_dynamic(unsafe { (*addr).next().unwrap_or(Dynamic::Null) })
589}
590
591extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
592    if !addr.is_null() && !value.is_null() {
593        unsafe {
594            (&mut *addr).push_dynamic((&*value).clone());
595        }
596    }
597}
598
599extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
600    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
601}
602
603extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
604    if addr.is_null() || key.is_null() {
605        any_null()
606    } else {
607        let key: &str = unsafe { &*key }.as_str();
608        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
609    }
610}
611
612extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
613    if addr.is_null() || key.is_null() {
614        any_null()
615    } else {
616        let key: &str = unsafe { &*key }.as_str();
617        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
618    }
619}
620
621extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
622    if addr.is_null() || key.is_null() {
623        false
624    } else {
625        let key: &str = unsafe { &*key }.as_str();
626        unsafe { (*addr).contains(key) }
627    }
628}
629
630extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
631    if addr.is_null() || prefix.is_null() {
632        false
633    } else {
634        let prefix: &str = unsafe { &*prefix }.as_str();
635        unsafe { (*addr).starts_with(prefix) }
636    }
637}
638
639extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
640    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
641}
642
643macro_rules! myvec_list_native {
644    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
645        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
646            if addr.is_null() {
647                return;
648            }
649            unsafe {
650                match &mut *addr {
651                    Dynamic::$vec(values) => values.push(value),
652                    list => {
653                        list.push_dynamic(Dynamic::$dynamic(value));
654                    }
655                }
656            }
657        }
658
659        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
660            if addr.is_null() {
661                return <$ty>::default();
662            }
663            let Ok(idx) = usize::try_from(idx) else {
664                return <$ty>::default();
665            };
666            unsafe {
667                match &*addr {
668                    Dynamic::$vec(values) => values.get(idx).unwrap_or_default(),
669                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
670                }
671            }
672        }
673
674        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
675            if addr.is_null() {
676                return;
677            }
678            let Ok(idx) = usize::try_from(idx) else {
679                return;
680            };
681            unsafe {
682                match &mut *addr {
683                    Dynamic::$vec(values) => values.set(idx, value),
684                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
685                }
686            }
687        }
688    };
689}
690
691macro_rules! stdvec_list_native {
692    ($push:ident, $get_idx:ident, $set_idx:ident, $vec:ident, $dynamic:ident, $ty:ty, $fallback:expr) => {
693        extern "C" fn $push(addr: *mut Dynamic, value: $ty) {
694            if addr.is_null() {
695                return;
696            }
697            unsafe {
698                match &mut *addr {
699                    Dynamic::$vec(values) => values.push(value),
700                    list => {
701                        list.push_dynamic(Dynamic::$dynamic(value));
702                    }
703                }
704            }
705        }
706
707        extern "C" fn $get_idx(addr: *const Dynamic, idx: i64) -> $ty {
708            if addr.is_null() {
709                return <$ty>::default();
710            }
711            let Ok(idx) = usize::try_from(idx) else {
712                return <$ty>::default();
713            };
714            unsafe {
715                match &*addr {
716                    Dynamic::$vec(values) => values.get(idx).copied().unwrap_or_default(),
717                    values => values.get_idx(idx).and_then($fallback).unwrap_or_default(),
718                }
719            }
720        }
721
722        extern "C" fn $set_idx(addr: *mut Dynamic, idx: i64, value: $ty) {
723            if addr.is_null() {
724                return;
725            }
726            let Ok(idx) = usize::try_from(idx) else {
727                return;
728            };
729            unsafe {
730                match &mut *addr {
731                    Dynamic::$vec(values) => {
732                        if let Some(slot) = values.get_mut(idx) {
733                            *slot = value;
734                        }
735                    }
736                    list => list.set_idx(idx, Dynamic::$dynamic(value)),
737                }
738            }
739        }
740    };
741}
742
743myvec_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));
744myvec_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));
745myvec_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));
746myvec_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));
747myvec_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));
748myvec_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));
749stdvec_list_native!(list_u64_push, list_u64_get_idx, list_u64_set_idx, VecU64, U64, u64, |value: Dynamic| value.as_uint());
750stdvec_list_native!(list_i64_push, list_i64_get_idx, list_i64_set_idx, VecI64, I64, i64, |value: Dynamic| value.as_int());
751stdvec_list_native!(list_f64_push, list_f64_get_idx, list_f64_set_idx, VecF64, F64, f64, |value: Dynamic| value.as_float());
752
753extern "C" fn list_bool_push(addr: *mut Dynamic, value: bool) {
754    if !addr.is_null() {
755        unsafe {
756            (&mut *addr).push_dynamic(Dynamic::Bool(value));
757        }
758    }
759}
760
761extern "C" fn list_bool_get_idx(addr: *const Dynamic, idx: i64) -> bool {
762    if addr.is_null() {
763        return false;
764    }
765    let Ok(idx) = usize::try_from(idx) else {
766        return false;
767    };
768    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_bool()).unwrap_or(false) }
769}
770
771extern "C" fn list_bool_set_idx(addr: *mut Dynamic, idx: i64, value: bool) {
772    if addr.is_null() {
773        return;
774    }
775    let Ok(idx) = usize::try_from(idx) else {
776        return;
777    };
778    unsafe {
779        (&mut *addr).set_idx(idx, Dynamic::Bool(value));
780    }
781}
782
783extern "C" fn list_u8_push(addr: *mut Dynamic, value: u8) {
784    if !addr.is_null() {
785        unsafe {
786            (&mut *addr).push_dynamic(Dynamic::U8(value));
787        }
788    }
789}
790
791extern "C" fn list_u8_get_idx(addr: *const Dynamic, idx: i64) -> u8 {
792    if addr.is_null() {
793        return 0;
794    }
795    let Ok(idx) = usize::try_from(idx) else {
796        return 0;
797    };
798    unsafe { (&*addr).get_idx(idx).and_then(|value| value.as_uint()).map(|value| value as u8).unwrap_or(0) }
799}
800
801extern "C" fn list_u8_set_idx(addr: *mut Dynamic, idx: i64, value: u8) {
802    if addr.is_null() {
803        return;
804    }
805    let Ok(idx) = usize::try_from(idx) else {
806        return;
807    };
808    unsafe {
809        (&mut *addr).set_idx(idx, Dynamic::U8(value));
810    }
811}
812
813extern "C" fn list_str_push(addr: *mut Dynamic, value: *const Dynamic) {
814    if addr.is_null() || value.is_null() {
815        return;
816    }
817    unsafe {
818        (&mut *addr).push_dynamic((&*value).clone());
819    }
820}
821
822extern "C" fn list_str_get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
823    if addr.is_null() {
824        return any_null();
825    };
826    let Ok(idx) = usize::try_from(idx) else {
827        return any_null();
828    };
829    if let Some(value) = unsafe { (&*addr).get_idx(idx) } { alloc_dynamic(value) } else { any_null() }
830}
831
832extern "C" fn list_str_set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
833    if addr.is_null() || value.is_null() {
834        return;
835    }
836    let Ok(idx) = usize::try_from(idx) else {
837        return;
838    };
839    unsafe {
840        (&mut *addr).set_idx(idx, (&*value).clone());
841    }
842}
843
844extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
845    if addr.is_null() {
846        return any_null();
847    }
848
849    let value = unsafe { &*addr };
850    let len = value.len() as i64;
851    let start = start.clamp(0, len) as usize;
852    let mut stop = if stop.is_null() {
853        len
854    } else {
855        let raw = unsafe { &*stop };
856        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
857    };
858    if inclusive && stop < len {
859        stop += 1;
860    }
861    let stop = stop.clamp(start as i64, len) as usize;
862
863    let sliced = if value.is_str() {
864        Dynamic::from(value.as_str().chars().skip(start).take(stop.saturating_sub(start)).collect::<String>())
865    } else {
866        match value {
867            Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
868            _ => Dynamic::Null,
869        }
870    };
871    alloc_dynamic(sliced)
872}
873
874extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
875    if addr.is_null() || key.is_null() {
876        return;
877    }
878    let key: &str = unsafe { &*key }.as_str();
879    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
880}
881
882extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
883    if addr.is_null() {
884        return;
885    }
886    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
887}
888
889extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
890    alloc_dynamic(Dynamic::I64(v))
891}
892
893extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
894    alloc_dynamic(Dynamic::Bool(v))
895}
896
897extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
898    if addr.is_null() {
899        return 0;
900    }
901    unsafe {
902        let value = &*addr;
903        value.as_int().or_else(|| value.as_float().map(|value| value as i64)).unwrap_or(0)
904    }
905}
906
907extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
908    if addr.is_null() {
909        return false;
910    }
911    unsafe {
912        let value = &*addr;
913        if let Some(v) = value.as_bool() {
914            v
915        } else if let Some(v) = value.as_int() {
916            v != 0
917        } else if let Some(v) = value.as_float() {
918            v != 0.0
919        } else {
920            !value.is_null()
921        }
922    }
923}
924
925extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
926    alloc_dynamic(Dynamic::F64(v))
927}
928
929extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
930    if addr.is_null() || s.is_null() {
931        return any_null();
932    }
933    let s: &str = unsafe { &*s }.as_str();
934    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
935}
936
937extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
938    if addr.is_null() {
939        return 0.0;
940    }
941    unsafe { (&*addr).as_float().unwrap_or(0.0) }
942}
943
944extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
945    if addr.is_null() {
946        return alloc_dynamic(Dynamic::from(""));
947    }
948    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
949}
950
951extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
952    if left.is_null() {
953        if right.is_null() {
954            return any_null();
955        }
956        return alloc_dynamic(unsafe { (&*right).clone() });
957    }
958    if right.is_null() {
959        return alloc_dynamic(unsafe { (&*left).clone() });
960    }
961    let op = BinaryOp::try_from(op).unwrap();
962    if op == BinaryOp::Add {
963        let (left_value, right_value) = unsafe { (&*left, &*right) };
964        if left_value.is_str() || right_value.is_str() {
965            return alloc_dynamic(left_value.clone() + right_value.clone());
966        }
967    }
968    unsafe {
969        let expr = Expr::new(
970            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())) },
971            Span::default(),
972        );
973        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
974    }
975}
976
977extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
978    let op = BinaryOp::try_from(op).unwrap();
979    unsafe {
980        let expr = Expr::new(
981            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())) },
982            Span::default(),
983        );
984        if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
985    }
986}
987
988pub const STD: [(&str, &[Type], Type, *const u8); 5] = [
989    ("print", &[Type::Any], Type::Void, print as *const u8),
990    ("sqrt", &[Type::F64], Type::F64, sqrt as *const u8),
991    ("log", &[Type::Any], Type::Void, log_any as *const u8),
992    ("uuid", &[], Type::Any, uuid as *const u8),
993    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
994];
995
996pub const ANY: [(&str, &[Type], Type, *const u8); 66] = [
997    ("Any::null", &[], Type::Any, any_null as *const u8),
998    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
999    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
1000    ("Any::is_string", &[Type::Any], Type::Bool, any_is_string as *const u8),
1001    ("Any::is_null", &[Type::Any], Type::Bool, any_is_null as *const u8),
1002    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
1003    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
1004    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
1005    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
1006    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
1007    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
1008    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
1009    ("Any::push_bool", &[Type::Any, Type::Bool], Type::Void, list_bool_push as *const u8),
1010    ("Any::get_idx_bool", &[Type::Any, Type::I64], Type::Bool, list_bool_get_idx as *const u8),
1011    ("Any::set_idx_bool", &[Type::Any, Type::I64, Type::Bool], Type::Void, list_bool_set_idx as *const u8),
1012    ("Any::push_u8", &[Type::Any, Type::U8], Type::Void, list_u8_push as *const u8),
1013    ("Any::get_idx_u8", &[Type::Any, Type::I64], Type::U8, list_u8_get_idx as *const u8),
1014    ("Any::set_idx_u8", &[Type::Any, Type::I64, Type::U8], Type::Void, list_u8_set_idx as *const u8),
1015    ("Any::push_i8", &[Type::Any, Type::I8], Type::Void, list_i8_push as *const u8),
1016    ("Any::get_idx_i8", &[Type::Any, Type::I64], Type::I8, list_i8_get_idx as *const u8),
1017    ("Any::set_idx_i8", &[Type::Any, Type::I64, Type::I8], Type::Void, list_i8_set_idx as *const u8),
1018    ("Any::push_u16", &[Type::Any, Type::U16], Type::Void, list_u16_push as *const u8),
1019    ("Any::get_idx_u16", &[Type::Any, Type::I64], Type::U16, list_u16_get_idx as *const u8),
1020    ("Any::set_idx_u16", &[Type::Any, Type::I64, Type::U16], Type::Void, list_u16_set_idx as *const u8),
1021    ("Any::push_i16", &[Type::Any, Type::I16], Type::Void, list_i16_push as *const u8),
1022    ("Any::get_idx_i16", &[Type::Any, Type::I64], Type::I16, list_i16_get_idx as *const u8),
1023    ("Any::set_idx_i16", &[Type::Any, Type::I64, Type::I16], Type::Void, list_i16_set_idx as *const u8),
1024    ("Any::push_u32", &[Type::Any, Type::U32], Type::Void, list_u32_push as *const u8),
1025    ("Any::get_idx_u32", &[Type::Any, Type::I64], Type::U32, list_u32_get_idx as *const u8),
1026    ("Any::set_idx_u32", &[Type::Any, Type::I64, Type::U32], Type::Void, list_u32_set_idx as *const u8),
1027    ("Any::push_i32", &[Type::Any, Type::I32], Type::Void, list_i32_push as *const u8),
1028    ("Any::get_idx_i32", &[Type::Any, Type::I64], Type::I32, list_i32_get_idx as *const u8),
1029    ("Any::set_idx_i32", &[Type::Any, Type::I64, Type::I32], Type::Void, list_i32_set_idx as *const u8),
1030    ("Any::push_f32", &[Type::Any, Type::F32], Type::Void, list_f32_push as *const u8),
1031    ("Any::get_idx_f32", &[Type::Any, Type::I64], Type::F32, list_f32_get_idx as *const u8),
1032    ("Any::set_idx_f32", &[Type::Any, Type::I64, Type::F32], Type::Void, list_f32_set_idx as *const u8),
1033    ("Any::push_u64", &[Type::Any, Type::U64], Type::Void, list_u64_push as *const u8),
1034    ("Any::get_idx_u64", &[Type::Any, Type::I64], Type::U64, list_u64_get_idx as *const u8),
1035    ("Any::set_idx_u64", &[Type::Any, Type::I64, Type::U64], Type::Void, list_u64_set_idx as *const u8),
1036    ("Any::push_i64", &[Type::Any, Type::I64], Type::Void, list_i64_push as *const u8),
1037    ("Any::get_idx_i64", &[Type::Any, Type::I64], Type::I64, list_i64_get_idx as *const u8),
1038    ("Any::set_idx_i64", &[Type::Any, Type::I64, Type::I64], Type::Void, list_i64_set_idx as *const u8),
1039    ("Any::push_f64", &[Type::Any, Type::F64], Type::Void, list_f64_push as *const u8),
1040    ("Any::get_idx_f64", &[Type::Any, Type::I64], Type::F64, list_f64_get_idx as *const u8),
1041    ("Any::set_idx_f64", &[Type::Any, Type::I64, Type::F64], Type::Void, list_f64_set_idx as *const u8),
1042    ("Any::push_str", &[Type::Any, Type::Str], Type::Void, list_str_push as *const u8),
1043    ("Any::get_idx_str", &[Type::Any, Type::I64], Type::Str, list_str_get_idx as *const u8),
1044    ("Any::set_idx_str", &[Type::Any, Type::I64, Type::Str], Type::Void, list_str_set_idx as *const u8),
1045    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
1046    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
1047    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
1048    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
1049    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
1050    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
1051    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
1052    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
1053    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
1054    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
1055    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
1056    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
1057    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
1058    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
1059    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
1060    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
1061    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
1062    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
1063];
1064
1065use std::rc::Rc;
1066impl JITRunTime {
1067    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
1068        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1069        self.add_native(full_name, name, arg_tys, ret_ty)
1070    }
1071
1072    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> {
1073        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
1074        self.add_context_native(full_name, name, arg_tys, ret_ty)
1075    }
1076
1077    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1078        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1079        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1080        let sig = self.get_sig(arg_tys, ret_ty)?;
1081        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1082        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
1083        Ok(id)
1084    }
1085
1086    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
1087        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
1088        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
1089        let mut sig = self.module.make_signature();
1090        sig.params.push(AbiParam::new(crate::ptr_type()));
1091        for arg in arg_tys.iter() {
1092            sig.params.push(AbiParam::new(crate::get_type(arg)?));
1093        }
1094        if !ret_ty.is_void() {
1095            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
1096        }
1097        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
1098        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
1099        Ok(id)
1100    }
1101}