goscript_vm/
instruction.rs

1#![allow(dead_code)]
2#![allow(non_camel_case_types)]
3use std::fmt;
4
5pub type OpIndex = i32;
6
7#[repr(u8)]
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub enum Opcode {
10    ZERO = 0, //place holder
11    // push pop load store
12    PUSH_CONST,
13    PUSH_NIL,
14    PUSH_FALSE,
15    PUSH_TRUE,
16    PUSH_IMM,
17    POP,
18    LOAD_LOCAL,
19    STORE_LOCAL, // stores the value on the top of the stack to local
20    LOAD_UPVALUE,
21    STORE_UPVALUE,
22    LOAD_INDEX,
23    STORE_INDEX,
24    LOAD_INDEX_IMM,
25    STORE_INDEX_IMM,
26    LOAD_STRUCT_FIELD,
27    STORE_STRUCT_FIELD,
28    LOAD_PKG_FIELD,
29    STORE_PKG_FIELD,
30    LOAD_FIELD,
31    STORE_FIELD,
32    STORE_DEREF,
33    BIND_METHOD,
34    BIND_INTERFACE_METHOD,
35    CAST,
36    // arithmetic, logical, ref, deref, arrow
37    ADD,       // +
38    SUB,       // -
39    MUL,       // *
40    QUO,       // /
41    REM,       // %
42    AND,       // &
43    OR,        // |
44    XOR,       // ^
45    SHL,       // <<
46    SHR,       // >>
47    AND_NOT,   // $^
48    UNARY_ADD, // +
49    UNARY_SUB, // -
50    UNARY_XOR, // ^
51    //REF,       // &
52    REF_LOCAL,
53    REF_UPVALUE,
54    REF_SLICE_MEMBER,
55    REF_STRUCT_FIELD,
56    REF_PKG_MEMBER,
57    REF_LITERAL,
58    DEREF, // *
59    SEND,  // <-
60    RECV,  // <-
61    NOT,   // !
62    EQL,   // ==
63    LSS,   // <
64    GTR,   // >
65    NEQ,   // !=
66    LEQ,   // <=
67    GEQ,   // >=
68
69    // call
70    PRE_CALL,
71    CALL,
72    RETURN,
73
74    // jump
75    JUMP,
76    JUMP_IF,
77    JUMP_IF_NOT,
78    SWITCH, // EQL + JUMP_IF + do not pop the first argument
79    SELECT,
80    LOOP,
81    RANGE_INIT,
82    RANGE, // for ... range statement
83
84    // type
85    TYPE_ASSERT,
86    TYPE,
87
88    // built-in functinalities
89    IMPORT,     // imports a package
90    SLICE,      // for slice expressions
91    SLICE_FULL, // for full slice expressions
92    LITERAL,    // for function literal or composite literal
93    NEW,        // for built-in function new
94    MAKE,       // for built-in function make
95    LEN,        // for built-in function len
96    CAP,        // for built-in function cap
97    APPEND,     // for built-in function append
98    CLOSE,      // for built-in function close
99    PANIC,      // for built-in function panic
100    RECOVER,    // for built-in function recover
101    ASSERT,     // for built-in function assert
102    FFI,        // for built-in function native
103}
104
105impl Opcode {
106    #[inline]
107    pub fn offset(&self, base: Opcode) -> OpIndex {
108        (*self as i16 - base as i16) as OpIndex
109    }
110
111    pub fn property(&self) -> (&str, i8) {
112        match self {
113            Opcode::ZERO => ("ZERO (place holder)", 0),
114            Opcode::PUSH_CONST => ("PUSH_CONST", 1),
115            Opcode::PUSH_NIL => ("PUSH_NIL", 1),
116            Opcode::PUSH_FALSE => ("PUSH_FALSE", 1),
117            Opcode::PUSH_TRUE => ("PUSH_TRUE", 1),
118            Opcode::PUSH_IMM => ("PUSH_IMM", 1),
119            Opcode::POP => ("POP", -1),
120            Opcode::LOAD_LOCAL => ("LOAD_LOCAL", 1),
121            Opcode::STORE_LOCAL => ("STORE_LOCAL", 0),
122            Opcode::LOAD_UPVALUE => ("LOAD_LOCAL", 1),
123            Opcode::STORE_UPVALUE => ("STORE_UPVALUE", 0),
124            Opcode::LOAD_INDEX => ("LOAD_INDEX", -1),
125            Opcode::STORE_INDEX => ("STORE_INDEX", 0),
126            Opcode::LOAD_INDEX_IMM => ("LOAD_INDEX_IMM", 0),
127            Opcode::STORE_INDEX_IMM => ("STORE_INDEX_IMM", 0),
128            Opcode::LOAD_STRUCT_FIELD => ("LOAD_STRUCT_FIELD", 0),
129            Opcode::STORE_STRUCT_FIELD => ("STORE_STRUCT_FIELD", 0),
130            Opcode::LOAD_PKG_FIELD => ("LOAD_PKG_FIELD", 1),
131            Opcode::STORE_PKG_FIELD => ("STORE_PKG_FIELD", 0),
132            Opcode::LOAD_FIELD => ("LOAD_FIELD", -1),
133            Opcode::STORE_FIELD => ("STORE_FIELD", 0),
134            Opcode::STORE_DEREF => ("STORE_DEREF", 0),
135            Opcode::BIND_METHOD => ("BIND_METHOD", 0),
136            Opcode::BIND_INTERFACE_METHOD => ("BIND_INTERFACE_METHOD", 0),
137            Opcode::CAST => ("CAST", 0),
138
139            Opcode::ADD => ("ADD", -1),
140            Opcode::SUB => ("SUB", -1),
141            Opcode::MUL => ("MUL", -1),
142            Opcode::QUO => ("QUO", -1),
143            Opcode::REM => ("REM", -1),
144            Opcode::AND => ("AND", -1),
145            Opcode::OR => ("OR", -1),
146            Opcode::XOR => ("XOR", -1),
147            Opcode::SHL => ("SHL", -1),
148            Opcode::SHR => ("SHR", -1),
149            Opcode::AND_NOT => ("AND_NOT", -1),
150            Opcode::UNARY_ADD => ("UNARY_ADD", 0),
151            Opcode::UNARY_SUB => ("UNARY_SUB", 0),
152            Opcode::UNARY_XOR => ("UNARY_XOR", 0),
153            Opcode::REF_LOCAL => ("REF_LOCAL", 0),
154            Opcode::REF_UPVALUE => ("REF_UPVALUE", 0),
155            Opcode::REF_SLICE_MEMBER => ("REF_SLICE_MEMBER", 0),
156            Opcode::REF_STRUCT_FIELD => ("REF_STRUCT_FIELD", 0),
157            Opcode::REF_PKG_MEMBER => ("REF_PKG_MEMBER", 0),
158            Opcode::REF_LITERAL => ("REF_LITERAL", 0),
159            Opcode::DEREF => ("DEREF", 0),
160            Opcode::SEND => ("SEND", -1),
161            Opcode::RECV => ("RECV", 1),
162            Opcode::NOT => ("LNOT", 0),
163            Opcode::EQL => ("EQL", -1),
164            Opcode::LSS => ("LSS", -1),
165            Opcode::GTR => ("GTR", -1),
166            Opcode::NEQ => ("NEQ", -1),
167            Opcode::LEQ => ("LEQ", -1),
168            Opcode::GEQ => ("GEQ", -1),
169
170            Opcode::PRE_CALL => ("PRE_CALL", -128),
171            Opcode::CALL => ("CALL", -128),
172            Opcode::RETURN => ("RETURN", -128),
173
174            Opcode::JUMP => ("JUMP", 0),
175            Opcode::LOOP => ("LOOP", 0),
176            Opcode::JUMP_IF => ("JUMP_IF", -1),
177            Opcode::JUMP_IF_NOT => ("JUMP_IF_NOT", -1),
178            Opcode::SWITCH => ("SWITCH", -1),
179            Opcode::SELECT => ("SELECT", -128),
180            Opcode::RANGE_INIT => ("RANGE_INIT", 0),
181            Opcode::RANGE => ("RANGE", 1),
182
183            Opcode::TYPE_ASSERT => ("TYPE_ASSERT", 0),
184            Opcode::TYPE => ("TYPE", 1),
185
186            Opcode::IMPORT => ("IMPORT", 0),
187            Opcode::SLICE => ("SLICE", -2),
188            Opcode::SLICE_FULL => ("SLICE_FULL", -3),
189            Opcode::LITERAL => ("LITERAL", 0),
190            Opcode::NEW => ("NEW", 0),
191            Opcode::MAKE => ("MAKE", 0),
192            Opcode::LEN => ("LEN", 0),
193            Opcode::CAP => ("CAP", 0),
194            Opcode::APPEND => ("APPEND", -128),
195            Opcode::CLOSE => ("CLOSE", -1),
196            Opcode::PANIC => ("PANIC", -1),
197            Opcode::RECOVER => ("RECOVER", 1),
198            Opcode::ASSERT => ("ASSERT", 0),
199            Opcode::FFI => ("FFI", 0),
200        }
201    }
202
203    pub fn text(&self) -> &str {
204        let (t, _) = self.property();
205        t
206    }
207}
208
209impl fmt::Display for Opcode {
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        let (t, _) = self.property();
212        write!(f, "OPCODE: {}", t)
213    }
214}
215
216pub const COPYABLE_END: ValueType = ValueType::Package;
217
218#[derive(Copy, Clone, Eq, PartialEq, Debug, Ord, PartialOrd)]
219#[repr(u8)]
220pub enum ValueType {
221    Zero, //place holder
222    Bool = 1,
223    Int,
224    Int8,
225    Int16,
226    Int32,
227    Int64,
228    Uint,
229    Uint8,
230    Uint16,
231    Uint32,
232    Uint64,
233    Float32,
234    Float64,
235    Complex64,
236    Function,
237    Package,
238    Metadata,
239
240    // Nil is a virtual type representing zero value for pointer, interfaces,
241    // maps, slices, channels and function types
242    Nil,
243    Pointer,
244    Closure,
245    Slice,
246    Map,
247    Interface,
248    Channel,
249
250    Complex128,
251    Str,
252    Array,
253    Struct,
254
255    Named,
256
257    FfiClosure,
258
259    FlagA, //not a type, works as a flag in instructions
260    FlagB,
261    FlagC,
262    FlagD,
263    FlagE,
264}
265
266impl ValueType {
267    #[inline]
268    pub fn copyable(&self) -> bool {
269        self <= &COPYABLE_END
270    }
271}
272
273/// Instruction is 64 bit
274/// |    8bit   |    8bit   |    8bit   |    8bit   |    32bit     |
275/// |  Opcode   |  <TypeA>  |  <TypeB>  |  <TypeC>  |   immediate  |
276/// or
277/// |    8bit   |    8bit   |    8bit   |    8bit   |    8bit      |    24bit     |
278/// |  Opcode   |  <TypeA>  |  <TypeB>  |  <TypeC>  |     ext      |   immediate  |
279/// or
280/// |    8bit   |    8bit   |    8bit   |    8bit   |    8bit      |    24bit     |
281/// |  Opcode   |  <TypeA>  |  <TypeB>  |    ext    |     ext      |   immediate  |
282/// or
283/// | package_key|
284#[derive(Clone, Copy)]
285pub struct Instruction {
286    val: u64,
287}
288
289impl Instruction {
290    pub fn new(
291        op: Opcode,
292        type0: Option<ValueType>,
293        type1: Option<ValueType>,
294        type2: Option<ValueType>,
295        imm: Option<OpIndex>,
296    ) -> Instruction {
297        let val = (op as u64) << (8 * 3 + 32);
298        let mut inst = Instruction { val: val };
299        if let Some(v) = type0 {
300            inst.val |= (v as u64) << (8 * 2 + 32);
301        }
302        if let Some(v) = type1 {
303            inst.val |= (v as u64) << (8 + 32);
304        }
305        if let Some(v) = type2 {
306            inst.val |= (v as u64) << 32;
307        }
308        if let Some(v) = imm {
309            inst.set_imm(v);
310        }
311        inst
312    }
313
314    #[inline]
315    pub fn from_u64(v: u64) -> Instruction {
316        Instruction { val: v }
317    }
318
319    #[inline]
320    pub fn set_imm(&mut self, imm: OpIndex) {
321        let uv: u32 = unsafe { std::mem::transmute(imm) };
322        self.val = (self.val & 0xffff_ffff_0000_0000) | uv as u64;
323    }
324
325    /// set_imm824 sets an 8bit imm and a 24bit imm at the lower 4 bytes
326    #[inline]
327    pub fn set_imm824(&mut self, imm0: OpIndex, imm1: OpIndex) {
328        assert!(Instruction::in_8bit_range(imm0));
329        assert!(Instruction::in_24bit_range(imm1));
330        let u0: u8 = unsafe { std::mem::transmute(imm0 as i8) };
331        let u0 = (u0 as u32) << 24;
332        let u1: u32 = unsafe { std::mem::transmute(imm1) };
333        let u1 = u1 & 0x00ff_ffff;
334        self.val = (self.val & 0xffff_ffff_0000_0000) | (u0 | u1) as u64;
335    }
336
337    /// set_t2_with_index tries to set an OpIndex to the space of t2
338    /// returns error if it's out of range
339    /// used by STORE_INDEX_IMM, STORE_STRUCT_FIELD
340    #[inline]
341    pub fn set_t2_with_index(&mut self, index: i8) {
342        let val8: u8 = unsafe { std::mem::transmute(index) };
343        let val64 = (val8 as u64) << 32;
344        self.val = (self.val & 0xffff_ff00_ffff_ffff) | val64;
345    }
346
347    #[inline]
348    pub fn get_u64(&self) -> u64 {
349        self.val
350    }
351
352    #[inline]
353    pub fn op(&self) -> Opcode {
354        unsafe { std::mem::transmute((self.val >> (8 * 3 + 32)) as u8) }
355    }
356
357    #[inline]
358    pub fn t0(&self) -> ValueType {
359        let v = ((self.val >> (8 * 2 + 32)) as u16) & 0xff;
360        unsafe { std::mem::transmute(v as u8) }
361    }
362
363    #[inline]
364    pub fn t1(&self) -> ValueType {
365        let v = ((self.val >> (8 + 32)) as u32) & 0xff;
366        unsafe { std::mem::transmute(v as u8) }
367    }
368
369    #[inline]
370    pub fn t2(&self) -> ValueType {
371        let v = ((self.val >> 32) as u32) & 0xff;
372        unsafe { std::mem::transmute(v as u8) }
373    }
374
375    #[inline]
376    pub fn t2_as_index(&self) -> OpIndex {
377        let v = ((self.val & 0x0000_00ff_0000_0000) >> 32) as u8;
378        let ival: i8 = unsafe { std::mem::transmute(v) };
379        ival as OpIndex
380    }
381
382    #[inline]
383    pub fn imm(&self) -> OpIndex {
384        unsafe { std::mem::transmute((self.val & 0xffff_ffff) as u32) }
385    }
386
387    #[inline]
388    pub fn imm824(&self) -> (OpIndex, OpIndex) {
389        let all = (self.val & 0xffff_ffff) as u32;
390        let i0: i8 = unsafe { std::mem::transmute((all >> 24) as u8) };
391        let all = all & 0x00ff_ffff;
392        let sign = all >> 23;
393        let all = ((sign * 0xff) << 24) | all;
394        let i1 = unsafe { std::mem::transmute(all) };
395        (i0 as OpIndex, i1)
396    }
397
398    #[inline]
399    pub fn code2index(op: Opcode) -> OpIndex {
400        op as OpIndex
401    }
402
403    #[inline]
404    pub fn index2code(i: OpIndex) -> Opcode {
405        unsafe { std::mem::transmute(i as u8) }
406    }
407
408    #[inline]
409    pub fn in_8bit_range(i: OpIndex) -> bool {
410        -(1 << 7) <= i && i < (1 << 7)
411    }
412
413    #[inline]
414    pub fn in_24bit_range(i: OpIndex) -> bool {
415        -(1 << 23) <= i && i < (1 << 23)
416    }
417}
418
419impl fmt::Debug for Instruction {
420    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421        let op = self.op();
422        match op {
423            Opcode::STORE_LOCAL
424            | Opcode::STORE_UPVALUE
425            | Opcode::STORE_FIELD
426            | Opcode::STORE_STRUCT_FIELD
427            | Opcode::STORE_PKG_FIELD
428            | Opcode::STORE_DEREF => {
429                let (i0, i1) = self.imm824();
430                if i0 < 0 {
431                    write!(f, "{}, IMM0: {}, IMM1: {}", op, i0, i1)
432                } else {
433                    let op_ex = Instruction::index2code(i0);
434                    write!(f, "{}, EX: {}, IMM0: {}, IMM1: {}", op, op_ex, i0, i1)
435                }
436            }
437            _ => {
438                let imm = self.imm();
439                write!(f, "{}, IMM: {}", op, imm)
440            }
441        }
442    }
443}
444
445#[cfg(test)]
446mod test {
447    use super::*;
448
449    #[test]
450    fn test_opcode() {
451        println!("opcode {} \n", Opcode::POP);
452    }
453
454    #[test]
455    fn test_instruction() {
456        let mut i = Instruction::new(
457            Opcode::ADD,
458            Some(ValueType::Str),
459            Some(ValueType::Closure),
460            Some(ValueType::Int),
461            Some(-99),
462        );
463        assert_eq!(i.op(), Opcode::ADD);
464        assert_eq!(i.t0(), ValueType::Str);
465        assert_eq!(i.t1(), ValueType::Closure);
466        assert_eq!(i.t2(), ValueType::Int);
467        assert_eq!(i.imm(), -99);
468
469        dbg!(1 << 8);
470        i.set_imm824(-128, -(1 << 23));
471        assert_eq!(i.imm824().0, -128);
472        assert_eq!(i.imm824().1, -(1 << 23));
473        i.set_imm824(127, 1 << 23 - 1);
474        assert_eq!(i.imm824().0, 127);
475        assert_eq!(i.imm824().1, 1 << 23 - 1);
476
477        assert!(!Instruction::in_8bit_range(128));
478        i.set_t2_with_index(-128);
479        assert_eq!(i.t2_as_index(), -128);
480        let _ = i.set_t2_with_index(90);
481        assert_eq!(i.t2_as_index(), 90);
482        assert_eq!(i.t0(), ValueType::Str);
483        assert_eq!(i.t1(), ValueType::Closure);
484        assert_ne!(i.t2(), ValueType::Int);
485        assert_eq!(i.imm824().0, 127);
486        assert_eq!(i.imm824().1, 1 << 23 - 1);
487    }
488}