github.com/cloudwego/frugal@v0.1.15/internal/binary/encoder/compiler_encode.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 `math` 21 22 `github.com/cloudwego/frugal/internal/atm/abi` 23 `github.com/cloudwego/frugal/internal/binary/defs` 24 ) 25 26 func (self *Compiler) compile(p *Program, sp int, vt *defs.Type, startpc int) { 27 rt := vt.S 28 tt := vt.T 29 30 /* only recurse on structs */ 31 if tt != defs.T_struct { 32 self.compileOne(p, sp, vt, startpc) 33 return 34 } 35 36 /* check for loops */ 37 if self.t[rt] || !self.o.CanInline(sp, (p.pc() - startpc) * 2) { 38 p.rtt(OP_defer, rt) 39 return 40 } 41 42 /* compile the type recursively */ 43 self.t[rt] = true 44 self.compileOne(p, sp, vt, startpc) 45 delete(self.t, rt) 46 } 47 48 func (self *Compiler) compileOne(p *Program, sp int, vt *defs.Type, startpc int) { 49 switch vt.T { 50 case defs.T_bool : p.i64(OP_size_check, 1); p.i64(OP_sint, 1) 51 case defs.T_i8 : p.i64(OP_size_check, 1); p.i64(OP_sint, 1) 52 case defs.T_i16 : p.i64(OP_size_check, 2); p.i64(OP_sint, 2) 53 case defs.T_i32 : p.i64(OP_size_check, 4); p.i64(OP_sint, 4) 54 case defs.T_i64 : p.i64(OP_size_check, 8); p.i64(OP_sint, 8) 55 case defs.T_enum : p.i64(OP_size_check, 4); p.i64(OP_sint, 4) 56 case defs.T_double : p.i64(OP_size_check, 8); p.i64(OP_sint, 8) 57 case defs.T_string : p.i64(OP_size_check, 4); p.i64(OP_length, abi.PtrSize); p.dyn(OP_memcpy_be, abi.PtrSize, 1) 58 case defs.T_binary : p.i64(OP_size_check, 4); p.i64(OP_length, abi.PtrSize); p.dyn(OP_memcpy_be, abi.PtrSize, 1) 59 case defs.T_map : self.compileMap(p, sp, vt, startpc) 60 case defs.T_set : self.compileSeq(p, sp, vt, startpc, true) 61 case defs.T_list : self.compileSeq(p, sp, vt, startpc, false) 62 case defs.T_struct : self.compileStruct(p, sp, vt, startpc) 63 case defs.T_pointer : self.compilePtr(p, sp, vt, startpc) 64 default : panic("unreachable") 65 } 66 } 67 68 func (self *Compiler) compilePtr(p *Program, sp int, vt *defs.Type, startpc int) { 69 i := p.pc() 70 p.tag(sp) 71 p.add(OP_if_nil) 72 p.add(OP_make_state) 73 p.add(OP_deref) 74 self.compile(p, sp + 1, vt.V, startpc) 75 p.add(OP_drop_state) 76 p.pin(i) 77 } 78 79 func (self *Compiler) compileMap(p *Program, sp int, vt *defs.Type, startpc int) { 80 kt := vt.K 81 et := vt.V 82 83 /* 6-byte map header */ 84 p.tag(sp) 85 p.i64(OP_size_check, 6) 86 p.i64(OP_byte, int64(kt.Tag())) 87 p.i64(OP_byte, int64(et.Tag())) 88 89 /* check for nil maps */ 90 i := p.pc() 91 p.add(OP_if_nil) 92 93 /* encode the map */ 94 p.add(OP_map_len) 95 j := p.pc() 96 p.add(OP_map_if_empty) 97 p.add(OP_make_state) 98 p.rtt(OP_map_begin, vt.S) 99 k := p.pc() 100 p.add(OP_map_key) 101 self.compileItem(p, sp + 1, kt, startpc) 102 p.add(OP_map_value) 103 self.compileItem(p, sp + 1, et, startpc) 104 p.add(OP_map_next) 105 p.jmp(OP_map_if_next, k) 106 p.add(OP_drop_state) 107 108 /* encode the length for nil maps */ 109 r := p.pc() 110 p.add(OP_goto) 111 p.pin(i) 112 p.i64(OP_long, 0) 113 p.pin(j) 114 p.pin(r) 115 } 116 117 func (self *Compiler) compileSeq(p *Program, sp int, vt *defs.Type, startpc int, verifyUnique bool) { 118 nb := -1 119 et := vt.V 120 121 /* 5-byte set or list header */ 122 p.tag(sp) 123 p.i64(OP_size_check, 5) 124 p.i64(OP_byte, int64(et.Tag())) 125 p.i64(OP_length, abi.PtrSize) 126 127 /* check for nil slice */ 128 i := p.pc() 129 p.add(OP_if_nil) 130 131 /* special case of primitive sets or lists */ 132 switch et.T { 133 case defs.T_bool : nb = 1 134 case defs.T_i8 : nb = 1 135 case defs.T_i16 : nb = 2 136 case defs.T_i32 : nb = 4 137 case defs.T_i64 : nb = 8 138 case defs.T_double : nb = 8 139 } 140 141 /* check for uniqueness if needed */ 142 if verifyUnique { 143 p.rtt(OP_unique, et.S) 144 } 145 146 /* check if this is the special case */ 147 if nb != -1 { 148 p.dyn(OP_memcpy_be, abi.PtrSize, int64(nb)) 149 p.pin(i) 150 return 151 } 152 153 /* complex sets or lists */ 154 j := p.pc() 155 p.add(OP_list_if_empty) 156 p.add(OP_make_state) 157 p.add(OP_list_begin) 158 k := p.pc() 159 p.add(OP_goto) 160 r := p.pc() 161 p.i64(OP_seek, int64(et.S.Size())) 162 p.pin(k) 163 self.compileItem(p, sp + 1, et, startpc) 164 p.add(OP_list_decr) 165 p.jmp(OP_list_if_next, r) 166 p.add(OP_drop_state) 167 p.pin(i) 168 p.pin(j) 169 } 170 171 func (self *Compiler) compileItem(p *Program, sp int, vt *defs.Type, startpc int) { 172 tag := vt.T 173 elem := vt.V 174 175 /* special handling for pointers */ 176 if tag != defs.T_pointer { 177 self.compile(p, sp, vt, startpc) 178 return 179 } 180 181 /* must be pointer struct at this point */ 182 if elem.T != defs.T_struct { 183 panic("fatal: non-struct pointers within container elements") 184 } 185 186 /* always add the STOP field for structs */ 187 i := p.pc() 188 p.tag(sp) 189 p.add(OP_if_nil) 190 p.add(OP_make_state) 191 p.add(OP_deref) 192 self.compile(p, sp + 1, elem, startpc) 193 p.add(OP_drop_state) 194 j := p.pc() 195 p.add(OP_goto) 196 p.pin(i) 197 p.i64(OP_size_check, 1) 198 p.i64(OP_byte, 0) 199 p.pin(j) 200 } 201 202 func (self *Compiler) compileStruct(p *Program, sp int, vt *defs.Type, startpc int) { 203 var err error 204 var fvs []defs.Field 205 206 /* resolve the field */ 207 if fvs, err = defs.ResolveFields(vt.S); err != nil { 208 panic(err) 209 } 210 211 /* compile every field */ 212 for _, fv := range fvs { 213 p.tag(sp) 214 p.i64(OP_seek, int64(fv.F)) 215 self.compileStructField(p, sp + 1, fv, startpc) 216 p.i64(OP_seek, -int64(fv.F)) 217 } 218 219 /* add the STOP field */ 220 p.i64(OP_size_check, 1) 221 p.i64(OP_byte, 0) 222 } 223 224 func (self *Compiler) compileStructField(p *Program, sp int, fv defs.Field, startpc int) { 225 switch fv.Type.T { 226 default: { 227 panic("fatal: invalid field type: " + fv.Type.String()) 228 } 229 230 /* non-pointer types */ 231 case defs.T_bool : fallthrough 232 case defs.T_i8 : fallthrough 233 case defs.T_double : fallthrough 234 case defs.T_i16 : fallthrough 235 case defs.T_i32 : fallthrough 236 case defs.T_i64 : fallthrough 237 case defs.T_string : fallthrough 238 case defs.T_enum : fallthrough 239 case defs.T_binary : { 240 if fv.Default.IsValid() && fv.Spec == defs.Optional { 241 self.compileStructDefault(p, sp, fv, startpc) 242 } else { 243 self.compileStructRequired(p, sp, fv, startpc) 244 } 245 } 246 247 /* struct types, only available in hand-written structs */ 248 case defs.T_struct: { 249 self.compileStructRequired(p, sp, fv, startpc) 250 } 251 252 /* sequencial types */ 253 case defs.T_map : fallthrough 254 case defs.T_set : fallthrough 255 case defs.T_list : { 256 if fv.Spec == defs.Optional { 257 self.compileStructIterable(p, sp, fv, startpc) 258 } else { 259 self.compileStructRequired(p, sp, fv, startpc) 260 } 261 } 262 263 /* pointers */ 264 case defs.T_pointer: { 265 if fv.Spec == defs.Optional { 266 self.compileStructOptional(p, sp, fv, startpc) 267 } else if fv.Type.V.T == defs.T_struct { 268 self.compileStructPointer(p, sp, fv, startpc) 269 } else { 270 panic("fatal: non-optional non-struct pointers") 271 } 272 } 273 } 274 } 275 276 func (self *Compiler) compileStructDefault(p *Program, sp int, fv defs.Field, startpc int) { 277 i := p.pc() 278 t := fv.Type.T 279 280 /* check for default values */ 281 switch t { 282 case defs.T_bool : p.dyn(OP_if_eq_imm, 1, bool2i64(fv.Default.Bool())) 283 case defs.T_i8 : p.dyn(OP_if_eq_imm, 1, fv.Default.Int()) 284 case defs.T_double : p.dyn(OP_if_eq_imm, 8, int64(math.Float64bits(fv.Default.Float()))) 285 case defs.T_i16 : p.dyn(OP_if_eq_imm, 2, fv.Default.Int()) 286 case defs.T_i32 : p.dyn(OP_if_eq_imm, 4, fv.Default.Int()) 287 case defs.T_i64 : p.dyn(OP_if_eq_imm, 8, fv.Default.Int()) 288 case defs.T_string : p.str(OP_if_eq_str, fv.Default.String()) 289 case defs.T_enum : p.dyn(OP_if_eq_imm, 4, fv.Default.Int()) 290 case defs.T_binary : p.str(OP_if_eq_str, mem2str(fv.Default.Bytes())) 291 default : panic("unreachable") 292 } 293 294 /* compile if it's not the default value */ 295 self.compileStructFieldBegin(p, fv, 3) 296 self.compile(p, sp, fv.Type, startpc) 297 p.pin(i) 298 } 299 300 func (self *Compiler) compileStructPointer(p *Program, sp int, fv defs.Field, startpc int) { 301 i := p.pc() 302 p.add(OP_if_nil) 303 self.compileStructFieldBegin(p, fv, 4) 304 p.add(OP_make_state) 305 p.add(OP_deref) 306 self.compile(p, sp + 1, fv.Type.V, startpc) 307 p.add(OP_drop_state) 308 j := p.pc() 309 p.add(OP_goto) 310 p.pin(i) 311 self.compileStructFieldBegin(p, fv, 4) 312 p.i64(OP_byte, 0) 313 p.pin(j) 314 } 315 316 func (self *Compiler) compileStructIterable(p *Program, sp int, fv defs.Field, startpc int) { 317 i := p.pc() 318 p.add(OP_if_nil) 319 self.compileStructFieldBegin(p, fv, 3) 320 self.compile(p, sp, fv.Type, startpc) 321 p.pin(i) 322 } 323 324 func (self *Compiler) compileStructOptional(p *Program, sp int, fv defs.Field, startpc int) { 325 i := p.pc() 326 p.add(OP_if_nil) 327 self.compileStructFieldBegin(p, fv, 3) 328 p.add(OP_make_state) 329 p.add(OP_deref) 330 self.compile(p, sp + 1, fv.Type.V, startpc) 331 p.add(OP_drop_state) 332 p.pin(i) 333 } 334 335 func (self *Compiler) compileStructRequired(p *Program, sp int, fv defs.Field, startpc int) { 336 self.compileStructFieldBegin(p, fv, 3) 337 self.compile(p, sp, fv.Type, startpc) 338 } 339 340 func (self *Compiler) compileStructFieldBegin(p *Program, fv defs.Field, nb int64) { 341 p.i64(OP_size_check, nb) 342 p.i64(OP_byte, int64(fv.Type.Tag())) 343 p.i64(OP_word, int64(fv.ID)) 344 }