go_vm/
vm.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5use crate::ffi::{FfiCtx, FfiFactory};
6use crate::gc::{collect, GcContainer};
7use crate::objects::ClosureObj;
8use crate::stack::{RangeStack, Stack};
9use crate::value::*;
10use go_parser::Map;
11use std::cell::{Cell, RefCell};
12use std::cmp::Ordering;
13use std::rc::Rc;
14
15#[cfg(feature = "async")]
16use crate::channel;
17#[cfg(feature = "async")]
18use async_executor::LocalExecutor;
19#[cfg(feature = "async")]
20use futures_lite::future;
21
22// restore stack_ref after drop to allow code in block call yield
23macro_rules! restore_stack_ref {
24    ($self_:ident, $stack:ident, $stack_ref:ident) => {{
25        $stack_ref = $self_.stack.borrow_mut();
26        $stack = &mut $stack_ref;
27    }};
28}
29
30macro_rules! go_panic {
31    ($panic:ident, $msg:expr, $frame:ident, $code:ident) => {{
32        let mut data = PanicData::new($msg);
33        data.call_stack.push(($frame.func(), $frame.pc - 1));
34        $panic = Some(data);
35        $frame.pc = $code.len() as OpIndex - 1;
36    }};
37}
38
39macro_rules! go_panic_str {
40    ($panic:ident, $msg:expr, $frame:ident, $code:ident) => {{
41        let str_val = GosValue::with_str($msg);
42        let iface = GosValue::empty_iface_with_val(str_val);
43        go_panic!($panic, iface, $frame, $code);
44    }};
45}
46
47#[cfg(not(feature = "async"))]
48macro_rules! go_panic_no_async {
49    ($panic:ident, $frame:ident, $code:ident) => {{
50        go_panic_str!($panic, "Async features disabled", $frame, $code)
51    }};
52}
53
54macro_rules! panic_if_err {
55    ($result:expr, $panic:ident, $frame:ident, $code:ident) => {{
56        if let Err(e) = $result {
57            go_panic_str!($panic, e.as_str(), $frame, $code);
58        }
59    }};
60}
61
62#[cfg(feature = "async")]
63macro_rules! unwrap_recv_val {
64    ($chan:expr, $val:expr, $gcc:expr) => {
65        match $val {
66            Some(v) => (v, true),
67            None => ($chan.recv_zero.copy_semantic($gcc), false),
68        }
69    };
70}
71
72macro_rules! binary_op {
73    ($stack:expr, $op:tt, $inst:expr, $sb:expr, $consts:expr) => {{
74        let vdata = $stack
75            .read($inst.s0, $sb, $consts)
76            .data()
77            .$op($stack.read($inst.s1, $sb, $consts).data(), $inst.t0);
78        let val = GosValue::new($inst.t0, vdata);
79        $stack.set($inst.d + $sb, val);
80    }};
81}
82
83macro_rules! binary_op_assign {
84    ($stack:ident, $op:tt, $inst:expr, $sb:expr, $consts:expr) => {{
85        let right = unsafe { $stack.read($inst.s0, $sb, $consts).data().copy_non_ptr() };
86        let d = $stack.get_data_mut($inst.d + $sb);
87        *d = d.$op(&right, $inst.t0);
88    }};
89}
90
91macro_rules! shift_op {
92    ($stack:expr, $op:tt, $inst:expr, $sb:expr, $consts:expr) => {{
93        let right = $stack
94            .read($inst.s1, $sb, $consts)
95            .data()
96            .cast_copyable($inst.t1, ValueType::Uint32);
97        let vdata = $stack
98            .read($inst.s0, $sb, $consts)
99            .data()
100            .$op(right.as_uint32(), $inst.t0);
101        let val = GosValue::new($inst.t0, vdata);
102        $stack.set($inst.d + $sb, val);
103    }};
104}
105
106macro_rules! shift_op_assign {
107    ($stack:ident, $op:tt, $inst:expr, $sb:expr, $consts:expr) => {{
108        let right = $stack
109            .read($inst.s0, $sb, $consts)
110            .data()
111            .cast_copyable($inst.t1, ValueType::Uint32);
112        let d = $stack.get_data_mut($inst.d + $sb);
113        *d = d.$op(right.as_uint32(), $inst.t0);
114    }};
115}
116
117macro_rules! unary_op {
118    ($stack:expr, $op:tt, $inst:expr, $sb:expr, $consts:expr) => {{
119        let vdata = $stack.read($inst.s0, $sb, $consts).data().$op($inst.t0);
120        let val = GosValue::new($inst.t0, vdata);
121        $stack.set($inst.d + $sb, val);
122    }};
123}
124
125/// Entry point
126pub fn run(code: &Bytecode, ffi: &FfiFactory) -> Option<PanicData> {
127    let gcc = GcContainer::new();
128    let panic_data = Rc::new(RefCell::new(None));
129
130    #[cfg(not(feature = "async"))]
131    {
132        let ctx = Context::new(code, &gcc, ffi, panic_data.clone());
133        let first_frame = ctx.new_entry_frame(code.entry);
134        Fiber::new(ctx, Stack::new(), first_frame).main_loop();
135    }
136    #[cfg(feature = "async")]
137    {
138        let exec = Rc::new(LocalExecutor::new());
139        let ctx = Context::new(exec.clone(), code, &gcc, ffi, panic_data.clone());
140        let entry = ctx.new_entry_frame(code.entry);
141        ctx.spawn_fiber(Stack::new(), entry);
142        future::block_on(async {
143            loop {
144                if !exec.try_tick() {
145                    break;
146                }
147            }
148        });
149    }
150    panic_data.replace(None)
151}
152
153#[derive(Clone, Debug)]
154struct Referers {
155    typ: ValueType,
156    weaks: Vec<WeakUpValue>,
157}
158
159#[derive(Clone, Debug)]
160struct CallFrame {
161    closure: ClosureObj,
162    pc: OpIndex,
163    stack_base: OpIndex,
164    var_ptrs: Option<Vec<UpValue>>,
165    // closures that have upvalues pointing to this frame
166    referred_by: Option<Map<OpIndex, Referers>>,
167
168    defer_stack: Option<Vec<DeferredCall>>,
169}
170
171impl CallFrame {
172    fn with_closure(c: ClosureObj, sbase: OpIndex) -> CallFrame {
173        CallFrame {
174            closure: c,
175            pc: 0,
176            stack_base: sbase,
177            var_ptrs: None,
178            referred_by: None,
179            defer_stack: None,
180        }
181    }
182
183    fn add_referred_by(&mut self, index: OpIndex, typ: ValueType, uv: &UpValue) {
184        if self.referred_by.is_none() {
185            self.referred_by = Some(Map::new());
186        }
187        let map = self.referred_by.as_mut().unwrap();
188        let weak = uv.downgrade();
189        match map.get_mut(&index) {
190            Some(v) => {
191                debug_assert!(v.typ == typ);
192                v.weaks.push(weak);
193            }
194            None => {
195                map.insert(
196                    index,
197                    Referers {
198                        typ: typ,
199                        weaks: vec![weak],
200                    },
201                );
202            }
203        }
204    }
205
206    #[inline]
207    fn func(&self) -> FunctionKey {
208        self.closure.as_gos().func
209    }
210
211    #[inline]
212    fn func_obj<'a>(&self, objs: &'a VMObjects) -> &'a FunctionObj {
213        let fkey = self.func();
214        &objs.functions[fkey]
215    }
216
217    #[inline]
218    fn on_drop(&mut self, stack: &Stack) {
219        if let Some(referred) = &self.referred_by {
220            for (ind, referrers) in referred {
221                if referrers.weaks.len() == 0 {
222                    continue;
223                }
224                let val = stack.get(self.stack_base + *ind);
225                for weak in referrers.weaks.iter() {
226                    if let Some(uv) = weak.upgrade() {
227                        uv.close(val.clone());
228                    }
229                }
230            }
231        }
232    }
233}
234
235#[derive(Clone, Debug)]
236struct DeferredCall {
237    frame: CallFrame,
238    vec: Vec<GosValue>,
239}
240
241#[derive(Debug)]
242enum Result {
243    Continue,
244    End,
245}
246
247#[derive(Debug)]
248pub struct PanicData {
249    pub msg: GosValue,
250    pub call_stack: Vec<(FunctionKey, OpIndex)>,
251}
252
253impl PanicData {
254    fn new(m: GosValue) -> PanicData {
255        PanicData {
256            msg: m,
257            call_stack: vec![],
258        }
259    }
260}
261
262#[derive(Clone)]
263struct Context<'a> {
264    #[cfg(feature = "async")]
265    exec: Rc<LocalExecutor<'a>>,
266    code: &'a Bytecode,
267    gcc: &'a GcContainer,
268    ffi_factory: &'a FfiFactory,
269    panic_data: Rc<RefCell<Option<PanicData>>>,
270    next_id: Cell<usize>,
271}
272
273impl<'a> Context<'a> {
274    fn new(
275        #[cfg(feature = "async")] exec: Rc<LocalExecutor<'a>>,
276        code: &'a Bytecode,
277        gcc: &'a GcContainer,
278        ffi_factory: &'a FfiFactory,
279        panic_data: Rc<RefCell<Option<PanicData>>>,
280    ) -> Context<'a> {
281        Context {
282            #[cfg(feature = "async")]
283            exec,
284            code,
285            gcc,
286            ffi_factory,
287            panic_data,
288            next_id: Cell::new(0),
289        }
290    }
291
292    fn new_entry_frame(&self, entry: FunctionKey) -> CallFrame {
293        let cls = ClosureObj::gos_from_func(entry, &self.code.objects.functions, None);
294        CallFrame::with_closure(cls, 0)
295    }
296
297    #[cfg(feature = "async")]
298    fn spawn_fiber(&self, stack: Stack, first_frame: CallFrame) {
299        let mut f = Fiber::new(self.clone(), stack, first_frame);
300        self.exec
301            .spawn(async move {
302                // let parent fiber go first
303                future::yield_now().await;
304                f.main_loop().await;
305            })
306            .detach();
307    }
308}
309
310struct Fiber<'a> {
311    stack: Rc<RefCell<Stack>>,
312    rstack: RangeStack,
313    frames: Vec<CallFrame>,
314    context: Context<'a>,
315    _id: usize,
316}
317
318impl<'a> Fiber<'a> {
319    pub fn _id(&self) -> usize {
320        self._id
321    }
322
323    fn new(context: Context<'a>, stack: Stack, first_frame: CallFrame) -> Fiber<'a> {
324        let _id = context.next_id.get();
325        context.next_id.set(_id + 1);
326        Fiber {
327            stack: Rc::new(RefCell::new(stack)),
328            rstack: RangeStack::new(),
329            frames: vec![first_frame],
330            context,
331            _id,
332        }
333    }
334
335    #[cfg_attr(feature = "async", go_pmacro::async_fn)]
336    fn main_loop(&mut self) {
337        let ctx = &self.context;
338        let gcc = ctx.gcc;
339        let objs: &VMObjects = &ctx.code.objects;
340        let caller: &ArrCaller = &objs.arr_slice_caller;
341        let consts = &ctx.code.consts;
342        let prim_meta: &PrimitiveMeta = &objs.prim_meta;
343        let ifaces = &ctx.code.ifaces;
344        let indices = &ctx.code.indices;
345        let mut frame_height = self.frames.len();
346        let fr = self.frames.last().unwrap();
347        let mut func = &objs.functions[fr.func()];
348        let mut sb = fr.stack_base;
349
350        let mut stack_mut_ref = self.stack.borrow_mut();
351        let mut stack: &mut Stack = &mut stack_mut_ref;
352        // allocate local variables
353        stack.set_vec(func.param_count(), func.local_zeros.clone());
354
355        let mut code = &func.code;
356
357        let mut total_inst = 0;
358        //let mut stats: Map<Opcode, usize> = Map::new();
359        loop {
360            let mut frame = self.frames.last_mut().unwrap();
361            let mut result: Result = Result::Continue;
362            let mut panic: Option<PanicData> = None;
363            let yield_unit = 1024;
364            for _ in 0..yield_unit {
365                let inst = &code[frame.pc as usize];
366                let inst_op = inst.op0;
367                total_inst += 1;
368                //stats.entry(*inst).and_modify(|e| *e += 1).or_insert(1);
369                frame.pc += 1;
370                //dbg!(inst);
371                match inst_op {
372                    // desc: local
373                    // s0: local/const
374                    Opcode::DUPLICATE => {
375                        //dbg!(stack.read(inst.s0, sb, consts));
376                        stack.set(
377                            sb + inst.d,
378                            stack.read(inst.s0, sb, consts).copy_semantic(gcc),
379                        )
380                    }
381                    // desc: local
382                    // s0: slice
383                    // s1: index
384                    Opcode::LOAD_SLICE => {
385                        let slice = stack.read(inst.s0, sb, consts);
386                        let index = stack.read(inst.s1, sb, consts).as_index();
387                        match slice.slice_array_equivalent(index) {
388                            Ok((array, i)) => match array.caller(caller).array_get(&array, i) {
389                                Ok(val) => stack.set(sb + inst.d, val),
390                                Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
391                            },
392                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
393                        }
394                    }
395                    // desc: slice
396                    // s0: index
397                    // s1: value
398                    Opcode::STORE_SLICE => {
399                        let dest = stack.read(inst.d, sb, consts);
400                        let index = stack.read(inst.s0, sb, consts).as_index();
401                        match dest.slice_array_equivalent(index) {
402                            Ok((array, i)) => match inst.op1 {
403                                Opcode::VOID => {
404                                    let val = stack.read(inst.s1, sb, consts).copy_semantic(gcc);
405                                    let result = array.caller(caller).array_set(&array, &val, i);
406                                    panic_if_err!(result, panic, frame, code);
407                                }
408                                _ => match array.caller(caller).array_get(&array, i) {
409                                    Ok(old) => {
410                                        let val = stack.read_and_op(
411                                            old.data(),
412                                            inst.t0,
413                                            inst.op1,
414                                            inst.s1,
415                                            sb,
416                                            &consts,
417                                        );
418                                        let result =
419                                            array.caller(caller).array_set(&array, &val, i);
420                                        panic_if_err!(result, panic, frame, code);
421                                    }
422                                    Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
423                                },
424                            },
425                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
426                        }
427                    }
428                    // desc: local
429                    // s0: array
430                    // s1: index
431                    Opcode::LOAD_ARRAY => {
432                        let array = stack.read(inst.s0, sb, consts);
433                        let index = stack.read(inst.s1, sb, consts).as_index();
434                        match array.caller(caller).array_get(&array, index) {
435                            Ok(val) => stack.set(inst.d + sb, val),
436                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
437                        }
438                    }
439                    // desc: array
440                    // s0: index
441                    // s1: value
442                    Opcode::STORE_ARRAY => {
443                        let array = stack.read(inst.d, sb, consts);
444                        let index = stack.read(inst.s0, sb, consts).as_index();
445                        match inst.op1 {
446                            Opcode::VOID => {
447                                let val = stack.read(inst.s1, sb, consts).copy_semantic(gcc);
448                                let result = array.caller(caller).array_set(&array, &val, index);
449                                panic_if_err!(result, panic, frame, code);
450                            }
451                            _ => match array.caller(caller).array_get(&array, index) {
452                                Ok(old) => {
453                                    let val = stack.read_and_op(
454                                        old.data(),
455                                        inst.t0,
456                                        inst.op1,
457                                        inst.s1,
458                                        sb,
459                                        &consts,
460                                    );
461                                    let result =
462                                        array.caller(caller).array_set(&array, &val, index);
463                                    panic_if_err!(result, panic, frame, code);
464                                }
465                                Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
466                            },
467                        }
468                    }
469                    // inst.d: local
470                    // inst_ex.d: local
471                    // inst.s0: map
472                    // inst.s1: key
473                    // inst_ex.s0: zero_val
474                    Opcode::LOAD_MAP => {
475                        let inst_ex = &code[frame.pc as usize];
476                        frame.pc += 1;
477                        let map = stack.read(inst.s0, sb, consts);
478                        let key = stack.read(inst.s1, sb, consts);
479                        let val = match map.as_map() {
480                            Some(map) => map.0.get(&key),
481                            None => None,
482                        };
483                        let (v, ok) = match val {
484                            Some(v) => (v, true),
485                            None => (stack.read(inst_ex.s0, sb, consts).copy_semantic(gcc), false),
486                        };
487                        stack.set(inst.d + sb, v);
488                        if inst.t1 == ValueType::FlagB {
489                            stack.set(inst_ex.d + sb, ok.into());
490                        }
491                    }
492                    // desc: map
493                    // s0: index
494                    // s1: value
495                    // inst_ex.s0: zero_val
496                    Opcode::STORE_MAP => {
497                        let inst_ex = &code[frame.pc as usize];
498                        frame.pc += 1;
499                        let dest = stack.read(inst.d, sb, consts);
500                        match dest.as_non_nil_map() {
501                            Ok(map) => {
502                                let key = stack.read(inst.s0, sb, consts);
503                                match inst.op1 {
504                                    Opcode::VOID => {
505                                        let val =
506                                            stack.read(inst.s1, sb, consts).copy_semantic(gcc);
507                                        map.0.insert(key.clone(), val);
508                                    }
509                                    _ => {
510                                        let old = match map.0.get(&key) {
511                                            Some(v) => v,
512                                            None => stack.read(inst_ex.s0, sb, consts).clone(),
513                                        };
514                                        let val = stack.read_and_op(
515                                            old.data(),
516                                            inst.t0,
517                                            inst.op1,
518                                            inst.s1,
519                                            sb,
520                                            &consts,
521                                        );
522                                        map.0.insert(key.clone(), val);
523                                    }
524                                }
525                            }
526                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
527                        }
528                    }
529                    // desc: local
530                    // s0: struct
531                    // s1: index
532                    Opcode::LOAD_STRUCT => {
533                        let struct_ = stack.read(inst.s0, sb, consts);
534                        let val = struct_.as_struct().0.borrow_fields()[inst.s1 as usize].clone();
535                        stack.set(inst.d + sb, val);
536                    }
537                    // desc: struct
538                    // s0: index
539                    // s1: value
540                    Opcode::STORE_STRUCT => {
541                        let dest = stack.read(inst.d, sb, consts);
542                        match inst.op1 {
543                            Opcode::VOID => {
544                                let val = stack.read(inst.s1, sb, consts).copy_semantic(gcc);
545                                dest.as_struct().0.borrow_fields_mut()[inst.s0 as usize] = val;
546                            }
547                            _ => {
548                                let old =
549                                    &mut dest.as_struct().0.borrow_fields_mut()[inst.s0 as usize];
550                                let val = stack.read_and_op(
551                                    old.data(),
552                                    inst.t0,
553                                    inst.op1,
554                                    inst.s1,
555                                    sb,
556                                    &consts,
557                                );
558                                *old = val;
559                            }
560                        }
561                    }
562                    // desc: local
563                    // s0: struct
564                    // s1: index of indices
565                    Opcode::LOAD_EMBEDDED => {
566                        let src = stack.read(inst.s0, sb, consts);
567                        let (struct_, index) = get_struct_and_index(
568                            src.clone(),
569                            &indices[inst.s1 as usize],
570                            stack,
571                            objs,
572                        );
573                        match struct_ {
574                            Ok(s) => {
575                                let val = s.as_struct().0.borrow_fields()[index].clone();
576                                stack.set(inst.d + sb, val);
577                            }
578                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
579                        }
580                    }
581                    // desc: struct
582                    // s0: index of indices
583                    // s1: value
584                    Opcode::STORE_EMBEDDED => {
585                        let dest = stack.read(inst.d, sb, consts);
586                        let (struct_, index) = get_struct_and_index(
587                            dest.clone(),
588                            &indices[inst.s0 as usize],
589                            stack,
590                            objs,
591                        );
592                        match struct_ {
593                            Ok(s) => match inst.op1 {
594                                Opcode::VOID => {
595                                    let val = stack.read(inst.s1, sb, consts).copy_semantic(gcc);
596                                    s.as_struct().0.borrow_fields_mut()[index] = val;
597                                }
598                                _ => {
599                                    let old = &s.as_struct().0.borrow_fields()[index as usize];
600                                    let val = stack.read_and_op(
601                                        old.data(),
602                                        inst.t0,
603                                        inst.op1,
604                                        inst.s1,
605                                        sb,
606                                        &consts,
607                                    );
608                                    s.as_struct().0.borrow_fields_mut()[index as usize] = val;
609                                }
610                            },
611                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
612                        }
613                    }
614                    // desc: local
615                    // s0: package
616                    // s1: index
617                    Opcode::LOAD_PKG => {
618                        let src = stack.read(inst.s0, sb, consts);
619                        let index = inst.s1;
620                        let pkg = &objs.packages[*src.as_package()];
621                        let val = pkg.member(index).clone();
622                        stack.set(inst.d + sb, val);
623                    }
624                    // desc: package
625                    // s0: index
626                    // s1: value
627                    Opcode::STORE_PKG => {
628                        let dest = stack.read(inst.d, sb, consts);
629                        let index = inst.s0;
630
631                        let pkg = &objs.packages[*dest.as_package()];
632                        match inst.op1 {
633                            Opcode::VOID => {
634                                let val = stack.read(inst.s1, sb, consts).copy_semantic(gcc);
635                                *pkg.member_mut(index) = val;
636                            }
637                            _ => {
638                                let mut old = pkg.member_mut(index);
639                                let val = stack.read_and_op(
640                                    old.data(),
641                                    inst.t0,
642                                    inst.op1,
643                                    inst.s1,
644                                    sb,
645                                    &consts,
646                                );
647                                *old = val;
648                            }
649                        }
650                    }
651                    // desc: local
652                    // s0: pointer
653                    Opcode::LOAD_POINTER => {
654                        let src = stack.read(inst.s0, sb, consts);
655                        match src.as_non_nil_pointer() {
656                            Ok(p) => match p.deref(stack, &objs.packages) {
657                                Ok(val) => stack.set(inst.d + sb, val),
658                                Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
659                            },
660                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
661                        }
662                    }
663                    // desc: pointer
664                    // s0: value
665                    Opcode::STORE_POINTER => {
666                        let dest = stack.read(inst.d, sb, consts).clone();
667                        let result = dest.as_non_nil_pointer().and_then(|p| {
668                            let val = match inst.op1 {
669                                Opcode::VOID => stack.read(inst.s0, sb, consts).copy_semantic(gcc),
670                                _ => {
671                                    let old = p.deref(stack, &objs.packages)?;
672                                    stack.read_and_op(
673                                        old.data(),
674                                        inst.t0,
675                                        inst.op1,
676                                        inst.s0,
677                                        sb,
678                                        &consts,
679                                    )
680                                }
681                            };
682                            match p {
683                                PointerObj::UpVal(uv) => {
684                                    uv.set_value(val, stack);
685                                    Ok(())
686                                }
687                                PointerObj::SliceMember(s, index) => {
688                                    let index = *index as usize;
689                                    let (array, index) = s.slice_array_equivalent(index)?;
690                                    array.caller(caller).array_set(&array, &val, index)
691                                }
692                                PointerObj::StructField(s, index) => {
693                                    s.as_struct().0.borrow_fields_mut()[*index as usize] = val;
694                                    Ok(())
695                                }
696                                PointerObj::PkgMember(p, index) => {
697                                    let pkg = &objs.packages[*p];
698                                    *pkg.member_mut(*index) = val;
699                                    Ok(())
700                                }
701                            }
702                        });
703                        panic_if_err!(result, panic, frame, code);
704                    }
705                    // desc: local
706                    // s0: upvalue
707                    Opcode::LOAD_UP_VALUE => {
708                        let uvs = frame.var_ptrs.as_ref().unwrap();
709                        let val = uvs[inst.s0 as usize].value(stack).into_owned();
710                        stack.set(inst.d + sb, val);
711                    }
712                    Opcode::STORE_UP_VALUE => {
713                        let uvs = frame.var_ptrs.as_ref().unwrap();
714                        let uv = &uvs[inst.d as usize];
715                        match inst.op1 {
716                            Opcode::VOID => {
717                                let val = stack.read(inst.s0, sb, consts).copy_semantic(gcc);
718                                uv.set_value(val, stack);
719                            }
720                            _ => {
721                                let old = uv.value(stack);
722                                let val = stack.read_and_op(
723                                    old.data(),
724                                    inst.t0,
725                                    inst.op1,
726                                    inst.s0,
727                                    sb,
728                                    &consts,
729                                );
730                                uv.set_value(val, stack);
731                            }
732                        }
733                    }
734                    Opcode::ADD => binary_op!(stack, binary_op_add, inst, sb, consts),
735                    Opcode::SUB => binary_op!(stack, binary_op_sub, inst, sb, consts),
736                    Opcode::MUL => binary_op!(stack, binary_op_mul, inst, sb, consts),
737                    Opcode::QUO => binary_op!(stack, binary_op_quo, inst, sb, consts),
738                    Opcode::REM => binary_op!(stack, binary_op_rem, inst, sb, consts),
739                    Opcode::AND => binary_op!(stack, binary_op_and, inst, sb, consts),
740                    Opcode::OR => binary_op!(stack, binary_op_or, inst, sb, consts),
741                    Opcode::XOR => binary_op!(stack, binary_op_xor, inst, sb, consts),
742                    Opcode::AND_NOT => binary_op!(stack, binary_op_and_not, inst, sb, consts),
743                    Opcode::SHL => shift_op!(stack, binary_op_shl, inst, sb, consts),
744                    Opcode::SHR => shift_op!(stack, binary_op_shr, inst, sb, consts),
745                    Opcode::ADD_ASSIGN => binary_op_assign!(stack, binary_op_add, inst, sb, consts),
746                    Opcode::SUB_ASSIGN => binary_op_assign!(stack, binary_op_sub, inst, sb, consts),
747                    Opcode::MUL_ASSIGN => binary_op_assign!(stack, binary_op_mul, inst, sb, consts),
748                    Opcode::QUO_ASSIGN => binary_op_assign!(stack, binary_op_quo, inst, sb, consts),
749                    Opcode::REM_ASSIGN => binary_op_assign!(stack, binary_op_rem, inst, sb, consts),
750                    Opcode::AND_ASSIGN => binary_op_assign!(stack, binary_op_and, inst, sb, consts),
751                    Opcode::OR_ASSIGN => binary_op_assign!(stack, binary_op_or, inst, sb, consts),
752                    Opcode::XOR_ASSIGN => binary_op_assign!(stack, binary_op_xor, inst, sb, consts),
753                    Opcode::AND_NOT_ASSIGN => {
754                        binary_op_assign!(stack, binary_op_and_not, inst, sb, consts)
755                    }
756                    Opcode::SHL_ASSIGN => shift_op_assign!(stack, binary_op_shl, inst, sb, consts),
757                    Opcode::SHR_ASSIGN => shift_op_assign!(stack, binary_op_shr, inst, sb, consts),
758                    Opcode::INC => unsafe {
759                        let v = stack.get_mut(inst.d + sb).data_mut();
760                        *v = v.inc(inst.t0);
761                    },
762                    Opcode::DEC => unsafe {
763                        let v = stack.get_mut(inst.d + sb).data_mut();
764                        *v = v.dec(inst.t0);
765                    },
766                    Opcode::UNARY_SUB => unary_op!(stack, unary_negate, inst, sb, consts),
767                    Opcode::UNARY_XOR => unary_op!(stack, unary_xor, inst, sb, consts),
768                    Opcode::NOT => unary_op!(stack, logical_not, inst, sb, consts),
769                    Opcode::EQL => {
770                        let a = stack.read(inst.s0, sb, consts);
771                        let b = stack.read(inst.s1, sb, consts);
772                        let eq = if inst.t0.copyable() && inst.t0 == inst.t1 {
773                            a.data().compare_eql(b.data(), inst.t0)
774                        } else {
775                            a.eq(b)
776                        };
777                        stack.set(inst.d + sb, eq.into());
778                    }
779                    Opcode::NEQ => {
780                        let a = stack.read(inst.s0, sb, consts);
781                        let b = stack.read(inst.s1, sb, consts);
782                        let neq = if inst.t0.copyable() {
783                            a.data().compare_neq(b.data(), inst.t0)
784                        } else {
785                            !a.eq(b)
786                        };
787                        stack.set(inst.d + sb, neq.into());
788                    }
789                    Opcode::LSS => {
790                        let a = stack.read(inst.s0, sb, consts);
791                        let b = stack.read(inst.s1, sb, consts);
792                        let lss = if inst.t0.copyable() {
793                            a.data().compare_lss(b.data(), inst.t0)
794                        } else {
795                            a.cmp(b) == Ordering::Less
796                        };
797                        stack.set(inst.d + sb, lss.into());
798                    }
799                    Opcode::GTR => {
800                        let a = stack.read(inst.s0, sb, consts);
801                        let b = stack.read(inst.s1, sb, consts);
802                        let gtr = if inst.t0.copyable() {
803                            a.data().compare_gtr(b.data(), inst.t0)
804                        } else {
805                            a.cmp(b) == Ordering::Greater
806                        };
807                        stack.set(inst.d + sb, gtr.into());
808                    }
809                    Opcode::LEQ => {
810                        let a = stack.read(inst.s0, sb, consts);
811                        let b = stack.read(inst.s1, sb, consts);
812                        let leq = if inst.t0.copyable() {
813                            a.data().compare_leq(b.data(), inst.t0)
814                        } else {
815                            a.cmp(b) != Ordering::Greater
816                        };
817                        stack.set(inst.d + sb, leq.into());
818                    }
819                    Opcode::GEQ => {
820                        let a = stack.read(inst.s0, sb, consts);
821                        let b = stack.read(inst.s1, sb, consts);
822                        let geq = if inst.t0.copyable() {
823                            a.data().compare_geq(b.data(), inst.t0)
824                        } else {
825                            a.cmp(b) != Ordering::Less
826                        };
827                        stack.set(inst.d + sb, geq.into());
828                    }
829                    Opcode::REF => {
830                        let val = stack.read(inst.s0, sb, consts);
831                        let boxed = PointerObj::new_closed_up_value(&val);
832                        stack.set(inst.d + sb, GosValue::new_pointer(boxed));
833                    }
834                    Opcode::REF_UPVALUE => {
835                        let uvs = frame.var_ptrs.as_ref().unwrap();
836                        let upvalue = uvs[inst.s0 as usize].clone();
837                        stack.set(
838                            inst.d + sb,
839                            GosValue::new_pointer(PointerObj::UpVal(upvalue.clone())),
840                        );
841                    }
842                    Opcode::REF_SLICE_MEMBER => {
843                        let arr_or_slice = stack.read(inst.s0, sb, consts).clone();
844                        let index = stack.read(inst.s1, sb, consts).as_index() as OpIndex;
845                        match PointerObj::new_slice_member_internal(
846                            arr_or_slice,
847                            index,
848                            inst.t0,
849                            caller.get(inst.t1),
850                        ) {
851                            Ok(p) => stack.set(inst.d + sb, GosValue::new_pointer(p)),
852                            Err(e) => {
853                                go_panic_str!(panic, e.as_str(), frame, code)
854                            }
855                        }
856                    }
857                    Opcode::REF_STRUCT_FIELD => {
858                        let struct_ = stack.read(inst.s0, sb, consts).clone();
859                        stack.set(
860                            inst.d + sb,
861                            GosValue::new_pointer(PointerObj::StructField(struct_, inst.s1)),
862                        );
863                    }
864                    Opcode::REF_EMBEDDED => {
865                        let src = stack.read(inst.s0, sb, consts);
866                        let (struct_, index) = get_struct_and_index(
867                            src.clone(),
868                            &indices[inst.s1 as usize],
869                            stack,
870                            objs,
871                        );
872                        match struct_ {
873                            Ok(target) => {
874                                stack.set(
875                                    inst.d + sb,
876                                    GosValue::new_pointer(PointerObj::StructField(
877                                        target,
878                                        index as OpIndex,
879                                    )),
880                                );
881                            }
882                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
883                        }
884                    }
885                    Opcode::REF_PKG_MEMBER => {
886                        let pkg = *stack.read(inst.s0, sb, consts).as_package();
887                        stack.set(
888                            inst.d + sb,
889                            GosValue::new_pointer(PointerObj::PkgMember(pkg, inst.s1)),
890                        );
891                    }
892                    #[cfg(not(feature = "async"))]
893                    Opcode::SEND => go_panic_no_async!(panic, frame, code),
894                    #[cfg(feature = "async")]
895                    Opcode::SEND => {
896                        let chan = stack.read(inst.s0, sb, consts).as_channel().cloned();
897                        let val = stack.read(inst.s1, sb, consts).clone();
898                        drop(stack_mut_ref);
899                        let re = match chan {
900                            Some(c) => c.send(&val).await,
901                            None => loop {
902                                future::yield_now().await;
903                            },
904                        };
905                        restore_stack_ref!(self, stack, stack_mut_ref);
906                        panic_if_err!(re, panic, frame, code);
907                    }
908                    #[cfg(not(feature = "async"))]
909                    Opcode::RECV => go_panic_no_async!(panic, frame, code),
910                    #[cfg(feature = "async")]
911                    Opcode::RECV => {
912                        match stack.read(inst.s0, sb, consts).as_channel().cloned() {
913                            Some(chan) => {
914                                drop(stack_mut_ref);
915                                let val = chan.recv().await;
916                                restore_stack_ref!(self, stack, stack_mut_ref);
917                                let (unwrapped, ok) = unwrap_recv_val!(chan, val, gcc);
918                                stack.set(inst.d + sb, unwrapped);
919                                if inst.t1 == ValueType::FlagB {
920                                    stack.set(inst.s1 + sb, ok.into());
921                                }
922                            }
923                            None => loop {
924                                future::yield_now().await;
925                            },
926                        };
927                    }
928                    Opcode::PACK_VARIADIC => {
929                        let v = stack.move_vec(inst.s0 + sb, inst.s1 + sb);
930                        let val = GosValue::slice_with_data(v, caller.get(inst.t0), gcc);
931                        stack.set(inst.d + sb, val);
932                    }
933                    // t0: call style
934                    // d: closure
935                    // s0: next stack base
936                    Opcode::CALL => {
937                        let call_style = inst.t0;
938                        let cls = stack
939                            .read(inst.d, sb, consts)
940                            .as_closure()
941                            .unwrap()
942                            .0
943                            .clone();
944                        let next_sb = sb + inst.s0;
945                        match &cls {
946                            ClosureObj::Gos(gosc) => {
947                                let next_func = &objs.functions[gosc.func];
948                                let mut returns_recv = next_func.ret_zeros.clone();
949                                if let Some(r) = &gosc.recv {
950                                    // push receiver on stack as the first parameter
951                                    // don't call copy_semantic because BIND_METHOD did it already
952                                    returns_recv.push(r.clone());
953                                }
954                                stack.set_min_size(
955                                    (next_sb + next_func.max_write_index + 1) as usize,
956                                );
957                                stack.set_vec(next_sb, returns_recv);
958                            }
959                            _ => {}
960                        }
961                        let mut nframe = CallFrame::with_closure(cls.clone(), next_sb);
962
963                        match cls {
964                            ClosureObj::Gos(gosc) => {
965                                let nfunc = &objs.functions[gosc.func];
966                                if let Some(uvs) = gosc.uvs {
967                                    let mut ptrs: Vec<UpValue> =
968                                        Vec::with_capacity(nfunc.up_ptrs.len());
969                                    for (i, p) in nfunc.up_ptrs.iter().enumerate() {
970                                        ptrs.push(if p.is_local {
971                                            // local pointers
972                                            let uv = UpValue::new(p.clone_with_stack(
973                                                Rc::downgrade(&self.stack),
974                                                nframe.stack_base as OpIndex,
975                                            ));
976                                            nframe.add_referred_by(p.index, p.typ, &uv);
977                                            uv
978                                        } else {
979                                            uvs[&i].clone()
980                                        });
981                                    }
982                                    nframe.var_ptrs = Some(ptrs);
983                                }
984                                match call_style {
985                                    ValueType::FlagA => {
986                                        // default call
987                                        self.frames.push(nframe);
988                                        frame_height += 1;
989                                        frame = self.frames.last_mut().unwrap();
990                                        func = nfunc;
991                                        sb = frame.stack_base;
992                                        code = &func.code;
993                                        //dbg!("default", &code);
994                                    }
995                                    #[cfg(not(feature = "async"))]
996                                    ValueType::FlagB => go_panic_no_async!(panic, frame, code),
997                                    #[cfg(feature = "async")]
998                                    ValueType::FlagB => {
999                                        // goroutine
1000                                        let begin = nframe.stack_base;
1001                                        let end = begin
1002                                            + nfunc.ret_count()
1003                                            + nfunc.param_count() as OpIndex;
1004                                        let vec = stack.move_vec(begin, end);
1005                                        let nstack = Stack::with_vec(vec);
1006                                        nframe.stack_base = 0;
1007                                        self.context.spawn_fiber(nstack, nframe);
1008                                    }
1009                                    ValueType::FlagC => {
1010                                        // deferred
1011                                        let begin = nframe.stack_base;
1012                                        let end = begin
1013                                            + nfunc.ret_count()
1014                                            + nfunc.param_count() as OpIndex;
1015                                        let vec = stack.move_vec(begin, end);
1016                                        let deferred = DeferredCall {
1017                                            frame: nframe,
1018                                            vec: vec,
1019                                        };
1020                                        frame.defer_stack.get_or_insert(vec![]).push(deferred);
1021                                    }
1022                                    _ => unreachable!(),
1023                                }
1024                            }
1025                            ClosureObj::Ffi(ffic) => {
1026                                let sig = objs.metas[ffic.meta.key].as_signature();
1027                                let result_begin = nframe.stack_base;
1028                                let param_begin = result_begin + 1 + sig.results.len() as OpIndex;
1029                                let end = param_begin + sig.params.len() as OpIndex;
1030                                let params = stack.move_vec(param_begin, end);
1031                                // release stack so that code in ffi can yield
1032                                drop(stack_mut_ref);
1033                                let returns = {
1034                                    let mut ctx = FfiCtx {
1035                                        func_name: &ffic.func_name,
1036                                        vm_objs: objs,
1037                                        user_data: ctx.ffi_factory.user_data(),
1038                                        stack: &mut self.stack.borrow_mut(),
1039                                        gcc,
1040                                        array_slice_caller: caller,
1041                                    };
1042                                    if !ffic.is_async {
1043                                        ffic.ffi.call(&mut ctx, params)
1044                                    } else {
1045                                        #[cfg(not(feature = "async"))]
1046                                        {
1047                                            Err("Async features disabled".to_owned().into())
1048                                        }
1049                                        #[cfg(feature = "async")]
1050                                        ffic.ffi.async_call(&mut ctx, params).await
1051                                    }
1052                                };
1053                                restore_stack_ref!(self, stack, stack_mut_ref);
1054                                match returns {
1055                                    Ok(result) => stack.set_vec(result_begin, result),
1056                                    Err(e) => {
1057                                        go_panic_str!(panic, e.as_str(), frame, code);
1058                                    }
1059                                }
1060                            }
1061                        }
1062                    }
1063                    Opcode::RETURN => {
1064                        //dbg!(stack.len());
1065                        //for s in stack.iter() {
1066                        //    dbg!(GosValueDebug::new(&s, &objs));
1067                        //}
1068
1069                        let clear_stack = match inst.t0 {
1070                            // default case
1071                            ValueType::FlagA => true,
1072                            // init_package func
1073                            ValueType::FlagB => {
1074                                let pkey = stack.read(inst.d, sb, consts).as_package();
1075                                let pkg = &objs.packages[*pkey];
1076                                // the var values left on the stack are for pkg members
1077                                let func = frame.func_obj(objs);
1078                                let begin = sb;
1079                                let end = begin + func.local_count();
1080                                pkg.init_vars(stack.move_vec(begin, end));
1081                                false
1082                            }
1083                            // func with deferred calls
1084                            ValueType::FlagC => {
1085                                if let Some(call) =
1086                                    frame.defer_stack.as_mut().map(|x| x.pop()).flatten()
1087                                {
1088                                    // run Opcode::RETURN to check if deferred_stack is empty
1089                                    frame.pc -= 1;
1090
1091                                    let call_vec_len = call.vec.len() as OpIndex;
1092                                    let cur_func = frame.func_obj(objs);
1093                                    // dont overwrite locals of current function
1094                                    let new_sb = sb
1095                                        + cur_func.ret_count()
1096                                        + cur_func.param_count()
1097                                        + cur_func.local_count();
1098                                    stack.set_vec(new_sb, call.vec);
1099                                    let nframe = call.frame;
1100
1101                                    self.frames.push(nframe);
1102                                    frame_height += 1;
1103                                    frame = self.frames.last_mut().unwrap();
1104                                    frame.stack_base = new_sb; // the saved sb is invalidated
1105                                    let fkey = frame.func();
1106                                    func = &objs.functions[fkey];
1107                                    sb = frame.stack_base;
1108                                    code = &func.code;
1109                                    //dbg!("deferred", &code);
1110                                    let index = new_sb + call_vec_len;
1111                                    stack.set_vec(index, func.local_zeros.clone());
1112                                    continue;
1113                                }
1114                                true
1115                            }
1116                            _ => unreachable!(),
1117                        };
1118
1119                        if clear_stack {
1120                            // println!(
1121                            //     "current line: {}",
1122                            //     self.context.fs.unwrap().position(
1123                            //         objs.functions[frame.func()].pos()[frame.pc - 1].unwrap()
1124                            //     )
1125                            // );
1126
1127                            frame.on_drop(&stack);
1128                            let func = frame.func_obj(objs);
1129                            let begin = sb + func.ret_count() as OpIndex;
1130                            let end = begin + func.param_count() + func.local_count();
1131                            stack.move_vec(begin, end);
1132                        }
1133
1134                        // We used to need this to make the compiler happy:
1135                        // drop(frame);
1136                        self.frames.pop();
1137                        frame_height -= 1;
1138                        if self.frames.is_empty() {
1139                            dbg!(total_inst);
1140
1141                            result = Result::End;
1142                            break;
1143                        }
1144                        frame = self.frames.last_mut().unwrap();
1145                        sb = frame.stack_base;
1146                        // restore func, consts, code
1147                        func = &objs.functions[frame.func()];
1148                        code = &func.code;
1149
1150                        if let Some(p) = &mut panic {
1151                            p.call_stack.push((frame.func(), frame.pc - 1));
1152                            frame.pc = code.len() as OpIndex - 1;
1153                        }
1154                    }
1155                    Opcode::JUMP => frame.pc += inst.d,
1156                    Opcode::JUMP_IF => {
1157                        if *stack.read(inst.s0, sb, consts).as_bool() {
1158                            frame.pc += inst.d;
1159                        }
1160                    }
1161                    Opcode::JUMP_IF_NOT => {
1162                        if !*stack.read(inst.s0, sb, consts).as_bool() {
1163                            frame.pc += inst.d;
1164                        }
1165                    }
1166                    Opcode::SWITCH => {
1167                        let t = inst.t0;
1168                        let a = stack.read(inst.s0, sb, consts);
1169                        let b = stack.read(inst.s1, sb, consts);
1170                        let ok = if t.copyable() {
1171                            a.data().compare_eql(b.data(), t)
1172                        } else if t != ValueType::Metadata {
1173                            a.eq(&b)
1174                        } else {
1175                            a.as_metadata().identical(b.as_metadata(), &objs.metas)
1176                        };
1177                        if ok {
1178                            frame.pc += inst.d;
1179                        }
1180                    }
1181                    #[cfg(not(feature = "async"))]
1182                    Opcode::SELECT => go_panic_no_async!(panic, frame, code),
1183                    #[cfg(feature = "async")]
1184                    Opcode::SELECT => {
1185                        let comm_count = inst.s0;
1186                        let has_default = inst.t0 == ValueType::FlagE;
1187                        let default_offset = has_default.then_some(inst.d);
1188                        let mut comms = Vec::with_capacity(comm_count as usize);
1189                        for _ in 0..comm_count {
1190                            let entry = &code[frame.pc as usize];
1191                            frame.pc += 1;
1192                            let chan = stack.read(entry.s0, sb, consts).clone();
1193                            let offset = entry.d;
1194                            let flag = entry.t0;
1195                            let typ = match &flag {
1196                                ValueType::FlagA => {
1197                                    let val = stack.read(entry.s1, sb, consts).copy_semantic(gcc);
1198                                    channel::SelectCommType::Send(val)
1199                                }
1200                                ValueType::FlagB | ValueType::FlagC | ValueType::FlagD => {
1201                                    channel::SelectCommType::Recv(flag, entry.s1)
1202                                }
1203                                _ => unreachable!(),
1204                            };
1205                            comms.push(channel::SelectComm { typ, chan, offset });
1206                        }
1207                        let selector = channel::Selector::new(comms, default_offset);
1208
1209                        drop(stack_mut_ref);
1210                        let re = selector.select().await;
1211                        restore_stack_ref!(self, stack, stack_mut_ref);
1212
1213                        match re {
1214                            Ok((i, val)) => {
1215                                let block_offset = if i >= selector.comms.len() {
1216                                    selector.default_offset.unwrap()
1217                                } else {
1218                                    let comm = &selector.comms[i];
1219                                    match comm.typ {
1220                                        channel::SelectCommType::Send(_) => {}
1221                                        channel::SelectCommType::Recv(flag, dst) => {
1222                                            let (unwrapped, ok) = unwrap_recv_val!(
1223                                                comm.chan.as_channel().as_ref().unwrap(),
1224                                                val,
1225                                                gcc
1226                                            );
1227                                            match flag {
1228                                                ValueType::FlagC => {
1229                                                    stack.set(dst + sb, unwrapped);
1230                                                }
1231                                                ValueType::FlagD => {
1232                                                    stack.set(dst + sb, unwrapped);
1233                                                    stack.set(dst + 1 + sb, ok.into());
1234                                                }
1235                                                _ => {}
1236                                            }
1237                                        }
1238                                    }
1239                                    comm.offset
1240                                };
1241                                // jump to the block
1242                                frame.pc += block_offset;
1243                            }
1244                            Err(e) => {
1245                                go_panic_str!(panic, e.as_str(), frame, code);
1246                            }
1247                        }
1248                    }
1249                    Opcode::RANGE_INIT => {
1250                        let target = stack.read(inst.s0, sb, consts);
1251                        let re = self.rstack.range_init(target, inst.t0, caller.get(inst.t1));
1252                        panic_if_err!(re, panic, frame, code);
1253                    }
1254                    Opcode::RANGE => {
1255                        if self.rstack.range_body(
1256                            inst.t0,
1257                            caller.get(inst.t1),
1258                            stack,
1259                            inst.d + sb,
1260                            inst.s1 + sb,
1261                        ) {
1262                            frame.pc += inst.s0;
1263                        }
1264                    }
1265                    // load user defined init function or jump 2 if failed
1266                    Opcode::LOAD_INIT_FUNC => {
1267                        let src = stack.read(inst.s0, sb, consts);
1268                        let index = *stack.read(inst.s1, sb, consts).as_int32();
1269                        let pkg = &objs.packages[*src.as_package()];
1270                        match pkg.init_func(index) {
1271                            Some(f) => {
1272                                stack.set(inst.d + sb, f.clone());
1273                                stack.set(inst.s1 + sb, (index + 1).into());
1274                            }
1275                            None => {
1276                                frame.pc += 2;
1277                            }
1278                        }
1279                    }
1280                    Opcode::BIND_METHOD => {
1281                        let recv = stack.read(inst.s0, sb, consts).copy_semantic(gcc);
1282                        let func = *stack.read(inst.s1, sb, consts).as_function();
1283                        stack.set(
1284                            inst.d + sb,
1285                            GosValue::new_closure(
1286                                ClosureObj::gos_from_func(func, &objs.functions, Some(recv)),
1287                                gcc,
1288                            ),
1289                        );
1290                    }
1291                    Opcode::BIND_I_METHOD => {
1292                        match stack.read(inst.s0, sb, consts).as_non_nil_interface() {
1293                            Ok(iface) => {
1294                                match bind_iface_method(iface, inst.s1 as usize, stack, objs, gcc) {
1295                                    Ok(cls) => stack.set(inst.d + sb, cls),
1296                                    Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
1297                                }
1298                            }
1299                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
1300                        }
1301                    }
1302                    Opcode::CAST => {
1303                        let from_type = inst.t1;
1304                        let to_type = inst.t0;
1305                        let val = match to_type {
1306                            ValueType::UintPtr => match from_type {
1307                                ValueType::UnsafePtr => {
1308                                    let up =
1309                                        stack.read(inst.s0, sb, consts).as_unsafe_ptr().cloned();
1310                                    GosValue::new_uint_ptr(
1311                                        up.map_or(0, |x| x.as_rust_ptr() as *const () as usize),
1312                                    )
1313                                }
1314                                _ => stack
1315                                    .read(inst.s0, sb, consts)
1316                                    .cast_copyable(from_type, to_type),
1317                            },
1318                            _ if to_type.copyable() => stack
1319                                .read(inst.s0, sb, consts)
1320                                .cast_copyable(from_type, to_type),
1321                            ValueType::Interface => {
1322                                let binding = ifaces[inst.s1 as usize].clone();
1323                                let under = stack.read(inst.s0, sb, consts).copy_semantic(gcc);
1324                                GosValue::new_interface(InterfaceObj::with_value(
1325                                    under,
1326                                    Some(binding),
1327                                ))
1328                            }
1329                            ValueType::String => match from_type {
1330                                ValueType::Slice => match inst.op1_as_t() {
1331                                    ValueType::Int32 => {
1332                                        let s = match stack
1333                                            .read(inst.s0, sb, consts)
1334                                            .as_slice::<Elem32>()
1335                                        {
1336                                            Some(slice) => slice
1337                                                .0
1338                                                .as_rust_slice()
1339                                                .iter()
1340                                                .map(|x| char_from_i32(x.cell.get() as i32))
1341                                                .collect(),
1342                                            None => "".to_owned(),
1343                                        };
1344                                        GosValue::with_str(&s)
1345                                    }
1346                                    ValueType::Uint8 => {
1347                                        match stack.read(inst.s0, sb, consts).as_slice::<Elem8>() {
1348                                            Some(slice) => GosValue::new_string(slice.0.clone()),
1349                                            None => GosValue::with_str(""),
1350                                        }
1351                                    }
1352                                    _ => unreachable!(),
1353                                },
1354                                _ => {
1355                                    let val = stack
1356                                        .read(inst.s0, sb, consts)
1357                                        .cast_copyable(from_type, ValueType::Uint32);
1358                                    GosValue::with_str(&char_from_u32(*val.as_uint32()).to_string())
1359                                }
1360                            },
1361                            ValueType::Slice => {
1362                                let from = stack.read(inst.s0, sb, consts).as_string();
1363                                match inst.op1_as_t() {
1364                                    ValueType::Int32 => {
1365                                        let data = from
1366                                            .as_str()
1367                                            .chars()
1368                                            .map(|x| (x as i32).into())
1369                                            .collect();
1370                                        GosValue::slice_with_data(
1371                                            data,
1372                                            caller.get(inst.op1_as_t()),
1373                                            gcc,
1374                                        )
1375                                    }
1376                                    ValueType::Uint8 => {
1377                                        GosValue::new_slice(from.clone(), ValueType::Uint8)
1378                                    }
1379                                    _ => unreachable!(),
1380                                }
1381                            }
1382                            ValueType::Pointer => match from_type {
1383                                ValueType::Pointer => stack.read(inst.s0, sb, consts).clone(),
1384                                ValueType::UnsafePtr => {
1385                                    match stack.read(inst.s0, sb, consts).as_unsafe_ptr() {
1386                                        Some(p) => {
1387                                            match p.ptr().as_any().downcast_ref::<PointerHandle>() {
1388                                                Some(h) => {
1389                                                    match h.ptr().cast(
1390                                                        inst.op1_as_t(),
1391                                                        &stack,
1392                                                        &objs.packages,
1393                                                    ) {
1394                                                        Ok(p) => GosValue::new_pointer(p),
1395                                                        Err(e) => {
1396                                                            go_panic_str!(
1397                                                                panic,
1398                                                                e.as_str(),
1399                                                                frame,
1400                                                                code
1401                                                            );
1402                                                            continue;
1403                                                        }
1404                                                    }
1405                                                }
1406                                                None => {
1407                                                    go_panic_str!(panic, "only a unsafe-pointer cast from a pointer can be cast back to a pointer", frame, code);
1408                                                    continue;
1409                                                }
1410                                            }
1411                                        }
1412                                        None => GosValue::new_nil(ValueType::Pointer),
1413                                    }
1414                                }
1415                                _ => unimplemented!(),
1416                            },
1417                            ValueType::UnsafePtr => match from_type {
1418                                ValueType::Pointer => {
1419                                    PointerHandle::new(stack.read(inst.s0, sb, consts))
1420                                }
1421                                _ => unimplemented!(),
1422                            },
1423                            _ => {
1424                                dbg!(to_type);
1425                                unimplemented!()
1426                            }
1427                        };
1428                        stack.set(inst.d + sb, val);
1429                    }
1430                    Opcode::TYPE_ASSERT => {
1431                        let val = stack.read(inst.s0, sb, consts);
1432                        match type_assert(val, cst(consts, inst.s1), gcc, &objs.metas) {
1433                            Ok((val, ok)) => {
1434                                stack.set(inst.d + sb, val);
1435                                if inst.t1 == ValueType::FlagB {
1436                                    let inst_ex = &code[frame.pc as usize];
1437                                    frame.pc += 1;
1438                                    stack.set(inst_ex.d + sb, ok.into());
1439                                }
1440                            }
1441                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
1442                        }
1443                    }
1444                    Opcode::TYPE => {
1445                        let iface_value = stack.read(inst.s0, sb, consts).clone();
1446                        if inst.t0 != ValueType::FlagA {
1447                            let meta = match iface_value.as_interface() {
1448                                Some(iface) => match &iface as &InterfaceObj {
1449                                    InterfaceObj::Gos(_, b) => b.as_ref().unwrap().0,
1450                                    _ => prim_meta.none,
1451                                },
1452                                _ => prim_meta.none,
1453                            };
1454                            stack.set(inst.d + sb, GosValue::new_metadata(meta));
1455                        } else {
1456                            let (val, meta) = match iface_value.as_interface() {
1457                                Some(iface) => match &iface as &InterfaceObj {
1458                                    InterfaceObj::Gos(v, b) => {
1459                                        (v.copy_semantic(gcc), b.as_ref().unwrap().0)
1460                                    }
1461                                    _ => (iface_value.clone(), prim_meta.none),
1462                                },
1463                                _ => (iface_value, prim_meta.none),
1464                            };
1465                            stack.set(inst.d + sb, GosValue::new_metadata(meta));
1466                            stack.set(inst.s1 + sb, val);
1467                        }
1468                    }
1469                    Opcode::IMPORT => {
1470                        let pkey = *stack.read(inst.s0, sb, consts).as_package();
1471                        if objs.packages[pkey].inited() {
1472                            frame.pc += inst.d
1473                        }
1474                    }
1475                    Opcode::SLICE => {
1476                        let inst_ex = &code[frame.pc as usize];
1477                        frame.pc += 1;
1478                        let s = stack.read(inst.s0, sb, consts);
1479                        let begin = *stack.read(inst.s1, sb, consts).as_int();
1480                        let end = *stack.read(inst_ex.s0, sb, consts).as_int();
1481                        let max = *stack.read(inst_ex.s1, sb, consts).as_int();
1482                        let result = match inst.t0 {
1483                            ValueType::Slice => s.caller(caller).slice_slice(s, begin, end, max),
1484                            ValueType::String => GosValue::slice_string(s, begin, end, max),
1485                            ValueType::Array => {
1486                                GosValue::slice_array(s.clone(), begin, end, caller.get(inst.t1))
1487                            }
1488                            _ => unreachable!(),
1489                        };
1490
1491                        match result {
1492                            Ok(v) => stack.set(inst.d + sb, v),
1493                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
1494                        }
1495                    }
1496                    Opcode::CLOSURE => {
1497                        let func = cst(consts, inst.s0);
1498                        let mut val =
1499                            ClosureObj::gos_from_func(*func.as_function(), &objs.functions, None);
1500                        match &mut val {
1501                            ClosureObj::Gos(gos) => {
1502                                if let Some(uvs) = &mut gos.uvs {
1503                                    // We used to need this to make the compiler happy:
1504                                    //drop(frame);
1505                                    for (_, uv) in uvs.iter_mut() {
1506                                        let r: &mut UpValueState = &mut uv.inner.borrow_mut();
1507                                        if let UpValueState::Open(d) = r {
1508                                            // get frame index, and add_referred_by
1509                                            for i in 1..frame_height {
1510                                                let index = frame_height - i;
1511                                                if self.frames[index].func() == d.func {
1512                                                    let upframe = &mut self.frames[index];
1513                                                    d.stack = Rc::downgrade(&self.stack);
1514                                                    d.stack_base = upframe.stack_base as OpIndex;
1515                                                    upframe.add_referred_by(d.index, d.typ, uv);
1516                                                    // if not found, the upvalue is already closed, nothing to be done
1517                                                    break;
1518                                                }
1519                                            }
1520                                        }
1521                                    }
1522                                    frame = self.frames.last_mut().unwrap();
1523                                }
1524                            }
1525                            _ => {}
1526                        };
1527                        stack.set(inst.d + sb, GosValue::new_closure(val, gcc));
1528                    }
1529                    Opcode::LITERAL => {
1530                        let inst_ex = &code[frame.pc as usize];
1531                        frame.pc += 1;
1532                        let md = cst(consts, inst_ex.s0).as_metadata();
1533
1534                        let begin = inst.s0 + sb;
1535                        let count = inst.s1;
1536                        let build_val = |m: &Meta| {
1537                            let zero_val = m.zero(&objs.metas, gcc);
1538                            let mut val = vec![];
1539                            let mut cur_index = -1;
1540                            for i in 0..count {
1541                                let index = *stack.get(begin + i * 2).as_int32();
1542                                let elem = stack.get(begin + 1 + i * 2).clone();
1543                                if index < 0 {
1544                                    cur_index += 1;
1545                                } else {
1546                                    cur_index = index;
1547                                }
1548                                let gap = cur_index - (val.len() as i32);
1549                                if gap == 0 {
1550                                    val.push(elem);
1551                                } else if gap > 0 {
1552                                    for _ in 0..gap {
1553                                        val.push(zero_val.clone());
1554                                    }
1555                                    val.push(elem);
1556                                } else {
1557                                    val[cur_index as usize] = elem;
1558                                }
1559                            }
1560                            (val, zero_val.typ())
1561                        };
1562                        let new_val = match &objs.metas[md.key] {
1563                            MetadataType::Slice(m) => {
1564                                let (val, typ) = build_val(m);
1565                                GosValue::slice_with_data(val, caller.get(typ), gcc)
1566                            }
1567                            MetadataType::Array(m, _) => {
1568                                let (val, typ) = build_val(m);
1569                                GosValue::array_with_data(val, caller.get(typ), gcc)
1570                            }
1571                            MetadataType::Map(_, _) => {
1572                                let map_val = GosValue::new_map(gcc);
1573                                let map = map_val.as_map().unwrap();
1574                                for i in 0..count {
1575                                    let k = stack.get(begin + i * 2).clone();
1576                                    let v = stack.get(begin + 1 + i * 2).clone();
1577                                    map.0.insert(k, v);
1578                                }
1579                                map_val
1580                            }
1581                            MetadataType::Struct(_) => {
1582                                let struct_val = md.zero(&objs.metas, gcc);
1583                                {
1584                                    let fields = &mut struct_val.as_struct().0.borrow_fields_mut();
1585                                    for i in 0..count {
1586                                        let index = *stack.get(begin + i * 2).as_uint();
1587                                        fields[index] = stack.get(begin + 1 + i * 2).clone();
1588                                    }
1589                                }
1590                                struct_val
1591                            }
1592                            _ => unreachable!(),
1593                        };
1594                        stack.set(inst.d + sb, new_val);
1595                    }
1596                    Opcode::NEW => {
1597                        let md = stack.read(inst.s0, sb, consts).as_metadata();
1598                        let v = md.into_value_category().zero(&objs.metas, gcc);
1599                        let p = GosValue::new_pointer(PointerObj::UpVal(UpValue::new_closed(v)));
1600                        stack.set(inst.d + sb, p);
1601                    }
1602                    Opcode::MAKE => {
1603                        let md = stack.read(inst.s0, sb, consts).as_metadata();
1604                        let val = match md.mtype_unwraped(&objs.metas) {
1605                            MetadataType::Slice(vmeta) => {
1606                                let (cap, len) = match inst.t0 {
1607                                    // 3 args
1608                                    ValueType::FlagC => {
1609                                        let inst_ex = &code[frame.pc as usize];
1610                                        frame.pc += 1;
1611                                        (
1612                                            *stack.read(inst.s1, sb, consts).as_int() as usize,
1613                                            *stack.read(inst_ex.s0, sb, consts).as_int() as usize,
1614                                        )
1615                                    }
1616                                    // 2 args
1617                                    ValueType::FlagB => {
1618                                        let len =
1619                                            *stack.read(inst.s1, sb, consts).as_int() as usize;
1620                                        (len, len)
1621                                    }
1622                                    _ => unreachable!(),
1623                                };
1624                                let zero = vmeta.zero(&objs.metas, gcc);
1625                                GosValue::slice_with_size(
1626                                    len,
1627                                    cap,
1628                                    &zero,
1629                                    caller.get(zero.typ()),
1630                                    gcc,
1631                                )
1632                            }
1633                            MetadataType::Map(_, _) => GosValue::new_map(gcc),
1634                            #[cfg(not(feature = "async"))]
1635                            MetadataType::Channel(_, _) => {
1636                                go_panic_no_async!(panic, frame, code);
1637                                GosValue::new_nil(ValueType::Void)
1638                            }
1639                            #[cfg(feature = "async")]
1640                            MetadataType::Channel(_, val_meta) => {
1641                                let cap = match inst.t0 {
1642                                    // 2 args
1643                                    ValueType::FlagB => {
1644                                        *stack.read(inst.s1, sb, consts).as_int() as usize
1645                                    }
1646                                    // 1 arg
1647                                    ValueType::FlagA => 0,
1648                                    _ => unreachable!(),
1649                                };
1650                                let zero = val_meta.zero(&objs.metas, gcc);
1651                                GosValue::new_channel(ChannelObj::new(cap, zero))
1652                            }
1653                            _ => unreachable!(),
1654                        };
1655                        stack.set(inst.d + sb, val);
1656                    }
1657                    Opcode::COMPLEX => {
1658                        // for the specs: For complex, the two arguments must be of the same
1659                        // floating-point type and the return type is the complex type with
1660                        // the corresponding floating-point constituents
1661                        let val = match inst.t0 {
1662                            ValueType::Float32 => {
1663                                let r = *stack.read(inst.s0, sb, consts).as_float32();
1664                                let i = *stack.read(inst.s1, sb, consts).as_float32();
1665                                GosValue::new_complex64(r, i)
1666                            }
1667                            ValueType::Float64 => {
1668                                let r = *stack.read(inst.s0, sb, consts).as_float64();
1669                                let i = *stack.read(inst.s1, sb, consts).as_float64();
1670                                GosValue::new_complex128(r, i)
1671                            }
1672                            _ => unreachable!(),
1673                        };
1674                        stack.set(inst.d + sb, val);
1675                    }
1676                    Opcode::REAL => {
1677                        let complex = stack.read(inst.s0, sb, consts);
1678                        let val = match inst.t0 {
1679                            ValueType::Complex64 => GosValue::new_float32(complex.as_complex64().r),
1680                            ValueType::Complex128 => {
1681                                GosValue::new_float64(complex.as_complex128().r)
1682                            }
1683                            _ => unreachable!(),
1684                        };
1685                        stack.set(inst.d + sb, val);
1686                    }
1687                    Opcode::IMAG => {
1688                        let complex = stack.read(inst.s0, sb, consts);
1689                        let val = match inst.t0 {
1690                            ValueType::Complex64 => GosValue::new_float32(complex.as_complex64().i),
1691                            ValueType::Complex128 => {
1692                                GosValue::new_float64(complex.as_complex128().i)
1693                            }
1694                            _ => unreachable!(),
1695                        };
1696                        stack.set(inst.d + sb, val);
1697                    }
1698                    Opcode::LEN => {
1699                        let l = stack.read(inst.s0, sb, consts).len();
1700                        stack.set(inst.d + sb, (l as isize).into());
1701                    }
1702                    Opcode::CAP => {
1703                        let l = stack.read(inst.s0, sb, consts).cap();
1704                        stack.set(inst.d + sb, (l as isize).into());
1705                    }
1706                    Opcode::APPEND => {
1707                        let a = stack.read(inst.s0, sb, consts).clone();
1708                        let b = if inst.t0 != ValueType::String {
1709                            stack.read(inst.s1, sb, consts).clone()
1710                        } else {
1711                            // special case, appending string as bytes
1712                            let s = stack.read(inst.s1, sb, consts).as_string();
1713                            let arr = GosValue::new_non_gc_array(
1714                                ArrayObj::with_raw_data(s.as_rust_slice().to_vec()),
1715                                ValueType::Uint8,
1716                            );
1717                            GosValue::slice_array(arr, 0, -1, caller.get(ValueType::Uint8)).unwrap()
1718                        };
1719
1720                        match caller.get(inst.t1).slice_append(a, b, gcc) {
1721                            Ok(slice) => stack.set(inst.d + sb, slice),
1722                            Err(e) => go_panic_str!(panic, e.as_str(), frame, code),
1723                        };
1724                    }
1725                    Opcode::COPY => {
1726                        let a = stack.read(inst.s0, sb, consts).clone();
1727                        let b = stack.read(inst.s1, sb, consts).clone();
1728                        let count = match inst.t0 {
1729                            ValueType::String => {
1730                                let string = b.as_string();
1731                                match a.as_slice::<Elem8>() {
1732                                    Some(s) => s.0.copy_from(&string),
1733                                    None => 0,
1734                                }
1735                            }
1736                            _ => caller.get(inst.t1).slice_copy_from(a, b),
1737                        };
1738                        stack.set(inst.d + sb, (count as isize).into());
1739                    }
1740                    Opcode::DELETE => {
1741                        let map = stack.read(inst.s0, sb, consts);
1742                        let key = stack.read(inst.s1, sb, consts);
1743                        match map.as_map() {
1744                            Some(m) => m.0.delete(key),
1745                            None => {}
1746                        }
1747                    }
1748                    #[cfg(not(feature = "async"))]
1749                    Opcode::CLOSE => go_panic_no_async!(panic, frame, code),
1750                    #[cfg(feature = "async")]
1751                    Opcode::CLOSE => match stack.read(inst.s0, sb, consts).as_channel() {
1752                        Some(c) => c.close(),
1753                        None => {}
1754                    },
1755                    Opcode::PANIC => {
1756                        let val = stack.read(inst.s0, sb, consts).clone();
1757                        go_panic!(panic, val, frame, code);
1758                    }
1759                    Opcode::RECOVER => {
1760                        let p = panic.take();
1761                        let val = p.map_or(GosValue::new_nil(ValueType::Void), |x| {
1762                            GosValue::new_interface(InterfaceObj::with_value(x.msg, None))
1763                        });
1764                        stack.set(inst.d + sb, val);
1765                    }
1766                    Opcode::ASSERT => {
1767                        let ok = *stack.read(inst.s0, sb, consts).as_bool();
1768                        if !ok {
1769                            go_panic_str!(panic, "Opcode::ASSERT: not true!", frame, code);
1770                        }
1771                    }
1772                    Opcode::FFI => {
1773                        let val = {
1774                            let itype = stack.read(inst.s0, sb, consts);
1775                            let name = stack.read(inst.s1, sb, consts);
1776                            let name_str = name.as_string().as_str();
1777                            match self.context.ffi_factory.create(&name_str) {
1778                                Ok(v) => {
1779                                    let meta = itype.as_metadata().underlying(&objs.metas).clone();
1780                                    GosValue::new_interface(InterfaceObj::Ffi(UnderlyingFfi::new(
1781                                        v, meta,
1782                                    )))
1783                                }
1784                                Err(e) => {
1785                                    go_panic_str!(panic, e.as_str(), frame, code);
1786                                    continue;
1787                                }
1788                            }
1789                        };
1790                        stack.set(inst.d + sb, val);
1791                    }
1792                    Opcode::VOID => unreachable!(),
1793                }
1794            } //yield unit
1795            match result {
1796                Result::End => {
1797                    *ctx.panic_data.borrow_mut() = panic.take();
1798                    break;
1799                }
1800                Result::Continue => {
1801                    drop(stack_mut_ref);
1802                    #[cfg(feature = "async")]
1803                    future::yield_now().await;
1804                    restore_stack_ref!(self, stack, stack_mut_ref);
1805                }
1806            };
1807        } //loop
1808
1809        collect(gcc);
1810    }
1811}
1812
1813#[inline]
1814fn char_from_u32(u: u32) -> char {
1815    unsafe { char::from_u32_unchecked(u) }
1816}
1817
1818#[inline]
1819fn char_from_i32(i: i32) -> char {
1820    unsafe { char::from_u32_unchecked(i as u32) }
1821}
1822
1823#[inline]
1824fn deref_value(v: &GosValue, stack: &Stack, objs: &VMObjects) -> RuntimeResult<GosValue> {
1825    v.as_non_nil_pointer()?.deref(stack, &objs.packages)
1826}
1827
1828#[inline(always)]
1829fn cst(consts: &Vec<GosValue>, i: OpIndex) -> &GosValue {
1830    &consts[(-i - 1) as usize]
1831}
1832
1833#[inline]
1834fn type_assert(
1835    val: &GosValue,
1836    want_meta: &GosValue,
1837    gcc: &GcContainer,
1838    metas: &MetadataObjs,
1839) -> RuntimeResult<(GosValue, bool)> {
1840    let want_meta = want_meta.as_metadata();
1841    match val.as_interface() {
1842        Some(iface) => match &iface as &InterfaceObj {
1843            InterfaceObj::Gos(v, mb) => match mb {
1844                Some((meta, _)) => {
1845                    if want_meta.identical(meta, metas) {
1846                        Ok((v.copy_semantic(gcc), true))
1847                    } else {
1848                        Ok((want_meta.zero(metas, gcc), false))
1849                    }
1850                }
1851                None => Err("No type info available for interface value"
1852                    .to_owned()
1853                    .into()),
1854            },
1855            InterfaceObj::Ffi(_) => Err("FFI interface do not support type assertion"
1856                .to_owned()
1857                .into()),
1858        },
1859        None => Ok((want_meta.zero(metas, gcc), false)),
1860    }
1861}
1862
1863#[inline(always)]
1864fn get_struct_and_index(
1865    val: GosValue,
1866    indices: &Vec<OpIndex>,
1867    stack: &mut Stack,
1868    objs: &VMObjects,
1869) -> (RuntimeResult<GosValue>, usize) {
1870    let (target, index) = {
1871        let val = get_embeded(val, &indices[..indices.len() - 1], stack, &objs.packages);
1872        (val, *indices.last().unwrap())
1873    };
1874    (
1875        match target {
1876            Ok(v) => match v.typ() {
1877                ValueType::Pointer => deref_value(&v, stack, objs),
1878                _ => Ok(v.clone()),
1879            },
1880            Err(e) => Err(e),
1881        },
1882        index as usize,
1883    )
1884}
1885
1886#[inline]
1887fn get_embeded(
1888    val: GosValue,
1889    indices: &[OpIndex],
1890    stack: &Stack,
1891    pkgs: &PackageObjs,
1892) -> RuntimeResult<GosValue> {
1893    let typ = val.typ();
1894    let mut cur_val: GosValue = val;
1895    if typ == ValueType::Pointer {
1896        cur_val = cur_val.as_non_nil_pointer()?.deref(stack, pkgs)?;
1897    }
1898    for &i in indices.iter() {
1899        let s = &cur_val.as_struct().0;
1900        let v = s.borrow_fields()[i as usize].clone();
1901        cur_val = v;
1902    }
1903    Ok(cur_val)
1904}
1905
1906#[inline]
1907fn cast_receiver(
1908    receiver: GosValue,
1909    b1: bool,
1910    stack: &Stack,
1911    objs: &VMObjects,
1912) -> RuntimeResult<GosValue> {
1913    let b0 = receiver.typ() == ValueType::Pointer;
1914    if b0 == b1 {
1915        Ok(receiver)
1916    } else if b1 {
1917        Ok(GosValue::new_pointer(PointerObj::UpVal(
1918            UpValue::new_closed(receiver.clone()),
1919        )))
1920    } else {
1921        deref_value(&receiver, stack, objs)
1922    }
1923}
1924
1925#[inline]
1926fn bind_iface_method(
1927    iface: &InterfaceObj,
1928    index: usize,
1929    stack: &Stack,
1930    objs: &VMObjects,
1931    gcc: &GcContainer,
1932) -> RuntimeResult<GosValue> {
1933    match iface {
1934        InterfaceObj::Gos(obj, b) => {
1935            let binding = &b.as_ref().unwrap().1[index];
1936            match binding {
1937                Binding4Runtime::Struct(func, ptr_recv, indices) => {
1938                    let obj = match indices {
1939                        None => obj.copy_semantic(gcc),
1940                        Some(inds) => get_embeded(obj.clone(), inds, stack, &objs.packages)?
1941                            .copy_semantic(gcc),
1942                    };
1943                    let obj = cast_receiver(obj, *ptr_recv, stack, objs)?;
1944                    let cls = ClosureObj::gos_from_func(*func, &objs.functions, Some(obj));
1945                    Ok(GosValue::new_closure(cls, gcc))
1946                }
1947                Binding4Runtime::Iface(i, indices) => {
1948                    let bind = |obj: &GosValue| {
1949                        bind_iface_method(&obj.as_interface().unwrap(), *i, stack, objs, gcc)
1950                    };
1951                    match indices {
1952                        None => bind(&obj),
1953                        Some(inds) => bind(&get_embeded(obj.clone(), inds, stack, &objs.packages)?),
1954                    }
1955                }
1956            }
1957        }
1958        InterfaceObj::Ffi(ffi) => {
1959            let method = &objs.metas[ffi.meta.key].as_interface().infos()[index];
1960            let (func_name, meta) = (method.name.clone(), method.meta);
1961            let cls = FfiClosureObj {
1962                ffi: ffi.ffi_obj.clone(),
1963                is_async: func_name.starts_with("async"),
1964                func_name,
1965                meta,
1966            };
1967            Ok(GosValue::new_closure(ClosureObj::new_ffi(cls), gcc))
1968        }
1969    }
1970}