gotosocial/vendor/github.com/bytedance/sonic/internal/encoder/ir/op.go

474 lines
9 KiB
Go
Raw Normal View History

/*
* 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 "<invalid>"
}
}
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")
}