github.com/cloudwego/frugal@v0.1.15/internal/binary/decoder/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 decoder 18 19 import ( 20 `fmt` 21 `reflect` 22 `sort` 23 `strconv` 24 `strings` 25 `unsafe` 26 27 `github.com/cloudwego/frugal/internal/binary/defs` 28 `github.com/cloudwego/frugal/internal/opts` 29 `github.com/cloudwego/frugal/internal/rt` 30 `github.com/cloudwego/frugal/internal/utils` 31 ) 32 33 type Instr struct { 34 Op OpCode 35 Tx defs.Tag 36 Id uint16 37 To int 38 Iv int64 39 Sw *int 40 Vt *rt.GoType 41 Fn unsafe.Pointer 42 } 43 44 func (self Instr) stab() string { 45 t := self.IntSeq() 46 s := make([]string, 0, self.Iv) 47 48 /* convert to strings */ 49 for i, v := range t { 50 if v >= 0 { 51 s = append(s, fmt.Sprintf("%4ccase %d: L_%d\n", ' ', i, v)) 52 } 53 } 54 55 /* join them together */ 56 return fmt.Sprintf( 57 "{\n%s}", 58 strings.Join(s, ""), 59 ) 60 } 61 62 func (self Instr) rtab() string { 63 t := self.IntSeq() 64 s := make([]string, 0, self.Iv) 65 66 /* convert to strings */ 67 for _, v := range t { 68 s = append(s, strconv.Itoa(v)) 69 } 70 71 /* join with ',' */ 72 return strings.Join(s, ", ") 73 } 74 75 func (self Instr) IntSeq() (p []int) { 76 (*rt.GoSlice)(unsafe.Pointer(&p)).Cap = int(self.Iv) 77 (*rt.GoSlice)(unsafe.Pointer(&p)).Len = int(self.Iv) 78 (*rt.GoSlice)(unsafe.Pointer(&p)).Ptr = unsafe.Pointer(self.Sw) 79 return 80 } 81 82 func (self Instr) Disassemble() string { 83 switch self.Op { 84 case OP_int : fallthrough 85 case OP_size : fallthrough 86 case OP_seek : fallthrough 87 case OP_struct_mark_tag : return fmt.Sprintf("%-18s%d", self.Op, self.Iv) 88 case OP_type : return fmt.Sprintf("%-18s%d", self.Op, self.Tx) 89 case OP_deref : fallthrough 90 case OP_map_alloc : fallthrough 91 case OP_map_set_i8 : fallthrough 92 case OP_map_set_i16 : fallthrough 93 case OP_map_set_i32 : fallthrough 94 case OP_map_set_i64 : fallthrough 95 case OP_map_set_str : fallthrough 96 case OP_map_set_enum : fallthrough 97 case OP_map_set_pointer : fallthrough 98 case OP_list_alloc : fallthrough 99 case OP_construct : fallthrough 100 case OP_defer : return fmt.Sprintf("%-18s%s", self.Op, self.Vt) 101 case OP_ctr_is_zero : fallthrough 102 case OP_struct_is_stop : fallthrough 103 case OP_goto : return fmt.Sprintf("%-18sL_%d", self.Op, self.To) 104 case OP_struct_bitmap : fallthrough 105 case OP_struct_require : return fmt.Sprintf("%-18s%s", self.Op, self.rtab()) 106 case OP_struct_switch : return fmt.Sprintf("%-18s%s", self.Op, self.stab()) 107 case OP_struct_check_type : return fmt.Sprintf("%-18s%d, L_%d", self.Op, self.Tx, self.To) 108 case OP_initialize : return fmt.Sprintf("%-18s*%p [%s]", self.Op, self.Fn, rt.FuncName(self.Fn)) 109 default : return self.Op.String() 110 } 111 } 112 113 func mkins(op OpCode, dt defs.Tag, id uint16, to int, iv int64, sw []int, vt reflect.Type, fn unsafe.Pointer) Instr { 114 return Instr { 115 Op: op, 116 Tx: dt, 117 Id: id, 118 To: to, 119 Fn: fn, 120 Vt: rt.UnpackType(vt), 121 Iv: int64(len(sw)) | iv, 122 Sw: (*int)((*rt.GoSlice)(unsafe.Pointer(&sw)).Ptr), 123 } 124 } 125 126 type ( 127 Program []Instr 128 ) 129 130 func (self Program) pc() int { 131 return len(self) 132 } 133 134 func (self Program) pin(i int) { 135 self[i].To = self.pc() 136 } 137 138 func (self Program) use(n int) { 139 if n >= defs.StackSize { 140 panic("type nesting too deep") 141 } 142 } 143 144 func (self *Program) ins(iv Instr) { *self = append(*self, iv) } 145 func (self *Program) add(op OpCode) { self.ins(mkins(op, 0, 0, 0, 0, nil, nil, nil)) } 146 func (self *Program) jmp(op OpCode, to int) { self.ins(mkins(op, 0, 0, to, 0, nil, nil, nil)) } 147 func (self *Program) i64(op OpCode, iv int64) { self.ins(mkins(op, 0, 0, 0, iv, nil, nil, nil)) } 148 func (self *Program) tab(op OpCode, tv []int) { self.ins(mkins(op, 0, 0, 0, 0, tv, nil, nil)) } 149 func (self *Program) tag(op OpCode, vt defs.Tag) { self.ins(mkins(op, vt, 0, 0, 0, nil, nil, nil)) } 150 func (self *Program) rtt(op OpCode, vt reflect.Type) { self.ins(mkins(op, 0, 0, 0, 0, nil, vt, nil)) } 151 func (self *Program) jsr(op OpCode, fn unsafe.Pointer) { self.ins(mkins(op, 0, 0, 0, 0, nil, nil, fn)) } 152 func (self *Program) jcc(op OpCode, vt defs.Tag, to int) { self.ins(mkins(op, vt, 0, to, 0, nil, nil, nil)) } 153 func (self *Program) req(op OpCode, vt reflect.Type, fv []int) { self.ins(mkins(op, 0, 0, 0, 0, fv, vt, nil)) } 154 155 func (self Program) Free() { 156 freeProgram(self) 157 } 158 159 func (self Program) Disassemble() string { 160 nb := len(self) 161 tab := make([]bool, nb + 1) 162 ret := make([]string, 0, nb + 1) 163 164 /* prescan to get all the labels */ 165 for _, ins := range self { 166 if _OpBranches[ins.Op] { 167 if ins.Op != OP_struct_switch { 168 tab[ins.To] = true 169 } else { 170 for _, v := range ins.IntSeq() { 171 if v >= 0 { 172 tab[v] = true 173 } 174 } 175 } 176 } 177 } 178 179 /* disassemble each instruction */ 180 for i, ins := range self { 181 ln := "" 182 ds := ins.Disassemble() 183 184 /* check for label reference */ 185 if tab[i] { 186 ret = append(ret, fmt.Sprintf("L_%d:", i)) 187 } 188 189 /* indent each line */ 190 for _, ln = range strings.Split(ds, "\n") { 191 ret = append(ret, " " + ln) 192 } 193 } 194 195 /* add the last label, if needed */ 196 if tab[nb] { 197 ret = append(ret, fmt.Sprintf("L_%d:", nb)) 198 } 199 200 /* add an "end" indicator, and join all the strings */ 201 return strings.Join(append(ret, " end"), "\n") 202 } 203 204 type Compiler struct { 205 o opts.Options 206 t map[reflect.Type]bool 207 d map[reflect.Type]struct{} 208 } 209 210 func CreateCompiler() *Compiler { 211 return newCompiler() 212 } 213 214 func (self *Compiler) rescue(ep *error) { 215 if val := recover(); val != nil { 216 if err, ok := val.(error); ok { 217 *ep = err 218 } else { 219 panic(val) 220 } 221 } 222 } 223 224 func (self *Compiler) compileDef(p *Program, vt *defs.Type) { 225 p.rtt(OP_defer, vt.S) 226 self.d[vt.S] = struct{}{} 227 } 228 229 func (self *Compiler) compileOne(p *Program, sp int, vt *defs.Type) { 230 if vt.T == defs.T_pointer { 231 self.compilePtr(p, sp, vt) 232 } else if vt.T != defs.T_struct { 233 self.compileRec(p, sp, vt) 234 } else if _, ok := self.t[vt.S]; !ok && self.o.CanInline(sp, p.pc()) { 235 self.compileTag(p, sp, vt) 236 } else { 237 self.compileDef(p, vt) 238 } 239 } 240 241 func (self *Compiler) compileTag(p *Program, sp int, vt *defs.Type) { 242 self.t[vt.S] = true 243 self.compileRec(p, sp, vt) 244 delete(self.t, vt.S) 245 } 246 247 func (self *Compiler) compileRec(p *Program, sp int, vt *defs.Type) { 248 switch vt.T { 249 case defs.T_bool : p.i64(OP_size, 1); p.i64(OP_int, 1) 250 case defs.T_i8 : p.i64(OP_size, 1); p.i64(OP_int, 1) 251 case defs.T_i16 : p.i64(OP_size, 2); p.i64(OP_int, 2) 252 case defs.T_i32 : p.i64(OP_size, 4); p.i64(OP_int, 4) 253 case defs.T_i64 : p.i64(OP_size, 8); p.i64(OP_int, 8) 254 case defs.T_double : p.i64(OP_size, 8); p.i64(OP_int, 8) 255 case defs.T_string : p.i64(OP_size, 4); p.add(OP_str) 256 case defs.T_binary : p.i64(OP_size, 4); p.add(OP_bin) 257 case defs.T_enum : p.i64(OP_size, 4); p.add(OP_enum) 258 case defs.T_struct : self.compileStruct (p, sp, vt) 259 case defs.T_map : self.compileMap (p, sp, vt) 260 case defs.T_set : self.compileSetList (p, sp, vt.V) 261 case defs.T_list : self.compileSetList (p, sp, vt.V) 262 default : panic("unreachable") 263 } 264 } 265 266 func (self *Compiler) compilePtr(p *Program, sp int, vt *defs.Type) { 267 p.use(sp) 268 p.add(OP_make_state) 269 p.rtt(OP_deref, vt.V.S) 270 self.compileOne(p, sp + 1, vt.V) 271 p.add(OP_drop_state) 272 } 273 274 func (self *Compiler) compileMap(p *Program, sp int, vt *defs.Type) { 275 p.use(sp) 276 p.i64(OP_size, 6) 277 p.tag(OP_type, vt.K.Tag()) 278 p.tag(OP_type, vt.V.Tag()) 279 p.add(OP_make_state) 280 p.add(OP_ctr_load) 281 p.rtt(OP_map_alloc, vt.S) 282 i := p.pc() 283 p.add(OP_ctr_is_zero) 284 self.compileKey(p, sp + 1, vt) 285 self.compileOne(p, sp + 1, vt.V) 286 p.add(OP_ctr_decr) 287 p.jmp(OP_goto, i) 288 p.pin(i) 289 p.add(OP_map_close) 290 p.add(OP_drop_state) 291 } 292 293 func (self *Compiler) compileKey(p *Program, sp int, vt *defs.Type) { 294 switch vt.K.T { 295 case defs.T_bool : p.i64(OP_size, 1); p.rtt(OP_map_set_i8, vt.S) 296 case defs.T_i8 : p.i64(OP_size, 1); p.rtt(OP_map_set_i8, vt.S) 297 case defs.T_double : p.i64(OP_size, 8); p.rtt(OP_map_set_i64, vt.S) 298 case defs.T_i16 : p.i64(OP_size, 2); p.rtt(OP_map_set_i16, vt.S) 299 case defs.T_i32 : p.i64(OP_size, 4); p.rtt(OP_map_set_i32, vt.S) 300 case defs.T_i64 : p.i64(OP_size, 8); p.rtt(OP_map_set_i64, vt.S) 301 case defs.T_binary : p.i64(OP_size, 4); p.rtt(OP_map_set_str, vt.S) 302 case defs.T_string : p.i64(OP_size, 4); p.rtt(OP_map_set_str, vt.S) 303 case defs.T_enum : p.i64(OP_size, 4); p.rtt(OP_map_set_enum, vt.S) 304 case defs.T_pointer : self.compileKeyPtr(p, sp, vt) 305 default : panic("unreachable") 306 } 307 } 308 309 func (self *Compiler) compileNoCopy(p *Program, sp int, vt *defs.Type) { 310 switch { 311 default: { 312 panic("invalid nocopy type: " + vt.String()) 313 } 314 315 /* simple strings */ 316 case vt.T == defs.T_string: { 317 p.i64(OP_size, 4) 318 p.add(OP_str_nocopy) 319 } 320 321 /* simple binaries */ 322 case vt.T == defs.T_binary: { 323 p.i64(OP_size, 4) 324 p.add(OP_bin_nocopy) 325 } 326 327 /* string pointers */ 328 case vt.T == defs.T_pointer && vt.V.T == defs.T_string: { 329 p.use(sp) 330 p.add(OP_make_state) 331 p.rtt(OP_deref, vt.V.S) 332 p.i64(OP_size, 4) 333 p.add(OP_str_nocopy) 334 p.add(OP_drop_state) 335 } 336 337 /* binary pointers */ 338 case vt.T == defs.T_pointer && vt.V.T == defs.T_binary: { 339 p.use(sp) 340 p.add(OP_make_state) 341 p.rtt(OP_deref, vt.V.S) 342 p.i64(OP_size, 4) 343 p.add(OP_bin_nocopy) 344 p.add(OP_drop_state) 345 } 346 } 347 } 348 349 func (self *Compiler) compileKeyPtr(p *Program, sp int, vt *defs.Type) { 350 pt := vt.K 351 st := pt.V 352 353 /* must be a struct */ 354 if st.T != defs.T_struct { 355 panic("map key cannot be non-struct pointers") 356 } 357 358 /* construct a new object */ 359 p.rtt(OP_construct, st.S) 360 self.compileOne(p, sp, st) 361 p.rtt(OP_map_set_pointer, vt.S) 362 } 363 364 func (self *Compiler) compileStruct(p *Program, sp int, vt *defs.Type) { 365 var fid int 366 var err error 367 var req []int 368 var fvs []defs.Field 369 var ifn unsafe.Pointer 370 371 /* resolve the fields */ 372 if fvs, err = defs.ResolveFields(vt.S); err != nil { 373 panic(err) 374 } 375 376 /* empty struct */ 377 if len(fvs) == 0 { 378 p.add(OP_struct_ignore) 379 return 380 } 381 382 /* find the default initializer */ 383 if ifn, err = defs.GetDefaultInitializer(vt.S); err != nil { 384 panic(err) 385 } 386 387 /* call the initializer if any */ 388 if ifn != nil { 389 p.jsr(OP_initialize, ifn) 390 } 391 392 /* find the maximum field IDs */ 393 for _, fv := range fvs { 394 if fid = utils.MaxInt(fid, int(fv.ID)); fv.Spec == defs.Required { 395 req = append(req, int(fv.ID)) 396 } 397 } 398 399 /* save the current state */ 400 p.use(sp) 401 p.add(OP_make_state) 402 403 /* allocate bitmap for required fields, if needed */ 404 if sort.Ints(req); len(req) != 0 { 405 p.tab(OP_struct_bitmap, req) 406 } 407 408 /* switch jump buffer */ 409 i := p.pc() 410 s := make([]int, fid + 1) 411 412 /* set the default branch */ 413 for v := range s { 414 s[v] = -1 415 } 416 417 /* dispatch the next field */ 418 p.i64(OP_size, 1) 419 p.add(OP_struct_read_type) 420 j := p.pc() 421 p.add(OP_struct_is_stop) 422 p.i64(OP_size, 2) 423 p.tab(OP_struct_switch, s) 424 k := p.pc() 425 p.add(OP_struct_skip) 426 p.jmp(OP_goto, i) 427 428 /* assemble every field */ 429 for _, fv := range fvs { 430 s[fv.ID] = p.pc() 431 p.jcc(OP_struct_check_type, fv.Type.Tag(), k) 432 433 /* mark the field as seen, if needed */ 434 if fv.Spec == defs.Required { 435 p.i64(OP_struct_mark_tag, int64(fv.ID)) 436 } 437 438 /* seek to the field */ 439 off := int64(fv.F) 440 p.i64(OP_seek, off) 441 442 /* check for no-copy strings */ 443 if fv.Opts & defs.NoCopy == 0 { 444 self.compileOne(p, sp + 1, fv.Type) 445 } else if fv.Type.Tag() == defs.T_string { 446 self.compileNoCopy(p, sp + 1, fv.Type) 447 } else { 448 panic(`"nocopy" is only applicable to "string" or "binary" types`) 449 } 450 451 /* seek back to the beginning */ 452 p.i64(OP_seek, -off) 453 p.jmp(OP_goto, i) 454 } 455 456 /* no required fields */ 457 if p.pin(j); len(req) == 0 { 458 p.add(OP_drop_state) 459 return 460 } 461 462 /* check all the required fields */ 463 p.req(OP_struct_require, vt.S, req) 464 p.add(OP_drop_state) 465 } 466 467 func (self *Compiler) compileSetList(p *Program, sp int, et *defs.Type) { 468 p.use(sp) 469 p.i64(OP_size, 5) 470 p.tag(OP_type, et.Tag()) 471 p.add(OP_make_state) 472 p.add(OP_ctr_load) 473 p.rtt(OP_list_alloc, et.S) 474 i := p.pc() 475 p.add(OP_ctr_is_zero) 476 j := p.pc() 477 self.compileOne(p, sp + 1, et) 478 p.add(OP_ctr_decr) 479 k := p.pc() 480 p.add(OP_ctr_is_zero) 481 p.i64(OP_seek, int64(et.S.Size())) 482 p.jmp(OP_goto, j) 483 p.pin(i) 484 p.pin(k) 485 p.add(OP_drop_state) 486 } 487 488 func (self *Compiler) Free() { 489 freeCompiler(self) 490 } 491 492 func (self *Compiler) Apply(o opts.Options) *Compiler { 493 self.o = o 494 return self 495 } 496 497 func (self *Compiler) Compile(vt reflect.Type) (_ Program, err error) { 498 ret := newProgram() 499 vtp := (*defs.Type)(nil) 500 501 /* parse the type */ 502 if vtp, err = defs.ParseType(vt, ""); err != nil { 503 return nil, err 504 } 505 506 /* catch the exceptions, and free the type */ 507 defer self.rescue(&err) 508 defer vtp.Free() 509 510 /* compile the actual type */ 511 self.compileOne(&ret, 0, vtp) 512 ret.add(OP_halt) 513 return Optimize(ret), nil 514 } 515 516 func (self *Compiler) CompileAndFree(vt reflect.Type) (ret Program, err error) { 517 ret, err = self.Compile(vt) 518 self.Free() 519 return 520 }