mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-01-23 14:50:21 +00:00
474 lines
9 KiB
Go
474 lines
9 KiB
Go
|
/*
|
||
|
* 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")
|
||
|
}
|