lust/bytecode/
value.rs

1use crate::ast::Type;
2use crate::jit;
3use crate::number::{
4    float_from_int, float_is_nan, float_to_hash_bits, int_from_float, int_from_usize, LustFloat,
5    LustInt,
6};
7use crate::vm::{pop_vm_ptr, push_vm_ptr, VM};
8use alloc::{
9    borrow::ToOwned,
10    format,
11    rc::{Rc, Weak},
12    string::{String, ToString},
13    vec,
14    vec::Vec,
15};
16use core::cell::RefCell;
17use core::fmt;
18use core::hash::{Hash, Hasher};
19use core::{ptr, slice, str};
20use hashbrown::HashMap;
21#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
22pub struct TaskHandle(pub u64);
23impl TaskHandle {
24    pub fn id(&self) -> u64 {
25        self.0
26    }
27}
28
29#[derive(Clone, Debug)]
30pub enum ValueKey {
31    Int(LustInt),
32    Float(LustFloat),
33    String(Rc<String>),
34    Bool(bool),
35}
36
37impl ValueKey {
38    pub fn from_value(value: &Value) -> Option<Self> {
39        match value {
40            Value::Int(i) => Some(ValueKey::Int(*i)),
41            Value::Float(f) => Some(ValueKey::Float(*f)),
42            Value::String(s) => Some(ValueKey::String(s.clone())),
43            Value::Bool(b) => Some(ValueKey::Bool(*b)),
44            _ => None,
45        }
46    }
47
48    pub fn string<S>(value: S) -> Self
49    where
50        S: Into<String>,
51    {
52        ValueKey::String(Rc::new(value.into()))
53    }
54
55    pub fn to_value(&self) -> Value {
56        match self {
57            ValueKey::Int(i) => Value::Int(*i),
58            ValueKey::Float(f) => Value::Float(*f),
59            ValueKey::String(s) => Value::String(s.clone()),
60            ValueKey::Bool(b) => Value::Bool(*b),
61        }
62    }
63}
64
65impl PartialEq for ValueKey {
66    fn eq(&self, other: &Self) -> bool {
67        match (self, other) {
68            (ValueKey::Int(a), ValueKey::Int(b)) => a == b,
69            (ValueKey::Float(a), ValueKey::Float(b)) => {
70                if float_is_nan(*a) && float_is_nan(*b) {
71                    true
72                } else {
73                    a == b
74                }
75            }
76
77            (ValueKey::String(a), ValueKey::String(b)) => a == b,
78            (ValueKey::Bool(a), ValueKey::Bool(b)) => a == b,
79            _ => false,
80        }
81    }
82}
83
84impl Eq for ValueKey {}
85impl Hash for ValueKey {
86    fn hash<H: Hasher>(&self, state: &mut H) {
87        match self {
88            ValueKey::Int(i) => {
89                0u8.hash(state);
90                i.hash(state);
91            }
92
93            ValueKey::Float(f) => {
94                1u8.hash(state);
95                if float_is_nan(*f) {
96                    u64::MAX.hash(state);
97                } else {
98                    float_to_hash_bits(*f).hash(state);
99                }
100            }
101
102            ValueKey::String(s) => {
103                2u8.hash(state);
104                s.hash(state);
105            }
106
107            ValueKey::Bool(b) => {
108                3u8.hash(state);
109                b.hash(state);
110            }
111        }
112    }
113}
114
115impl fmt::Display for ValueKey {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        match self {
118            ValueKey::Int(i) => write!(f, "{}", i),
119            ValueKey::Float(fl) => write!(f, "{}", fl),
120            ValueKey::String(s) => write!(f, "{}", s),
121            ValueKey::Bool(b) => write!(f, "{}", b),
122        }
123    }
124}
125
126impl From<LustInt> for ValueKey {
127    fn from(value: LustInt) -> Self {
128        ValueKey::Int(value)
129    }
130}
131
132impl From<LustFloat> for ValueKey {
133    fn from(value: LustFloat) -> Self {
134        ValueKey::Float(value)
135    }
136}
137
138impl From<bool> for ValueKey {
139    fn from(value: bool) -> Self {
140        ValueKey::Bool(value)
141    }
142}
143
144impl From<String> for ValueKey {
145    fn from(value: String) -> Self {
146        ValueKey::String(Rc::new(value))
147    }
148}
149
150impl From<&str> for ValueKey {
151    fn from(value: &str) -> Self {
152        ValueKey::String(Rc::new(value.to_owned()))
153    }
154}
155
156impl From<Rc<String>> for ValueKey {
157    fn from(value: Rc<String>) -> Self {
158        ValueKey::String(value)
159    }
160}
161
162#[repr(u8)]
163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum ValueTag {
165    Nil,
166    Bool,
167    Int,
168    Float,
169    String,
170    Array,
171    Tuple,
172    Map,
173    Struct,
174    Enum,
175    Function,
176    NativeFunction,
177    Closure,
178    Iterator,
179    Task,
180}
181
182impl ValueTag {
183    #[inline]
184    pub const fn as_u8(self) -> u8 {
185        self as u8
186    }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
190pub enum FieldStorage {
191    Strong,
192    Weak,
193}
194
195#[derive(Debug)]
196pub struct StructLayout {
197    name: String,
198    field_names: Vec<Rc<String>>,
199    field_lookup_ptr: HashMap<usize, usize>,
200    field_lookup_str: HashMap<String, usize>,
201    field_storage: Vec<FieldStorage>,
202    field_types: Vec<Type>,
203    weak_targets: Vec<Option<Type>>,
204}
205
206impl StructLayout {
207    pub fn new(
208        name: String,
209        field_names: Vec<Rc<String>>,
210        field_storage: Vec<FieldStorage>,
211        field_types: Vec<Type>,
212        weak_targets: Vec<Option<Type>>,
213    ) -> Self {
214        debug_assert_eq!(
215            field_names.len(),
216            field_storage.len(),
217            "StructLayout::new expects field names and storage metadata to align"
218        );
219        debug_assert_eq!(
220            field_names.len(),
221            field_types.len(),
222            "StructLayout::new expects field names and type metadata to align"
223        );
224        debug_assert_eq!(
225            field_names.len(),
226            weak_targets.len(),
227            "StructLayout::new expects field names and weak target metadata to align"
228        );
229        let mut field_lookup_ptr = HashMap::with_capacity(field_names.len());
230        let mut field_lookup_str = HashMap::with_capacity(field_names.len());
231        for (index, field_name_rc) in field_names.iter().enumerate() {
232            let ptr = Rc::as_ptr(field_name_rc) as usize;
233            field_lookup_ptr.insert(ptr, index);
234            field_lookup_str.insert((**field_name_rc).clone(), index);
235        }
236
237        Self {
238            name,
239            field_names,
240            field_lookup_ptr,
241            field_lookup_str,
242            field_storage,
243            field_types,
244            weak_targets,
245        }
246    }
247
248    #[inline]
249    pub fn name(&self) -> &str {
250        &self.name
251    }
252
253    #[inline]
254    pub fn field_names(&self) -> &[Rc<String>] {
255        &self.field_names
256    }
257
258    #[inline]
259    pub fn index_of_rc(&self, key: &Rc<String>) -> Option<usize> {
260        let ptr = Rc::as_ptr(key) as usize;
261        self.field_lookup_ptr
262            .get(&ptr)
263            .copied()
264            .or_else(|| self.field_lookup_str.get(key.as_str()).copied())
265    }
266
267    #[inline]
268    pub fn index_of_str(&self, key: &str) -> Option<usize> {
269        self.field_lookup_str.get(key).copied()
270    }
271
272    #[inline]
273    pub fn field_storage(&self, index: usize) -> FieldStorage {
274        self.field_storage[index]
275    }
276
277    #[inline]
278    pub fn field_type(&self, index: usize) -> &Type {
279        &self.field_types[index]
280    }
281
282    #[inline]
283    pub fn weak_target(&self, index: usize) -> Option<&Type> {
284        self.weak_targets[index].as_ref()
285    }
286
287    #[inline]
288    pub fn is_weak(&self, index: usize) -> bool {
289        matches!(self.field_storage(index), FieldStorage::Weak)
290    }
291
292    pub fn canonicalize_field_value(&self, index: usize, value: Value) -> Result<Value, String> {
293        match self.field_storage(index) {
294            FieldStorage::Strong => Ok(value),
295            FieldStorage::Weak => self.canonicalize_weak_field(index, value),
296        }
297    }
298
299    pub fn materialize_field_value(&self, index: usize, value: Value) -> Value {
300        match self.field_storage(index) {
301            FieldStorage::Strong => value,
302            FieldStorage::Weak => self.materialize_weak_field(value),
303        }
304    }
305
306    fn canonicalize_weak_field(&self, index: usize, value: Value) -> Result<Value, String> {
307        let field_name = self.field_names[index].as_str();
308        match value {
309            Value::Enum {
310                enum_name,
311                variant,
312                values,
313            } if enum_name == "Option" => {
314                if variant == "Some" {
315                    if let Some(inner_values) = values {
316                        if let Some(inner) = inner_values.get(0) {
317                            let coerced = self.to_weak_struct(field_name, inner.clone())?;
318                            Ok(Value::enum_variant("Option", "Some", vec![coerced]))
319                        } else {
320                            Ok(Value::enum_unit("Option", "None"))
321                        }
322                    } else {
323                        Ok(Value::enum_unit("Option", "None"))
324                    }
325                } else if variant == "None" {
326                    Ok(Value::enum_unit("Option", "None"))
327                } else {
328                    Err(format!(
329                        "Struct '{}' field '{}' uses 'ref' and must store Option values; received variant '{}'",
330                        self.name, field_name, variant
331                    ))
332                }
333            }
334
335            Value::Nil => Ok(Value::enum_unit("Option", "None")),
336            other => {
337                let coerced = self.to_weak_struct(field_name, other)?;
338                Ok(Value::enum_variant("Option", "Some", vec![coerced]))
339            }
340        }
341    }
342
343    fn materialize_weak_field(&self, value: Value) -> Value {
344        match value {
345            Value::Enum {
346                enum_name,
347                variant,
348                values,
349            } if enum_name == "Option" => {
350                if variant == "Some" {
351                    if let Some(inner_values) = values {
352                        if let Some(inner) = inner_values.get(0) {
353                            match inner {
354                                Value::WeakStruct(ref weak) => {
355                                    if let Some(upgraded) = weak.upgrade() {
356                                        Value::enum_variant("Option", "Some", vec![upgraded])
357                                    } else {
358                                        Value::enum_unit("Option", "None")
359                                    }
360                                }
361
362                                _ => Value::enum_variant("Option", "Some", vec![inner.clone()]),
363                            }
364                        } else {
365                            Value::enum_unit("Option", "None")
366                        }
367                    } else {
368                        Value::enum_unit("Option", "None")
369                    }
370                } else {
371                    Value::enum_unit("Option", "None")
372                }
373            }
374
375            Value::Nil => Value::enum_unit("Option", "None"),
376            other => Value::enum_variant("Option", "Some", vec![other]),
377        }
378    }
379
380    fn to_weak_struct(&self, field_name: &str, value: Value) -> Result<Value, String> {
381        match value {
382            Value::Struct {
383                name,
384                layout,
385                fields,
386            } => Ok(Value::WeakStruct(WeakStructRef::new(name, layout, &fields))),
387            Value::WeakStruct(_) => Ok(value),
388            other => {
389                let ty = other.type_of();
390                Err(format!(
391                    "Struct '{}' field '{}' expects a struct reference but received value of type '{:?}'",
392                    self.name, field_name, ty
393                ))
394            }
395        }
396    }
397}
398
399#[repr(C, u8)]
400#[derive(Clone)]
401pub enum Value {
402    Nil,
403    Bool(bool),
404    Int(LustInt),
405    Float(LustFloat),
406    String(Rc<String>),
407    Array(Rc<RefCell<Vec<Value>>>),
408    Tuple(Rc<Vec<Value>>),
409    Map(Rc<RefCell<HashMap<ValueKey, Value>>>),
410    Struct {
411        name: String,
412        layout: Rc<StructLayout>,
413        fields: Rc<RefCell<Vec<Value>>>,
414    },
415    WeakStruct(WeakStructRef),
416    Enum {
417        enum_name: String,
418        variant: String,
419        values: Option<Rc<Vec<Value>>>,
420    },
421    Function(usize),
422    NativeFunction(NativeFn),
423    Closure {
424        function_idx: usize,
425        upvalues: Rc<Vec<Upvalue>>,
426    },
427    Iterator(Rc<RefCell<IteratorState>>),
428    Task(TaskHandle),
429}
430
431#[derive(Debug, Clone)]
432pub struct WeakStructRef {
433    name: String,
434    layout: Rc<StructLayout>,
435    fields: Weak<RefCell<Vec<Value>>>,
436}
437
438impl WeakStructRef {
439    pub fn new(name: String, layout: Rc<StructLayout>, fields: &Rc<RefCell<Vec<Value>>>) -> Self {
440        Self {
441            name,
442            layout,
443            fields: Rc::downgrade(fields),
444        }
445    }
446
447    pub fn upgrade(&self) -> Option<Value> {
448        self.fields.upgrade().map(|fields| Value::Struct {
449            name: self.name.clone(),
450            layout: self.layout.clone(),
451            fields,
452        })
453    }
454
455    pub fn struct_name(&self) -> &str {
456        &self.name
457    }
458}
459
460#[derive(Clone)]
461pub enum IteratorState {
462    Array {
463        items: Vec<Value>,
464        index: usize,
465    },
466    MapPairs {
467        items: Vec<(ValueKey, Value)>,
468        index: usize,
469    },
470}
471
472#[derive(Clone)]
473pub struct Upvalue {
474    value: Rc<RefCell<Value>>,
475}
476
477impl Upvalue {
478    pub fn new(value: Value) -> Self {
479        Self {
480            value: Rc::new(RefCell::new(value)),
481        }
482    }
483
484    pub fn get(&self) -> Value {
485        self.value.borrow().clone()
486    }
487
488    pub fn set(&self, value: Value) {
489        *self.value.borrow_mut() = value;
490    }
491}
492
493impl fmt::Debug for Upvalue {
494    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495        write!(f, "Upvalue({:?})", self.value.borrow())
496    }
497}
498
499#[derive(Debug, Clone)]
500pub enum NativeCallResult {
501    Return(Value),
502    Yield(Value),
503    Stop(Value),
504}
505
506impl From<Value> for NativeCallResult {
507    fn from(value: Value) -> Self {
508        NativeCallResult::Return(value)
509    }
510}
511
512pub type NativeFn = Rc<dyn Fn(&[Value]) -> Result<NativeCallResult, String>>;
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
514pub enum ValueType {
515    Nil,
516    Bool,
517    Int,
518    Float,
519    String,
520    Array,
521    Tuple,
522    Map,
523    Struct,
524    Enum,
525    Function,
526    NativeFunction,
527    Closure,
528    Iterator,
529    Task,
530}
531
532impl Value {
533    #[inline]
534    pub fn tag(&self) -> ValueTag {
535        match self {
536            Value::Nil => ValueTag::Nil,
537            Value::Bool(_) => ValueTag::Bool,
538            Value::Int(_) => ValueTag::Int,
539            Value::Float(_) => ValueTag::Float,
540            Value::String(_) => ValueTag::String,
541            Value::Array(_) => ValueTag::Array,
542            Value::Tuple(_) => ValueTag::Tuple,
543            Value::Map(_) => ValueTag::Map,
544            Value::Struct { .. } | Value::WeakStruct(_) => ValueTag::Struct,
545            Value::Enum { .. } => ValueTag::Enum,
546            Value::Function(_) => ValueTag::Function,
547            Value::NativeFunction(_) => ValueTag::NativeFunction,
548            Value::Closure { .. } => ValueTag::Closure,
549            Value::Iterator(_) => ValueTag::Iterator,
550            Value::Task(_) => ValueTag::Task,
551        }
552    }
553
554    pub fn type_of(&self) -> ValueType {
555        match self {
556            Value::Nil => ValueType::Nil,
557            Value::Bool(_) => ValueType::Bool,
558            Value::Int(_) => ValueType::Int,
559            Value::Float(_) => ValueType::Float,
560            Value::String(_) => ValueType::String,
561            Value::Array(_) => ValueType::Array,
562            Value::Tuple(_) => ValueType::Tuple,
563            Value::Map(_) => ValueType::Map,
564            Value::Struct { .. } | Value::WeakStruct(_) => ValueType::Struct,
565            Value::Enum { .. } => ValueType::Enum,
566            Value::Function(_) => ValueType::Function,
567            Value::NativeFunction(_) => ValueType::NativeFunction,
568            Value::Closure { .. } => ValueType::Closure,
569            Value::Iterator(_) => ValueType::Iterator,
570            Value::Task(_) => ValueType::Task,
571        }
572    }
573
574    pub fn is_truthy(&self) -> bool {
575        match self {
576            Value::Nil => false,
577            Value::Bool(false) => false,
578            Value::Enum {
579                enum_name, variant, ..
580            } if enum_name == "Option" && variant == "None" => false,
581            _ => true,
582        }
583    }
584
585    pub fn to_bool(&self) -> bool {
586        self.is_truthy()
587    }
588
589    pub fn as_int(&self) -> Option<LustInt> {
590        match self {
591            Value::Int(i) => Some(*i),
592            Value::Float(f) => Some(int_from_float(*f)),
593            _ => None,
594        }
595    }
596
597    pub fn as_float(&self) -> Option<LustFloat> {
598        match self {
599            Value::Float(f) => Some(*f),
600            Value::Int(i) => Some(float_from_int(*i)),
601            _ => None,
602        }
603    }
604
605    pub fn as_string(&self) -> Option<&str> {
606        match self {
607            Value::String(s) => Some(s.as_str()),
608            _ => None,
609        }
610    }
611
612    pub fn as_string_rc(&self) -> Option<Rc<String>> {
613        match self {
614            Value::String(s) => Some(s.clone()),
615            _ => None,
616        }
617    }
618
619    pub fn as_task_handle(&self) -> Option<TaskHandle> {
620        match self {
621            Value::Task(handle) => Some(*handle),
622            _ => None,
623        }
624    }
625
626    pub fn as_array(&self) -> Option<Vec<Value>> {
627        match self {
628            Value::Array(arr) => Some(arr.borrow().clone()),
629            _ => None,
630        }
631    }
632
633    pub fn array_len(&self) -> Option<usize> {
634        match self {
635            Value::Array(arr) => Some(arr.borrow().len()),
636            _ => None,
637        }
638    }
639
640    pub fn array_get(&self, index: usize) -> Option<Value> {
641        match self {
642            Value::Array(arr) => arr.borrow().get(index).cloned(),
643            _ => None,
644        }
645    }
646
647    pub fn array_push(&self, value: Value) -> Result<(), String> {
648        match self {
649            Value::Array(arr) => {
650                arr.borrow_mut().push(value);
651                Ok(())
652            }
653
654            _ => Err("Cannot push to non-array".to_string()),
655        }
656    }
657
658    pub fn array_pop(&self) -> Result<Option<Value>, String> {
659        match self {
660            Value::Array(arr) => Ok(arr.borrow_mut().pop()),
661            _ => Err("Cannot pop from non-array".to_string()),
662        }
663    }
664
665    pub fn as_map(&self) -> Option<HashMap<ValueKey, Value>> {
666        match self {
667            Value::Map(map) => Some(map.borrow().clone()),
668            _ => None,
669        }
670    }
671
672    pub fn map_get(&self, key: &ValueKey) -> Option<Value> {
673        match self {
674            Value::Map(map) => map.borrow().get(key).cloned(),
675            _ => None,
676        }
677    }
678
679    pub fn map_set(&self, key: ValueKey, value: Value) -> Result<(), String> {
680        match self {
681            Value::Map(map) => {
682                map.borrow_mut().insert(key, value);
683                Ok(())
684            }
685
686            _ => Err("Cannot set key on non-map".to_string()),
687        }
688    }
689
690    pub fn map_has(&self, key: &ValueKey) -> Option<bool> {
691        match self {
692            Value::Map(map) => Some(map.borrow().contains_key(key)),
693            _ => None,
694        }
695    }
696
697    pub fn map_delete(&self, key: &ValueKey) -> Result<Option<Value>, String> {
698        match self {
699            Value::Map(map) => Ok(map.borrow_mut().remove(key)),
700            _ => Err("Cannot delete key from non-map".to_string()),
701        }
702    }
703
704    pub fn map_len(&self) -> Option<usize> {
705        match self {
706            Value::Map(map) => Some(map.borrow().len()),
707            _ => None,
708        }
709    }
710
711    pub fn string(s: impl Into<String>) -> Self {
712        Value::String(Rc::new(s.into()))
713    }
714
715    pub fn array(values: Vec<Value>) -> Self {
716        Value::Array(Rc::new(RefCell::new(values)))
717    }
718
719    pub fn tuple(values: Vec<Value>) -> Self {
720        Value::Tuple(Rc::new(values))
721    }
722
723    pub fn tuple_len(&self) -> Option<usize> {
724        match self {
725            Value::Tuple(values) => Some(values.len()),
726            _ => None,
727        }
728    }
729
730    pub fn tuple_get(&self, index: usize) -> Option<Value> {
731        match self {
732            Value::Tuple(values) => values.get(index).cloned(),
733            _ => None,
734        }
735    }
736
737    pub fn map(entries: HashMap<ValueKey, Value>) -> Self {
738        Value::Map(Rc::new(RefCell::new(entries)))
739    }
740
741    pub fn task(handle: TaskHandle) -> Self {
742        Value::Task(handle)
743    }
744
745    pub fn struct_get_field_rc(&self, field: &Rc<String>) -> Option<Value> {
746        match self {
747            Value::Struct { layout, fields, .. } => layout
748                .index_of_rc(field)
749                .or_else(|| layout.index_of_str(field.as_str()))
750                .or_else(|| {
751                    layout
752                        .field_names()
753                        .iter()
754                        .position(|name| name.as_str() == field.as_str())
755                })
756                .and_then(|idx| {
757                    fields
758                        .borrow()
759                        .get(idx)
760                        .cloned()
761                        .map(|value| layout.materialize_field_value(idx, value))
762                }),
763            _ => None,
764        }
765    }
766
767    pub fn struct_get_field(&self, field: &str) -> Option<Value> {
768        match self {
769            Value::Struct { layout, fields, .. } => layout.index_of_str(field).and_then(|idx| {
770                fields
771                    .borrow()
772                    .get(idx)
773                    .cloned()
774                    .map(|value| layout.materialize_field_value(idx, value))
775            }),
776            _ => None,
777        }
778    }
779
780    pub fn struct_get_field_indexed(&self, index: usize) -> Option<Value> {
781        match self {
782            Value::Struct { layout, fields, .. } => fields
783                .borrow()
784                .get(index)
785                .cloned()
786                .map(|value| layout.materialize_field_value(index, value)),
787            _ => None,
788        }
789    }
790
791    pub fn struct_set_field_rc(&self, field: &Rc<String>, value: Value) -> Result<(), String> {
792        match self {
793            Value::Struct { layout, .. } => {
794                if let Some(index) = layout
795                    .index_of_rc(field)
796                    .or_else(|| layout.index_of_str(field.as_str()))
797                {
798                    self.struct_set_field_indexed(index, value)
799                } else {
800                    Err(format!(
801                        "Struct '{}' has no field '{}'",
802                        layout.name(),
803                        field.as_str()
804                    ))
805                }
806            }
807
808            _ => Err("Attempted to set field on non-struct value".to_string()),
809        }
810    }
811
812    pub fn struct_set_field(&self, field: &str, value: Value) -> Result<(), String> {
813        match self {
814            Value::Struct { layout, .. } => {
815                if let Some(index) = layout.index_of_str(field) {
816                    self.struct_set_field_indexed(index, value)
817                } else {
818                    Err(format!(
819                        "Struct '{}' has no field '{}'",
820                        layout.name(),
821                        field
822                    ))
823                }
824            }
825
826            _ => Err("Attempted to set field on non-struct value".to_string()),
827        }
828    }
829
830    pub fn struct_set_field_indexed(&self, index: usize, value: Value) -> Result<(), String> {
831        match self {
832            Value::Struct {
833                name,
834                layout,
835                fields,
836            } => {
837                let mut borrowed = fields.borrow_mut();
838                if index < borrowed.len() {
839                    let canonical = layout.canonicalize_field_value(index, value)?;
840                    borrowed[index] = canonical;
841                    Ok(())
842                } else {
843                    Err(format!(
844                        "Struct '{}' field index {} out of bounds (len {})",
845                        name,
846                        index,
847                        borrowed.len()
848                    ))
849                }
850            }
851
852            _ => Err("Attempted to set field on non-struct value".to_string()),
853        }
854    }
855
856    pub fn enum_unit(enum_name: impl Into<String>, variant: impl Into<String>) -> Self {
857        Value::Enum {
858            enum_name: enum_name.into(),
859            variant: variant.into(),
860            values: None,
861        }
862    }
863
864    pub fn enum_variant(
865        enum_name: impl Into<String>,
866        variant: impl Into<String>,
867        values: Vec<Value>,
868    ) -> Self {
869        Value::Enum {
870            enum_name: enum_name.into(),
871            variant: variant.into(),
872            values: Some(Rc::new(values)),
873        }
874    }
875
876    pub fn as_enum(&self) -> Option<(&str, &str, Option<&[Value]>)> {
877        match self {
878            Value::Enum {
879                enum_name,
880                variant,
881                values,
882            } => Some((
883                enum_name.as_str(),
884                variant.as_str(),
885                values.as_ref().map(|v| v.as_slice()),
886            )),
887            _ => None,
888        }
889    }
890
891    pub fn is_enum_variant(&self, enum_name: &str, variant: &str) -> bool {
892        match self {
893            Value::Enum {
894                enum_name: en,
895                variant: v,
896                ..
897            } => (enum_name.is_empty() || en == enum_name) && v == variant,
898            _ => false,
899        }
900    }
901
902    pub fn some(value: Value) -> Self {
903        Value::enum_variant("Option", "Some", vec![value])
904    }
905
906    pub fn none() -> Self {
907        Value::enum_unit("Option", "None")
908    }
909
910    pub fn ok(value: Value) -> Self {
911        Value::enum_variant("Result", "Ok", vec![value])
912    }
913
914    pub fn err(error: Value) -> Self {
915        Value::enum_variant("Result", "Err", vec![error])
916    }
917
918    pub fn to_string(&self) -> String {
919        format!("{}", self)
920    }
921}
922
923impl fmt::Debug for Value {
924    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
925        match self {
926            Value::Nil => write!(f, "Nil"),
927            Value::Bool(b) => write!(f, "Bool({})", b),
928            Value::Int(i) => write!(f, "Int({})", i),
929            Value::Float(fl) => write!(f, "Float({})", fl),
930            Value::String(s) => write!(f, "String({:?})", s),
931            Value::Array(arr) => write!(f, "Array({:?})", arr.borrow()),
932            Value::Tuple(values) => write!(f, "Tuple({:?})", values),
933            Value::Map(map) => write!(f, "Map({:?})", map.borrow()),
934            Value::Struct {
935                name,
936                layout,
937                fields,
938            } => {
939                let borrowed = fields.borrow();
940                let mut display_fields = Vec::with_capacity(borrowed.len());
941                for (idx, field_name) in layout.field_names().iter().enumerate() {
942                    let value = borrowed.get(idx).cloned().unwrap_or(Value::Nil);
943                    display_fields.push((field_name.as_str().to_string(), value));
944                }
945
946                write!(
947                    f,
948                    "Struct {{ name: {:?}, fields: {:?} }}",
949                    name, display_fields
950                )
951            }
952
953            Value::WeakStruct(weak) => {
954                if let Some(upgraded) = weak.upgrade() {
955                    write!(f, "WeakStruct({:?})", upgraded)
956                } else {
957                    write!(f, "WeakStruct(<dangling>)")
958                }
959            }
960
961            Value::Enum {
962                enum_name,
963                variant,
964                values,
965            } => {
966                write!(
967                    f,
968                    "Enum {{ enum: {:?}, variant: {:?}, values: {:?} }}",
969                    enum_name, variant, values
970                )
971            }
972
973            Value::Function(idx) => write!(f, "Function({})", idx),
974            Value::NativeFunction(_) => write!(f, "NativeFunction(<fn>)"),
975            Value::Closure {
976                function_idx,
977                upvalues,
978            } => {
979                write!(
980                    f,
981                    "Closure {{ function: {}, upvalues: {:?} }}",
982                    function_idx, upvalues
983                )
984            }
985
986            Value::Iterator(_) => write!(f, "Iterator(<state>)"),
987            Value::Task(handle) => write!(f, "Task({})", handle.0),
988        }
989    }
990}
991
992impl fmt::Display for Value {
993    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994        match self {
995            Value::Nil => write!(f, "nil"),
996            Value::Bool(b) => write!(f, "{}", b),
997            Value::Int(i) => write!(f, "{}", i),
998            Value::Float(fl) => write!(f, "{}", fl),
999            Value::String(s) => write!(f, "{}", s),
1000            Value::Array(arr) => {
1001                write!(f, "[")?;
1002                let borrowed = arr.borrow();
1003                for (i, val) in borrowed.iter().enumerate() {
1004                    if i > 0 {
1005                        write!(f, ", ")?;
1006                    }
1007
1008                    write!(f, "{}", val)?;
1009                }
1010
1011                write!(f, "]")
1012            }
1013
1014            Value::Tuple(values) => {
1015                write!(f, "(")?;
1016                for (i, val) in values.iter().enumerate() {
1017                    if i > 0 {
1018                        write!(f, ", ")?;
1019                    }
1020
1021                    write!(f, "{}", val)?;
1022                }
1023
1024                write!(f, ")")
1025            }
1026
1027            Value::Map(map) => {
1028                write!(f, "{{")?;
1029                let borrowed = map.borrow();
1030                for (i, (k, v)) in borrowed.iter().enumerate() {
1031                    if i > 0 {
1032                        write!(f, ", ")?;
1033                    }
1034
1035                    write!(f, "{}: {}", k, v)?;
1036                }
1037
1038                write!(f, "}}")
1039            }
1040
1041            Value::Struct {
1042                name,
1043                layout,
1044                fields,
1045            } => {
1046                let borrowed = fields.borrow();
1047                write!(f, "{} {{", name)?;
1048                for (i, field_name) in layout.field_names().iter().enumerate() {
1049                    if i > 0 {
1050                        write!(f, ", ")?;
1051                    }
1052
1053                    let value = borrowed.get(i).unwrap_or(&Value::Nil);
1054                    write!(f, "{}: {}", field_name, value)?;
1055                }
1056
1057                write!(f, "}}")
1058            }
1059
1060            Value::WeakStruct(weak) => {
1061                if let Some(strong) = weak.upgrade() {
1062                    strong.fmt(f)
1063                } else {
1064                    write!(f, "nil")
1065                }
1066            }
1067
1068            Value::Enum {
1069                enum_name,
1070                variant,
1071                values,
1072            } => {
1073                write!(f, "{}.{}", enum_name, variant)?;
1074                if let Some(vals) = values {
1075                    write!(f, "(")?;
1076                    for (i, val) in vals.iter().enumerate() {
1077                        if i > 0 {
1078                            write!(f, ", ")?;
1079                        }
1080
1081                        write!(f, "{}", val)?;
1082                    }
1083
1084                    write!(f, ")")?;
1085                }
1086
1087                Ok(())
1088            }
1089
1090            Value::Function(idx) => write!(f, "<function@{}>", idx),
1091            Value::NativeFunction(_) => write!(f, "<native function>"),
1092            Value::Closure { function_idx, .. } => write!(f, "<closure@{}>", function_idx),
1093            Value::Iterator(_) => write!(f, "<iterator>"),
1094            Value::Task(handle) => write!(f, "<task {}>", handle.0),
1095        }
1096    }
1097}
1098
1099impl PartialEq for Value {
1100    fn eq(&self, other: &Self) -> bool {
1101        match (self, other) {
1102            (Value::Nil, Value::Nil) => true,
1103            (Value::Bool(a), Value::Bool(b)) => a == b,
1104            (Value::Int(a), Value::Int(b)) => a == b,
1105            (Value::Float(a), Value::Float(b)) => a == b,
1106            (Value::String(a), Value::String(b)) => a == b,
1107            (Value::Array(a), Value::Array(b)) => *a.borrow() == *b.borrow(),
1108            (Value::Tuple(a), Value::Tuple(b)) => *a == *b,
1109            (Value::Map(a), Value::Map(b)) => *a.borrow() == *b.borrow(),
1110            (
1111                Value::Struct {
1112                    name: n1,
1113                    layout: l1,
1114                    fields: f1,
1115                },
1116                Value::Struct {
1117                    name: n2,
1118                    layout: l2,
1119                    fields: f2,
1120                },
1121            ) => {
1122                if n1 != n2 {
1123                    return false;
1124                }
1125
1126                let borrowed_f1 = f1.borrow();
1127                let borrowed_f2 = f2.borrow();
1128                if borrowed_f1.len() != borrowed_f2.len() {
1129                    return false;
1130                }
1131
1132                if Rc::ptr_eq(l1, l2) {
1133                    return borrowed_f1
1134                        .iter()
1135                        .zip(borrowed_f2.iter())
1136                        .all(|(a, b)| a == b);
1137                }
1138
1139                l1.field_names()
1140                    .iter()
1141                    .enumerate()
1142                    .all(|(idx, field_name)| {
1143                        if let Some(other_idx) = l2.index_of_rc(field_name) {
1144                            borrowed_f1
1145                                .get(idx)
1146                                .zip(borrowed_f2.get(other_idx))
1147                                .map(|(a, b)| a == b)
1148                                .unwrap_or(false)
1149                        } else {
1150                            false
1151                        }
1152                    })
1153            }
1154
1155            (Value::WeakStruct(a), Value::WeakStruct(b)) => match (a.upgrade(), b.upgrade()) {
1156                (Some(left), Some(right)) => left == right,
1157                (None, None) => true,
1158                _ => false,
1159            },
1160            (Value::WeakStruct(a), other) => a
1161                .upgrade()
1162                .map(|upgraded| upgraded == *other)
1163                .unwrap_or(matches!(other, Value::Nil)),
1164            (value, Value::WeakStruct(b)) => b
1165                .upgrade()
1166                .map(|upgraded| *value == upgraded)
1167                .unwrap_or(matches!(value, Value::Nil)),
1168            (
1169                Value::Enum {
1170                    enum_name: e1,
1171                    variant: v1,
1172                    values: vals1,
1173                },
1174                Value::Enum {
1175                    enum_name: e2,
1176                    variant: v2,
1177                    values: vals2,
1178                },
1179            ) => e1 == e2 && v1 == v2 && vals1 == vals2,
1180            (Value::Function(a), Value::Function(b)) => a == b,
1181            (
1182                Value::Closure {
1183                    function_idx: f1,
1184                    upvalues: u1,
1185                },
1186                Value::Closure {
1187                    function_idx: f2,
1188                    upvalues: u2,
1189                },
1190            ) => f1 == f2 && Rc::ptr_eq(u1, u2),
1191            (Value::Iterator(_), Value::Iterator(_)) => false,
1192            (Value::Task(a), Value::Task(b)) => a == b,
1193            _ => false,
1194        }
1195    }
1196}
1197
1198#[cfg(feature = "std")]
1199#[no_mangle]
1200pub unsafe extern "C" fn jit_array_get_safe(
1201    array_value_ptr: *const Value,
1202    index: i64,
1203    out: *mut Value,
1204) -> u8 {
1205    if array_value_ptr.is_null() || out.is_null() {
1206        eprintln!("❌ jit_array_get_safe: null pointer detected!");
1207        return 0;
1208    }
1209
1210    let array_value = &*array_value_ptr;
1211    let arr = match array_value {
1212        Value::Array(arr) => arr,
1213        _ => {
1214            return 0;
1215        }
1216    };
1217    if index < 0 {
1218        return 0;
1219    }
1220
1221    let idx = index as usize;
1222    let borrowed = match arr.try_borrow() {
1223        Ok(b) => b,
1224        Err(_) => {
1225            return 0;
1226        }
1227    };
1228    if idx >= borrowed.len() {
1229        return 0;
1230    }
1231
1232    ptr::write(out, borrowed[idx].clone());
1233    1
1234}
1235
1236#[cfg(feature = "std")]
1237#[no_mangle]
1238pub unsafe extern "C" fn jit_array_len_safe(array_value_ptr: *const Value) -> i64 {
1239    if array_value_ptr.is_null() {
1240        return -1;
1241    }
1242
1243    let array_value = &*array_value_ptr;
1244    match array_value {
1245        Value::Array(arr) => match arr.try_borrow() {
1246            Ok(borrowed) => int_from_usize(borrowed.len()),
1247            Err(_) => -1,
1248        },
1249        _ => -1,
1250    }
1251}
1252
1253#[cfg(feature = "std")]
1254static JIT_NEW_ARRAY_COUNTER: core::sync::atomic::AtomicUsize =
1255    core::sync::atomic::AtomicUsize::new(0);
1256
1257#[cfg(feature = "std")]
1258#[no_mangle]
1259pub unsafe extern "C" fn jit_new_array_safe(
1260    elements_ptr: *const Value,
1261    element_count: usize,
1262    out_ptr: *mut Value,
1263) -> u8 {
1264    let call_num = JIT_NEW_ARRAY_COUNTER.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
1265    // jit::log(|| format!("jit_new_array_safe call #{}: ENTER - elements_ptr={:?}, count={}, out_ptr={:?}", call_num, elements_ptr, element_count, out_ptr));
1266
1267    if out_ptr.is_null() {
1268        // jit::log(|| "jit_new_array_safe: out_ptr is null".to_string());
1269        return 0;
1270    }
1271
1272    // jit::log(|| format!("jit_new_array_safe #{}: about to create Vec", call_num));
1273    let elements = if element_count == 0 {
1274        Vec::new()
1275    } else {
1276        if elements_ptr.is_null() {
1277            // jit::log(|| "jit_new_array_safe: elements_ptr is null but count > 0".to_string());
1278            return 0;
1279        }
1280
1281        let slice = slice::from_raw_parts(elements_ptr, element_count);
1282        slice.to_vec()
1283    };
1284
1285    // jit::log(|| format!("jit_new_array_safe #{}: about to call Value::array with {} elements", call_num, elements.len()));
1286    let array_value = Value::array(elements);
1287    // jit::log(|| format!("jit_new_array_safe #{}: about to write to out_ptr", call_num));
1288    ptr::write(out_ptr, array_value);
1289    // jit::log(|| format!("jit_new_array_safe #{}: EXIT - success, returning 1", call_num));
1290    1
1291}
1292
1293#[cfg(feature = "std")]
1294#[no_mangle]
1295pub unsafe extern "C" fn jit_array_push_safe(
1296    array_ptr: *const Value,
1297    value_ptr: *const Value,
1298) -> u8 {
1299    if array_ptr.is_null() || value_ptr.is_null() {
1300        return 0;
1301    }
1302
1303    let array_value = &*array_ptr;
1304    let value = &*value_ptr;
1305
1306    match array_value {
1307        Value::Array(arr) => {
1308            // Use unchecked borrow for maximum performance
1309            let cell_ptr = arr.as_ptr();
1310            (*cell_ptr).push(value.clone());
1311            1
1312        }
1313        _ => 0,
1314    }
1315}
1316
1317/// Unbox Array<int> from Value to Vec<LustInt> for specialized JIT operations
1318/// IMPORTANT: This takes ownership of the array's data. The original Vec<Value> is emptied.
1319/// Returns 1 on success, 0 on failure
1320/// Outputs: vec_ptr (pointer to data), vec_len, vec_cap
1321#[cfg(feature = "std")]
1322#[no_mangle]
1323pub unsafe extern "C" fn jit_unbox_array_int(
1324    array_value_ptr: *const Value,
1325    out_vec_ptr: *mut *mut LustInt,
1326    out_len: *mut usize,
1327    out_cap: *mut usize,
1328) -> u8 {
1329    if array_value_ptr.is_null() || out_vec_ptr.is_null() || out_len.is_null() || out_cap.is_null()
1330    {
1331        return 0;
1332    }
1333
1334    let array_value = &*array_value_ptr;
1335    match array_value {
1336        Value::Array(arr_rc) => {
1337            // Get exclusive access to the inner vector
1338            let cell_ptr = arr_rc.as_ptr();
1339            let vec_ref = &mut *cell_ptr;
1340
1341            // Take ownership of the Vec<Value> by swapping with empty vec
1342            let original_vec = core::mem::replace(vec_ref, Vec::new());
1343
1344            // Convert Vec<Value> to Vec<LustInt>
1345            let mut specialized_vec: Vec<LustInt> = Vec::with_capacity(original_vec.len());
1346            for elem in original_vec.into_iter() {
1347                match elem {
1348                    Value::Int(i) => specialized_vec.push(i),
1349                    _ => {
1350                        // Type mismatch - restore original data and fail
1351                        // This shouldn't happen if types are correct, but be safe
1352                        return 0;
1353                    }
1354                }
1355            }
1356
1357            // Extract Vec metadata
1358            let len = specialized_vec.len();
1359            let cap = specialized_vec.capacity();
1360            let ptr = specialized_vec.as_mut_ptr();
1361
1362            // Prevent Vec from being dropped
1363            core::mem::forget(specialized_vec);
1364
1365            // Write outputs
1366            ptr::write(out_vec_ptr, ptr);
1367            ptr::write(out_len, len);
1368            ptr::write(out_cap, cap);
1369
1370            // Note: The original Rc<RefCell<Vec<Value>>> now contains an empty Vec
1371            // This is fine - when we rebox, we'll refill it
1372
1373            1
1374        }
1375        _ => 0,
1376    }
1377}
1378
1379/// Rebox Vec<LustInt> back to Array Value
1380/// IMPORTANT: Writes the specialized vec data back into the EXISTING Rc<RefCell<Vec<Value>>>
1381/// This ensures the original array is updated, not replaced
1382#[cfg(feature = "std")]
1383#[no_mangle]
1384pub unsafe extern "C" fn jit_rebox_array_int(
1385    vec_ptr: *mut LustInt,
1386    vec_len: usize,
1387    vec_cap: usize,
1388    array_value_ptr: *mut Value,
1389) -> u8 {
1390    if vec_ptr.is_null() || array_value_ptr.is_null() {
1391        return 0;
1392    }
1393
1394    // Reconstruct Vec<LustInt> from raw parts
1395    let specialized_vec = Vec::from_raw_parts(vec_ptr, vec_len, vec_cap);
1396
1397    // Get the existing Array value
1398    let array_value = &mut *array_value_ptr;
1399    match array_value {
1400        Value::Array(arr_rc) => {
1401            // Get exclusive access to the inner vector (should be empty from unbox)
1402            let cell_ptr = arr_rc.as_ptr();
1403            let vec_ref = &mut *cell_ptr;
1404
1405            // Convert Vec<LustInt> back to Vec<Value> and write into the existing RefCell
1406            *vec_ref = specialized_vec.into_iter().map(Value::Int).collect();
1407
1408            1
1409        }
1410        _ => {
1411            // This shouldn't happen - the register should still contain the Array
1412            // But if it doesn't, create a new array
1413            let value_vec: Vec<Value> = specialized_vec.into_iter().map(Value::Int).collect();
1414            let array_value_new = Value::array(value_vec);
1415            ptr::write(array_value_ptr, array_value_new);
1416            1
1417        }
1418    }
1419}
1420
1421/// Specialized push operation for Vec<LustInt>
1422/// Directly pushes LustInt to the specialized vector
1423#[cfg(feature = "std")]
1424#[no_mangle]
1425pub unsafe extern "C" fn jit_vec_int_push(
1426    vec_ptr: *mut *mut LustInt,
1427    vec_len: *mut usize,
1428    vec_cap: *mut usize,
1429    value: LustInt,
1430) -> u8 {
1431    if vec_ptr.is_null() || vec_len.is_null() || vec_cap.is_null() {
1432        return 0;
1433    }
1434
1435    let ptr = *vec_ptr;
1436    let len = *vec_len;
1437    let cap = *vec_cap;
1438
1439    // Reconstruct Vec temporarily
1440    let mut vec = Vec::from_raw_parts(ptr, len, cap);
1441
1442    // Push the value
1443    vec.push(value);
1444
1445    // Extract new metadata
1446    let new_len = vec.len();
1447    let new_cap = vec.capacity();
1448    let new_ptr = vec.as_mut_ptr();
1449
1450    // Prevent drop
1451    core::mem::forget(vec);
1452
1453    // Update outputs
1454    ptr::write(vec_ptr, new_ptr);
1455    ptr::write(vec_len, new_len);
1456    ptr::write(vec_cap, new_cap);
1457
1458    1
1459}
1460
1461/// Drop a specialized Vec<LustInt> (cleanup for leaked specializations)
1462/// WARNING: This should NOT be called! Specialized values that get invalidated
1463/// during loop recording don't actually exist on the stack during execution.
1464#[cfg(feature = "std")]
1465#[no_mangle]
1466pub unsafe extern "C" fn jit_drop_vec_int(vec_ptr: *mut LustInt, vec_len: usize, vec_cap: usize) {
1467    eprintln!(
1468        "🗑️  jit_drop_vec_int: ptr={:p}, len={}, cap={}",
1469        vec_ptr, vec_len, vec_cap
1470    );
1471    eprintln!("🗑️  jit_drop_vec_int: THIS SHOULD NOT BE CALLED - THE VEC DATA IS STALE!");
1472
1473    // DO NOT drop - the Vec data on the stack is stale from trace recording
1474    // The actual arrays are managed by their Rc<RefCell<>> wrappers
1475    eprintln!("🗑️  jit_drop_vec_int: skipping drop (would cause corruption)");
1476}
1477
1478#[cfg(feature = "std")]
1479#[no_mangle]
1480pub unsafe extern "C" fn jit_enum_is_some_safe(enum_ptr: *const Value, out_ptr: *mut Value) -> u8 {
1481    if enum_ptr.is_null() || out_ptr.is_null() {
1482        return 0;
1483    }
1484
1485    let enum_value = &*enum_ptr;
1486    match enum_value {
1487        Value::Enum { variant, .. } => {
1488            let is_some = variant == "Some";
1489            ptr::write(out_ptr, Value::Bool(is_some));
1490            1
1491        }
1492        _ => 0,
1493    }
1494}
1495
1496#[cfg(feature = "std")]
1497#[no_mangle]
1498pub unsafe extern "C" fn jit_enum_unwrap_safe(enum_ptr: *const Value, out_ptr: *mut Value) -> u8 {
1499    if enum_ptr.is_null() || out_ptr.is_null() {
1500        return 0;
1501    }
1502
1503    let enum_value = &*enum_ptr;
1504    match enum_value {
1505        Value::Enum {
1506            values: Some(vals), ..
1507        } if vals.len() == 1 => {
1508            ptr::write(out_ptr, vals[0].clone());
1509            1
1510        }
1511        _ => 0,
1512    }
1513}
1514
1515#[cfg(feature = "std")]
1516#[no_mangle]
1517pub unsafe extern "C" fn jit_set_field_strong_safe(
1518    object_ptr: *const Value,
1519    field_index: usize,
1520    value_ptr: *const Value,
1521) -> u8 {
1522    if object_ptr.is_null() || value_ptr.is_null() {
1523        return 0;
1524    }
1525
1526    let object = &*object_ptr;
1527    let value = (&*value_ptr).clone();
1528
1529    match object {
1530        Value::Struct { fields, .. } => {
1531            // Skip canonicalization for strong fields - just set directly
1532            match fields.try_borrow_mut() {
1533                Ok(mut borrowed) => {
1534                    if field_index < borrowed.len() {
1535                        borrowed[field_index] = value;
1536                        1
1537                    } else {
1538                        0
1539                    }
1540                }
1541                Err(_) => 0,
1542            }
1543        }
1544        _ => 0,
1545    }
1546}
1547
1548#[cfg(feature = "std")]
1549#[no_mangle]
1550pub unsafe extern "C" fn jit_concat_safe(
1551    left_value_ptr: *const Value,
1552    right_value_ptr: *const Value,
1553    out: *mut Value,
1554) -> u8 {
1555    if left_value_ptr.is_null() || right_value_ptr.is_null() || out.is_null() {
1556        return 0;
1557    }
1558
1559    let left = &*left_value_ptr;
1560    let right = &*right_value_ptr;
1561    const NO_VM_ERROR: &str = "task API requires a running VM";
1562    let left_str = match VM::with_current(|vm| {
1563        let left_copy = left.clone();
1564        vm.value_to_string_for_concat(&left_copy)
1565            .map_err(|err| err.to_string())
1566    }) {
1567        Ok(rc) => rc,
1568        Err(err) if err == NO_VM_ERROR => Rc::new(left.to_string()),
1569        Err(_) => return 0,
1570    };
1571    let right_str = match VM::with_current(|vm| {
1572        let right_copy = right.clone();
1573        vm.value_to_string_for_concat(&right_copy)
1574            .map_err(|err| err.to_string())
1575    }) {
1576        Ok(rc) => rc,
1577        Err(err) if err == NO_VM_ERROR => Rc::new(right.to_string()),
1578        Err(_) => return 0,
1579    };
1580    let mut combined = String::with_capacity(left_str.len() + right_str.len());
1581    combined.push_str(left_str.as_ref());
1582    combined.push_str(right_str.as_ref());
1583    let result = Value::string(combined);
1584    ptr::write(out, result);
1585    1
1586}
1587
1588#[no_mangle]
1589pub unsafe extern "C" fn jit_guard_native_function(
1590    value_ptr: *const Value,
1591    expected_fn_ptr: *const (),
1592    register_index: u8,
1593) -> u8 {
1594    if value_ptr.is_null() || expected_fn_ptr.is_null() {
1595        jit::log(|| "jit_guard_native_function: null pointer input".to_string());
1596        return 0;
1597    }
1598
1599    match &*value_ptr {
1600        Value::NativeFunction(func) => {
1601            let actual = Rc::as_ptr(func) as *const ();
1602            if actual == expected_fn_ptr {
1603                1
1604            } else {
1605                jit::log(|| {
1606                    format!(
1607                        "jit_guard_native_function: pointer mismatch (reg {}) actual={:p} expected={:p}",
1608                        register_index, actual, expected_fn_ptr
1609                    )
1610                });
1611                0
1612            }
1613        }
1614
1615        other => {
1616            jit::log(|| {
1617                format!(
1618                    "jit_guard_native_function: value not native in reg {} ({:?})",
1619                    register_index,
1620                    other.tag()
1621                )
1622            });
1623            0
1624        }
1625    }
1626}
1627
1628#[no_mangle]
1629pub unsafe extern "C" fn jit_guard_function_identity(
1630    value_ptr: *const Value,
1631    expected_kind: u8,
1632    expected_function_idx: usize,
1633    expected_upvalues: *const (),
1634    register_index: u8,
1635) -> u8 {
1636    if value_ptr.is_null() {
1637        jit::log(|| "jit_guard_function_identity: null pointer input".to_string());
1638        return 0;
1639    }
1640
1641    let value = &*value_ptr;
1642    match (expected_kind, value) {
1643        (0, Value::Function(idx)) => {
1644            if *idx == expected_function_idx {
1645                1
1646            } else {
1647                jit::log(|| {
1648                    format!(
1649                        "jit_guard_function_identity: function idx mismatch (reg {}) actual={} expected={}",
1650                        register_index, idx, expected_function_idx
1651                    )
1652                });
1653                0
1654            }
1655        }
1656
1657        (
1658            1,
1659            Value::Closure {
1660                function_idx,
1661                upvalues,
1662            },
1663        ) => {
1664            if *function_idx != expected_function_idx {
1665                jit::log(|| {
1666                    format!(
1667                        "jit_guard_function_identity: closure idx mismatch (reg {}) actual={} expected={}",
1668                        register_index, function_idx, expected_function_idx
1669                    )
1670                });
1671                return 0;
1672            }
1673
1674            let actual_ptr = Rc::as_ptr(upvalues) as *const ();
1675            if actual_ptr == expected_upvalues {
1676                1
1677            } else {
1678                jit::log(|| {
1679                    format!(
1680                        "jit_guard_function_identity: upvalues mismatch (reg {}) actual={:p} expected={:p}",
1681                        register_index, actual_ptr, expected_upvalues
1682                    )
1683                });
1684                0
1685            }
1686        }
1687
1688        (0, Value::Closure { function_idx, .. }) => {
1689            jit::log(|| {
1690                format!(
1691                    "jit_guard_function_identity: expected function, saw closure (reg {}, idx {})",
1692                    register_index, function_idx
1693                )
1694            });
1695            0
1696        }
1697
1698        (1, Value::Function(idx)) => {
1699            jit::log(|| {
1700                format!(
1701                    "jit_guard_function_identity: expected closure, saw function (reg {}, idx {})",
1702                    register_index, idx
1703                )
1704            });
1705            0
1706        }
1707
1708        (_, other) => {
1709            jit::log(|| {
1710                format!(
1711                    "jit_guard_function_identity: value in reg {} not callable ({:?})",
1712                    register_index,
1713                    other.tag()
1714                )
1715            });
1716            0
1717        }
1718    }
1719}
1720
1721#[no_mangle]
1722pub unsafe extern "C" fn jit_call_native_safe(
1723    vm_ptr: *mut VM,
1724    callee_ptr: *const Value,
1725    expected_fn_ptr: *const (),
1726    args_ptr: *const Value,
1727    arg_count: u8,
1728    out: *mut Value,
1729) -> u8 {
1730    if vm_ptr.is_null() || callee_ptr.is_null() || expected_fn_ptr.is_null() || out.is_null() {
1731        jit::log(|| "jit_call_native_safe: null argument".to_string());
1732        return 0;
1733    }
1734
1735    let callee = &*callee_ptr;
1736    let native_fn = match callee {
1737        Value::NativeFunction(func) => func.clone(),
1738        other => {
1739            jit::log(|| {
1740                format!(
1741                    "jit_call_native_safe: callee not native ({:?})",
1742                    other.tag()
1743                )
1744            });
1745            return 0;
1746        }
1747    };
1748
1749    if Rc::as_ptr(&native_fn) as *const () != expected_fn_ptr {
1750        jit::log(|| {
1751            format!(
1752                "jit_call_native_safe: pointer mismatch actual={:p} expected={:p}",
1753                Rc::as_ptr(&native_fn),
1754                expected_fn_ptr
1755            )
1756        });
1757        return 0;
1758    }
1759
1760    let mut args = Vec::with_capacity(arg_count as usize);
1761    if arg_count > 0 {
1762        if args_ptr.is_null() {
1763            jit::log(|| "jit_call_native_safe: args_ptr null with non-zero arg_count".to_string());
1764            return 0;
1765        }
1766
1767        for i in 0..(arg_count as usize) {
1768            let arg = &*args_ptr.add(i);
1769            args.push(arg.clone());
1770        }
1771    }
1772
1773    push_vm_ptr(vm_ptr);
1774    let outcome = native_fn(&args);
1775    pop_vm_ptr();
1776
1777    let outcome = match outcome {
1778        Ok(result) => result,
1779        Err(err) => {
1780            jit::log(|| format!("jit_call_native_safe: native returned error: {}", err));
1781            return 0;
1782        }
1783    };
1784
1785    match outcome {
1786        NativeCallResult::Return(value) => {
1787            ptr::write(out, value);
1788            1
1789        }
1790
1791        NativeCallResult::Yield(_) => {
1792            jit::log(|| "jit_call_native_safe: native attempted to yield".to_string());
1793            0
1794        }
1795
1796        NativeCallResult::Stop(_) => {
1797            jit::log(|| "jit_call_native_safe: native attempted to stop".to_string());
1798            0
1799        }
1800    }
1801}
1802
1803#[no_mangle]
1804pub unsafe extern "C" fn jit_call_function_safe(
1805    vm_ptr: *mut VM,
1806    callee_ptr: *const Value,
1807    args_ptr: *const Value,
1808    arg_count: u8,
1809    dest_reg: u8,
1810) -> u8 {
1811    if vm_ptr.is_null() || callee_ptr.is_null() {
1812        jit::log(|| "jit_call_function_safe: null argument".to_string());
1813        return 0;
1814    }
1815
1816    if arg_count > 0 && args_ptr.is_null() {
1817        jit::log(|| "jit_call_function_safe: args_ptr null with non-zero arg_count".to_string());
1818        return 0;
1819    }
1820
1821    // Clone the callee BEFORE any operations that might reallocate registers
1822    let callee = (&*callee_ptr).clone();
1823    let mut args = Vec::with_capacity(arg_count as usize);
1824    for i in 0..(arg_count as usize) {
1825        let arg_ptr = args_ptr.add(i);
1826        args.push((&*arg_ptr).clone());
1827    }
1828
1829    let vm = &mut *vm_ptr;
1830    push_vm_ptr(vm_ptr);
1831
1832    // Temporarily disable JIT to prevent recursive JIT execution
1833    let jit_was_enabled = vm.jit.enabled;
1834    vm.jit.enabled = false;
1835
1836    let call_result = vm.call_value(&callee, args);
1837
1838    // Restore JIT state
1839    vm.jit.enabled = jit_was_enabled;
1840    pop_vm_ptr();
1841
1842    match call_result {
1843        Ok(value) => {
1844            // Get current registers pointer AFTER the call (it may have reallocated)
1845            let vm = &mut *vm_ptr;
1846            if let Some(frame) = vm.call_stack.last_mut() {
1847                if (dest_reg as usize) < frame.registers.len() {
1848                    frame.registers[dest_reg as usize] = value;
1849                    1
1850                } else {
1851                    jit::log(|| {
1852                        format!(
1853                            "jit_call_function_safe: dest_reg {} out of bounds",
1854                            dest_reg
1855                        )
1856                    });
1857                    0
1858                }
1859            } else {
1860                jit::log(|| "jit_call_function_safe: no call frame".to_string());
1861                0
1862            }
1863        }
1864
1865        Err(err) => {
1866            jit::log(|| format!("jit_call_function_safe: {}", err));
1867            0
1868        }
1869    }
1870}
1871
1872#[no_mangle]
1873pub unsafe extern "C" fn jit_current_registers(vm_ptr: *mut VM) -> *mut Value {
1874    if vm_ptr.is_null() {
1875        return core::ptr::null_mut();
1876    }
1877
1878    let vm = &mut *vm_ptr;
1879    vm.call_stack
1880        .last_mut()
1881        .map(|frame| frame.registers.as_mut_ptr())
1882        .unwrap_or(core::ptr::null_mut())
1883}
1884
1885#[no_mangle]
1886pub unsafe extern "C" fn jit_value_is_truthy(value_ptr: *const Value) -> u8 {
1887    if value_ptr.is_null() {
1888        return 0;
1889    }
1890
1891    let value = &*value_ptr;
1892    if value.is_truthy() {
1893        1
1894    } else {
1895        0
1896    }
1897}
1898
1899#[no_mangle]
1900pub unsafe extern "C" fn jit_new_enum_unit_safe(
1901    enum_name_ptr: *const u8,
1902    enum_name_len: usize,
1903    variant_name_ptr: *const u8,
1904    variant_name_len: usize,
1905    out: *mut Value,
1906) -> u8 {
1907    if enum_name_ptr.is_null() || variant_name_ptr.is_null() || out.is_null() {
1908        return 0;
1909    }
1910
1911    let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1912    let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1913    let enum_name = match str::from_utf8(enum_name_slice) {
1914        Ok(s) => s.to_string(),
1915        Err(_) => return 0,
1916    };
1917    let variant_name = match str::from_utf8(variant_name_slice) {
1918        Ok(s) => s.to_string(),
1919        Err(_) => return 0,
1920    };
1921    let value = Value::enum_unit(enum_name, variant_name);
1922    ptr::write(out, value);
1923    1
1924}
1925
1926#[no_mangle]
1927pub unsafe extern "C" fn jit_new_enum_variant_safe(
1928    enum_name_ptr: *const u8,
1929    enum_name_len: usize,
1930    variant_name_ptr: *const u8,
1931    variant_name_len: usize,
1932    values_ptr: *const Value,
1933    value_count: usize,
1934    out: *mut Value,
1935) -> u8 {
1936    if enum_name_ptr.is_null() || variant_name_ptr.is_null() || out.is_null() {
1937        return 0;
1938    }
1939
1940    if value_count > 0 && values_ptr.is_null() {
1941        return 0;
1942    }
1943
1944    let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1945    let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1946    let enum_name = match str::from_utf8(enum_name_slice) {
1947        Ok(s) => s.to_string(),
1948        Err(_) => return 0,
1949    };
1950    let variant_name = match str::from_utf8(variant_name_slice) {
1951        Ok(s) => s.to_string(),
1952        Err(_) => return 0,
1953    };
1954    let mut values = Vec::with_capacity(value_count);
1955    for i in 0..value_count {
1956        let value = &*values_ptr.add(i);
1957        values.push(value.clone());
1958    }
1959
1960    let value = Value::enum_variant(enum_name, variant_name, values);
1961    ptr::write(out, value);
1962    1
1963}
1964
1965#[no_mangle]
1966pub unsafe extern "C" fn jit_is_enum_variant_safe(
1967    value_ptr: *const Value,
1968    enum_name_ptr: *const u8,
1969    enum_name_len: usize,
1970    variant_name_ptr: *const u8,
1971    variant_name_len: usize,
1972) -> u8 {
1973    if value_ptr.is_null() || enum_name_ptr.is_null() || variant_name_ptr.is_null() {
1974        return 0;
1975    }
1976
1977    let value = &*value_ptr;
1978    let enum_name_slice = slice::from_raw_parts(enum_name_ptr, enum_name_len);
1979    let variant_name_slice = slice::from_raw_parts(variant_name_ptr, variant_name_len);
1980    let enum_name = match str::from_utf8(enum_name_slice) {
1981        Ok(s) => s,
1982        Err(_) => return 0,
1983    };
1984    let variant_name = match str::from_utf8(variant_name_slice) {
1985        Ok(s) => s,
1986        Err(_) => return 0,
1987    };
1988    if value.is_enum_variant(enum_name, variant_name) {
1989        1
1990    } else {
1991        0
1992    }
1993}
1994
1995#[no_mangle]
1996pub unsafe extern "C" fn jit_get_enum_value_safe(
1997    enum_ptr: *const Value,
1998    index: usize,
1999    out: *mut Value,
2000) -> u8 {
2001    if enum_ptr.is_null() || out.is_null() {
2002        return 0;
2003    }
2004
2005    let enum_value = &*enum_ptr;
2006    if let Some((_, _, Some(values))) = enum_value.as_enum() {
2007        if index < values.len() {
2008            ptr::write(out, values[index].clone());
2009            1
2010        } else {
2011            0
2012        }
2013    } else {
2014        0
2015    }
2016}
2017
2018#[no_mangle]
2019pub unsafe extern "C" fn jit_call_method_safe(
2020    vm_ptr: *mut VM,
2021    object_ptr: *const Value,
2022    method_name_ptr: *const u8,
2023    method_name_len: usize,
2024    args_ptr: *const Value,
2025    arg_count: u8,
2026    dest_reg: u8,
2027) -> u8 {
2028    if vm_ptr.is_null() || object_ptr.is_null() || method_name_ptr.is_null() {
2029        jit::log(|| "jit_call_method_safe: null pointer argument".to_string());
2030        return 0;
2031    }
2032
2033    if arg_count > 0 && args_ptr.is_null() {
2034        return 0;
2035    }
2036
2037    let method_name_slice = slice::from_raw_parts(method_name_ptr, method_name_len);
2038    let method_name = match str::from_utf8(method_name_slice) {
2039        Ok(s) => s,
2040        Err(_) => return 0,
2041    };
2042
2043    let object = (&*object_ptr).clone();
2044    if matches!(object, Value::Struct { .. }) {
2045        return 0;
2046    }
2047
2048    let mut args = Vec::with_capacity(arg_count as usize);
2049    for i in 0..arg_count {
2050        let arg_ptr = args_ptr.add(i as usize);
2051        args.push((&*arg_ptr).clone());
2052    }
2053
2054    crate::vm::push_vm_ptr(vm_ptr);
2055    let outcome = call_builtin_method_simple(&object, method_name, args);
2056    crate::vm::pop_vm_ptr();
2057    match outcome {
2058        Ok(val) => {
2059            let vm = &mut *vm_ptr;
2060            if let Some(frame) = vm.call_stack.last_mut() {
2061                if (dest_reg as usize) < frame.registers.len() {
2062                    frame.registers[dest_reg as usize] = val;
2063                    1
2064                } else {
2065                    jit::log(|| {
2066                        format!("jit_call_method_safe: dest_reg {} out of bounds", dest_reg)
2067                    });
2068                    0
2069                }
2070            } else {
2071                jit::log(|| "jit_call_method_safe: no call frame".to_string());
2072                0
2073            }
2074        }
2075        Err(_) => 0,
2076    }
2077}
2078
2079fn call_builtin_method_simple(
2080    object: &Value,
2081    method_name: &str,
2082    args: Vec<Value>,
2083) -> Result<Value, String> {
2084    match object {
2085        Value::Struct { name, .. } => Err(format!(
2086            "User-defined methods on {} require deoptimization",
2087            name
2088        )),
2089        Value::Iterator(state_rc) => match method_name {
2090            "next" => {
2091                let mut state = state_rc.borrow_mut();
2092                match &mut *state {
2093                    IteratorState::Array { items, index } => {
2094                        if *index < items.len() {
2095                            let v = items[*index].clone();
2096                            *index += 1;
2097                            Ok(Value::some(v))
2098                        } else {
2099                            Ok(Value::none())
2100                        }
2101                    }
2102
2103                    IteratorState::MapPairs { items, index } => {
2104                        if *index < items.len() {
2105                            let (k, v) = items[*index].clone();
2106                            *index += 1;
2107                            Ok(Value::some(Value::array(vec![k.to_value(), v])))
2108                        } else {
2109                            Ok(Value::none())
2110                        }
2111                    }
2112                }
2113            }
2114
2115            _ => Err(format!(
2116                "Iterator method '{}' not supported in JIT",
2117                method_name
2118            )),
2119        },
2120        Value::Enum {
2121            enum_name,
2122            variant,
2123            values,
2124        } if enum_name == "Option" => match method_name {
2125            "is_some" => Ok(Value::Bool(variant == "Some")),
2126            "is_none" => Ok(Value::Bool(variant == "None")),
2127            "unwrap" => {
2128                if variant == "Some" {
2129                    if let Some(vals) = values {
2130                        if vals.len() == 1 {
2131                            Ok(vals[0].clone())
2132                        } else {
2133                            Err("Option::Some should have exactly 1 value".to_string())
2134                        }
2135                    } else {
2136                        Err("Option::Some should have a value".to_string())
2137                    }
2138                } else {
2139                    Err("Called unwrap() on Option::None".to_string())
2140                }
2141            }
2142
2143            _ => Err(format!(
2144                "Option method '{}' not supported in JIT",
2145                method_name
2146            )),
2147        },
2148        Value::Array(arr) => match method_name {
2149            "len" => Ok(Value::Int(int_from_usize(arr.borrow().len()))),
2150            "push" => {
2151                let value = args
2152                    .get(0)
2153                    .cloned()
2154                    .ok_or_else(|| "Array:push requires a value argument".to_string())?;
2155                arr.borrow_mut().push(value);
2156                Ok(Value::Nil)
2157            }
2158            "pop" => {
2159                let popped = arr.borrow_mut().pop();
2160                Ok(popped.map(Value::some).unwrap_or_else(Value::none))
2161            }
2162            "first" => {
2163                let borrowed = arr.borrow();
2164                Ok(borrowed
2165                    .first()
2166                    .cloned()
2167                    .map(Value::some)
2168                    .unwrap_or_else(Value::none))
2169            }
2170            "last" => {
2171                let borrowed = arr.borrow();
2172                Ok(borrowed
2173                    .last()
2174                    .cloned()
2175                    .map(Value::some)
2176                    .unwrap_or_else(Value::none))
2177            }
2178            "get" => {
2179                let index = args
2180                    .get(0)
2181                    .and_then(Value::as_int)
2182                    .ok_or_else(|| "Array:get requires an integer index".to_string())?;
2183                let borrowed = arr.borrow();
2184                Ok(borrowed
2185                    .get(index as usize)
2186                    .cloned()
2187                    .map(Value::some)
2188                    .unwrap_or_else(Value::none))
2189            }
2190            "iter" => {
2191                let items = arr.borrow().clone();
2192                let iter = IteratorState::Array { items, index: 0 };
2193                Ok(Value::Iterator(Rc::new(RefCell::new(iter))))
2194            }
2195            _ => Err(format!(
2196                "Array method '{}' not supported in JIT",
2197                method_name
2198            )),
2199        },
2200        _ => Err(format!(
2201            "Method '{}' not supported in JIT (deoptimizing)",
2202            method_name
2203        )),
2204    }
2205}
2206
2207#[no_mangle]
2208pub unsafe extern "C" fn jit_get_field_safe(
2209    object_ptr: *const Value,
2210    field_name_ptr: *const u8,
2211    field_name_len: usize,
2212    out: *mut Value,
2213) -> u8 {
2214    if object_ptr.is_null() || field_name_ptr.is_null() || out.is_null() {
2215        return 0;
2216    }
2217
2218    let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2219    let field_name = match str::from_utf8(field_name_slice) {
2220        Ok(s) => s,
2221        Err(_) => return 0,
2222    };
2223    let object = &*object_ptr;
2224    let field_value = match object {
2225        Value::Struct { layout, fields, .. } => match layout.index_of_str(field_name) {
2226            Some(idx) => match fields.borrow().get(idx) {
2227                Some(val) => val.clone(),
2228                None => return 0,
2229            },
2230            None => return 0,
2231        },
2232        _ => return 0,
2233    };
2234    ptr::write(out, field_value);
2235    1
2236}
2237
2238#[no_mangle]
2239pub unsafe extern "C" fn jit_set_field_safe(
2240    object_ptr: *const Value,
2241    field_name_ptr: *const u8,
2242    field_name_len: usize,
2243    value_ptr: *const Value,
2244) -> u8 {
2245    if object_ptr.is_null() || field_name_ptr.is_null() || value_ptr.is_null() {
2246        return 0;
2247    }
2248
2249    let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2250    let field_name = match str::from_utf8(field_name_slice) {
2251        Ok(s) => s,
2252        Err(_) => return 0,
2253    };
2254    let object = &*object_ptr;
2255    let value = (&*value_ptr).clone();
2256    match object {
2257        Value::Struct { .. } => match object.struct_set_field(field_name, value) {
2258            Ok(()) => 1,
2259            Err(_) => 0,
2260        },
2261        Value::Map(map) => {
2262            use crate::bytecode::ValueKey;
2263            let key = ValueKey::String(Rc::new(field_name.to_string()));
2264            map.borrow_mut().insert(key, value);
2265            1
2266        }
2267
2268        _ => 0,
2269    }
2270}
2271
2272#[no_mangle]
2273pub unsafe extern "C" fn jit_get_field_indexed_safe(
2274    object_ptr: *const Value,
2275    field_index: usize,
2276    out: *mut Value,
2277) -> u8 {
2278    if object_ptr.is_null() || out.is_null() {
2279        return 0;
2280    }
2281
2282    let object = &*object_ptr;
2283    match object.struct_get_field_indexed(field_index) {
2284        Some(value) => {
2285            ptr::write(out, value);
2286            1
2287        }
2288
2289        None => 0,
2290    }
2291}
2292
2293#[no_mangle]
2294pub unsafe extern "C" fn jit_set_field_indexed_safe(
2295    object_ptr: *const Value,
2296    field_index: usize,
2297    value_ptr: *const Value,
2298) -> u8 {
2299    if object_ptr.is_null() || value_ptr.is_null() {
2300        return 0;
2301    }
2302
2303    let object = &*object_ptr;
2304    let value = (&*value_ptr).clone();
2305    match object.struct_set_field_indexed(field_index, value) {
2306        Ok(()) => 1,
2307        Err(_) => 0,
2308    }
2309}
2310
2311#[no_mangle]
2312pub unsafe extern "C" fn jit_get_field_indexed_int_fast(
2313    object_ptr: *const Value,
2314    field_index: usize,
2315    out: *mut Value,
2316) -> u8 {
2317    if object_ptr.is_null() || out.is_null() {
2318        return 0;
2319    }
2320
2321    let object = &*object_ptr;
2322    let out_ref = &mut *out;
2323    match object {
2324        Value::Struct { layout, fields, .. } => {
2325            if layout.is_weak(field_index) {
2326                return 0;
2327            }
2328
2329            if let Ok(borrowed) = fields.try_borrow() {
2330                if let Some(Value::Int(val)) = borrowed.get(field_index) {
2331                    *out_ref = Value::Int(*val);
2332                    return 1;
2333                }
2334            }
2335
2336            0
2337        }
2338
2339        _ => 0,
2340    }
2341}
2342
2343#[no_mangle]
2344pub unsafe extern "C" fn jit_set_field_indexed_int_fast(
2345    object_ptr: *const Value,
2346    field_index: usize,
2347    value_ptr: *const Value,
2348) -> u8 {
2349    if object_ptr.is_null() || value_ptr.is_null() {
2350        return 0;
2351    }
2352
2353    let object = &*object_ptr;
2354    let value = &*value_ptr;
2355    let new_value = match value {
2356        Value::Int(v) => *v,
2357        _ => return 0,
2358    };
2359    match object {
2360        Value::Struct { layout, fields, .. } => {
2361            if layout.is_weak(field_index) {
2362                return 0;
2363            }
2364
2365            if let Ok(mut borrowed) = fields.try_borrow_mut() {
2366                if field_index < borrowed.len() {
2367                    borrowed[field_index] = Value::Int(new_value);
2368                    return 1;
2369                }
2370            }
2371
2372            0
2373        }
2374
2375        _ => 0,
2376    }
2377}
2378
2379#[no_mangle]
2380pub unsafe extern "C" fn jit_new_struct_safe(
2381    vm_ptr: *mut VM,
2382    struct_name_ptr: *const u8,
2383    struct_name_len: usize,
2384    field_names_ptr: *const *const u8,
2385    field_name_lens_ptr: *const usize,
2386    field_values_ptr: *const Value,
2387    field_count: usize,
2388    out: *mut Value,
2389) -> u8 {
2390    if struct_name_ptr.is_null() || out.is_null() || vm_ptr.is_null() {
2391        jit::log(|| "jit_new_struct_safe: null pointer input".to_string());
2392        return 0;
2393    }
2394
2395    if field_count > 0
2396        && (field_names_ptr.is_null()
2397            || field_name_lens_ptr.is_null()
2398            || field_values_ptr.is_null())
2399    {
2400        return 0;
2401    }
2402
2403    let struct_name_slice = slice::from_raw_parts(struct_name_ptr, struct_name_len);
2404    let struct_name = match str::from_utf8(struct_name_slice) {
2405        Ok(s) => s.to_string(),
2406        Err(_) => return 0,
2407    };
2408    let mut fields = Vec::with_capacity(field_count);
2409    for i in 0..field_count {
2410        let field_name_ptr = *field_names_ptr.add(i);
2411        let field_name_len = *field_name_lens_ptr.add(i);
2412        let field_name_slice = slice::from_raw_parts(field_name_ptr, field_name_len);
2413        let field_name = match str::from_utf8(field_name_slice) {
2414            Ok(s) => Rc::new(s.to_string()),
2415            Err(_) => return 0,
2416        };
2417        let field_value_ptr = field_values_ptr.add(i);
2418        let field_value = (&*field_value_ptr).clone();
2419        fields.push((field_name, field_value));
2420    }
2421
2422    let vm = &mut *vm_ptr;
2423    let struct_value = match vm.instantiate_struct(&struct_name, fields) {
2424        Ok(value) => value,
2425        Err(err) => {
2426            jit::log(|| {
2427                format!(
2428                    "jit_new_struct_safe: failed to instantiate '{}': {}",
2429                    struct_name, err
2430                )
2431            });
2432            return 0;
2433        }
2434    };
2435    ptr::write(out, struct_value);
2436    1
2437}
2438
2439#[no_mangle]
2440pub unsafe extern "C" fn jit_move_safe(src_ptr: *const Value, dest_ptr: *mut Value) -> u8 {
2441    if src_ptr.is_null() || dest_ptr.is_null() {
2442        return 0;
2443    }
2444
2445    let src_value = &*src_ptr;
2446    let cloned_value = src_value.clone();
2447    ptr::write(dest_ptr, cloned_value);
2448    1
2449}