github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/dump/dump.go (about) 1 package dump 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "io" 7 8 "github.com/hirochachacha/plua/internal/limits" 9 "github.com/hirochachacha/plua/internal/version" 10 "github.com/hirochachacha/plua/object" 11 "github.com/hirochachacha/plua/opcode" 12 ) 13 14 var ( 15 errIntegerOverflow = &Error{errors.New("integer overflow")} 16 errFloatOverflow = &Error{errors.New("float overflow")} 17 errFloatUnderflow = &Error{errors.New("float underflow")} 18 errByteOverflow = &Error{errors.New("byte overflow")} 19 errInvalidIntSize = &Error{errors.New("IntSize should be power of 2")} 20 errInvalidSizeTSize = &Error{errors.New("SizeTSize should be power of 2")} 21 errInvalidIntegerSize = &Error{errors.New("IntegerSize should be power of 2")} 22 errInvalidNumberSize = &Error{errors.New("NumberSize should be 4 or 8")} 23 errInvalidByteOrder = &Error{errors.New("ByteOrder should not be nil")} 24 ) 25 26 type Mode uint 27 28 const ( 29 StripDebugInfo Mode = 1 << iota 30 ) 31 32 func DumpTo(w io.Writer, p *object.Proto, mode Mode) (err error) { 33 return defaultConfig.DumpTo(w, p, mode) 34 } 35 36 var defaultConfig = &Config{ 37 IntSize: 8, 38 SizeTSize: 8, 39 IntegerSize: 8, 40 NumberSize: 8, 41 ByteOrder: binary.LittleEndian, 42 } 43 44 type Config struct { 45 IntSize int // size of int 46 SizeTSize int // size of size_t 47 IntegerSize int // size of lua integer 48 NumberSize int // size of lua number 49 ByteOrder binary.ByteOrder // byte order 50 } 51 52 func (cfg *Config) validate() error { 53 if !isPowerOfTwo(cfg.IntSize) { 54 return errInvalidIntSize 55 } 56 57 if !isPowerOfTwo(cfg.SizeTSize) { 58 return errInvalidSizeTSize 59 } 60 61 if !isPowerOfTwo(cfg.IntegerSize) { 62 return errInvalidIntegerSize 63 } 64 65 if !(cfg.NumberSize == 4 || cfg.NumberSize == 8) { 66 return errInvalidNumberSize 67 } 68 69 if cfg.ByteOrder == nil { 70 return errInvalidByteOrder 71 } 72 73 return nil 74 } 75 76 func isPowerOfTwo(x int) bool { 77 return x&(x-1) == 0 78 // for x%2 == 0 && x > 1 { 79 // x /= 2 80 // } 81 // return x == 1 82 } 83 84 func (cfg *Config) DumpTo(w io.Writer, p *object.Proto, mode Mode) (err error) { 85 err = cfg.validate() 86 if err != nil { 87 return err 88 } 89 90 d := &dumper{ 91 w: w, 92 mode: mode, 93 cfg: cfg, 94 int: makeInt(cfg.IntSize), 95 sizeT: makeInt(cfg.SizeTSize), 96 integer: makeInteger(cfg.IntegerSize), 97 number: makeNumber(cfg.NumberSize), 98 } 99 100 if bw, ok := w.(io.ByteWriter); ok { 101 d.byte = func(b byte) error { 102 return bw.WriteByte(b) 103 } 104 } else { 105 d.byte = func(b byte) error { 106 _, err := w.Write([]byte{b}) 107 108 return err 109 } 110 } 111 112 if sw, ok := w.(stringWriter); ok { 113 d.str = func(s string) error { 114 _, err := sw.WriteString(s) 115 return err 116 } 117 } else { 118 d.str = func(s string) error { 119 _, err := w.Write([]byte(s)) 120 return err 121 } 122 } 123 124 err = d.dumpHeader() 125 if err != nil { 126 return err 127 } 128 129 err = d.dumpByte(len(p.Upvalues)) 130 if err != nil { 131 return err 132 } 133 134 err = d.dumpFunction(p, "") 135 if err != nil { 136 return err 137 } 138 139 return 140 } 141 142 type stringWriter interface { 143 WriteString(string) (int, error) 144 } 145 146 type dumper struct { 147 w io.Writer 148 mode Mode 149 cfg *Config 150 byte func(byte) error 151 str func(string) error 152 int func(*dumper, int) error 153 sizeT func(*dumper, int) error 154 integer func(*dumper, object.Integer) error 155 number func(*dumper, object.Number) error 156 } 157 158 func (d *dumper) dumpByte(x int) error { 159 if x < 0 || x > 255 { 160 return errByteOverflow 161 } 162 return d.byte(byte(x)) 163 } 164 165 func (d *dumper) dumpBool(b bool) error { 166 if b { 167 return d.dumpByte(1) 168 } 169 170 return d.dumpByte(0) 171 } 172 173 func (d *dumper) dumpInt(x int) error { 174 return d.int(d, x) 175 } 176 177 func (d *dumper) dumpSizeT(x int) error { 178 return d.sizeT(d, x) 179 } 180 181 func (d *dumper) dumpStr(s string) error { 182 return d.str(s) 183 } 184 185 func (d *dumper) dumpNumber(x object.Number) error { 186 return d.number(d, x) 187 } 188 189 func (d *dumper) dumpInteger(x object.Integer) error { 190 return d.integer(d, x) 191 } 192 193 func (d *dumper) dumpString(s string) error { 194 length := len(s) 195 if length == 0 { 196 return d.dumpByte(0) 197 } 198 199 length++ // trailing '\0' 200 201 var err error 202 if length < 0xFF { 203 err = d.dumpByte(length) 204 } else { 205 err = d.dumpByte(0xFF) 206 if err != nil { 207 return err 208 } 209 err = d.dumpSizeT(length) 210 } 211 212 if err != nil { 213 return err 214 } 215 216 return d.dumpStr(string(s)) 217 } 218 219 func (d *dumper) dumpCode(p *object.Proto) error { 220 err := d.dumpInt(len(p.Code)) 221 if err != nil { 222 return err 223 } 224 225 return binary.Write(d.w, d.cfg.ByteOrder, p.Code) 226 } 227 228 func (d *dumper) dumpConstants(p *object.Proto) error { 229 err := d.dumpInt(len(p.Constants)) 230 if err != nil { 231 return err 232 } 233 234 for _, c := range p.Constants { 235 switch c := c.(type) { 236 case nil: 237 // do nothing 238 err = d.dumpByte(int(object.TNIL)) 239 case object.Boolean: 240 err = d.dumpByte(int(object.TBOOLEAN)) 241 if err == nil { 242 err = d.dumpBool(bool(c)) 243 } 244 case object.Integer: 245 err = d.dumpByte(int(object.TNUMINT)) 246 if err == nil { 247 err = d.dumpInteger(c) 248 } 249 case object.Number: 250 err = d.dumpByte(int(object.TNUMFLT)) 251 if err == nil { 252 err = d.dumpNumber(c) 253 } 254 case object.String: 255 err = d.dumpByte(int(object.TSTRING)) 256 if err == nil { 257 err = d.dumpString(string(c)) 258 } 259 default: 260 panic("unreachable") 261 } 262 263 if err != nil { 264 return err 265 } 266 } 267 268 return nil 269 } 270 271 func (d *dumper) dumpUpvalues(p *object.Proto) error { 272 err := d.dumpInt(len(p.Upvalues)) 273 if err != nil { 274 return err 275 } 276 277 for _, u := range p.Upvalues { 278 d.dumpBool(u.Instack) 279 d.dumpByte(u.Index) 280 } 281 282 return nil 283 } 284 285 func (d *dumper) dumpProtos(p *object.Proto) error { 286 err := d.dumpInt(len(p.Protos)) 287 if err != nil { 288 return err 289 } 290 291 for _, p := range p.Protos { 292 err = d.dumpFunction(p, p.Source) 293 if err != nil { 294 return err 295 } 296 } 297 298 return nil 299 } 300 301 func (d *dumper) dumpDebug(p *object.Proto) (err error) { 302 if d.mode&StripDebugInfo != 0 { 303 err = d.dumpInt(0) // len(p.LineInfo) 304 if err != nil { 305 return err 306 } 307 err = d.dumpInt(0) // len(p.LocVars) 308 if err != nil { 309 return err 310 } 311 err = d.dumpInt(0) // len(p.Upvalues) 312 313 return 314 } 315 316 err = d.dumpInt(len(p.LineInfo)) 317 if err != nil { 318 return err 319 } 320 for _, line := range p.LineInfo { 321 err = d.dumpInt(line) 322 if err != nil { 323 return err 324 } 325 } 326 327 err = d.dumpInt(len(p.LocVars)) 328 if err != nil { 329 return err 330 } 331 for _, l := range p.LocVars { 332 err = d.dumpString(l.Name) 333 if err != nil { 334 return err 335 } 336 err = d.dumpInt(l.StartPC) 337 if err != nil { 338 return err 339 } 340 err = d.dumpInt(l.EndPC) 341 if err != nil { 342 return err 343 } 344 } 345 346 err = d.dumpInt(len(p.Upvalues)) 347 if err != nil { 348 return err 349 } 350 for _, u := range p.Upvalues { 351 err = d.dumpString(u.Name) 352 if err != nil { 353 return err 354 } 355 } 356 357 return 358 } 359 360 func (d *dumper) dumpFunction(p *object.Proto, psource string) (err error) { 361 if d.mode&StripDebugInfo != 0 || p.Source == psource { 362 err = d.dumpString("") 363 } else { 364 err = d.dumpString(p.Source) 365 } 366 if err != nil { 367 return err 368 } 369 370 err = d.dumpInt(p.LineDefined) 371 if err != nil { 372 return err 373 } 374 err = d.dumpInt(p.LastLineDefined) 375 if err != nil { 376 return err 377 } 378 err = d.dumpByte(p.NParams) 379 if err != nil { 380 return err 381 } 382 err = d.dumpBool(p.IsVararg) 383 if err != nil { 384 return err 385 } 386 err = d.dumpByte(p.MaxStackSize) 387 if err != nil { 388 return err 389 } 390 err = d.dumpCode(p) 391 if err != nil { 392 return err 393 } 394 err = d.dumpConstants(p) 395 if err != nil { 396 return err 397 } 398 err = d.dumpUpvalues(p) 399 if err != nil { 400 return err 401 } 402 err = d.dumpProtos(p) 403 if err != nil { 404 return err 405 } 406 err = d.dumpDebug(p) 407 408 return 409 } 410 411 func (d *dumper) dumpHeader() (err error) { 412 err = d.dumpStr(version.LUA_SIGNATURE) 413 if err != nil { 414 return err 415 } 416 err = d.dumpByte(version.LUAC_VERSION) 417 if err != nil { 418 return err 419 } 420 err = d.dumpByte(version.LUAC_FORMAT) 421 if err != nil { 422 return err 423 } 424 err = d.dumpStr(version.LUAC_DATA) 425 if err != nil { 426 return err 427 } 428 err = d.dumpByte(d.cfg.IntSize) 429 if err != nil { 430 return err 431 } 432 err = d.dumpByte(d.cfg.SizeTSize) 433 if err != nil { 434 return err 435 } 436 err = d.dumpByte(opcode.InstructionSize) 437 if err != nil { 438 return err 439 } 440 err = d.dumpByte(d.cfg.IntegerSize) 441 if err != nil { 442 return err 443 } 444 err = d.dumpByte(d.cfg.NumberSize) 445 if err != nil { 446 return err 447 } 448 err = d.dumpInteger(version.LUAC_INT) 449 if err != nil { 450 return err 451 } 452 err = d.dumpNumber(version.LUAC_NUM) 453 454 return 455 } 456 457 func makeInt(size int) (f func(*dumper, int) error) { 458 switch size { 459 case 1: 460 f = func(d *dumper, x int) error { 461 if x < limits.MinInt8 || x > limits.MaxInt8 { 462 return errIntegerOverflow 463 } 464 return binary.Write(d.w, d.cfg.ByteOrder, int8(x)) 465 } 466 case 2: 467 f = func(d *dumper, x int) error { 468 if x < limits.MinInt16 || x > limits.MaxInt16 { 469 return errIntegerOverflow 470 } 471 return binary.Write(d.w, d.cfg.ByteOrder, int16(x)) 472 } 473 case 4: 474 f = func(d *dumper, x int) error { 475 if x < limits.MinInt32 || x > limits.MaxInt32 { 476 return errIntegerOverflow 477 } 478 return binary.Write(d.w, d.cfg.ByteOrder, int32(x)) 479 } 480 case 8: 481 f = func(d *dumper, x int) error { 482 return binary.Write(d.w, d.cfg.ByteOrder, int64(x)) 483 } 484 default: 485 panic("unreachable") 486 } 487 488 return 489 } 490 491 func makeInteger(size int) (f func(*dumper, object.Integer) error) { 492 switch size { 493 case 1: 494 f = func(d *dumper, x object.Integer) error { 495 if x < limits.MinInt8 || x > limits.MaxInt8 { 496 return errIntegerOverflow 497 } 498 return binary.Write(d.w, d.cfg.ByteOrder, int8(x)) 499 } 500 case 2: 501 f = func(d *dumper, x object.Integer) error { 502 if x < limits.MinInt16 || x > limits.MaxInt16 { 503 return errIntegerOverflow 504 } 505 return binary.Write(d.w, d.cfg.ByteOrder, int16(x)) 506 } 507 case 4: 508 f = func(d *dumper, x object.Integer) error { 509 if x < limits.MinInt32 || x > limits.MaxInt32 { 510 return errIntegerOverflow 511 } 512 return binary.Write(d.w, d.cfg.ByteOrder, int32(x)) 513 } 514 case 8: 515 f = func(d *dumper, x object.Integer) error { 516 return binary.Write(d.w, d.cfg.ByteOrder, int64(x)) 517 } 518 default: 519 panic("unreachable") 520 } 521 522 return 523 } 524 525 func makeNumber(size int) (f func(*dumper, object.Number) error) { 526 switch size { 527 case 4: 528 f = func(d *dumper, x object.Number) error { 529 abs := x 530 if x < 0 { 531 abs = -x 532 } 533 534 if abs > limits.MaxFloat32 { 535 return errFloatOverflow 536 } 537 538 if abs < limits.SmallestNonzeroFloat32 { 539 return errFloatUnderflow 540 } 541 542 return binary.Write(d.w, d.cfg.ByteOrder, float32(x)) 543 } 544 case 8: 545 f = func(d *dumper, x object.Number) error { 546 return binary.Write(d.w, d.cfg.ByteOrder, float64(x)) 547 } 548 default: 549 panic("unreachable") 550 } 551 552 return 553 }