goscript_vm/
vm.rs

1#![allow(dead_code)]
2use super::channel;
3use super::ffi::FfiFactory;
4use super::gc::{gc, GcoVec};
5use super::instruction::*;
6use super::metadata::*;
7use super::objects::{u64_to_key, ClosureObj, GosHashMap};
8use super::stack::{RangeStack, Stack};
9use super::value::*;
10use super::vm_util;
11use async_executor::LocalExecutor;
12use futures_lite::future;
13use goscript_parser::FileSet;
14use std::cell::{Cell, RefCell};
15use std::collections::HashMap;
16use std::convert::TryInto;
17use std::pin::Pin;
18use std::ptr;
19use std::rc::Rc;
20use std::str;
21
22#[derive(Debug)]
23pub struct ByteCode {
24    pub objects: Pin<Box<VMObjects>>,
25    pub packages: Vec<PackageKey>,
26    pub ifaces: Vec<(GosMetadata, Option<Rc<Vec<FunctionKey>>>)>,
27    pub entry: FunctionKey,
28}
29
30#[derive(Clone, Debug)]
31struct Referers {
32    typ: ValueType,
33    weaks: Vec<WeakUpValue>,
34}
35
36#[derive(Clone, Debug)]
37struct CallFrame {
38    closure: Rc<(RefCell<ClosureObj>, RCount)>,
39    pc: usize,
40    stack_base: usize,
41    // var pointers are used in two cases
42    // - a real "upvalue" of a real closure
43    // - a local var that has pointer(s) point to it
44    var_ptrs: Option<Vec<UpValue>>,
45    // closures that have upvalues pointing to this frame
46    referred_by: Option<HashMap<OpIndex, Referers>>,
47
48    defer_stack: Option<Vec<DeferredCall>>,
49}
50
51impl CallFrame {
52    fn with_closure(c: Rc<(RefCell<ClosureObj>, RCount)>, sbase: usize) -> CallFrame {
53        CallFrame {
54            closure: c,
55            pc: 0,
56            stack_base: sbase,
57            var_ptrs: None,
58            referred_by: None,
59            defer_stack: None,
60        }
61    }
62
63    fn add_referred_by(&mut self, index: OpIndex, typ: ValueType, uv: &UpValue) {
64        if self.referred_by.is_none() {
65            self.referred_by = Some(HashMap::new());
66        }
67        let map = self.referred_by.as_mut().unwrap();
68        let weak = uv.downgrade();
69        match map.get_mut(&index) {
70            Some(v) => {
71                debug_assert!(v.typ == typ);
72                v.weaks.push(weak);
73            }
74            None => {
75                map.insert(
76                    index,
77                    Referers {
78                        typ: typ,
79                        weaks: vec![weak],
80                    },
81                );
82            }
83        }
84    }
85
86    #[inline]
87    fn func(&self) -> FunctionKey {
88        self.closure.0.borrow().func.unwrap()
89    }
90
91    #[inline]
92    fn closure(&self) -> &Rc<(RefCell<ClosureObj>, RCount)> {
93        &self.closure
94    }
95
96    #[inline]
97    fn ret_count(&self, objs: &VMObjects) -> usize {
98        let fkey = self.func();
99        objs.functions[fkey].ret_count()
100    }
101
102    #[inline]
103    fn on_drop(&mut self, stack: &Stack) {
104        if let Some(referred) = &self.referred_by {
105            for (ind, referrers) in referred {
106                if referrers.weaks.len() == 0 {
107                    continue;
108                }
109                let val = stack.get_with_type(Stack::offset(self.stack_base, *ind), referrers.typ);
110                for weak in referrers.weaks.iter() {
111                    if let Some(uv) = weak.upgrade() {
112                        uv.close(val.clone());
113                    }
114                }
115            }
116        }
117    }
118}
119
120#[derive(Clone, Debug)]
121struct DeferredCall {
122    frame: CallFrame,
123    stack_c: Vec<GosValue64>,
124    stack_rc: Vec<GosValue>,
125}
126
127#[derive(Debug)]
128enum Result {
129    Continue,
130    End,
131}
132
133#[derive(Debug)]
134struct PanicData {
135    msg: GosValue,
136    call_stack: Vec<(FunctionKey, usize)>,
137}
138
139impl PanicData {
140    fn new(m: GosValue) -> PanicData {
141        PanicData {
142            msg: m,
143            call_stack: vec![],
144        }
145    }
146}
147
148#[derive(Clone)]
149struct Context<'a> {
150    exec: Rc<LocalExecutor<'a>>,
151    code: &'a ByteCode,
152    gcv: &'a GcoVec,
153    ffi_factory: &'a FfiFactory,
154    fs: Option<&'a FileSet>,
155}
156
157impl<'a> Context<'a> {
158    fn new(
159        exec: Rc<LocalExecutor<'a>>,
160        code: &'a ByteCode,
161        gcv: &'a GcoVec,
162        ffi_factory: &'a FfiFactory,
163        fs: Option<&'a FileSet>,
164    ) -> Context<'a> {
165        Context {
166            exec: exec,
167            code: code,
168            gcv: gcv,
169            ffi_factory: ffi_factory,
170            fs: fs,
171        }
172    }
173
174    fn new_entry_frame(&self, entry: FunctionKey) -> CallFrame {
175        let cls = GosValue::new_closure(entry, &self.code.objects.functions);
176        CallFrame::with_closure(cls.as_closure().clone(), 0)
177    }
178
179    fn spawn_fiber(&self, stack: Stack, first_frame: CallFrame) {
180        let mut f = Fiber::new(self.clone(), stack, first_frame);
181        self.exec
182            .spawn(async move {
183                // let parent fiber go first
184                future::yield_now().await;
185                f.main_loop().await;
186            })
187            .detach();
188    }
189}
190
191pub struct Fiber<'a> {
192    stack: Rc<RefCell<Stack>>,
193    rstack: RangeStack,
194    frames: Vec<CallFrame>,
195    next_frames: Vec<CallFrame>,
196    context: Context<'a>,
197}
198
199impl<'a> Fiber<'a> {
200    fn new(c: Context<'a>, stack: Stack, first_frame: CallFrame) -> Fiber<'a> {
201        Fiber {
202            stack: Rc::new(RefCell::new(stack)),
203            rstack: RangeStack::new(),
204            frames: vec![first_frame],
205            next_frames: Vec::new(),
206            context: c,
207        }
208    }
209
210    async fn main_loop(&mut self) {
211        let ctx = &self.context;
212        let gcv = ctx.gcv;
213        let objs: &VMObjects = &ctx.code.objects;
214        let metadata: &Metadata = &objs.metadata;
215        let pkgs = &ctx.code.packages;
216        let ifaces = &ctx.code.ifaces;
217        let frame = self.frames.last_mut().unwrap();
218        let mut func = &objs.functions[frame.func()];
219
220        let mut stack_mut_ref = self.stack.borrow_mut();
221        let mut stack: &mut Stack = &mut stack_mut_ref;
222        // allocate local variables
223        stack.append(&mut func.local_zeros.clone());
224
225        let mut consts = &func.consts;
226        let mut code = func.code();
227        let mut stack_base = frame.stack_base;
228        let mut frame_height = self.frames.len();
229
230        let mut total_inst = 0;
231        //let mut stats: HashMap<Opcode, usize> = HashMap::new();
232        loop {
233            let mut frame = self.frames.last_mut().unwrap();
234            let mut result: Result = Result::Continue;
235            let mut panic: Option<PanicData> = None;
236            let yield_unit = 1024;
237            for _ in 0..yield_unit {
238                let inst = code[frame.pc];
239                let inst_op = inst.op();
240                total_inst += 1;
241                //stats.entry(*inst).and_modify(|e| *e += 1).or_insert(1);
242                frame.pc += 1;
243                //dbg!(inst_op);
244                match inst_op {
245                    Opcode::PUSH_CONST => {
246                        let index = inst.imm();
247                        let gos_val = &consts[index as usize];
248                        // Slice/Map/Array are special cases here because, they are stored literal,
249                        // and when it gets cloned, the underlying rust vec is not copied
250                        // which leads to all function calls shares the same vec instance
251                        stack.push(gos_val.deep_clone(gcv));
252                    }
253                    Opcode::PUSH_NIL => stack.push_nil(),
254                    Opcode::PUSH_FALSE => stack.push_bool(false),
255                    Opcode::PUSH_TRUE => stack.push_bool(true),
256                    Opcode::PUSH_IMM => stack.push_int32_as(inst.imm(), inst.t0()),
257                    Opcode::POP => {
258                        stack.pop_discard_n(inst.imm() as usize);
259                    }
260                    Opcode::LOAD_LOCAL => {
261                        let index = Stack::offset(stack_base, inst.imm());
262                        stack.push_from_index(index, inst.t0()); // (index![stack, index]);
263                    }
264                    Opcode::STORE_LOCAL => {
265                        let (rhs_index, index) = inst.imm824();
266                        let s_index = Stack::offset(stack_base, index);
267                        store_local!(stack, s_index, rhs_index, inst.t0(), gcv);
268                    }
269                    Opcode::LOAD_UPVALUE => {
270                        let index = inst.imm();
271                        let upvalue = frame.var_ptrs.as_ref().unwrap()[index as usize].clone();
272                        let val = load_up_value!(upvalue, self, stack, self.frames);
273                        stack.push(val);
274                        frame = self.frames.last_mut().unwrap();
275                    }
276                    Opcode::STORE_UPVALUE => {
277                        let (rhs_index, index) = inst.imm824();
278                        let upvalue = frame.var_ptrs.as_ref().unwrap()[index as usize].clone();
279                        store_up_value!(
280                            upvalue,
281                            self,
282                            stack,
283                            self.frames,
284                            rhs_index,
285                            inst.t0(),
286                            gcv
287                        );
288                        frame = self.frames.last_mut().unwrap();
289                    }
290                    Opcode::LOAD_INDEX => {
291                        let ind = stack.pop_with_type(inst.t1());
292                        let val = &stack.pop_with_type(inst.t0());
293                        if inst.t2_as_index() == 0 {
294                            match vm_util::load_index(val, &ind) {
295                                Ok(v) => stack.push(v),
296                                Err(e) => {
297                                    go_panic_str!(panic, &objs.metadata, e, frame, code);
298                                }
299                            }
300                        } else {
301                            vm_util::push_index_comma_ok(stack, val, &ind);
302                        }
303                    }
304                    Opcode::LOAD_INDEX_IMM => {
305                        let val = &stack.pop_with_type(inst.t0());
306                        let index = inst.imm() as usize;
307                        if inst.t2_as_index() == 0 {
308                            match vm_util::load_index_int(val, index) {
309                                Ok(v) => stack.push(v),
310                                Err(e) => {
311                                    go_panic_str!(panic, metadata, e, frame, code);
312                                }
313                            }
314                        } else {
315                            vm_util::push_index_comma_ok(
316                                stack,
317                                val,
318                                &GosValue::Int(index as isize),
319                            );
320                        }
321                    }
322                    Opcode::STORE_INDEX => {
323                        let (rhs_index, index) = inst.imm824();
324                        let s_index = Stack::offset(stack.len(), index);
325                        let key = stack.get_with_type(s_index + 1, inst.t2());
326                        let target = &stack.get_with_type(s_index, inst.t1());
327                        vm_util::store_index(stack, target, &key, rhs_index, inst.t0(), gcv);
328                    }
329                    Opcode::STORE_INDEX_IMM => {
330                        // the only place we can store the immediate index is t2
331                        let (rhs_index, imm) = inst.imm824();
332                        let index = inst.t2_as_index();
333                        let s_index = Stack::offset(stack.len(), index);
334                        let target = &stack.get_with_type(s_index, inst.t1());
335                        if let Err(e) = vm_util::store_index_int(
336                            stack,
337                            target,
338                            imm as usize,
339                            rhs_index,
340                            inst.t0(),
341                            gcv,
342                        ) {
343                            go_panic_str!(panic, metadata, e, frame, code);
344                        }
345                    }
346                    Opcode::LOAD_FIELD => {
347                        let ind = stack.pop_with_type(inst.t1());
348                        let val = stack.pop_with_type(inst.t0());
349                        stack.push(vm_util::load_field(&val, &ind, objs));
350                    }
351                    Opcode::LOAD_STRUCT_FIELD => {
352                        let ind = inst.imm();
353                        let mut target = stack.pop_with_type(inst.t0());
354                        if let GosValue::Pointer(_) = &target {
355                            target = deref_value!(target, self, stack, self.frames, objs);
356                            frame = self.frames.last_mut().unwrap();
357                        }
358                        let val = match &target {
359                            GosValue::Named(n) => {
360                                n.0.as_struct().0.borrow().fields[ind as usize].clone()
361                            }
362                            GosValue::Struct(sval) => sval.0.borrow().fields[ind as usize].clone(),
363                            _ => {
364                                dbg!(&target);
365                                unreachable!()
366                            }
367                        };
368
369                        stack.push(val);
370                    }
371                    Opcode::BIND_METHOD => {
372                        let val = stack.pop_with_type(inst.t0());
373                        let func = *consts[inst.imm() as usize].as_function();
374                        stack.push(GosValue::Closure(Rc::new((
375                            RefCell::new(ClosureObj::new_gos(
376                                func,
377                                &objs.functions,
378                                Some(val.copy_semantic(gcv)),
379                            )),
380                            Cell::new(0),
381                        ))));
382                    }
383                    Opcode::BIND_INTERFACE_METHOD => {
384                        let val = stack.pop_with_type(inst.t0());
385                        let val = match &val {
386                            GosValue::Named(n) => n.0.clone(),
387                            GosValue::Interface(_) => val,
388                            _ => unreachable!(),
389                        };
390                        let borrowed = val.as_interface().borrow();
391                        let cls = match borrowed.underlying() {
392                            IfaceUnderlying::Gos(val, funcs) => {
393                                let func = funcs.as_ref().unwrap()[inst.imm() as usize];
394                                let cls = ClosureObj::new_gos(
395                                    func,
396                                    &objs.functions,
397                                    Some(val.copy_semantic(gcv)),
398                                );
399                                GosValue::Closure(Rc::new((RefCell::new(cls), Cell::new(0))))
400                            }
401                            IfaceUnderlying::Ffi(ffi) => {
402                                let (name, meta) = ffi.methods[inst.imm() as usize].clone();
403                                let cls = FfiClosureObj {
404                                    ffi: ffi.ffi_obj.clone(),
405                                    func_name: name,
406                                    meta: meta,
407                                };
408                                GosValue::Closure(Rc::new((
409                                    RefCell::new(ClosureObj::new_ffi(cls)),
410                                    Cell::new(0),
411                                )))
412                            }
413                            IfaceUnderlying::None => {
414                                let msg = "access nil interface".to_string();
415                                go_panic_str!(panic, metadata, msg, frame, code);
416                                continue;
417                            }
418                        };
419                        stack.push(cls);
420                    }
421                    Opcode::STORE_FIELD => {
422                        let (rhs_index, _) = inst.imm824();
423                        let index = inst.t2_as_index();
424                        let s_index = Stack::offset(stack.len(), index);
425                        let key = stack.get_with_type(s_index + 1, inst.t2());
426                        let target = stack.get_with_type(s_index, inst.t1());
427                        match target {
428                            GosValue::Pointer(_) => {
429                                let unboxed = deref_value!(target, self, stack, self.frames, objs);
430                                frame = self.frames.last_mut().unwrap();
431                                vm_util::store_field(
432                                    stack,
433                                    &unboxed,
434                                    &key,
435                                    rhs_index,
436                                    inst.t0(),
437                                    &objs.metas,
438                                    gcv,
439                                );
440                            }
441                            _ => vm_util::store_field(
442                                stack,
443                                &target,
444                                &key,
445                                rhs_index,
446                                inst.t0(),
447                                &objs.metas,
448                                gcv,
449                            ),
450                        };
451                    }
452                    Opcode::STORE_STRUCT_FIELD => {
453                        let (rhs_index, imm) = inst.imm824();
454                        let index = inst.t2_as_index();
455                        let s_index = Stack::offset(stack.len(), index);
456                        let mut target = stack.get_with_type(s_index, inst.t1());
457                        if let GosValue::Pointer(_) = &target {
458                            target = deref_value!(target, self, stack, self.frames, objs);
459                            frame = self.frames.last_mut().unwrap();
460                        }
461                        match &target {
462                            GosValue::Named(n) => {
463                                let field =
464                                    &mut n.0.as_struct().0.borrow_mut().fields[imm as usize];
465                                stack.store_val(field, rhs_index, inst.t0(), gcv);
466                            }
467                            GosValue::Struct(s) => {
468                                let field = &mut s.0.borrow_mut().fields[imm as usize];
469                                stack.store_val(field, rhs_index, inst.t0(), gcv);
470                            }
471                            _ => {
472                                dbg!(&target);
473                                unreachable!()
474                            }
475                        }
476                    }
477                    Opcode::LOAD_PKG_FIELD => {
478                        let index = inst.imm();
479                        let pkg_key = read_imm_pkg!(code, frame, objs);
480                        let pkg = &objs.packages[pkg_key];
481                        stack.push(pkg.member(index).clone());
482                    }
483                    Opcode::STORE_PKG_FIELD => {
484                        let (rhs_index, imm) = inst.imm824();
485                        let pkg = &objs.packages[read_imm_pkg!(code, frame, objs)];
486                        stack.store_val(&mut pkg.member_mut(imm), rhs_index, inst.t0(), gcv);
487                    }
488                    Opcode::STORE_DEREF => {
489                        let (rhs_index, index) = inst.imm824();
490                        let s_index = Stack::offset(stack.len(), index);
491                        match stack.get_with_type(s_index, ValueType::Pointer) {
492                            GosValue::Pointer(b) => {
493                                let r: &PointerObj = &b;
494                                match r {
495                                    PointerObj::UpVal(uv) => {
496                                        store_up_value!(
497                                            uv,
498                                            self,
499                                            stack,
500                                            self.frames,
501                                            rhs_index,
502                                            inst.t0(),
503                                            gcv
504                                        );
505                                        frame = self.frames.last_mut().unwrap();
506                                    }
507                                    PointerObj::Struct(r, _) => {
508                                        let rhs_s_index = Stack::offset(stack.len(), rhs_index);
509                                        let val = stack.get_with_type(rhs_s_index, inst.t0());
510                                        let mref: &mut StructObj = &mut r.0.borrow_mut();
511                                        *mref = val.try_get_struct().unwrap().0.borrow().clone();
512                                    }
513                                    PointerObj::Array(a, _) => {
514                                        let rhs_s_index = Stack::offset(stack.len(), rhs_index);
515                                        let val = stack.get_with_type(rhs_s_index, inst.t0());
516                                        a.0.set_from(&val.as_array().0);
517                                    }
518                                    PointerObj::Slice(r, _) => {
519                                        let rhs_s_index = Stack::offset(stack.len(), rhs_index);
520                                        let val = stack.get_with_type(rhs_s_index, inst.t0());
521                                        r.0.set_from(&val.as_slice().0);
522                                    }
523                                    PointerObj::Map(r, _) => {
524                                        let rhs_s_index = Stack::offset(stack.len(), rhs_index);
525                                        let val = stack.get_with_type(rhs_s_index, inst.t0());
526                                        let mref: &mut GosHashMap = &mut r.0.borrow_data_mut();
527                                        *mref = val.try_get_map().unwrap().0.borrow_data().clone();
528                                    }
529                                    PointerObj::SliceMember(s, index) => {
530                                        let vborrow = s.0.borrow_data();
531                                        let target: &mut GosValue = &mut vborrow
532                                            [s.0.begin() + *index as usize]
533                                            .borrow_mut();
534                                        stack.store_val(target, rhs_index, inst.t0(), gcv);
535                                    }
536                                    PointerObj::StructField(s, index) => {
537                                        let target: &mut GosValue =
538                                            &mut s.0.borrow_mut().fields[*index as usize];
539                                        stack.store_val(target, rhs_index, inst.t0(), gcv);
540                                    }
541                                    PointerObj::PkgMember(p, index) => {
542                                        let target: &mut GosValue =
543                                            &mut objs.packages[*p].member_mut(*index);
544                                        stack.store_val(target, rhs_index, inst.t0(), gcv);
545                                    }
546                                    PointerObj::Released => unreachable!(),
547                                };
548                            }
549                            _ => unreachable!(),
550                        }
551                    }
552                    Opcode::CAST => {
553                        let (target, mapping) = inst.imm824();
554                        let rhs_s_index = Stack::offset(stack.len(), target);
555                        match inst.t0() {
556                            ValueType::Interface => {
557                                let iface = ifaces[mapping as usize].clone();
558                                let under = stack.get_with_type(rhs_s_index, inst.t1());
559                                let val = match &objs.metas[iface.0.as_non_ptr()] {
560                                    MetadataType::Named(_, md) => GosValue::Named(Box::new((
561                                        GosValue::new_iface(
562                                            *md,
563                                            IfaceUnderlying::Gos(under, iface.1),
564                                        ),
565                                        iface.0,
566                                    ))),
567                                    MetadataType::Interface(_) => GosValue::new_iface(
568                                        iface.0,
569                                        IfaceUnderlying::Gos(under, iface.1),
570                                    ),
571                                    _ => unreachable!(),
572                                };
573                                stack.set(rhs_s_index, val);
574                            }
575                            ValueType::Str => {
576                                let result = match inst.t1() {
577                                    ValueType::Slice => {
578                                        let slice = stack.get_rc(rhs_s_index).as_slice();
579                                        match inst.t2() {
580                                            ValueType::Int32 => slice
581                                                .0
582                                                .borrow_data()
583                                                .iter()
584                                                .map(|x| {
585                                                    vm_util::char_from_i32(*(x.borrow().as_int32()))
586                                                })
587                                                .collect(),
588                                            ValueType::Uint8 => {
589                                                let buf: Vec<u8> = slice
590                                                    .0
591                                                    .borrow_data()
592                                                    .iter()
593                                                    .map(|x| *(x.borrow().as_uint8()))
594                                                    .collect();
595                                                // todo: error handling
596                                                str::from_utf8(&buf).unwrap().to_string()
597                                            }
598                                            _ => unreachable!(),
599                                        }
600                                    }
601                                    _ => {
602                                        let target = stack.get_c_mut(rhs_s_index);
603                                        target.to_uint32(inst.t1());
604                                        vm_util::char_from_u32(target.get_uint32()).to_string()
605                                    }
606                                };
607                                stack.set(rhs_s_index, GosValue::new_str(result));
608                            }
609                            ValueType::Slice => {
610                                let from = stack.get_rc(rhs_s_index).as_str();
611                                let result = match inst.t2() {
612                                    ValueType::Int32 => (
613                                        objs.metadata.mint32,
614                                        from.as_str()
615                                            .chars()
616                                            .map(|x| GosValue::Int32(x as i32))
617                                            .collect(),
618                                    ),
619                                    ValueType::Uint8 => (
620                                        objs.metadata.muint8,
621                                        from.as_str().bytes().map(|x| GosValue::Uint8(x)).collect(),
622                                    ),
623                                    _ => unreachable!(),
624                                };
625                                stack.set(
626                                    rhs_s_index,
627                                    GosValue::slice_with_val(result.1, result.0, gcv),
628                                )
629                            }
630                            ValueType::Uint => stack.get_c_mut(rhs_s_index).to_uint(inst.t1()),
631                            ValueType::Uint8 => stack.get_c_mut(rhs_s_index).to_uint8(inst.t1()),
632                            ValueType::Uint16 => stack.get_c_mut(rhs_s_index).to_uint16(inst.t1()),
633                            ValueType::Uint32 => stack.get_c_mut(rhs_s_index).to_uint32(inst.t1()),
634                            ValueType::Uint64 => stack.get_c_mut(rhs_s_index).to_uint64(inst.t1()),
635                            ValueType::Int => stack.get_c_mut(rhs_s_index).to_int(inst.t1()),
636                            ValueType::Int8 => stack.get_c_mut(rhs_s_index).to_int8(inst.t1()),
637                            ValueType::Int16 => stack.get_c_mut(rhs_s_index).to_int16(inst.t1()),
638                            ValueType::Int32 => stack.get_c_mut(rhs_s_index).to_int32(inst.t1()),
639                            ValueType::Int64 => stack.get_c_mut(rhs_s_index).to_int64(inst.t1()),
640                            ValueType::Float32 => {
641                                stack.get_c_mut(rhs_s_index).to_float32(inst.t1())
642                            }
643                            ValueType::Float64 => {
644                                stack.get_c_mut(rhs_s_index).to_float64(inst.t1())
645                            }
646                            _ => {
647                                // we do not support tags yet, is there anything to implement?
648                                dbg!(inst.t0());
649                                unimplemented!()
650                            }
651                        }
652                    }
653                    Opcode::ADD => stack.add(inst.t0()),
654                    Opcode::SUB => stack.sub(inst.t0()),
655                    Opcode::MUL => stack.mul(inst.t0()),
656                    Opcode::QUO => stack.quo(inst.t0()),
657                    Opcode::REM => stack.rem(inst.t0()),
658                    Opcode::AND => stack.and(inst.t0()),
659                    Opcode::OR => stack.or(inst.t0()),
660                    Opcode::XOR => stack.xor(inst.t0()),
661                    Opcode::AND_NOT => stack.and_not(inst.t0()),
662                    Opcode::SHL => stack.shl(inst.t0(), inst.t1()),
663                    Opcode::SHR => stack.shr(inst.t0(), inst.t1()),
664                    Opcode::UNARY_ADD => {}
665                    Opcode::UNARY_SUB => stack.unary_negate(inst.t0()),
666                    Opcode::UNARY_XOR => stack.unary_xor(inst.t0()),
667                    Opcode::NOT => stack.logical_not(inst.t0()),
668                    Opcode::EQL => stack.compare_eql(inst.t0()),
669                    Opcode::LSS => stack.compare_lss(inst.t0()),
670                    Opcode::GTR => stack.compare_gtr(inst.t0()),
671                    Opcode::NEQ => stack.compare_neq(inst.t0()),
672                    Opcode::LEQ => stack.compare_leq(inst.t0()),
673                    Opcode::GEQ => stack.compare_geq(inst.t0()),
674                    Opcode::SEND => {
675                        let val = stack.pop_with_type(inst.t0());
676                        let chan = stack.pop_rc();
677                        drop(stack_mut_ref);
678                        let re = chan.as_channel().send(&val).await;
679                        restore_stack_ref!(self, stack, stack_mut_ref);
680                        if let Err(e) = re {
681                            go_panic_str!(panic, metadata, e, frame, code);
682                        }
683                    }
684                    Opcode::RECV => {
685                        let chan_val = stack.pop_rc();
686                        let chan = chan_val.as_channel();
687                        drop(stack_mut_ref);
688                        let val = chan.recv().await;
689                        restore_stack_ref!(self, stack, stack_mut_ref);
690                        let (unwrapped, ok) = unwrap_recv_val!(chan, val, objs.metas, gcv);
691                        stack.push(unwrapped);
692                        if inst.t1() == ValueType::FlagA {
693                            stack.push(GosValue::Bool(ok));
694                        }
695                    }
696                    Opcode::REF_UPVALUE => {
697                        let index = inst.imm();
698                        let upvalue = frame.var_ptrs.as_ref().unwrap()[index as usize].clone();
699                        stack.push(GosValue::new_pointer(PointerObj::UpVal(upvalue.clone())));
700                    }
701                    Opcode::REF_LOCAL => {
702                        let t = inst.t0();
703                        let val = if inst.imm() >= 0 {
704                            let s_index = Stack::offset(stack_base, inst.imm());
705                            stack.get_with_type(s_index, t)
706                        } else {
707                            stack.pop_with_type(t)
708                        };
709                        let boxed = PointerObj::new_local(val);
710                        stack.push(GosValue::new_pointer(boxed));
711                    }
712                    Opcode::REF_SLICE_MEMBER => {
713                        let index = stack.pop_int();
714                        let typ = inst.t0();
715                        let mut slice = stack.pop_with_type(typ);
716                        // create a slice if it's an array
717                        if typ == ValueType::Array {
718                            slice = GosValue::slice_with_array(&slice, 0, -1, gcv);
719                        }
720                        stack.push(GosValue::new_pointer(PointerObj::SliceMember(
721                            slice.as_slice().clone(),
722                            index.try_into().unwrap(),
723                        )));
724                    }
725                    Opcode::REF_STRUCT_FIELD => {
726                        let struct_ = stack.pop_with_type(inst.t0());
727                        let struct_ = match &struct_ {
728                            GosValue::Named(n) => n.0.clone(),
729                            GosValue::Struct(_) => struct_,
730                            _ => unreachable!(),
731                        };
732                        stack.push(GosValue::new_pointer(PointerObj::StructField(
733                            struct_.as_struct().clone(),
734                            inst.imm(),
735                        )));
736                    }
737                    Opcode::REF_PKG_MEMBER => {
738                        let pkg = read_imm_pkg!(code, frame, objs);
739                        stack.push(GosValue::new_pointer(PointerObj::PkgMember(
740                            pkg,
741                            inst.imm(),
742                        )));
743                    }
744                    Opcode::REF_LITERAL => {
745                        let v = stack.pop_with_type(inst.t0());
746                        stack.push(GosValue::new_pointer(PointerObj::UpVal(
747                            UpValue::new_closed(v),
748                        )))
749                    }
750                    Opcode::DEREF => {
751                        let boxed = stack.pop_with_type(inst.t0());
752                        let val = deref_value!(boxed, self, stack, self.frames, objs);
753                        stack.push(val);
754                        frame = self.frames.last_mut().unwrap();
755                    }
756                    Opcode::PRE_CALL => {
757                        let val = stack.pop_with_type(ValueType::Closure);
758                        let cls_rc = val.as_closure();
759                        let cls: &ClosureObj = &*cls_rc.0.borrow();
760                        let next_frame = CallFrame::with_closure(cls_rc.clone(), stack.len());
761                        match cls.func {
762                            Some(key) => {
763                                let next_func = &objs.functions[key];
764                                stack.append(&mut next_func.ret_zeros.clone());
765                                if let Some(r) = &cls.recv {
766                                    // push receiver on stack as the first parameter
767                                    // don't call copy_semantic because BIND_METHOD did it already
768                                    stack.push(r.clone());
769                                }
770                            }
771                            None => {} //ffi
772                        }
773                        self.next_frames.push(next_frame);
774                    }
775                    Opcode::CALL => {
776                        let mut nframe = self.next_frames.pop().unwrap();
777                        let ref_cls = nframe.closure().clone();
778                        let cls: &ClosureObj = &ref_cls.0.borrow();
779                        let call_style = inst.t0();
780                        let pack = inst.t1() == ValueType::FlagA;
781                        if pack {
782                            let sig = &objs.metas[cls.meta.as_non_ptr()].as_signature();
783                            let (meta, v_meta) = sig.variadic.unwrap();
784                            let vt = v_meta.get_value_type(&objs.metas);
785                            let index =
786                                nframe.stack_base + sig.params.len() + sig.results.len() - 1;
787                            stack.pack_variadic(index, meta, vt, gcv);
788                        }
789                        match cls.func {
790                            Some(key) => {
791                                let nfunc = &objs.functions[key];
792                                if let Some(uvs) = &cls.uvs {
793                                    let mut ptrs: Vec<UpValue> =
794                                        Vec::with_capacity(nfunc.up_ptrs.len());
795                                    for (i, p) in nfunc.up_ptrs.iter().enumerate() {
796                                        ptrs.push(if p.is_up_value {
797                                            uvs[&i].clone()
798                                        } else {
799                                            // local pointers
800                                            let uv = UpValue::new(p.clone_with_stack(
801                                                Rc::downgrade(&self.stack),
802                                                nframe.stack_base as OpIndex,
803                                            ));
804                                            nframe.add_referred_by(p.index, p.typ, &uv);
805                                            uv
806                                        });
807                                    }
808                                    nframe.var_ptrs = Some(ptrs);
809                                }
810                                match call_style {
811                                    ValueType::Zero => {
812                                        // default call
813                                        self.frames.push(nframe);
814                                        frame_height += 1;
815                                        frame = self.frames.last_mut().unwrap();
816                                        func = nfunc;
817                                        stack_base = frame.stack_base;
818                                        consts = &func.consts;
819                                        code = func.code();
820                                        //dbg!(&consts);
821                                        //dbg!(&code);
822                                        //dbg!(&stack);
823                                        debug_assert!(func.local_count() == func.local_zeros.len());
824                                        // allocate local variables
825                                        stack.append(&mut func.local_zeros.clone());
826                                    }
827                                    ValueType::FlagA => {
828                                        // goroutine
829                                        nframe.stack_base = 0;
830                                        let nstack = Stack::move_from(stack, nfunc.param_count());
831                                        self.context.spawn_fiber(nstack, nframe);
832                                    }
833                                    ValueType::FlagB => {
834                                        let (c, rc) = stack.pop_n(nfunc.param_count());
835                                        let deferred = DeferredCall {
836                                            frame: nframe,
837                                            stack_c: c,
838                                            stack_rc: rc,
839                                        };
840                                        frame.defer_stack.get_or_insert(vec![]).push(deferred);
841                                    }
842                                    _ => unreachable!(),
843                                }
844                            }
845                            None => {
846                                let call = cls.ffi.as_ref().unwrap();
847                                let ptypes = &objs.metas[call.meta.as_non_ptr()]
848                                    .as_signature()
849                                    .params_type;
850                                let params = stack.pop_with_type_n(ptypes);
851                                // release stack so that code in ffi can yield
852                                drop(stack_mut_ref);
853                                let mut returns = call.ffi.borrow().call(&call.func_name, params);
854                                restore_stack_ref!(self, stack, stack_mut_ref);
855                                stack.append(&mut returns);
856                            }
857                        }
858                    }
859                    Opcode::RETURN => {
860                        //dbg!(stack.len());
861                        //for s in stack.iter() {
862                        //    dbg!(GosValueDebug::new(&s, &objs));
863                        //}
864                        match inst.t0() {
865                            // default case
866                            ValueType::Zero => {
867                                stack.truncate(stack_base + frame.ret_count(objs));
868                            }
869                            // init_package func
870                            ValueType::FlagA => {
871                                let index = inst.imm() as usize;
872                                let pkey = pkgs[index];
873                                let pkg = &objs.packages[pkey];
874                                let count = pkg.var_count();
875                                // remove garbage first
876                                debug_assert!(stack.len() == stack_base + count);
877                                // the var values left on the stack are for pkg members
878                                stack.init_pkg_vars(pkg, count);
879                            }
880                            // func with deferred calls
881                            ValueType::FlagB => {
882                                match frame.defer_stack.as_mut().map(|x| x.pop()).flatten() {
883                                    Some(call) => {
884                                        // run Opcode::RETURN to check if deferred_stack is empty
885                                        frame.pc -= 1;
886
887                                        stack.push_n(call.stack_c, call.stack_rc);
888                                        let nframe = call.frame;
889
890                                        self.frames.push(nframe);
891                                        frame_height += 1;
892                                        frame = self.frames.last_mut().unwrap();
893                                        let fkey = frame.closure.0.borrow().func.unwrap();
894                                        func = &objs.functions[fkey];
895                                        stack_base = frame.stack_base;
896                                        consts = &func.consts;
897                                        code = func.code();
898                                        debug_assert!(func.local_count() == func.local_zeros.len());
899                                        stack.append(&mut func.local_zeros.clone());
900                                        continue;
901                                    }
902                                    None => {
903                                        stack.truncate(stack_base + frame.ret_count(objs));
904                                    }
905                                }
906                            }
907                            _ => unreachable!(),
908                        }
909
910                        frame.on_drop(&stack);
911                        drop(frame);
912                        self.frames.pop();
913                        frame_height -= 1;
914                        if self.frames.is_empty() {
915                            dbg!(total_inst);
916                            /* dbg!
917                            let mut s = stats
918                                .iter()
919                                .map(|(&k, &v)| (k, v))
920                                .collect::<Vec<(Opcode, usize)>>();
921                            s.sort_by(|a, b| b.1.cmp(&a.1));
922                            dbg!(s);
923                            */
924                            result = Result::End;
925                            break;
926                        }
927                        frame = self.frames.last_mut().unwrap();
928                        stack_base = frame.stack_base;
929                        // restore func, consts, code
930                        func = &objs.functions[frame.func()];
931                        consts = &func.consts;
932                        code = func.code();
933
934                        if let Some(p) = &mut panic {
935                            p.call_stack.push((frame.func(), frame.pc - 1));
936                            frame.pc = code.len() - 1;
937                        }
938                    }
939
940                    Opcode::JUMP => {
941                        frame.pc = Stack::offset(frame.pc, inst.imm());
942                    }
943                    Opcode::JUMP_IF => {
944                        if stack.pop_bool() {
945                            frame.pc = Stack::offset(frame.pc, inst.imm());
946                        }
947                    }
948                    Opcode::JUMP_IF_NOT => {
949                        if !stack.pop_bool() {
950                            frame.pc = Stack::offset(frame.pc, inst.imm());
951                        }
952                    }
953                    Opcode::SWITCH => {
954                        if stack.switch_cmp(inst.t0(), objs) {
955                            frame.pc = Stack::offset(frame.pc, inst.imm());
956                        }
957                    }
958                    Opcode::SELECT => {
959                        let blocks = inst.imm();
960                        let begin = frame.pc - 1;
961                        let mut end = begin + blocks as usize;
962                        let end_code = &code[end - 1];
963                        let default_offset = match end_code.t0() {
964                            ValueType::FlagE => {
965                                end -= 1;
966                                Some(end_code.imm())
967                            }
968                            _ => None,
969                        };
970                        let comms = code[begin..end]
971                            .iter()
972                            .enumerate()
973                            .rev()
974                            .map(|(i, sel_code)| {
975                                let offset = if i == 0 { 0 } else { sel_code.imm() };
976                                let flag = sel_code.t0();
977                                match &flag {
978                                    ValueType::FlagA => {
979                                        let val = stack.pop_with_type(sel_code.t1());
980                                        let chan = stack.pop_rc();
981                                        channel::SelectComm::Send(chan, val, offset)
982                                    }
983                                    ValueType::FlagB | ValueType::FlagC | ValueType::FlagD => {
984                                        let chan = stack.pop_rc();
985                                        channel::SelectComm::Recv(chan, flag, offset)
986                                    }
987                                    _ => unreachable!(),
988                                }
989                            })
990                            .collect();
991                        let selector = channel::Selector::new(comms, default_offset);
992
993                        drop(stack_mut_ref);
994                        let re = selector.select().await;
995                        restore_stack_ref!(self, stack, stack_mut_ref);
996
997                        match re {
998                            Ok((i, val)) => {
999                                let block_offset = if i >= selector.comms.len() {
1000                                    selector.default_offset.unwrap()
1001                                } else {
1002                                    match &selector.comms[i] {
1003                                        channel::SelectComm::Send(_, _, offset) => *offset,
1004                                        channel::SelectComm::Recv(c, flag, offset) => {
1005                                            let (unwrapped, ok) = unwrap_recv_val!(
1006                                                c.as_channel(),
1007                                                val,
1008                                                objs.metas,
1009                                                gcv
1010                                            );
1011                                            match flag {
1012                                                ValueType::FlagC => {
1013                                                    stack.push(unwrapped);
1014                                                }
1015                                                ValueType::FlagD => {
1016                                                    stack.push(unwrapped);
1017                                                    stack.push_bool(ok);
1018                                                }
1019                                                _ => {}
1020                                            }
1021                                            *offset
1022                                        }
1023                                    }
1024                                };
1025                                // jump to the block
1026                                frame.pc = Stack::offset(frame.pc, (blocks - 1) + block_offset);
1027                            }
1028                            Err(e) => {
1029                                go_panic_str!(panic, &objs.metadata, e, frame, code);
1030                            }
1031                        }
1032                    }
1033                    Opcode::RANGE_INIT => {
1034                        let len = stack.len();
1035                        let t = stack.get_with_type(len - 1, inst.t0());
1036                        self.rstack.range_init(&t);
1037                        stack.pop_discard();
1038                    }
1039                    // Opcode::RANGE assumes a container and an int(as the cursor) on the stack
1040                    Opcode::RANGE => {
1041                        let offset = inst.imm();
1042                        if self.rstack.range_body(inst.t0(), stack) {
1043                            frame.pc = Stack::offset(frame.pc, offset);
1044                        }
1045                    }
1046
1047                    Opcode::TYPE_ASSERT => {
1048                        let val = match stack.pop_interface().borrow().underlying() {
1049                            IfaceUnderlying::Gos(v, _) => v.copy_semantic(gcv),
1050                            _ => GosValue::new_nil(),
1051                        };
1052                        let meta = GosValue::Metadata(val.get_meta(objs, stack));
1053                        stack.push(val);
1054                        let ok = &consts[inst.imm() as usize] == &meta;
1055                        let do_try = inst.t2_as_index() > 0;
1056                        if !do_try {
1057                            if !ok {
1058                                // todo go_panic
1059                                unimplemented!()
1060                            }
1061                        } else {
1062                            stack.push_bool(ok);
1063                        }
1064                    }
1065                    Opcode::TYPE => {
1066                        let val = match stack.pop_interface().borrow().underlying() {
1067                            IfaceUnderlying::Gos(v, _) => v.copy_semantic(gcv),
1068                            _ => GosValue::new_nil(),
1069                        };
1070                        stack.push(GosValue::Metadata(val.get_meta(objs, stack)));
1071                        if inst.t2_as_index() > 0 {
1072                            let index = inst.imm();
1073                            let s_index = Stack::offset(stack_base, index);
1074                            stack.set(s_index, val);
1075                        }
1076                    }
1077                    Opcode::IMPORT => {
1078                        let pkey = pkgs[inst.imm() as usize];
1079                        stack.push(GosValue::Bool(!objs.packages[pkey].inited()));
1080                    }
1081                    Opcode::SLICE | Opcode::SLICE_FULL => {
1082                        let max = if inst_op == Opcode::SLICE_FULL {
1083                            stack.pop_int()
1084                        } else {
1085                            -1
1086                        };
1087                        let end = stack.pop_int();
1088                        let begin = stack.pop_int();
1089                        let target = stack.pop_with_type(inst.t0());
1090                        let result = match &target {
1091                            GosValue::Slice(sl) => GosValue::Slice(Rc::new((
1092                                sl.0.slice(begin, end, max),
1093                                Cell::new(0),
1094                            ))),
1095                            GosValue::Str(s) => GosValue::Str(Rc::new(s.slice(begin, end))),
1096                            GosValue::Array(_) => {
1097                                GosValue::slice_with_array(&target, begin, end, gcv)
1098                            }
1099                            _ => unreachable!(),
1100                        };
1101                        stack.push(result);
1102                    }
1103                    Opcode::LITERAL => {
1104                        let index = inst.imm();
1105                        let param = &consts[index as usize];
1106                        let new_val = match param {
1107                            GosValue::Function(fkey) => {
1108                                // NEW a closure
1109                                let mut val = ClosureObj::new_gos(*fkey, &objs.functions, None);
1110                                if let Some(uvs) = &mut val.uvs {
1111                                    drop(frame);
1112                                    for (_, uv) in uvs.iter_mut() {
1113                                        let r: &mut UpValueState = &mut uv.inner.borrow_mut();
1114                                        if let UpValueState::Open(d) = r {
1115                                            // get frame index, and add_referred_by
1116                                            for i in 1..frame_height {
1117                                                let index = frame_height - i;
1118                                                if self.frames[index].func() == d.func {
1119                                                    let upframe = &mut self.frames[index];
1120                                                    d.stack = Rc::downgrade(&self.stack);
1121                                                    d.stack_base = upframe.stack_base as OpIndex;
1122                                                    upframe.add_referred_by(d.index, d.typ, uv);
1123                                                    // if not found, the upvalue is already closed, nothing to be done
1124                                                    break;
1125                                                }
1126                                            }
1127                                        }
1128                                        //dbg!(&desc, &upframe);
1129                                    }
1130                                    frame = self.frames.last_mut().unwrap();
1131                                }
1132                                GosValue::new_runtime_closure(val, gcv)
1133                            }
1134                            GosValue::Metadata(md) => {
1135                                let umd = md.get_underlying(&objs.metas);
1136                                let (key, mc) = umd.unwrap_non_ptr();
1137                                let count = stack.pop_int32();
1138                                let val = match &objs.metas[key] {
1139                                    MetadataType::SliceOrArray(asm, _) => {
1140                                        let elem_type = asm.get_value_type(&objs.metas);
1141                                        let zero_val = asm.zero_val(&objs.metas, gcv);
1142                                        let mut val = vec![];
1143                                        let mut cur_index = -1;
1144                                        for _ in 0..count {
1145                                            let i = stack.pop_int();
1146                                            let elem = stack.pop_with_type(elem_type);
1147                                            if i < 0 {
1148                                                cur_index += 1;
1149                                            } else {
1150                                                cur_index = i;
1151                                            }
1152                                            let gap = cur_index - (val.len() as isize);
1153                                            if gap == 0 {
1154                                                val.push(elem);
1155                                            } else if gap > 0 {
1156                                                for _ in 0..gap {
1157                                                    val.push(zero_val.clone());
1158                                                }
1159                                                val.push(elem);
1160                                            } else {
1161                                                val[cur_index as usize] = elem;
1162                                            }
1163                                        }
1164                                        match mc {
1165                                            MetaCategory::Default => {
1166                                                GosValue::slice_with_val(val, *md, gcv)
1167                                            }
1168                                            MetaCategory::Array => {
1169                                                GosValue::array_with_val(val, *md, gcv)
1170                                            }
1171                                            _ => unreachable!(),
1172                                        }
1173                                    }
1174                                    MetadataType::Map(km, vm) => {
1175                                        let gosv =
1176                                            GosValue::new_map(*md, zero_val!(vm, objs, gcv), gcv);
1177                                        let map = gosv.as_map();
1178                                        let tk = km.get_value_type(&objs.metas);
1179                                        let tv = vm.get_value_type(&objs.metas);
1180                                        for _ in 0..count {
1181                                            let k = stack.pop_with_type(tk);
1182                                            let v = stack.pop_with_type(tv);
1183                                            map.0.insert(k, v);
1184                                        }
1185                                        gosv
1186                                    }
1187                                    MetadataType::Struct(f, zero) => {
1188                                        let struct_val = zero.copy_semantic(gcv);
1189                                        let mut sref = struct_val.as_struct().0.borrow_mut();
1190                                        for _ in 0..count {
1191                                            let index = stack.pop_uint();
1192                                            let tv = f.fields[index].get_value_type(&objs.metas);
1193                                            sref.fields[index] = stack.pop_with_type(tv);
1194                                        }
1195                                        drop(sref);
1196                                        struct_val
1197                                    }
1198                                    _ => unreachable!(),
1199                                };
1200                                if umd == *md {
1201                                    val
1202                                } else {
1203                                    GosValue::Named(Box::new((val, *md)))
1204                                }
1205                            }
1206                            _ => unimplemented!(),
1207                        };
1208                        stack.push(new_val);
1209                    }
1210
1211                    Opcode::NEW => {
1212                        let param = stack.pop_with_type(inst.t0());
1213                        let new_val = match param {
1214                            GosValue::Metadata(md) => {
1215                                let v = md.default_val(&objs.metas, gcv);
1216                                GosValue::new_pointer(PointerObj::UpVal(UpValue::new_closed(v)))
1217                            }
1218                            _ => unimplemented!(),
1219                        };
1220                        stack.push(new_val);
1221                    }
1222                    Opcode::MAKE => {
1223                        let index = inst.imm();
1224                        let i = Stack::offset(stack.len(), index - 1);
1225                        let meta_val = stack.get_with_type(i, ValueType::Metadata);
1226                        let meta = meta_val.as_meta();
1227                        let metadata = &objs.metas[meta.as_non_ptr()];
1228                        let val = match metadata {
1229                            MetadataType::SliceOrArray(vmeta, _) => {
1230                                let (cap, len) = match index {
1231                                    -2 => (stack.pop_int() as usize, stack.pop_int() as usize),
1232                                    -1 => {
1233                                        let len = stack.pop_int() as usize;
1234                                        (len, len)
1235                                    }
1236                                    _ => unreachable!(),
1237                                };
1238                                GosValue::new_slice(
1239                                    len,
1240                                    cap,
1241                                    *meta,
1242                                    Some(&zero_val!(vmeta, objs, gcv)),
1243                                    gcv,
1244                                )
1245                            }
1246                            MetadataType::Map(_, v) => {
1247                                let default = zero_val!(v, objs, gcv);
1248                                GosValue::new_map(*meta, default, gcv)
1249                            }
1250                            MetadataType::Channel(_, _) => {
1251                                let cap = match index {
1252                                    -1 => stack.pop_int() as usize,
1253                                    0 => 0,
1254                                    _ => unreachable!(),
1255                                };
1256                                GosValue::new_channel(*meta, cap)
1257                            }
1258                            _ => unreachable!(),
1259                        };
1260                        stack.pop_discard();
1261                        stack.push(val);
1262                    }
1263                    Opcode::LEN => {
1264                        let l = match &stack.pop_with_type(inst.t0()) {
1265                            GosValue::Slice(slice) => slice.0.len(),
1266                            GosValue::Map(map) => map.0.len(),
1267                            GosValue::Str(sval) => sval.len(),
1268                            GosValue::Channel(chan) => chan.len(),
1269                            _ => unreachable!(),
1270                        };
1271                        stack.push(GosValue::Int(l as isize));
1272                    }
1273                    Opcode::CAP => {
1274                        let l = match &stack.pop_with_type(inst.t0()) {
1275                            GosValue::Slice(slice) => slice.0.cap(),
1276                            GosValue::Channel(chan) => chan.cap(),
1277                            _ => unreachable!(),
1278                        };
1279                        stack.push(GosValue::Int(l as isize));
1280                    }
1281                    Opcode::APPEND => {
1282                        let index = Stack::offset(stack.len(), inst.imm());
1283                        let a = stack.get_with_type(index - 2, ValueType::Slice);
1284                        let vala = a.as_slice();
1285                        stack.pack_variadic(index, vala.0.meta, inst.t1(), gcv);
1286                        let b = stack.pop_with_type(ValueType::Slice);
1287                        let valb = b.as_slice();
1288                        vala.0
1289                            .borrow_data_mut()
1290                            .append(&mut valb.0.borrow_data().clone());
1291                    }
1292                    Opcode::CLOSE => {
1293                        let chan = stack.pop_with_type(ValueType::Channel);
1294                        chan.as_channel().close();
1295                    }
1296                    Opcode::PANIC => {
1297                        let val = stack.pop_rc();
1298                        go_panic!(panic, val, frame, code);
1299                    }
1300                    Opcode::RECOVER => {
1301                        let p = panic.take();
1302                        let val = p.map_or(GosValue::new_nil(), |x| x.msg);
1303                        stack.push(val);
1304                    }
1305                    Opcode::ASSERT => {
1306                        if !stack.pop_bool() {
1307                            let msg = "Opcode::ASSERT: not true!".to_string();
1308                            go_panic_str!(panic, metadata, msg, frame, code);
1309                        }
1310                    }
1311                    Opcode::FFI => {
1312                        let meta = stack.pop_with_type(ValueType::Metadata);
1313                        let total_params = inst.imm();
1314                        let index = Stack::offset(stack.len(), -total_params);
1315                        let itype = stack.get_with_type(index, ValueType::Metadata);
1316                        let name = stack.get_with_type(index + 1, ValueType::Str);
1317                        let name_str = name.as_str().as_str();
1318                        let ptypes = &objs.metas[meta.as_meta().as_non_ptr()]
1319                            .as_signature()
1320                            .params_type[2..];
1321                        let params = stack.pop_with_type_n(ptypes);
1322                        let v = match self.context.ffi_factory.create_by_name(name_str, params) {
1323                            Ok(v) => {
1324                                let meta = itype.as_meta().get_underlying(&objs.metas).clone();
1325                                let info = objs.metas[meta.as_non_ptr()]
1326                                    .as_interface()
1327                                    .iface_ffi_info();
1328                                GosValue::new_iface(
1329                                    meta,
1330                                    IfaceUnderlying::Ffi(UnderlyingFfi::new(v, info)),
1331                                )
1332                            }
1333                            Err(e) => {
1334                                go_panic_str!(panic, metadata, e, frame, code);
1335                                continue;
1336                            }
1337                        };
1338                        stack.push(v);
1339                    }
1340                    _ => {
1341                        dbg!(inst_op);
1342                        unimplemented!();
1343                    }
1344                };
1345                //dbg!(inst_op, stack.len());
1346            } //yield unit
1347            match result {
1348                Result::End => {
1349                    if let Some(p) = panic {
1350                        println!("panic: {}", p.msg);
1351                        if let Some(files) = self.context.fs {
1352                            for (fkey, pc) in p.call_stack.iter() {
1353                                let func = &objs.functions[*fkey];
1354                                if let Some(p) = func.pos()[*pc] {
1355                                    println!("{}", files.position(p));
1356                                } else {
1357                                    println!("<no debug info available>");
1358                                }
1359                            }
1360                        }
1361
1362                        // a hack to make the test case fail
1363                        if let GosValue::Str(s) =
1364                            p.msg.as_interface().borrow().underlying_value().unwrap()
1365                        {
1366                            if s.as_str().starts_with("Opcode::ASSERT") {
1367                                panic!("ASSERT");
1368                            }
1369                        }
1370                    }
1371                    break;
1372                }
1373                Result::Continue => {
1374                    drop(stack_mut_ref);
1375                    future::yield_now().await;
1376                    restore_stack_ref!(self, stack, stack_mut_ref);
1377                }
1378            };
1379        } //loop
1380
1381        stack.clear_rc_garbage();
1382        gc(gcv);
1383    }
1384}
1385
1386pub struct GosVM<'a> {
1387    code: ByteCode,
1388    gcv: GcoVec,
1389    ffi: &'a FfiFactory,
1390    fs: Option<&'a FileSet>,
1391}
1392
1393impl<'a> GosVM<'a> {
1394    pub fn new(bc: ByteCode, ffi: &'a FfiFactory, fs: Option<&'a FileSet>) -> GosVM<'a> {
1395        GosVM {
1396            code: bc,
1397            gcv: GcoVec::new(),
1398            ffi: ffi,
1399            fs: fs,
1400        }
1401    }
1402
1403    pub fn run(&self) {
1404        let exec = Rc::new(LocalExecutor::new());
1405        let ctx = Context::new(exec.clone(), &self.code, &self.gcv, self.ffi, self.fs);
1406        let entry = ctx.new_entry_frame(self.code.entry);
1407        ctx.spawn_fiber(Stack::new(), entry);
1408
1409        future::block_on(async {
1410            loop {
1411                if !exec.try_tick() {
1412                    break;
1413                }
1414            }
1415        });
1416    }
1417}
1418
1419#[cfg(test)]
1420mod test {}