Skip to main content

vm/
native.rs

1use super::FnVariant;
2use crate::JITRunTime;
3use crate::memory::{alloc_dynamic, alloc_struct_bytes};
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::sync::{Mutex, Weak};
11
12extern "C" fn any_clone(addr: *const Dynamic) -> *const Dynamic {
13    //在堆上分配内存 复制 addr 到内存中
14    unsafe {
15        let cloned_value = (*addr).deep_clone();
16        alloc_dynamic(cloned_value)
17    }
18}
19
20extern "C" fn any_null() -> *const Dynamic {
21    //在堆上分配内存 复制 addr 到内存中
22    alloc_dynamic(Dynamic::Null)
23}
24
25extern "C" fn print(addr: *const Dynamic) {
26    if !addr.is_null() {
27        unsafe {
28            println!("{}", (*addr).to_string());
29        }
30    }
31}
32
33extern "C" fn log_any(addr: *const Dynamic) {
34    if addr.is_null() {
35        log::info!("{:?}", Dynamic::Null);
36    } else {
37        log::info!("{:?}", unsafe { &*addr });
38    }
39}
40
41extern "C" fn any_is_map(addr: *const Dynamic) -> bool {
42    !addr.is_null() && unsafe { (*addr).is_map() }
43}
44
45extern "C" fn any_is_list(addr: *const Dynamic) -> bool {
46    !addr.is_null() && unsafe { (*addr).is_list() }
47}
48
49extern "C" fn random(start: *const Dynamic, stop: *const Dynamic) -> *const Dynamic {
50    if !start.is_null() && !stop.is_null() {
51        let mut rng = rand::rng();
52        unsafe {
53            if (&*start).is_int() {
54                let start = (*start).as_int().unwrap_or(0);
55                let stop = (*stop).as_int().unwrap_or(100);
56                return alloc_dynamic(Dynamic::I64(rng.random_range(start..stop)));
57            } else if (&*start).is_f32() || (&*start).is_f64() {
58                let start = (*start).as_float().unwrap_or(0.0);
59                let stop = (*stop).as_float().unwrap_or(1.0);
60                return alloc_dynamic(Dynamic::F64(rng.random_range(start..stop)));
61            }
62        }
63    }
64    alloc_dynamic(Dynamic::Null)
65}
66
67extern "C" fn uuid() -> *const Dynamic {
68    alloc_dynamic(uuid::Uuid::new_v4().to_string().into())
69}
70
71pub(crate) extern "C" fn struct_alloc(size: i64) -> *mut u8 {
72    let size = size.max(0) as usize;
73    let ptr = alloc_struct_bytes(size);
74    unsafe {
75        std::ptr::write_bytes(ptr, 0, size);
76    }
77    ptr
78}
79
80pub(crate) extern "C" fn struct_from_ptr(addr: i64, ty: i64) -> *const Dynamic {
81    let ty = unsafe { (&*(ty as *const Type)).clone() };
82    alloc_dynamic(Dynamic::Struct { addr: addr as usize, ty })
83}
84
85pub(crate) extern "C" fn import_with_vm(context: *const Weak<Mutex<JITRunTime>>, addr: *const Dynamic, path: *const Dynamic) -> bool {
86    if addr.is_null() || path.is_null() {
87        return false;
88    }
89    super::with_vm_context(context, |vm| vm.import(unsafe { &*addr }.as_str(), unsafe { &*path }.as_str())).map_err(|e| println!("import {:?}", e)).is_ok()
90}
91
92extern "C" fn any_len(addr: *const Dynamic) -> i64 {
93    if addr.is_null() { 0 } else { unsafe { (&*addr).len() as i64 } }
94}
95
96extern "C" fn any_keys(addr: *const Dynamic) -> *const Dynamic {
97    if addr.is_null() {
98        return alloc_dynamic(Dynamic::list(Vec::new()));
99    }
100    let keys = match unsafe { &*addr } {
101        Dynamic::Map(map) => map.read().unwrap().keys().map(|key| Dynamic::from(key.as_str())).collect(),
102        _ => Vec::new(),
103    };
104    alloc_dynamic(Dynamic::list(keys))
105}
106
107extern "C" fn any_iter(addr: *const Dynamic) -> *const Dynamic {
108    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).clone().into_iter() }) }
109}
110
111extern "C" fn any_next(addr: *mut Dynamic) -> *const Dynamic {
112    alloc_dynamic(unsafe { (*addr).next().unwrap_or(Dynamic::Null) })
113}
114
115extern "C" fn any_push(addr: *mut Dynamic, value: *mut Dynamic) {
116    if !addr.is_null() && !value.is_null() {
117        unsafe {
118            (&mut *addr).push((&*value).clone());
119        }
120    }
121}
122
123extern "C" fn any_pop(addr: *mut Dynamic) -> *const Dynamic {
124    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).pop().unwrap_or(Dynamic::Null) }) }
125}
126
127extern "C" fn get_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
128    if addr.is_null() || key.is_null() {
129        any_null()
130    } else {
131        let key: &str = unsafe { &*key }.as_str();
132        alloc_dynamic(unsafe { (*addr).get_dynamic(key).unwrap_or(Dynamic::Null) })
133    }
134}
135
136extern "C" fn del_key(addr: *const Dynamic, key: *const Dynamic) -> *const Dynamic {
137    if addr.is_null() || key.is_null() {
138        any_null()
139    } else {
140        let key: &str = unsafe { &*key }.as_str();
141        alloc_dynamic(unsafe { (*addr).remove_dynamic(key).unwrap_or(Dynamic::Null) })
142    }
143}
144
145extern "C" fn contains(addr: *const Dynamic, key: *const Dynamic) -> bool {
146    if addr.is_null() || key.is_null() {
147        false
148    } else {
149        let key: &str = unsafe { &*key }.as_str();
150        unsafe { (*addr).contains(key) }
151    }
152}
153
154extern "C" fn starts_with(addr: *const Dynamic, prefix: *const Dynamic) -> bool {
155    if addr.is_null() || prefix.is_null() {
156        false
157    } else {
158        let prefix: &str = unsafe { &*prefix }.as_str();
159        unsafe { (*addr).starts_with(prefix) }
160    }
161}
162
163extern "C" fn get_idx(addr: *const Dynamic, idx: i64) -> *const Dynamic {
164    if addr.is_null() { any_null() } else { alloc_dynamic(unsafe { (*addr).get_idx(idx as usize).unwrap_or(Dynamic::Null) }) }
165}
166
167extern "C" fn slice(addr: *const Dynamic, start: i64, stop: *const Dynamic, inclusive: bool) -> *const Dynamic {
168    if addr.is_null() {
169        return any_null();
170    }
171
172    let value = unsafe { &*addr };
173    let len = value.len() as i64;
174    let start = start.clamp(0, len) as usize;
175    let mut stop = if stop.is_null() {
176        len
177    } else {
178        let raw = unsafe { &*stop };
179        if raw.is_null() { len } else { raw.as_int().unwrap_or(len) }
180    };
181    if inclusive && stop < len {
182        stop += 1;
183    }
184    let stop = stop.clamp(start as i64, len) as usize;
185
186    let sliced = match value {
187        Dynamic::String(text) => Dynamic::from(text.chars().skip(start).take(stop.saturating_sub(start)).collect::<String>()),
188        Dynamic::List(list) => Dynamic::list(list.read().unwrap()[start..stop].to_vec()),
189        _ => Dynamic::Null,
190    };
191    alloc_dynamic(sliced)
192}
193
194extern "C" fn set_key(addr: *mut Dynamic, key: *const Dynamic, value: *const Dynamic) {
195    if addr.is_null() || key.is_null() {
196        return;
197    }
198    let key: &str = unsafe { &*key }.as_str();
199    unsafe { (&mut *addr).set_dynamic(key.into(), (&*value).clone()) }
200}
201
202extern "C" fn set_idx(addr: *mut Dynamic, idx: i64, value: *const Dynamic) {
203    if addr.is_null() {
204        return;
205    }
206    unsafe { (&mut *addr).set_idx(idx as usize, (&*value).clone()) }
207}
208
209extern "C" fn any_from_i64(v: i64) -> *const Dynamic {
210    alloc_dynamic(Dynamic::I64(v))
211}
212
213extern "C" fn any_from_bool(v: bool) -> *const Dynamic {
214    alloc_dynamic(Dynamic::Bool(v))
215}
216
217extern "C" fn any_to_i64(addr: *const Dynamic) -> i64 {
218    if addr.is_null() {
219        return 0;
220    }
221    unsafe { (&*addr).as_int().unwrap_or(0) }
222}
223
224extern "C" fn any_to_bool(addr: *const Dynamic) -> bool {
225    if addr.is_null() {
226        return false;
227    }
228    unsafe {
229        let value = &*addr;
230        if let Some(v) = value.as_bool() {
231            v
232        } else if let Some(v) = value.as_int() {
233            v != 0
234        } else if let Some(v) = value.as_float() {
235            v != 0.0
236        } else {
237            !value.is_null()
238        }
239    }
240}
241
242extern "C" fn any_from_f64(v: f64) -> *const Dynamic {
243    alloc_dynamic(Dynamic::F64(v))
244}
245
246extern "C" fn any_split(addr: *mut Dynamic, s: *const Dynamic) -> *const Dynamic {
247    if addr.is_null() || s.is_null() {
248        return any_null();
249    }
250    let s: &str = unsafe { &*s }.as_str();
251    alloc_dynamic(unsafe { (&*addr).clone() }.split(s))
252}
253
254extern "C" fn any_to_f64(addr: *const Dynamic) -> f64 {
255    if addr.is_null() {
256        return 0.0;
257    }
258    unsafe { (&*addr).as_float().unwrap_or(0.0) }
259}
260
261extern "C" fn any_to_string(addr: *const Dynamic) -> *const Dynamic {
262    if addr.is_null() {
263        return alloc_dynamic(Dynamic::from(""));
264    }
265    alloc_dynamic(Dynamic::from(unsafe { &*addr }.to_string()))
266}
267
268extern "C" fn any_binary(left: *const Dynamic, op: i32, right: *const Dynamic) -> *const Dynamic {
269    if left.is_null() {
270        if right.is_null() {
271            return any_null();
272        }
273        return alloc_dynamic(unsafe { (&*right).clone() });
274    }
275    if right.is_null() {
276        return alloc_dynamic(unsafe { (&*left).clone() });
277    }
278    let op = BinaryOp::try_from(op).unwrap();
279    unsafe {
280        let expr = Expr::new(
281            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())) },
282            Span::default(),
283        );
284        alloc_dynamic(expr.compact().unwrap_or(Dynamic::Null))
285    }
286}
287
288extern "C" fn any_logic(left: *const Dynamic, op: i32, right: *const Dynamic) -> i32 {
289    let op = BinaryOp::try_from(op).unwrap();
290    unsafe {
291        let expr = Expr::new(
292            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())) },
293            Span::default(),
294        );
295        if expr.compact().and_then(|r| r.as_bool()).unwrap_or(false) { 1 } else { 0 }
296    }
297}
298
299pub const STD: [(&str, &[Type], Type, *const u8); 4] = [
300    ("print", &[Type::Any], Type::Void, print as *const u8),
301    ("log", &[Type::Any], Type::Void, log_any as *const u8),
302    ("uuid", &[], Type::Any, uuid as *const u8),
303    ("rand", &[Type::Any, Type::Any], Type::Any, random as *const u8),
304];
305
306pub const ANY: [(&str, &[Type], Type, *const u8); 28] = [
307    ("Any::null", &[], Type::Any, any_null as *const u8),
308    ("Any::is_map", &[Type::Any], Type::Bool, any_is_map as *const u8),
309    ("Any::is_list", &[Type::Any], Type::Bool, any_is_list as *const u8),
310    ("Any::clone", &[Type::Any], Type::Any, any_clone as *const u8),
311    ("Any::len", &[Type::Any], Type::I32, any_len as *const u8),
312    ("Any::keys", &[Type::Any], Type::Any, any_keys as *const u8),
313    ("Any::split", &[Type::Any, Type::Any], Type::Any, any_split as *const u8),
314    ("Any::push", &[Type::Any, Type::Any], Type::Void, any_push as *const u8),
315    ("Any::pop", &[Type::Any], Type::Any, any_pop as *const u8),
316    ("Any::get_idx", &[Type::Any, Type::I64], Type::Any, get_idx as *const u8),
317    ("Any::slice", &[Type::Any, Type::I64, Type::Any, Type::Bool], Type::Any, slice as *const u8),
318    ("Any::contains", &[Type::Any, Type::Any], Type::Bool, contains as *const u8),
319    ("Any::starts_with", &[Type::Any, Type::Any], Type::Bool, starts_with as *const u8),
320    ("Any::get_key", &[Type::Any, Type::Any], Type::Any, get_key as *const u8),
321    ("Any::del_key", &[Type::Any, Type::Any], Type::Any, del_key as *const u8),
322    ("Any::set_idx", &[Type::Any, Type::I64, Type::Any], Type::Void, set_idx as *const u8),
323    ("Any::set_key", &[Type::Any, Type::Any, Type::Any], Type::Void, set_key as *const u8),
324    ("Any::from_i64", &[Type::I64], Type::Any, any_from_i64 as *const u8),
325    ("Any::from_bool", &[Type::Bool], Type::Any, any_from_bool as *const u8),
326    ("Any::to_i64", &[Type::Any], Type::I64, any_to_i64 as *const u8),
327    ("Any::to_bool", &[Type::Any], Type::Bool, any_to_bool as *const u8),
328    ("Any::from_f64", &[Type::F64], Type::Any, any_from_f64 as *const u8),
329    ("Any::to_f64", &[Type::Any], Type::F64, any_to_f64 as *const u8),
330    ("Any::to_string", &[Type::Any], Type::Str, any_to_string as *const u8),
331    ("Any::binary", &[Type::Any, Type::I32, Type::Any], Type::Any, any_binary as *const u8),
332    ("Any::logic", &[Type::Any, Type::I32, Type::Any], Type::Bool, any_logic as *const u8),
333    ("Any::iter", &[Type::Any], Type::Any, any_iter as *const u8),
334    ("Any::next", &[Type::Any], Type::Any, any_next as *const u8),
335];
336
337use std::rc::Rc;
338impl JITRunTime {
339    pub fn add_native_ptr(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type, fn_ptr: *const u8) -> Result<u32> {
340        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
341        self.add_native(full_name, name, arg_tys, ret_ty)
342    }
343
344    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> {
345        self.native_symbols.write().unwrap().insert(full_name.to_string(), fn_ptr as usize);
346        self.add_context_native(full_name, name, arg_tys, ret_ty)
347    }
348
349    pub fn add_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
350        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
351        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
352        let sig = self.get_sig(arg_tys, ret_ty)?;
353        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
354        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: None });
355        Ok(id)
356    }
357
358    pub(crate) fn add_context_native(&mut self, full_name: &str, name: &str, arg_tys: &[Type], ret_ty: Type) -> Result<u32> {
359        let fn_ty = Type::Fn { tys: arg_tys.to_vec(), ret: Rc::new(ret_ty.clone()) };
360        let id = self.compiler.add_symbol(name, compiler::Symbol::Native(fn_ty.clone()));
361        let mut sig = self.module.make_signature();
362        sig.params.push(AbiParam::new(crate::ptr_type()));
363        for arg in arg_tys.iter() {
364            sig.params.push(AbiParam::new(crate::get_type(arg)?));
365        }
366        if !ret_ty.is_void() {
367            sig.returns.push(AbiParam::new(crate::get_type(&ret_ty)?));
368        }
369        let fn_id = self.module.declare_function(full_name, Linkage::Import, &sig)?;
370        self.fns.insert(id, FnVariant::Native { ty: fn_ty, fn_id, context: Some(self.owner_context_ptr()) });
371        Ok(id)
372    }
373}