Skip to main content

vm/
native.rs

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