goscript_vm/
objects.rs

1#![macro_use]
2use super::channel::Channel;
3use super::ffi::Ffi;
4use super::gc::GcoVec;
5use super::instruction::{Instruction, OpIndex, Opcode, ValueType};
6use super::metadata::*;
7use super::stack::Stack;
8use super::value::{rcount_mark_and_queue, EmptyResult, GosValue, RCQueue, RCount};
9use goscript_parser::objects::{EntityKey, IdentKey};
10use slotmap::{new_key_type, DenseSlotMap};
11use std::cell::{Cell, Ref, RefCell, RefMut};
12use std::cmp::Ordering;
13use std::collections::HashMap;
14use std::convert::TryFrom;
15use std::convert::TryInto;
16use std::fmt::Write;
17use std::fmt::{self, Display};
18use std::hash::{Hash, Hasher};
19use std::iter::FromIterator;
20use std::rc::{Rc, Weak};
21
22const DEFAULT_CAPACITY: usize = 128;
23
24#[macro_export]
25macro_rules! null_key {
26    () => {
27        slotmap::Key::null()
28    };
29}
30
31new_key_type! { pub struct MetadataKey; }
32new_key_type! { pub struct FunctionKey; }
33new_key_type! { pub struct PackageKey; }
34
35pub type MetadataObjs = DenseSlotMap<MetadataKey, MetadataType>;
36pub type FunctionObjs = DenseSlotMap<FunctionKey, FunctionVal>;
37pub type PackageObjs = DenseSlotMap<PackageKey, PackageVal>;
38
39pub fn key_to_u64<K>(key: K) -> u64
40where
41    K: slotmap::Key,
42{
43    let data: slotmap::KeyData = key.into();
44    data.as_ffi()
45}
46
47pub fn u64_to_key<K>(u: u64) -> K
48where
49    K: slotmap::Key,
50{
51    let data = slotmap::KeyData::from_ffi(u);
52    data.into()
53}
54
55#[derive(Debug)]
56pub struct VMObjects {
57    pub metas: MetadataObjs,
58    pub functions: FunctionObjs,
59    pub packages: PackageObjs,
60    pub metadata: Metadata,
61}
62
63impl VMObjects {
64    pub fn new() -> VMObjects {
65        let mut metas = DenseSlotMap::with_capacity_and_key(DEFAULT_CAPACITY);
66        let md = Metadata::new(&mut metas);
67        VMObjects {
68            metas: metas,
69            functions: DenseSlotMap::with_capacity_and_key(DEFAULT_CAPACITY),
70            packages: DenseSlotMap::with_capacity_and_key(DEFAULT_CAPACITY),
71            metadata: md,
72        }
73    }
74}
75
76// ----------------------------------------------------------------------------
77// StringObj
78
79pub type StringIter<'a> = std::str::Chars<'a>;
80
81pub type StringEnumIter<'a> = std::iter::Enumerate<StringIter<'a>>;
82
83#[derive(Debug)]
84pub struct StringObj {
85    data: Rc<String>,
86    begin: usize,
87    end: usize,
88}
89
90impl StringObj {
91    #[inline]
92    pub fn with_str(s: String) -> StringObj {
93        let len = s.len();
94        StringObj {
95            data: Rc::new(s),
96            begin: 0,
97            end: len,
98        }
99    }
100
101    #[inline]
102    pub fn as_str(&self) -> &str {
103        &self.data.as_ref()[self.begin..self.end]
104    }
105
106    #[inline]
107    pub fn into_string(self) -> String {
108        Rc::try_unwrap(self.data).unwrap()
109    }
110
111    #[inline]
112    pub fn len(&self) -> usize {
113        self.end - self.begin
114    }
115
116    #[inline]
117    pub fn get_byte(&self, i: usize) -> Option<&u8> {
118        self.as_str().as_bytes().get(i)
119    }
120
121    pub fn slice(&self, begin: isize, end: isize) -> StringObj {
122        let self_end = self.len() as isize + 1;
123        let bi = begin as usize;
124        let ei = ((self_end + end) % self_end) as usize;
125        StringObj {
126            data: Rc::clone(&self.data),
127            begin: bi,
128            end: ei,
129        }
130    }
131
132    pub fn iter(&self) -> StringIter {
133        self.as_str().chars()
134    }
135}
136
137impl Clone for StringObj {
138    #[inline]
139    fn clone(&self) -> Self {
140        StringObj {
141            data: Rc::clone(&self.data),
142            begin: self.begin,
143            end: self.end,
144        }
145    }
146}
147
148impl PartialEq for StringObj {
149    #[inline]
150    fn eq(&self, other: &StringObj) -> bool {
151        self.as_str().eq(other.as_str())
152    }
153}
154
155impl Eq for StringObj {}
156
157impl PartialOrd for StringObj {
158    #[inline]
159    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
160        Some(self.cmp(other))
161    }
162}
163
164impl Ord for StringObj {
165    #[inline]
166    fn cmp(&self, other: &Self) -> Ordering {
167        self.as_str().cmp(other.as_str())
168    }
169}
170
171// ----------------------------------------------------------------------------
172// MapObj
173
174pub type GosHashMap = HashMap<GosValue, RefCell<GosValue>>;
175
176pub type GosHashMapIter<'a> = std::collections::hash_map::Iter<'a, GosValue, RefCell<GosValue>>;
177
178#[derive(Debug)]
179pub struct MapObj {
180    pub meta: GosMetadata,
181    default_val: RefCell<GosValue>,
182    pub map: Option<Rc<RefCell<GosHashMap>>>,
183}
184
185impl MapObj {
186    pub fn new(meta: GosMetadata, default_val: GosValue) -> MapObj {
187        MapObj {
188            meta: meta,
189            default_val: RefCell::new(default_val),
190            map: Some(Rc::new(RefCell::new(HashMap::new()))),
191        }
192    }
193
194    pub fn new_nil(meta: GosMetadata, default_val: GosValue) -> MapObj {
195        MapObj {
196            meta: meta,
197            default_val: RefCell::new(default_val),
198            map: None,
199        }
200    }
201
202    /// deep_clone creates a new MapObj with duplicated content of 'self.map'
203    pub fn deep_clone(&self, gcos: &GcoVec) -> MapObj {
204        let m = self.map.as_ref().map(|x| {
205            Rc::new(RefCell::new(
206                x.borrow()
207                    .iter()
208                    .map(|(k, v)| {
209                        (
210                            k.deep_clone(gcos),
211                            RefCell::new(v.borrow().deep_clone(gcos)),
212                        )
213                    })
214                    .collect(),
215            ))
216        });
217        MapObj {
218            meta: self.meta,
219            default_val: self.default_val.clone(),
220            map: m,
221        }
222    }
223
224    #[inline]
225    pub fn insert(&self, key: GosValue, val: GosValue) -> Option<GosValue> {
226        self.borrow_data_mut()
227            .insert(key, RefCell::new(val))
228            .map(|x| x.into_inner())
229    }
230
231    #[inline]
232    pub fn is_nil(&self) -> bool {
233        self.map.is_none()
234    }
235
236    #[inline]
237    pub fn get(&self, key: &GosValue) -> GosValue {
238        let mref = self.borrow_data();
239        let cell = match mref.get(key) {
240            Some(v) => v,
241            None => &self.default_val,
242        };
243        cell.clone().into_inner()
244    }
245
246    #[inline]
247    pub fn try_get(&self, key: &GosValue) -> Option<GosValue> {
248        let mref = self.borrow_data();
249        mref.get(key).map(|x| x.clone().into_inner())
250    }
251
252    /// touch_key makes sure there is a value for the 'key', a default value is set if
253    /// the value is empty
254    #[inline]
255    pub fn touch_key(&self, key: &GosValue) {
256        if self.borrow_data().get(&key).is_none() {
257            self.borrow_data_mut()
258                .insert(key.clone(), self.default_val.clone());
259        }
260    }
261
262    #[inline]
263    pub fn len(&self) -> usize {
264        self.borrow_data().len()
265    }
266
267    #[inline]
268    pub fn borrow_data_mut(&self) -> RefMut<GosHashMap> {
269        self.map.as_ref().unwrap().borrow_mut()
270    }
271
272    #[inline]
273    pub fn borrow_data(&self) -> Ref<GosHashMap> {
274        self.map.as_ref().unwrap().borrow()
275    }
276
277    #[inline]
278    pub fn clone_inner(&self) -> Rc<RefCell<GosHashMap>> {
279        self.map.as_ref().unwrap().clone()
280    }
281}
282
283impl Clone for MapObj {
284    fn clone(&self) -> Self {
285        MapObj {
286            meta: self.meta,
287            default_val: self.default_val.clone(),
288            map: self.map.clone(),
289        }
290    }
291}
292
293impl PartialEq for MapObj {
294    fn eq(&self, _other: &MapObj) -> bool {
295        unreachable!() //false
296    }
297}
298
299impl Eq for MapObj {}
300
301impl Display for MapObj {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        f.write_str("map[")?;
304        if let Some(m) = &self.map {
305            for (i, kv) in m.borrow().iter().enumerate() {
306                if i > 0 {
307                    f.write_char(' ')?;
308                }
309                let v: &GosValue = &kv.1.borrow();
310                write!(f, "{}:{}", kv.0, v)?
311            }
312        }
313        f.write_char(']')
314    }
315}
316
317// ----------------------------------------------------------------------------
318// ArrayObj
319
320pub type GosVec = Vec<RefCell<GosValue>>;
321
322#[derive(Debug)]
323pub struct ArrayObj {
324    pub meta: GosMetadata,
325    pub vec: Rc<RefCell<GosVec>>,
326}
327
328impl ArrayObj {
329    pub fn with_size(size: usize, val: &GosValue, meta: GosMetadata, gcos: &GcoVec) -> ArrayObj {
330        let mut v = GosVec::with_capacity(size);
331        for _ in 0..size {
332            v.push(RefCell::new(val.copy_semantic(gcos)))
333        }
334        ArrayObj {
335            meta: meta,
336            vec: Rc::new(RefCell::new(v)),
337        }
338    }
339
340    pub fn with_data(val: Vec<GosValue>, meta: GosMetadata) -> ArrayObj {
341        ArrayObj {
342            meta: meta,
343            vec: Rc::new(RefCell::new(
344                val.into_iter().map(|x| RefCell::new(x)).collect(),
345            )),
346        }
347    }
348
349    pub fn deep_clone(&self, gcos: &GcoVec) -> ArrayObj {
350        ArrayObj {
351            meta: self.meta,
352            vec: Rc::new(RefCell::new(
353                self.borrow_data()
354                    .iter()
355                    .map(|x| RefCell::new(x.borrow().deep_clone(gcos)))
356                    .collect(),
357            )),
358        }
359    }
360
361    #[inline]
362    pub fn len(&self) -> usize {
363        self.borrow_data().len()
364    }
365
366    #[inline]
367    pub fn borrow_data_mut(&self) -> std::cell::RefMut<GosVec> {
368        self.vec.borrow_mut()
369    }
370
371    #[inline]
372    pub fn borrow_data(&self) -> std::cell::Ref<GosVec> {
373        self.vec.borrow()
374    }
375
376    #[inline]
377    pub fn get(&self, i: usize) -> Option<GosValue> {
378        self.borrow_data().get(i).map(|x| x.clone().into_inner())
379    }
380
381    #[inline]
382    pub fn set_from(&self, other: &ArrayObj) {
383        *self.borrow_data_mut() = other.borrow_data().clone()
384    }
385}
386
387impl Display for ArrayObj {
388    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389        f.write_char('[')?;
390        for (i, e) in self.vec.borrow().iter().enumerate() {
391            if i > 0 {
392                f.write_char(' ')?;
393            }
394            write!(f, "{}", e.borrow())?
395        }
396        f.write_char(']')
397    }
398}
399
400impl Hash for ArrayObj {
401    fn hash<H: Hasher>(&self, state: &mut H) {
402        for e in self.borrow_data().iter() {
403            e.borrow().hash(state);
404        }
405    }
406}
407
408impl Eq for ArrayObj {}
409
410impl PartialEq for ArrayObj {
411    fn eq(&self, b: &ArrayObj) -> bool {
412        if self.borrow_data().len() != b.borrow_data().len() {
413            return false;
414        }
415        for (i, e) in self.borrow_data().iter().enumerate() {
416            if e != b.borrow_data().get(i).unwrap() {
417                return false;
418            }
419        }
420        true
421    }
422}
423
424impl Clone for ArrayObj {
425    fn clone(&self) -> Self {
426        ArrayObj {
427            meta: self.meta,
428            vec: self.vec.clone(),
429        }
430    }
431}
432
433// ----------------------------------------------------------------------------
434// SliceObj
435
436#[derive(Debug)]
437pub struct SliceObj {
438    pub meta: GosMetadata,
439    begin: Cell<usize>,
440    end: Cell<usize>,
441    soft_cap: Cell<usize>, // <= self.vec.capacity()
442    pub vec: Option<Rc<RefCell<GosVec>>>,
443}
444
445impl<'a> SliceObj {
446    pub fn new(
447        len: usize,
448        cap: usize,
449        meta: GosMetadata,
450        default_val: Option<&GosValue>,
451    ) -> SliceObj {
452        assert!(cap >= len);
453        let mut val = SliceObj {
454            meta: meta,
455            begin: Cell::from(0),
456            end: Cell::from(0),
457            soft_cap: Cell::from(cap),
458            vec: Some(Rc::new(RefCell::new(Vec::with_capacity(cap)))),
459        };
460        for _ in 0..len {
461            val.push(default_val.unwrap().clone());
462        }
463        val
464    }
465
466    pub fn with_data(val: Vec<GosValue>, meta: GosMetadata) -> SliceObj {
467        SliceObj {
468            meta: meta,
469            begin: Cell::from(0),
470            end: Cell::from(val.len()),
471            soft_cap: Cell::from(val.len()),
472            vec: Some(Rc::new(RefCell::new(
473                val.into_iter().map(|x| RefCell::new(x)).collect(),
474            ))),
475        }
476    }
477
478    pub fn with_array(arr: &ArrayObj, begin: isize, end: isize) -> SliceObj {
479        let elem_meta = GosMetadata::new_slice_from_array(arr.meta);
480        let len = arr.len();
481        let self_end = len as isize + 1;
482        let bi = begin as usize;
483        let ei = ((self_end + end) % self_end) as usize;
484        SliceObj {
485            meta: elem_meta,
486            begin: Cell::from(bi),
487            end: Cell::from(ei),
488            soft_cap: Cell::from(len),
489            vec: Some(arr.vec.clone()),
490        }
491    }
492
493    pub fn new_nil(meta: GosMetadata) -> SliceObj {
494        SliceObj {
495            meta: meta,
496            begin: Cell::from(0),
497            end: Cell::from(0),
498            soft_cap: Cell::from(0),
499            vec: None,
500        }
501    }
502
503    pub fn set_from(&self, other: &SliceObj) {
504        self.begin.set(other.begin());
505        self.end.set(other.end());
506        self.soft_cap.set(other.soft_cap());
507        *self.borrow_data_mut() = other.borrow_data().clone()
508    }
509
510    /// deep_clone creates a new SliceObj with duplicated content of 'self.vec'
511    pub fn deep_clone(&self, gcos: &GcoVec) -> SliceObj {
512        SliceObj {
513            meta: self.meta,
514            begin: Cell::from(0),
515            end: Cell::from(self.cap()),
516            soft_cap: Cell::from(self.cap()),
517            vec: self.vec.clone().map(|vec| {
518                Rc::new(RefCell::new(Vec::from_iter(
519                    vec.borrow()[self.begin()..self.end()]
520                        .iter()
521                        .map(|x| RefCell::new(x.borrow().deep_clone(gcos))),
522                )))
523            }),
524        }
525    }
526
527    #[inline]
528    pub fn is_nil(&self) -> bool {
529        self.vec.is_none()
530    }
531
532    #[inline]
533    pub fn begin(&self) -> usize {
534        self.begin.get()
535    }
536
537    #[inline]
538    pub fn end(&self) -> usize {
539        self.end.get()
540    }
541
542    #[inline]
543    pub fn soft_cap(&self) -> usize {
544        self.soft_cap.get()
545    }
546
547    #[inline]
548    pub fn len(&self) -> usize {
549        self.end() - self.begin()
550    }
551
552    #[inline]
553    pub fn cap(&self) -> usize {
554        self.soft_cap() - self.begin()
555    }
556
557    #[inline]
558    pub fn borrow(&self) -> SliceRef {
559        SliceRef::new(self)
560    }
561
562    #[inline]
563    pub fn borrow_data_mut(&self) -> std::cell::RefMut<GosVec> {
564        match &self.vec {
565            Some(v) => v.borrow_mut(),
566            None => unreachable!(), //todo: error handling
567        }
568    }
569
570    #[inline]
571    pub fn borrow_data(&self) -> std::cell::Ref<GosVec> {
572        match &self.vec {
573            Some(v) => v.borrow(),
574            None => unreachable!(), //todo: error handling
575        }
576    }
577
578    #[inline]
579    pub fn push(&mut self, val: GosValue) {
580        self.try_grow_vec(self.len() + 1);
581        self.borrow_data_mut().push(RefCell::new(val));
582        *self.end.get_mut() += 1;
583    }
584
585    #[inline]
586    pub fn append(&mut self, vals: &mut GosVec) {
587        let new_len = self.len() + vals.len();
588        self.try_grow_vec(new_len);
589        self.borrow_data_mut().append(vals);
590        *self.end.get_mut() = self.begin() + new_len;
591    }
592
593    #[inline]
594    pub fn get(&self, i: usize) -> Option<GosValue> {
595        self.borrow_data()
596            .get(self.begin() + i)
597            .map(|x| x.clone().into_inner())
598    }
599
600    #[inline]
601    pub fn set(&self, i: usize, val: GosValue) {
602        self.borrow_data()[self.begin() + i].replace(val);
603    }
604
605    #[inline]
606    pub fn slice(&self, begin: isize, end: isize, max: isize) -> SliceObj {
607        let self_len = self.len() as isize + 1;
608        let self_cap = self.cap() as isize + 1;
609        let bi = begin as usize;
610        let ei = ((self_len + end) % self_len) as usize;
611        let mi = ((self_cap + max) % self_cap) as usize;
612        SliceObj {
613            meta: self.meta,
614            begin: Cell::from(self.begin() + bi),
615            end: Cell::from(self.begin() + ei),
616            soft_cap: Cell::from(self.begin() + mi),
617            vec: self.vec.clone(),
618        }
619    }
620
621    #[inline]
622    pub fn get_vec(&self) -> Vec<GosValue> {
623        self.borrow_data()
624            .iter()
625            .map(|x| x.borrow().clone())
626            .collect()
627    }
628
629    fn try_grow_vec(&mut self, len: usize) {
630        let mut cap = self.cap();
631        assert!(cap >= self.len());
632        if cap >= len {
633            return;
634        }
635        while cap < len {
636            if cap < 1024 {
637                cap *= 2
638            } else {
639                cap = (cap as f32 * 1.25) as usize
640            }
641        }
642        let data_len = self.len();
643        let mut vec = Vec::from_iter(self.borrow_data()[self.begin()..self.end()].iter().cloned());
644        vec.reserve_exact(cap - vec.len());
645        self.vec = Some(Rc::new(RefCell::new(vec)));
646        self.begin.set(0);
647        self.end.set(data_len);
648        self.soft_cap.set(cap);
649    }
650}
651
652impl Clone for SliceObj {
653    fn clone(&self) -> Self {
654        SliceObj {
655            meta: self.meta,
656            begin: self.begin.clone(),
657            end: self.end.clone(),
658            soft_cap: self.soft_cap.clone(),
659            vec: self.vec.clone(),
660        }
661    }
662}
663
664impl Display for SliceObj {
665    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
666        f.write_char('[')?;
667        for (i, e) in self.borrow().iter().enumerate() {
668            if i > 0 {
669                f.write_char(' ')?;
670            }
671            write!(f, "{}", e.borrow())?
672        }
673        f.write_char(']')
674    }
675}
676
677pub struct SliceRef<'a> {
678    vec_ref: Ref<'a, GosVec>,
679    begin: usize,
680    end: usize,
681}
682
683pub type SliceIter<'a> = std::slice::Iter<'a, RefCell<GosValue>>;
684
685pub type SliceEnumIter<'a> = std::iter::Enumerate<SliceIter<'a>>;
686
687impl<'a> SliceRef<'a> {
688    pub fn new(s: &SliceObj) -> SliceRef {
689        SliceRef {
690            vec_ref: s.borrow_data(),
691            begin: s.begin(),
692            end: s.end(),
693        }
694    }
695
696    pub fn iter(&self) -> SliceIter {
697        self.vec_ref[self.begin..self.end].iter()
698    }
699
700    #[inline]
701    pub fn get(&self, i: usize) -> Option<&RefCell<GosValue>> {
702        self.vec_ref.get(self.begin + i)
703    }
704}
705
706impl PartialEq for SliceObj {
707    fn eq(&self, _other: &SliceObj) -> bool {
708        unreachable!() //false
709    }
710}
711
712impl Eq for SliceObj {}
713
714// ----------------------------------------------------------------------------
715// StructObj
716
717#[derive(Clone, Debug)]
718pub struct StructObj {
719    pub meta: GosMetadata,
720    pub fields: Vec<GosValue>,
721}
722
723impl StructObj {
724    pub fn deep_clone(&self, gcos: &GcoVec) -> StructObj {
725        StructObj {
726            meta: self.meta,
727            fields: Vec::from_iter(self.fields.iter().map(|x| x.deep_clone(gcos))),
728        }
729    }
730}
731
732impl Eq for StructObj {}
733
734impl PartialEq for StructObj {
735    #[inline]
736    fn eq(&self, other: &StructObj) -> bool {
737        for (i, f) in self.fields.iter().enumerate() {
738            if f != &other.fields[i] {
739                return false;
740            }
741        }
742        return true;
743    }
744}
745
746impl Hash for StructObj {
747    #[inline]
748    fn hash<H: Hasher>(&self, state: &mut H) {
749        for f in self.fields.iter() {
750            f.hash(state)
751        }
752    }
753}
754
755impl Display for StructObj {
756    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
757        f.write_char('{')?;
758        for (i, fld) in self.fields.iter().enumerate() {
759            if i > 0 {
760                f.write_char(' ')?;
761            }
762            write!(f, "{}", fld)?
763        }
764        f.write_char('}')
765    }
766}
767
768// ----------------------------------------------------------------------------
769// InterfaceObj
770
771#[derive(Clone, Debug)]
772pub struct UnderlyingFfi {
773    pub ffi_obj: Rc<RefCell<dyn Ffi>>,
774    pub methods: Vec<(String, GosMetadata)>,
775}
776
777impl UnderlyingFfi {
778    pub fn new(obj: Rc<RefCell<dyn Ffi>>, methods: Vec<(String, GosMetadata)>) -> UnderlyingFfi {
779        UnderlyingFfi {
780            ffi_obj: obj,
781            methods: methods,
782        }
783    }
784}
785
786#[derive(Clone, Debug)]
787pub enum IfaceUnderlying {
788    None,
789    Gos(GosValue, Option<Rc<Vec<FunctionKey>>>),
790    Ffi(UnderlyingFfi),
791}
792
793impl Eq for IfaceUnderlying {}
794
795impl PartialEq for IfaceUnderlying {
796    #[inline]
797    fn eq(&self, other: &IfaceUnderlying) -> bool {
798        match (self, other) {
799            (Self::None, Self::None) => true,
800            (Self::Gos(x, _), Self::Gos(y, _)) => x == y,
801            (Self::Ffi(x), Self::Ffi(y)) => Rc::ptr_eq(&x.ffi_obj, &y.ffi_obj),
802            _ => false,
803        }
804    }
805}
806
807#[derive(Clone, Debug)]
808pub struct InterfaceObj {
809    pub meta: GosMetadata,
810    // the Named object behind the interface
811    // mapping from interface's methods to object's methods
812    underlying: IfaceUnderlying,
813}
814
815impl InterfaceObj {
816    pub fn new(meta: GosMetadata, underlying: IfaceUnderlying) -> InterfaceObj {
817        InterfaceObj {
818            meta: meta,
819            underlying: underlying,
820        }
821    }
822
823    #[inline]
824    pub fn underlying(&self) -> &IfaceUnderlying {
825        &self.underlying
826    }
827
828    #[inline]
829    pub fn set_underlying(&mut self, v: IfaceUnderlying) {
830        self.underlying = v;
831    }
832
833    #[inline]
834    pub fn underlying_value(&self) -> Option<&GosValue> {
835        match self.underlying() {
836            IfaceUnderlying::Gos(v, _) => Some(v),
837            _ => None,
838        }
839    }
840
841    #[inline]
842    pub fn is_nil(&self) -> bool {
843        self.underlying() == &IfaceUnderlying::None
844    }
845
846    /// for gc
847    pub fn ref_sub_one(&self) {
848        match self.underlying() {
849            IfaceUnderlying::Gos(v, _) => v.ref_sub_one(),
850            _ => {}
851        };
852    }
853
854    /// for gc
855    pub fn mark_dirty(&self, queue: &mut RCQueue) {
856        match self.underlying() {
857            IfaceUnderlying::Gos(v, _) => v.mark_dirty(queue),
858            _ => {}
859        };
860    }
861}
862
863impl Eq for InterfaceObj {}
864
865impl PartialEq for InterfaceObj {
866    #[inline]
867    fn eq(&self, other: &InterfaceObj) -> bool {
868        self.underlying() == other.underlying()
869    }
870}
871
872impl Hash for InterfaceObj {
873    #[inline]
874    fn hash<H: Hasher>(&self, state: &mut H) {
875        match self.underlying() {
876            IfaceUnderlying::Gos(v, _) => v.hash(state),
877            IfaceUnderlying::Ffi(ffi) => Rc::as_ptr(&ffi.ffi_obj).hash(state),
878            IfaceUnderlying::None => 0.hash(state),
879        }
880    }
881}
882
883impl Display for InterfaceObj {
884    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
885        match self.underlying() {
886            IfaceUnderlying::Gos(v, _) => write!(f, "{}", v),
887            IfaceUnderlying::Ffi(ffi) => write!(f, "<ffi>{:?}", ffi.ffi_obj.borrow()),
888            IfaceUnderlying::None => f.write_str("<nil>"),
889        }
890    }
891}
892
893// ----------------------------------------------------------------------------
894// ChannelObj
895
896#[derive(Clone, Debug)]
897pub struct ChannelObj {
898    pub meta: GosMetadata,
899    pub chan: Channel,
900}
901
902impl ChannelObj {
903    pub fn new(meta: GosMetadata, cap: usize) -> ChannelObj {
904        ChannelObj {
905            meta: meta,
906            chan: Channel::new(cap),
907        }
908    }
909
910    #[inline]
911    pub fn len(&self) -> usize {
912        self.chan.len()
913    }
914
915    #[inline]
916    pub fn cap(&self) -> usize {
917        self.chan.cap()
918    }
919
920    #[inline]
921    pub fn close(&self) {
922        self.chan.close()
923    }
924
925    pub async fn send(&self, v: &GosValue) -> EmptyResult {
926        self.chan.send(v).await
927    }
928
929    pub async fn recv(&self) -> Option<GosValue> {
930        self.chan.recv().await
931    }
932}
933
934// ----------------------------------------------------------------------------
935// PointerObj
936/// Logically there are 4 types of pointers, they point to:
937/// - local
938/// - slice member
939/// - struct field
940/// - package member
941/// and for pointers to locals, the default way of handling it is to use "UpValue"
942/// (PointerObj::UpVal). Struct/Map/Slice are optimizations for this type, when
943/// the pointee has a "real" pointer
944///
945
946#[derive(Debug, Clone)]
947pub enum PointerObj {
948    Released,
949    UpVal(UpValue),
950    Struct(Rc<(RefCell<StructObj>, RCount)>, GosMetadata),
951    Array(Rc<(ArrayObj, RCount)>, GosMetadata),
952    Slice(Rc<(SliceObj, RCount)>, GosMetadata),
953    Map(Rc<(MapObj, RCount)>, GosMetadata),
954    SliceMember(Rc<(SliceObj, RCount)>, OpIndex),
955    StructField(Rc<(RefCell<StructObj>, RCount)>, OpIndex),
956    PkgMember(PackageKey, OpIndex),
957}
958
959impl PointerObj {
960    #[inline]
961    pub fn new_local(val: GosValue) -> PointerObj {
962        match val {
963            GosValue::Named(s) => match &s.0 {
964                GosValue::Struct(stru) => PointerObj::Struct(stru.clone(), s.1),
965                GosValue::Array(arr) => PointerObj::Array(arr.clone(), s.1),
966                GosValue::Slice(slice) => PointerObj::Slice(slice.clone(), s.1),
967                GosValue::Map(map) => PointerObj::Map(map.clone(), s.1),
968                _ => {
969                    dbg!(s);
970                    unreachable!()
971                }
972            },
973            GosValue::Struct(s) => PointerObj::Struct(s.clone(), GosMetadata::Untyped),
974            GosValue::Array(a) => PointerObj::Array(a.clone(), GosMetadata::Untyped),
975            GosValue::Slice(s) => PointerObj::Slice(s.clone(), GosMetadata::Untyped),
976            GosValue::Map(m) => PointerObj::Map(m.clone(), GosMetadata::Untyped),
977            _ => {
978                dbg!(val);
979                unreachable!()
980            }
981        }
982    }
983
984    #[inline]
985    pub fn set_local_ref_type(&self, val: GosValue) {
986        match self {
987            Self::Struct(v, _) => {
988                let mref: &mut StructObj = &mut v.0.borrow_mut();
989                *mref = val.try_get_struct().unwrap().0.borrow().clone();
990            }
991            _ => unreachable!(),
992        }
993    }
994
995    pub fn deep_clone(&self, gcos: &GcoVec) -> PointerObj {
996        match &self {
997            PointerObj::Released => PointerObj::Released,
998            PointerObj::Struct(s, m) => PointerObj::Struct(
999                Rc::new((RefCell::new(s.0.borrow().deep_clone(gcos)), Cell::new(0))),
1000                *m,
1001            ),
1002            PointerObj::Slice(s, m) => {
1003                PointerObj::Slice(Rc::new((s.0.deep_clone(gcos), Cell::new(0))), *m)
1004            }
1005            PointerObj::Map(map, m) => {
1006                PointerObj::Map(Rc::new((map.0.deep_clone(gcos), Cell::new(0))), *m)
1007            }
1008            _ => unreachable!(),
1009        }
1010    }
1011
1012    /// for gc
1013    pub fn ref_sub_one(&self) {
1014        match &self {
1015            PointerObj::UpVal(uv) => uv.ref_sub_one(),
1016            PointerObj::Struct(s, _) => s.1.set(s.1.get() - 1),
1017            PointerObj::Slice(s, _) => s.1.set(s.1.get() - 1),
1018            PointerObj::Map(s, _) => s.1.set(s.1.get() - 1),
1019            PointerObj::SliceMember(s, _) => s.1.set(s.1.get() - 1),
1020            PointerObj::StructField(s, _) => s.1.set(s.1.get() - 1),
1021            _ => {}
1022        };
1023    }
1024
1025    /// for gc
1026    pub fn mark_dirty(&self, queue: &mut RCQueue) {
1027        match &self {
1028            PointerObj::UpVal(uv) => uv.mark_dirty(queue),
1029            PointerObj::Struct(s, _) => rcount_mark_and_queue(&s.1, queue),
1030            PointerObj::Slice(s, _) => rcount_mark_and_queue(&s.1, queue),
1031            PointerObj::Map(s, _) => rcount_mark_and_queue(&s.1, queue),
1032            PointerObj::SliceMember(s, _) => rcount_mark_and_queue(&s.1, queue),
1033            PointerObj::StructField(s, _) => rcount_mark_and_queue(&s.1, queue),
1034            _ => {}
1035        };
1036    }
1037}
1038
1039impl Eq for PointerObj {}
1040
1041impl PartialEq for PointerObj {
1042    #[inline]
1043    fn eq(&self, other: &PointerObj) -> bool {
1044        match (self, other) {
1045            (Self::UpVal(x), Self::UpVal(y)) => x == y,
1046            (Self::Struct(x, _), Self::Struct(y, _)) => x == y,
1047            (Self::Array(x, _), Self::Array(y, _)) => x == y,
1048            (Self::Slice(x, _), Self::Slice(y, _)) => x == y,
1049            (Self::Map(x, _), Self::Map(y, _)) => x == y,
1050            (Self::SliceMember(x, ix), Self::SliceMember(y, iy)) => Rc::ptr_eq(x, y) && ix == iy,
1051            (Self::StructField(x, ix), Self::StructField(y, iy)) => Rc::ptr_eq(x, y) && ix == iy,
1052            (Self::PkgMember(ka, ix), Self::PkgMember(kb, iy)) => ka == kb && ix == iy,
1053            _ => false,
1054        }
1055    }
1056}
1057
1058impl Hash for PointerObj {
1059    fn hash<H: Hasher>(&self, state: &mut H) {
1060        match self {
1061            Self::UpVal(x) => x.hash(state),
1062            Self::Struct(s, _) => Rc::as_ptr(s).hash(state),
1063            Self::Array(s, _) => Rc::as_ptr(s).hash(state),
1064            Self::Slice(s, _) => Rc::as_ptr(s).hash(state),
1065            Self::Map(s, _) => Rc::as_ptr(s).hash(state),
1066            Self::SliceMember(s, index) => {
1067                Rc::as_ptr(s).hash(state);
1068                index.hash(state);
1069            }
1070            Self::StructField(s, index) => {
1071                Rc::as_ptr(s).hash(state);
1072                index.hash(state);
1073            }
1074            Self::PkgMember(p, index) => {
1075                p.hash(state);
1076                index.hash(state);
1077            }
1078            Self::Released => unreachable!(),
1079        }
1080    }
1081}
1082
1083impl Display for PointerObj {
1084    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1085        match self {
1086            Self::UpVal(uv) => f.write_fmt(format_args!("{:p}", Rc::as_ptr(&uv.inner))),
1087            Self::Struct(s, _) => f.write_fmt(format_args!("{:p}", Rc::as_ptr(&s))),
1088            Self::Array(s, _) => f.write_fmt(format_args!("{:p}", Rc::as_ptr(&s))),
1089            Self::Slice(s, _) => f.write_fmt(format_args!("{:p}", Rc::as_ptr(&s))),
1090            Self::Map(m, _) => f.write_fmt(format_args!("{:p}", Rc::as_ptr(&m))),
1091            Self::SliceMember(s, i) => f.write_fmt(format_args!("{:p}i{}", Rc::as_ptr(&s), i)),
1092            Self::StructField(s, i) => f.write_fmt(format_args!("{:p}i{}", Rc::as_ptr(&s), i)),
1093            Self::PkgMember(p, i) => f.write_fmt(format_args!("{:x}i{}", key_to_u64(*p), i)),
1094            Self::Released => f.write_str("released!!!"),
1095        }
1096    }
1097}
1098
1099// ----------------------------------------------------------------------------
1100// ClosureObj
1101
1102#[derive(Clone, Debug)]
1103pub struct ValueDesc {
1104    pub func: FunctionKey,
1105    pub index: OpIndex,
1106    pub typ: ValueType,
1107    pub is_up_value: bool,
1108    pub stack: Weak<RefCell<Stack>>,
1109    pub stack_base: OpIndex,
1110}
1111
1112impl Eq for ValueDesc {}
1113
1114impl PartialEq for ValueDesc {
1115    #[inline]
1116    fn eq(&self, other: &ValueDesc) -> bool {
1117        self.index == other.index
1118    }
1119}
1120
1121impl ValueDesc {
1122    pub fn new(func: FunctionKey, index: OpIndex, typ: ValueType, is_up_value: bool) -> ValueDesc {
1123        ValueDesc {
1124            func: func,
1125            index: index,
1126            typ: typ,
1127            is_up_value: is_up_value,
1128            stack: Weak::new(),
1129            stack_base: 0,
1130        }
1131    }
1132
1133    pub fn clone_with_stack(&self, stack: Weak<RefCell<Stack>>, stack_base: OpIndex) -> ValueDesc {
1134        ValueDesc {
1135            func: self.func,
1136            index: self.index,
1137            typ: self.typ,
1138            is_up_value: self.is_up_value,
1139            stack: stack,
1140            stack_base: stack_base,
1141        }
1142    }
1143}
1144
1145#[derive(Clone, Debug, PartialEq, Eq)]
1146pub enum UpValueState {
1147    /// Parent CallFrame is still alive, pointing to a local variable
1148    Open(ValueDesc), // (what func is the var defined, the index of the var)
1149    // Parent CallFrame is released, pointing to a pointer value in the global pool
1150    Closed(GosValue),
1151}
1152
1153#[derive(Clone, Debug, PartialEq)]
1154pub struct UpValue {
1155    pub inner: Rc<RefCell<UpValueState>>,
1156}
1157
1158impl UpValue {
1159    pub fn new(d: ValueDesc) -> UpValue {
1160        UpValue {
1161            inner: Rc::new(RefCell::new(UpValueState::Open(d))),
1162        }
1163    }
1164
1165    pub fn new_closed(v: GosValue) -> UpValue {
1166        UpValue {
1167            inner: Rc::new(RefCell::new(UpValueState::Closed(v))),
1168        }
1169    }
1170
1171    pub fn downgrade(&self) -> WeakUpValue {
1172        WeakUpValue {
1173            inner: Rc::downgrade(&self.inner),
1174        }
1175    }
1176
1177    pub fn desc(&self) -> ValueDesc {
1178        let r: &UpValueState = &self.inner.borrow();
1179        match r {
1180            UpValueState::Open(d) => d.clone(),
1181            _ => unreachable!(),
1182        }
1183    }
1184
1185    pub fn close(&self, val: GosValue) {
1186        *self.inner.borrow_mut() = UpValueState::Closed(val);
1187    }
1188
1189    /// for gc
1190    pub fn ref_sub_one(&self) {
1191        let state: &UpValueState = &self.inner.borrow();
1192        if let UpValueState::Closed(uvs) = state {
1193            uvs.ref_sub_one()
1194        }
1195    }
1196
1197    /// for gc
1198    pub fn mark_dirty(&self, queue: &mut RCQueue) {
1199        let state: &UpValueState = &self.inner.borrow();
1200        if let UpValueState::Closed(uvs) = state {
1201            uvs.mark_dirty(queue)
1202        }
1203    }
1204}
1205
1206impl Hash for UpValue {
1207    #[inline]
1208    fn hash<H: Hasher>(&self, state: &mut H) {
1209        let b: &UpValueState = &self.inner.borrow();
1210        match b {
1211            UpValueState::Open(desc) => desc.index.hash(state),
1212            UpValueState::Closed(_) => Rc::as_ptr(&self.inner).hash(state),
1213        }
1214    }
1215}
1216
1217#[derive(Clone, Debug)]
1218pub struct WeakUpValue {
1219    pub inner: Weak<RefCell<UpValueState>>,
1220}
1221
1222impl WeakUpValue {
1223    pub fn upgrade(&self) -> Option<UpValue> {
1224        Weak::upgrade(&self.inner).map(|x| UpValue { inner: x })
1225    }
1226}
1227
1228#[derive(Clone, Debug)]
1229pub struct FfiClosureObj {
1230    pub ffi: Rc<RefCell<dyn Ffi>>,
1231    pub func_name: String,
1232    pub meta: GosMetadata,
1233}
1234
1235#[derive(Clone, Debug)]
1236pub struct ClosureObj {
1237    pub func: Option<FunctionKey>,
1238    pub uvs: Option<HashMap<usize, UpValue>>,
1239    pub recv: Option<GosValue>,
1240
1241    pub ffi: Option<Box<FfiClosureObj>>,
1242
1243    pub meta: GosMetadata,
1244}
1245
1246impl ClosureObj {
1247    pub fn new_gos(key: FunctionKey, fobjs: &FunctionObjs, recv: Option<GosValue>) -> ClosureObj {
1248        let func = &fobjs[key];
1249        let uvs: Option<HashMap<usize, UpValue>> = if func.up_ptrs.len() > 0 {
1250            Some(
1251                func.up_ptrs
1252                    .iter()
1253                    .enumerate()
1254                    .filter(|(_, x)| x.is_up_value)
1255                    .map(|(i, x)| (i, UpValue::new(x.clone())))
1256                    .collect(),
1257            )
1258        } else {
1259            None
1260        };
1261        ClosureObj {
1262            func: Some(key),
1263            uvs: uvs,
1264            recv: recv,
1265            ffi: None,
1266            meta: func.meta,
1267        }
1268    }
1269
1270    #[inline]
1271    pub fn new_ffi(ffi: FfiClosureObj) -> ClosureObj {
1272        let m = ffi.meta;
1273        ClosureObj {
1274            func: None,
1275            uvs: None,
1276            recv: None,
1277            ffi: Some(Box::new(ffi)),
1278            meta: m,
1279        }
1280    }
1281
1282    /// for gc
1283    pub fn ref_sub_one(&self) {
1284        if self.func.is_some() {
1285            if let Some(uvs) = &self.uvs {
1286                for (_, v) in uvs.iter() {
1287                    v.ref_sub_one()
1288                }
1289            }
1290            if let Some(recv) = &self.recv {
1291                recv.ref_sub_one()
1292            }
1293        }
1294    }
1295
1296    /// for gc
1297    pub fn mark_dirty(&self, queue: &mut RCQueue) {
1298        if self.func.is_some() {
1299            if let Some(uvs) = &self.uvs {
1300                for (_, v) in uvs.iter() {
1301                    v.mark_dirty(queue)
1302                }
1303            }
1304            if let Some(recv) = &self.recv {
1305                recv.mark_dirty(queue)
1306            }
1307        }
1308    }
1309}
1310
1311// ----------------------------------------------------------------------------
1312// PackageVal
1313
1314/// PackageVal is part of the generated Bytecode, it stores imports, consts,
1315/// vars, funcs declared in a package
1316#[derive(Clone, Debug)]
1317pub struct PackageVal {
1318    name: String,
1319    members: Vec<Rc<RefCell<GosValue>>>, // imports, const, var, func are all stored here
1320    member_indices: HashMap<String, OpIndex>,
1321    // maps func_member_index of the constructor to pkg_member_index
1322    var_mapping: Option<HashMap<OpIndex, OpIndex>>,
1323}
1324
1325impl PackageVal {
1326    pub fn new(name: String) -> PackageVal {
1327        PackageVal {
1328            name: name,
1329            members: Vec::new(),
1330            member_indices: HashMap::new(),
1331            var_mapping: Some(HashMap::new()),
1332        }
1333    }
1334
1335    pub fn add_member(&mut self, name: String, val: GosValue) -> OpIndex {
1336        self.members.push(Rc::new(RefCell::new(val)));
1337        let index = (self.members.len() - 1) as OpIndex;
1338        self.member_indices.insert(name, index);
1339        index as OpIndex
1340    }
1341
1342    pub fn add_var_mapping(&mut self, name: String, fn_index: OpIndex) -> OpIndex {
1343        let index = *self.get_member_index(&name).unwrap();
1344        self.var_mapping
1345            .as_mut()
1346            .unwrap()
1347            .insert(fn_index.into(), index);
1348        index
1349    }
1350
1351    pub fn var_mut(&self, fn_member_index: OpIndex) -> RefMut<GosValue> {
1352        let index = self.var_mapping.as_ref().unwrap()[&fn_member_index];
1353        self.members[index as usize].borrow_mut()
1354    }
1355
1356    pub fn var_count(&self) -> usize {
1357        self.var_mapping.as_ref().unwrap().len()
1358    }
1359
1360    pub fn get_member_index(&self, name: &str) -> Option<&OpIndex> {
1361        self.member_indices.get(name)
1362    }
1363
1364    pub fn inited(&self) -> bool {
1365        self.var_mapping.is_none()
1366    }
1367
1368    pub fn set_inited(&mut self) {
1369        self.var_mapping = None
1370    }
1371
1372    #[inline]
1373    pub fn member(&self, i: OpIndex) -> Ref<GosValue> {
1374        self.members[i as usize].borrow()
1375    }
1376
1377    #[inline]
1378    pub fn member_mut(&self, i: OpIndex) -> RefMut<GosValue> {
1379        self.members[i as usize].borrow_mut()
1380    }
1381}
1382
1383// ----------------------------------------------------------------------------
1384// FunctionVal
1385
1386/// EntIndex is for addressing a variable in the scope of a function
1387#[derive(Clone, Copy, Debug, PartialEq)]
1388pub enum EntIndex {
1389    Const(OpIndex),
1390    LocalVar(OpIndex),
1391    UpValue(OpIndex),
1392    PackageMember(PackageKey, IdentKey),
1393    BuiltInVal(Opcode), // built-in identifiers
1394    BuiltInType(GosMetadata),
1395    Blank,
1396}
1397
1398impl From<EntIndex> for OpIndex {
1399    fn from(t: EntIndex) -> OpIndex {
1400        match t {
1401            EntIndex::Const(i) => i,
1402            EntIndex::LocalVar(i) => i,
1403            EntIndex::UpValue(i) => i,
1404            EntIndex::PackageMember(_, _) => unreachable!(),
1405            EntIndex::BuiltInVal(_) => unreachable!(),
1406            EntIndex::BuiltInType(_) => unreachable!(),
1407            EntIndex::Blank => unreachable!(),
1408        }
1409    }
1410}
1411
1412#[derive(Eq, PartialEq, Copy, Clone, Debug)]
1413pub enum FuncFlag {
1414    Default,
1415    PkgCtor,
1416    HasDefer,
1417}
1418
1419/// FunctionVal is the direct container of the Opcode.
1420#[derive(Clone, Debug)]
1421pub struct FunctionVal {
1422    pub package: PackageKey,
1423    pub meta: GosMetadata,
1424    code: Vec<Instruction>,
1425    pos: Vec<Option<usize>>,
1426    pub consts: Vec<GosValue>,
1427    pub up_ptrs: Vec<ValueDesc>,
1428
1429    pub ret_zeros: Vec<GosValue>,
1430    pub local_zeros: Vec<GosValue>,
1431    pub flag: FuncFlag,
1432
1433    param_count: usize,
1434    entities: HashMap<EntityKey, EntIndex>,
1435    uv_entities: HashMap<EntityKey, EntIndex>,
1436    local_alloc: u16,
1437}
1438
1439impl FunctionVal {
1440    pub fn new(
1441        package: PackageKey,
1442        meta: GosMetadata,
1443        objs: &VMObjects,
1444        gcv: &GcoVec,
1445        flag: FuncFlag,
1446    ) -> FunctionVal {
1447        match &objs.metas[meta.as_non_ptr()] {
1448            MetadataType::Signature(s) => {
1449                let mut returns = vec![];
1450                for m in s.results.iter() {
1451                    returns.push(zero_val!(m, objs, gcv));
1452                }
1453                let params = s.params.len() + s.recv.map_or(0, |_| 1);
1454                FunctionVal {
1455                    package: package,
1456                    meta: meta,
1457                    code: Vec::new(),
1458                    pos: Vec::new(),
1459                    consts: Vec::new(),
1460                    up_ptrs: Vec::new(),
1461                    ret_zeros: returns,
1462                    local_zeros: Vec::new(),
1463                    flag: flag,
1464                    param_count: params,
1465                    entities: HashMap::new(),
1466                    uv_entities: HashMap::new(),
1467                    local_alloc: 0,
1468                }
1469            }
1470            _ => unreachable!(),
1471        }
1472    }
1473
1474    #[inline]
1475    pub fn code(&self) -> &Vec<Instruction> {
1476        &self.code
1477    }
1478
1479    #[inline]
1480    pub fn instruction_mut(&mut self, i: usize) -> &mut Instruction {
1481        self.code.get_mut(i).unwrap()
1482    }
1483
1484    #[inline]
1485    pub fn pos(&self) -> &Vec<Option<usize>> {
1486        &self.pos
1487    }
1488
1489    #[inline]
1490    pub fn param_count(&self) -> usize {
1491        self.param_count
1492    }
1493
1494    #[inline]
1495    pub fn ret_count(&self) -> usize {
1496        self.ret_zeros.len()
1497    }
1498
1499    #[inline]
1500    pub fn is_ctor(&self) -> bool {
1501        self.flag == FuncFlag::PkgCtor
1502    }
1503
1504    #[inline]
1505    pub fn local_count(&self) -> usize {
1506        self.local_alloc as usize - self.param_count() - self.ret_count()
1507    }
1508
1509    #[inline]
1510    pub fn entity_index(&self, entity: &EntityKey) -> Option<&EntIndex> {
1511        self.entities.get(entity)
1512    }
1513
1514    #[inline]
1515    pub fn const_val(&self, index: OpIndex) -> &GosValue {
1516        &self.consts[index as usize]
1517    }
1518
1519    #[inline]
1520    pub fn offset(&self, loc: usize) -> OpIndex {
1521        // todo: don't crash if OpIndex overflows
1522        OpIndex::try_from((self.code.len() - loc) as isize).unwrap()
1523    }
1524
1525    #[inline]
1526    pub fn next_code_index(&self) -> usize {
1527        self.code.len()
1528    }
1529
1530    #[inline]
1531    pub fn push_inst_pos(&mut self, i: Instruction, pos: Option<usize>) {
1532        self.code.push(i);
1533        self.pos.push(pos);
1534    }
1535
1536    #[inline]
1537    pub fn emit_inst(
1538        &mut self,
1539        op: Opcode,
1540        types: [Option<ValueType>; 3],
1541        imm: Option<i32>,
1542        pos: Option<usize>,
1543    ) {
1544        let i = Instruction::new(op, types[0], types[1], types[2], imm);
1545        self.code.push(i);
1546        self.pos.push(pos);
1547    }
1548
1549    pub fn emit_raw_inst(&mut self, u: u64, pos: Option<usize>) {
1550        let i = Instruction::from_u64(u);
1551        self.code.push(i);
1552        self.pos.push(pos);
1553    }
1554
1555    pub fn emit_code_with_type(&mut self, code: Opcode, t: ValueType, pos: Option<usize>) {
1556        self.emit_inst(code, [Some(t), None, None], None, pos);
1557    }
1558
1559    pub fn emit_code_with_type2(
1560        &mut self,
1561        code: Opcode,
1562        t0: ValueType,
1563        t1: Option<ValueType>,
1564        pos: Option<usize>,
1565    ) {
1566        self.emit_inst(code, [Some(t0), t1, None], None, pos);
1567    }
1568
1569    pub fn emit_code_with_imm(&mut self, code: Opcode, imm: OpIndex, pos: Option<usize>) {
1570        self.emit_inst(code, [None, None, None], Some(imm), pos);
1571    }
1572
1573    pub fn emit_code_with_type_imm(
1574        &mut self,
1575        code: Opcode,
1576        t: ValueType,
1577        imm: OpIndex,
1578        pos: Option<usize>,
1579    ) {
1580        self.emit_inst(code, [Some(t), None, None], Some(imm), pos);
1581    }
1582
1583    pub fn emit_code_with_flag_imm(
1584        &mut self,
1585        code: Opcode,
1586        comma_ok: bool,
1587        imm: OpIndex,
1588        pos: Option<usize>,
1589    ) {
1590        let mut inst = Instruction::new(code, None, None, None, Some(imm));
1591        let flag = if comma_ok { 1 } else { 0 };
1592        inst.set_t2_with_index(flag);
1593        self.code.push(inst);
1594        self.pos.push(pos);
1595    }
1596
1597    pub fn emit_code(&mut self, code: Opcode, pos: Option<usize>) {
1598        self.emit_inst(code, [None, None, None], None, pos);
1599    }
1600
1601    /// returns the index of the const if it's found
1602    pub fn get_const_index(&self, val: &GosValue) -> Option<EntIndex> {
1603        self.consts.iter().enumerate().find_map(|(i, x)| {
1604            if val.identical(x) {
1605                Some(EntIndex::Const(i as OpIndex))
1606            } else {
1607                None
1608            }
1609        })
1610    }
1611
1612    pub fn add_local(&mut self, entity: Option<EntityKey>) -> EntIndex {
1613        let result = self.local_alloc as OpIndex;
1614        if let Some(key) = entity {
1615            let old = self.entities.insert(key, EntIndex::LocalVar(result));
1616            assert_eq!(old, None);
1617        };
1618        self.local_alloc += 1;
1619        EntIndex::LocalVar(result)
1620    }
1621
1622    pub fn add_local_zero(&mut self, zero: GosValue) {
1623        self.local_zeros.push(zero)
1624    }
1625
1626    /// add a const or get the index of a const.
1627    /// when 'entity' is no none, it's a const define, so it should not be called with the
1628    /// same 'entity' more than once
1629    pub fn add_const(&mut self, entity: Option<EntityKey>, cst: GosValue) -> EntIndex {
1630        if let Some(index) = self.get_const_index(&cst) {
1631            index
1632        } else {
1633            self.consts.push(cst);
1634            let result = (self.consts.len() - 1).try_into().unwrap();
1635            if let Some(key) = entity {
1636                let old = self.entities.insert(key, EntIndex::Const(result));
1637                assert_eq!(old, None);
1638            }
1639            EntIndex::Const(result)
1640        }
1641    }
1642
1643    pub fn try_add_upvalue(&mut self, entity: &EntityKey, uv: ValueDesc) -> EntIndex {
1644        match self.uv_entities.get(entity) {
1645            Some(i) => *i,
1646            None => self.add_upvalue(entity, uv),
1647        }
1648    }
1649
1650    fn add_upvalue(&mut self, entity: &EntityKey, uv: ValueDesc) -> EntIndex {
1651        self.up_ptrs.push(uv);
1652        let i = (self.up_ptrs.len() - 1).try_into().unwrap();
1653        let et = EntIndex::UpValue(i);
1654        self.uv_entities.insert(*entity, et);
1655        et
1656    }
1657}