/* * Copyright 2021 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ir import ( "fmt" "reflect" "strconv" "strings" "unsafe" "github.com/bytedance/sonic/internal/encoder/vars" "github.com/bytedance/sonic/internal/rt" ) type Op uint8 const ( OP_null Op = iota + 1 OP_empty_arr OP_empty_obj OP_bool OP_i8 OP_i16 OP_i32 OP_i64 OP_u8 OP_u16 OP_u32 OP_u64 OP_f32 OP_f64 OP_str OP_bin OP_quote OP_number OP_eface OP_iface OP_byte OP_text OP_deref OP_index OP_load OP_save OP_drop OP_drop_2 OP_recurse OP_is_nil OP_is_nil_p1 OP_is_zero_1 OP_is_zero_2 OP_is_zero_4 OP_is_zero_8 OP_is_zero_map OP_goto OP_map_iter OP_map_stop OP_map_check_key OP_map_write_key OP_map_value_next OP_slice_len OP_slice_next OP_marshal OP_marshal_p OP_marshal_text OP_marshal_text_p OP_cond_set OP_cond_testc ) const ( _INT_SIZE = 32 << (^uint(0) >> 63) _PTR_SIZE = 32 << (^uintptr(0) >> 63) _PTR_BYTE = unsafe.Sizeof(uintptr(0)) ) const OpSize = unsafe.Sizeof(NewInsOp(0)) var OpNames = [256]string{ OP_null: "null", OP_empty_arr: "empty_arr", OP_empty_obj: "empty_obj", OP_bool: "bool", OP_i8: "i8", OP_i16: "i16", OP_i32: "i32", OP_i64: "i64", OP_u8: "u8", OP_u16: "u16", OP_u32: "u32", OP_u64: "u64", OP_f32: "f32", OP_f64: "f64", OP_str: "str", OP_bin: "bin", OP_quote: "quote", OP_number: "number", OP_eface: "eface", OP_iface: "iface", OP_byte: "byte", OP_text: "text", OP_deref: "deref", OP_index: "index", OP_load: "load", OP_save: "save", OP_drop: "drop", OP_drop_2: "drop_2", OP_recurse: "recurse", OP_is_nil: "is_nil", OP_is_nil_p1: "is_nil_p1", OP_is_zero_1: "is_zero_1", OP_is_zero_2: "is_zero_2", OP_is_zero_4: "is_zero_4", OP_is_zero_8: "is_zero_8", OP_is_zero_map: "is_zero_map", OP_goto: "goto", OP_map_iter: "map_iter", OP_map_stop: "map_stop", OP_map_check_key: "map_check_key", OP_map_write_key: "map_write_key", OP_map_value_next: "map_value_next", OP_slice_len: "slice_len", OP_slice_next: "slice_next", OP_marshal: "marshal", OP_marshal_p: "marshal_p", OP_marshal_text: "marshal_text", OP_marshal_text_p: "marshal_text_p", OP_cond_set: "cond_set", OP_cond_testc: "cond_testc", } func (self Op) String() string { if ret := OpNames[self]; ret != "" { return ret } else { return "" } } func OP_int() Op { switch _INT_SIZE { case 32: return OP_i32 case 64: return OP_i64 default: panic("unsupported int size") } } func OP_uint() Op { switch _INT_SIZE { case 32: return OP_u32 case 64: return OP_u64 default: panic("unsupported uint size") } } func OP_uintptr() Op { switch _PTR_SIZE { case 32: return OP_u32 case 64: return OP_u64 default: panic("unsupported pointer size") } } func OP_is_zero_ints() Op { switch _INT_SIZE { case 32: return OP_is_zero_4 case 64: return OP_is_zero_8 default: panic("unsupported integer size") } } type Instr struct { o Op u int // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str) p unsafe.Pointer // maybe GoString.Ptr, or *GoType } func NewInsOp(op Op) Instr { return Instr{o: op} } func NewInsVi(op Op, vi int) Instr { return Instr{o: op, u: vi} } func NewInsVs(op Op, vs string) Instr { return Instr{ o: op, u: len(vs), p: (*rt.GoString)(unsafe.Pointer(&vs)).Ptr, } } func NewInsVt(op Op, vt reflect.Type) Instr { return Instr{ o: op, p: unsafe.Pointer(rt.UnpackType(vt)), } } type typAndTab struct { vt *rt.GoType itab *rt.GoItab } func NewInsVtab(op Op, vt reflect.Type, itab *rt.GoItab) Instr { return Instr{ o: op, p: unsafe.Pointer(&typAndTab{ vt: rt.UnpackType(vt), itab: itab, }), } } func NewInsVp(op Op, vt reflect.Type, pv bool) Instr { i := 0 if pv { i = 1 } return Instr{ o: op, u: i, p: unsafe.Pointer(rt.UnpackType(vt)), } } func (self Instr) Op() Op { return Op(self.o) } func (self Instr) Vi() int { return self.u } func (self Instr) Vf() uint8 { return (*rt.GoType)(self.p).KindFlags } func (self Instr) Vs() (v string) { (*rt.GoString)(unsafe.Pointer(&v)).Ptr = self.p (*rt.GoString)(unsafe.Pointer(&v)).Len = self.Vi() return } func (self Instr) Vk() reflect.Kind { return (*rt.GoType)(self.p).Kind() } func (self Instr) Vt() reflect.Type { return (*rt.GoType)(self.p).Pack() } func (self Instr) Vr() *rt.GoType { return (*rt.GoType)(self.p) } func (self Instr) Vp() (vt reflect.Type, pv bool) { return (*rt.GoType)(self.p).Pack(), self.u == 1 } func (self Instr) Vtab() (vt *rt.GoType, itab *rt.GoItab) { tt := (*typAndTab)(self.p) return tt.vt, tt.itab } func (self Instr) Vp2() (vt *rt.GoType, pv bool) { return (*rt.GoType)(self.p), self.u == 1 } func (self Instr) I64() int64 { return int64(self.Vi()) } func (self Instr) Byte() byte { return byte(self.Vi()) } func (self Instr) Vlen() int { return int((*rt.GoType)(self.p).Size) } func (self Instr) isBranch() bool { switch self.Op() { case OP_goto: fallthrough case OP_is_nil: fallthrough case OP_is_nil_p1: fallthrough case OP_is_zero_1: fallthrough case OP_is_zero_2: fallthrough case OP_is_zero_4: fallthrough case OP_is_zero_8: fallthrough case OP_map_check_key: fallthrough case OP_map_write_key: fallthrough case OP_slice_next: fallthrough case OP_cond_testc: return true default: return false } } func (self Instr) Disassemble() string { switch self.Op() { case OP_byte: return fmt.Sprintf("%-18s%s", self.Op().String(), strconv.QuoteRune(rune(self.Vi()))) case OP_text: return fmt.Sprintf("%-18s%s", self.Op().String(), strconv.Quote(self.Vs())) case OP_index: return fmt.Sprintf("%-18s%d", self.Op().String(), self.Vi()) case OP_recurse: fallthrough case OP_map_iter: return fmt.Sprintf("%-18s%s", self.Op().String(), self.Vt()) case OP_marshal: fallthrough case OP_marshal_p: fallthrough case OP_marshal_text: fallthrough case OP_marshal_text_p: vt, _ := self.Vtab() return fmt.Sprintf("%-18s%s", self.Op().String(), vt.Pack()) case OP_goto: fallthrough case OP_is_nil: fallthrough case OP_is_nil_p1: fallthrough case OP_is_zero_1: fallthrough case OP_is_zero_2: fallthrough case OP_is_zero_4: fallthrough case OP_is_zero_8: fallthrough case OP_is_zero_map: fallthrough case OP_cond_testc: fallthrough case OP_map_check_key: fallthrough case OP_map_write_key: return fmt.Sprintf("%-18sL_%d", self.Op().String(), self.Vi()) case OP_slice_next: return fmt.Sprintf("%-18sL_%d, %s", self.Op().String(), self.Vi(), self.Vt()) default: return fmt.Sprintf("%#v", self) } } type ( Program []Instr ) func (self Program) PC() int { return len(self) } func (self Program) Tag(n int) { if n >= vars.MaxStack { panic("type nesting too deep") } } func (self Program) Pin(i int) { v := &self[i] v.u = self.PC() } func (self Program) Rel(v []int) { for _, i := range v { self.Pin(i) } } func (self *Program) Add(op Op) { *self = append(*self, NewInsOp(op)) } func (self *Program) Key(op Op) { *self = append(*self, NewInsVi(OP_byte, '"'), NewInsOp(op), NewInsVi(OP_byte, '"'), ) } func (self *Program) Int(op Op, vi int) { *self = append(*self, NewInsVi(op, vi)) } func (self *Program) Str(op Op, vs string) { *self = append(*self, NewInsVs(op, vs)) } func (self *Program) Rtt(op Op, vt reflect.Type) { *self = append(*self, NewInsVt(op, vt)) } func (self *Program) Vp(op Op, vt reflect.Type, pv bool) { *self = append(*self, NewInsVp(op, vt, pv)) } func (self *Program) Vtab(op Op, vt reflect.Type, itab *rt.GoItab) { *self = append(*self, NewInsVtab(op, vt, itab)) } func (self Program) Disassemble() string { nb := len(self) tab := make([]bool, nb+1) ret := make([]string, 0, nb+1) /* prescan to get all the labels */ for _, ins := range self { if ins.isBranch() { tab[ins.Vi()] = true } } /* disassemble each instruction */ for i, ins := range self { if !tab[i] { ret = append(ret, "\t"+ins.Disassemble()) } else { ret = append(ret, fmt.Sprintf("L_%d:\n\t%s", i, ins.Disassemble())) } } /* add the last label, if needed */ if tab[nb] { ret = append(ret, fmt.Sprintf("L_%d:", nb)) } /* add an "end" indicator, and join all the strings */ return strings.Join(append(ret, "\tend"), "\n") }