github.com/cloudwego/frugal@v0.1.15/internal/binary/encoder/compiler.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package encoder 18 19 import ( 20 `fmt` 21 `reflect` 22 `strings` 23 `unsafe` 24 25 `github.com/cloudwego/frugal/internal/binary/defs` 26 `github.com/cloudwego/frugal/internal/opts` 27 `github.com/cloudwego/frugal/internal/rt` 28 ) 29 30 type Instr struct { 31 Op OpCode 32 Uv int32 33 Iv int64 34 To int 35 Pr unsafe.Pointer 36 } 37 38 type ( 39 Program []Instr 40 ) 41 42 func (self Instr) Vt() *rt.GoType { 43 return (*rt.GoType)(self.Pr) 44 } 45 46 func (self Instr) Str() string { 47 return rt.StringFrom(self.Pr, int(self.Uv)) 48 } 49 50 func (self Instr) Byte(i int64) int8 { 51 return *(*int8)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i))) 52 } 53 54 func (self Instr) Word(i int64) int16 { 55 return *(*int16)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i))) 56 } 57 58 func (self Instr) Long(i int64) int32 { 59 return *(*int32)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i))) 60 } 61 62 func (self Instr) Quad(i int64) int64 { 63 return *(*int64)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i))) 64 } 65 66 func (self Instr) Disassemble() string { 67 switch self.Op { 68 case OP_size_check : fallthrough 69 case OP_size_const : fallthrough 70 case OP_size_map : fallthrough 71 case OP_seek : fallthrough 72 case OP_sint : fallthrough 73 case OP_length : return fmt.Sprintf("%-18s%d", self.Op, self.Iv) 74 case OP_size_dyn : fallthrough 75 case OP_memcpy_be : return fmt.Sprintf("%-18s%d, %d", self.Op, self.Uv, self.Iv) 76 case OP_size_defer : fallthrough 77 case OP_defer : fallthrough 78 case OP_map_begin : fallthrough 79 case OP_unique : return fmt.Sprintf("%-18s%s", self.Op, self.Vt()) 80 case OP_byte : return fmt.Sprintf("%-18s0x%02x", self.Op, self.Iv) 81 case OP_word : return fmt.Sprintf("%-18s0x%04x", self.Op, self.Iv) 82 case OP_long : return fmt.Sprintf("%-18s0x%08x", self.Op, self.Iv) 83 case OP_quad : return fmt.Sprintf("%-18s0x%016x", self.Op, self.Iv) 84 case OP_map_if_next : fallthrough 85 case OP_map_if_empty : fallthrough 86 case OP_list_if_next : fallthrough 87 case OP_list_if_empty : fallthrough 88 case OP_goto : fallthrough 89 case OP_if_nil : fallthrough 90 case OP_if_hasbuf : return fmt.Sprintf("%-18sL_%d", self.Op, self.To) 91 case OP_if_eq_imm : return fmt.Sprintf("%-18s%d:%d, L_%d", self.Op, self.Iv, self.Uv, self.To) 92 case OP_if_eq_str : return fmt.Sprintf("%-18s%q, L_%d", self.Op, self.Str(), self.To) 93 default : return self.Op.String() 94 } 95 } 96 97 func (self Program) pc() int { return len(self) } 98 func (self Program) pin(i int) { self[i].To = self.pc() } 99 100 func (self Program) tag(n int) { 101 if n >= defs.StackSize { 102 panic("type nesting too deep") 103 } 104 } 105 106 func (self *Program) ins(iv Instr) { *self = append(*self, iv) } 107 func (self *Program) add(op OpCode) { self.ins(Instr { Op: op }) } 108 func (self *Program) jmp(op OpCode, to int) { self.ins(Instr { Op: op, To: to }) } 109 func (self *Program) i64(op OpCode, iv int64) { self.ins(Instr { Op: op, Iv: iv }) } 110 func (self *Program) str(op OpCode, sv string) { self.ins(Instr { Op: op, Iv: int64(len(sv)), Pr: rt.StringPtr(sv) }) } 111 func (self *Program) rtt(op OpCode, vt reflect.Type) { self.ins(Instr { Op: op, Pr: unsafe.Pointer(rt.UnpackType(vt)) }) } 112 func (self *Program) dyn(op OpCode, uv int32, iv int64) { self.ins(Instr { Op: op, Uv: uv, Iv: iv }) } 113 114 func (self Program) Free() { 115 freeProgram(self) 116 } 117 118 func (self Program) Disassemble() string { 119 nb := len(self) 120 tab := make([]bool, nb + 1) 121 ret := make([]string, 0, nb + 1) 122 123 /* prescan to get all the labels */ 124 for _, ins := range self { 125 if _OpBranches[ins.Op] { 126 tab[ins.To] = true 127 } 128 } 129 130 /* disassemble each instruction */ 131 for i, ins := range self { 132 if !tab[i] { 133 ret = append(ret, " " + ins.Disassemble()) 134 } else { 135 ret = append(ret, fmt.Sprintf("L_%d:\n %s", i, ins.Disassemble())) 136 } 137 } 138 139 /* add an "end" indicator, and join all the strings */ 140 if !tab[nb] { 141 return strings.Join(append(ret, " end"), "\n") 142 } else { 143 return strings.Join(append(ret, fmt.Sprintf("L_%d:", nb), " end"), "\n") 144 } 145 } 146 147 type Compiler struct { 148 o opts.Options 149 t map[reflect.Type]bool 150 } 151 152 func CreateCompiler() *Compiler { 153 return newCompiler() 154 } 155 156 func (self *Compiler) rescue(ep *error) { 157 if val := recover(); val != nil { 158 if err, ok := val.(error); ok { 159 *ep = err 160 } else { 161 panic(val) 162 } 163 } 164 } 165 166 func (self *Compiler) Free() { 167 freeCompiler(self) 168 } 169 170 func (self *Compiler) Apply(o opts.Options) *Compiler { 171 self.o = o 172 return self 173 } 174 175 func (self *Compiler) Compile(vt reflect.Type) (_ Program, err error) { 176 ret := newProgram() 177 vtp := (*defs.Type)(nil) 178 179 /* parse the type */ 180 if vtp, err = defs.ParseType(vt, ""); err != nil { 181 return nil, err 182 } 183 184 /* catch the exceptions, and free the type */ 185 defer self.rescue(&err) 186 defer vtp.Free() 187 188 /* object measuring */ 189 i := ret.pc() 190 ret.add(OP_if_hasbuf) 191 resetCompiler(self).measure(&ret, 0, vtp, ret.pc()) 192 193 /* object encoding */ 194 j := ret.pc() 195 ret.add(OP_goto) 196 ret.pin(i) 197 resetCompiler(self).compile(&ret, 0, vtp, ret.pc()) 198 199 /* halt the program */ 200 ret.pin(j) 201 ret.add(OP_halt) 202 return Optimize(ret), nil 203 } 204 205 func (self *Compiler) CompileAndFree(vt reflect.Type) (ret Program, err error) { 206 ret, err = self.Compile(vt) 207 self.Free() 208 return 209 }