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