github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/codegen/optimize.go (about) 1 package codegen 2 3 import ( 4 "github.com/hirochachacha/plua/compiler/ast" 5 "github.com/hirochachacha/plua/compiler/token" 6 "github.com/hirochachacha/plua/internal/arith" 7 "github.com/hirochachacha/plua/object" 8 "github.com/hirochachacha/plua/opcode" 9 ) 10 11 // constant folding 12 13 func (g *generator) foldExpr(expr ast.Expr) (val object.Value, ok bool) { 14 if skipConstantFolding { 15 return nil, false 16 } 17 18 switch expr := expr.(type) { 19 case *ast.ParenExpr: 20 return g.foldExpr(expr.X) 21 case *ast.BasicLit: 22 return g.foldBasic(expr) 23 case *ast.UnaryExpr: 24 return g.foldUnary(expr) 25 case *ast.BinaryExpr: 26 return g.foldBinary(expr) 27 } 28 29 return nil, false 30 } 31 32 func (g *generator) foldBasic(expr *ast.BasicLit) (val object.Value, ok bool) { 33 if skipConstantFolding { 34 return nil, false 35 } 36 37 g.tokLine = expr.Pos().Line 38 39 if c, ok := g.cfolds[expr]; ok { 40 return c, true 41 } 42 43 tok := expr.Token 44 45 switch tok.Type { 46 case token.NIL: 47 val = nil 48 case token.FALSE: 49 val = object.False 50 case token.TRUE: 51 val = object.True 52 case token.INT: 53 if i, ok := g.parseInteger(tok, false); ok { 54 val = i 55 } else { 56 val = g.parseNumber(tok, false) 57 } 58 case token.FLOAT: 59 val = g.parseNumber(tok, false) 60 case token.STRING: 61 val = object.String(g.unquoteString(tok)) 62 default: 63 panic("unreachable") 64 } 65 66 g.cfolds[expr] = val 67 68 return val, true 69 } 70 71 func (g *generator) foldUnary(expr *ast.UnaryExpr) (val object.Value, ok bool) { 72 if skipConstantFolding { 73 return nil, false 74 } 75 76 g.tokLine = expr.Pos().Line 77 78 if c, ok := g.cfolds[expr]; ok { 79 return c, c != nil 80 } 81 82 if expr.Op == token.UNM { 83 if x, ok := expr.X.(*ast.BasicLit); ok { 84 tok := x.Token 85 86 switch tok.Type { 87 case token.INT: 88 var val object.Value 89 90 if i, ok := g.parseInteger(tok, true); ok { 91 val = i 92 } else { 93 val = g.parseNumber(tok, true) 94 } 95 96 g.cfolds[expr] = val 97 98 return val, true 99 case token.FLOAT: 100 val := g.parseNumber(tok, true) 101 102 g.cfolds[expr] = val 103 104 return val, true 105 } 106 } 107 } 108 109 switch expr.Op { 110 case token.UNM: 111 if x, ok := g.foldExpr(expr.X); ok { 112 if unm := arith.Unm(x); unm != nil { 113 val = unm 114 } 115 } 116 case token.BNOT: 117 if x, ok := g.foldExpr(expr.X); ok { 118 if bnot := arith.Bnot(x); bnot != nil { 119 val = bnot 120 } 121 } 122 case token.NOT: 123 if x, ok := g.foldExpr(expr.X); ok { 124 if not := arith.Not(x); not != nil { 125 val = not 126 } 127 } 128 case token.LEN: 129 x := expr.X 130 131 for { 132 paren, ok := x.(*ast.ParenExpr) 133 if !ok { 134 break 135 } 136 x = paren.X 137 } 138 139 switch x := x.(type) { 140 case *ast.BasicLit: 141 tok := x.Token 142 if tok.Type == token.STRING { 143 val = object.Integer(len(g.unquoteString(tok))) 144 } 145 case *ast.TableLit: 146 var a []ast.Expr 147 for _, e := range x.Fields { 148 if _, ok := e.(*ast.KeyValueExpr); !ok { 149 if _, ok := g.foldExpr(e); !ok { 150 g.cfolds[expr] = nil 151 152 return nil, false 153 } 154 a = append(a, e) 155 } 156 } 157 158 for len(a) > 0 { 159 if lit, ok := a[len(a)-1].(*ast.BasicLit); ok && lit.Token.Type == token.NIL { 160 a = a[:len(a)-1] 161 162 continue 163 } 164 165 break 166 } 167 168 val = object.Integer(len(a)) 169 } 170 default: 171 panic("unreachable") 172 } 173 174 g.cfolds[expr] = val 175 176 return val, val != nil 177 } 178 179 func (g *generator) foldBinary(expr *ast.BinaryExpr) (val object.Value, ok bool) { 180 if skipConstantFolding { 181 return nil, false 182 } 183 184 g.tokLine = expr.Pos().Line 185 186 if c, ok := g.cfolds[expr]; ok { 187 return c, c != nil 188 } 189 190 switch expr.Op { 191 case token.EQ: 192 if x, ok := g.foldExpr(expr.X); ok { 193 if y, ok := g.foldExpr(expr.Y); ok { 194 if b := arith.Equal(x, y); b != nil { 195 val = b 196 } 197 } 198 } 199 case token.NE: 200 if x, ok := g.foldExpr(expr.X); ok { 201 if y, ok := g.foldExpr(expr.Y); ok { 202 if b := arith.NotEqual(x, y); b != nil { 203 val = b 204 } 205 } 206 } 207 case token.LT: 208 if x, ok := g.foldExpr(expr.X); ok { 209 if y, ok := g.foldExpr(expr.Y); ok { 210 if b := arith.LessThan(x, y); b != nil { 211 val = b 212 } 213 } 214 } 215 case token.LE: 216 if x, ok := g.foldExpr(expr.X); ok { 217 if y, ok := g.foldExpr(expr.Y); ok { 218 if b := arith.LessThanOrEqualTo(x, y); b != nil { 219 val = b 220 } 221 } 222 } 223 case token.GT: 224 if x, ok := g.foldExpr(expr.X); ok { 225 if y, ok := g.foldExpr(expr.Y); ok { 226 if b := arith.LessThan(y, x); b != nil { 227 val = b 228 } 229 } 230 } 231 case token.GE: 232 if x, ok := g.foldExpr(expr.X); ok { 233 if y, ok := g.foldExpr(expr.Y); ok { 234 if b := arith.LessThanOrEqualTo(y, x); b != nil { 235 val = b 236 } 237 } 238 } 239 240 case token.ADD: 241 if x, ok := g.foldExpr(expr.X); ok { 242 if y, ok := g.foldExpr(expr.Y); ok { 243 if sum := arith.Add(x, y); sum != nil { 244 val = sum 245 } 246 } 247 } 248 case token.SUB: 249 if x, ok := g.foldExpr(expr.X); ok { 250 if y, ok := g.foldExpr(expr.Y); ok { 251 if diff := arith.Sub(x, y); diff != nil { 252 val = diff 253 } 254 } 255 } 256 case token.MUL: 257 if x, ok := g.foldExpr(expr.X); ok { 258 if y, ok := g.foldExpr(expr.Y); ok { 259 if prod := arith.Mul(x, y); prod != nil { 260 val = prod 261 } 262 } 263 } 264 case token.MOD: 265 if x, ok := g.foldExpr(expr.X); ok { 266 if y, ok := g.foldExpr(expr.Y); ok { 267 if rem, _ := arith.Mod(x, y); rem != nil { 268 val = rem 269 } 270 } 271 } 272 case token.POW: 273 if x, ok := g.foldExpr(expr.X); ok { 274 if y, ok := g.foldExpr(expr.Y); ok { 275 if prod := arith.Pow(x, y); prod != nil { 276 val = prod 277 } 278 } 279 } 280 case token.DIV: 281 if x, ok := g.foldExpr(expr.X); ok { 282 if y, ok := g.foldExpr(expr.Y); ok { 283 if quo := arith.Div(x, y); quo != nil { 284 val = quo 285 } 286 } 287 } 288 case token.IDIV: 289 if x, ok := g.foldExpr(expr.X); ok { 290 if y, ok := g.foldExpr(expr.Y); ok { 291 if quo, _ := arith.Idiv(x, y); quo != nil { 292 val = quo 293 } 294 } 295 } 296 case token.BAND: 297 if x, ok := g.foldExpr(expr.X); ok { 298 if y, ok := g.foldExpr(expr.Y); ok { 299 if band := arith.Band(x, y); band != nil { 300 val = band 301 } 302 } 303 } 304 case token.BOR: 305 if x, ok := g.foldExpr(expr.X); ok { 306 if y, ok := g.foldExpr(expr.Y); ok { 307 if bor := arith.Bor(x, y); bor != nil { 308 val = bor 309 } 310 } 311 } 312 case token.BXOR: 313 if x, ok := g.foldExpr(expr.X); ok { 314 if y, ok := g.foldExpr(expr.Y); ok { 315 if bxor := arith.Bxor(x, y); bxor != nil { 316 val = bxor 317 } 318 } 319 } 320 case token.SHL: 321 if x, ok := g.foldExpr(expr.X); ok { 322 if y, ok := g.foldExpr(expr.Y); ok { 323 if shl := arith.Shl(x, y); shl != nil { 324 val = shl 325 } 326 } 327 } 328 case token.SHR: 329 if x, ok := g.foldExpr(expr.X); ok { 330 if y, ok := g.foldExpr(expr.Y); ok { 331 if shr := arith.Shr(x, y); shr != nil { 332 val = shr 333 } 334 } 335 } 336 case token.CONCAT: 337 if x, ok := g.foldExpr(expr.X); ok { 338 if y, ok := g.foldExpr(expr.Y); ok { 339 if con := arith.Concat(x, y); con != nil { 340 val = con 341 } 342 } 343 } 344 case token.AND: 345 if x, ok := g.foldExpr(expr.X); ok { 346 if object.ToBoolean(x) { 347 return g.foldExpr(expr.Y) 348 } 349 350 return x, true 351 } 352 case token.OR: 353 if x, ok := g.foldExpr(expr.X); ok { 354 if object.ToBoolean(x) { 355 return x, true 356 } 357 358 return g.foldExpr(expr.Y) 359 } 360 default: 361 panic("unreachable") 362 } 363 364 g.cfolds[expr] = val 365 366 return val, val != nil 367 } 368 369 // peep hole optimization 370 371 // optimize load to same address twice 372 func (g *generator) peepLoad(i0 opcode.Instruction, i opcode.Instruction) bool { 373 a := i.A() 374 375 switch i0.OpCode() { 376 case opcode.MOVE, opcode.LOADK, opcode.GETUPVAL, opcode.NEWTABLE, opcode.CLOSURE: 377 378 a0 := i0.A() 379 380 if a0 == a { // local x = any; local x = 1 => local x = 1 381 return true 382 } 383 case opcode.LOADBOOL: 384 c0 := i0.C() 385 386 if c0 == 0 { 387 a0 := i0.A() 388 389 if a0 == a { // local x = true; local x = 1 => local x = 1 390 return true 391 } 392 } 393 case opcode.LOADNIL: 394 a0 := i0.A() 395 b0 := i0.B() 396 397 if a0 == a && b0 == 0 { // local x = nil; local x = 1 => local x = 1 398 return true 399 } 400 } 401 402 return false 403 } 404 405 func (g *generator) peepLine(i opcode.Instruction, line int) { 406 var offset int 407 var i0 opcode.Instruction 408 409 for { 410 if len(g.Code) > offset { 411 i0 = g.Code[len(g.Code)-offset-1] 412 op0 := i0.OpCode() 413 414 switch op := i.OpCode(); op { 415 case opcode.LOADNIL: 416 a := i.A() 417 b := i.B() 418 419 switch op0 { 420 case opcode.MOVE, opcode.LOADK, opcode.GETUPVAL, opcode.NEWTABLE, opcode.CLOSURE: 421 a0 := i0.A() 422 423 if a <= a0 && a0 <= a+b { // local x = any; x = nil => local x = nil 424 offset++ 425 426 continue 427 } 428 case opcode.LOADBOOL: 429 c0 := i0.C() 430 431 if c0 == 0 { 432 a0 := i0.A() 433 434 if a <= a0 && a0 <= a+b { // local x = true; x = nil => local x = nil 435 offset++ 436 437 continue 438 } 439 } 440 case opcode.LOADNIL: 441 a0 := i0.A() 442 b0 := i0.B() 443 444 // local x = nil; x = nil => local x = nil 445 switch { 446 case a0 < a: 447 if a <= a0+b0 { 448 if a+b > a0+b0 { 449 i = opcode.AB(opcode.LOADNIL, a0, a+b-a0) 450 451 offset++ 452 453 continue 454 } 455 456 g.Code = g.Code[:len(g.Code)-offset] 457 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 458 459 return 460 } 461 462 if a == a0+b0+1 { 463 i = opcode.AB(opcode.LOADNIL, a0, a+b-a0) 464 465 offset++ 466 467 continue 468 } 469 470 if a == a0+1 { 471 i = opcode.AB(opcode.LOADNIL, a0, a+b-a0) 472 473 offset++ 474 475 continue 476 } 477 case a < a0: 478 if a0 <= a+b { 479 if a+b > a0+b0 { 480 offset++ 481 482 continue 483 } 484 485 i = opcode.AB(opcode.LOADNIL, a, a0+b0-a) 486 487 offset++ 488 489 continue 490 } 491 492 if a0 == a+b+1 { 493 i = opcode.AB(opcode.LOADNIL, a, a0+b0-a) 494 495 offset++ 496 497 continue 498 } 499 500 if a0 == a+1 { 501 i = opcode.AB(opcode.LOADNIL, a, a0+b0-a) 502 503 offset++ 504 505 continue 506 } 507 default: // a == a0 508 if b > b0 { 509 offset++ 510 511 continue 512 } 513 514 g.Code = g.Code[:len(g.Code)-offset] 515 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 516 517 return 518 } 519 } 520 case opcode.MOVE: 521 a := i.A() 522 b := i.B() 523 524 if a == b { // local x = local x => none 525 g.Code = g.Code[:len(g.Code)-offset] 526 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 527 528 return 529 } 530 531 if g.peepLoad(i0, i) { 532 offset++ 533 534 continue 535 } 536 537 switch op0 { 538 case opcode.MOVE: 539 a0 := i0.A() 540 b0 := i0.B() 541 542 if a0 == b { 543 if b0 == a { // local x = local y; y = x => local x = local y 544 g.Code = g.Code[:len(g.Code)-offset] 545 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 546 547 return 548 } 549 550 if !g.locktmp && a0 >= g.nlocals { // tmp x = local y; local z = tmp x => local z = local y 551 b0 := i0.B() 552 553 i = opcode.AB(op0, a, b0) 554 555 offset++ 556 557 continue 558 } 559 } 560 case opcode.LOADK: 561 a0 := i0.A() 562 563 if !g.locktmp && a0 >= g.nlocals { 564 if a0 == b { // tmp x = 1; local z = tmp x => local z = 1 565 bx0 := i0.Bx() 566 567 i = opcode.ABx(op0, a, bx0) 568 569 offset++ 570 571 continue 572 } 573 } 574 case opcode.LOADBOOL: 575 c0 := i0.C() 576 577 if c0 == 0 { 578 a0 := i0.A() 579 580 if !g.locktmp && a0 >= g.nlocals { 581 if a0 == b { // tmp x = true; local z = tmp x => local z = true 582 b0 := i0.B() 583 584 i = opcode.ABC(op0, a, b0, 0) 585 586 offset++ 587 588 continue 589 } 590 } 591 } 592 case opcode.LOADNIL: 593 a0 := i0.A() 594 b0 := i0.B() 595 596 if a0 <= b && b <= a0+b0 { 597 if a0 <= a && a <= a0+b0 { 598 g.Code = g.Code[:len(g.Code)-offset] 599 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 600 601 return 602 } 603 604 if a == a0-1 { 605 i = opcode.AB(op0, a, a0+b0-a) 606 607 offset++ 608 609 continue 610 } 611 612 if a == a0+b0+1 { 613 i = opcode.AB(op0, a0, b0+1) 614 615 offset++ 616 617 continue 618 } 619 620 if !g.locktmp && a0 >= g.nlocals { 621 if b0 == 0 { // tmp x = nil; local z = tmp x => local z = nil 622 i = opcode.AB(op0, a, 0) 623 624 offset++ 625 626 continue 627 } 628 } 629 } 630 case opcode.GETUPVAL: 631 a0 := i0.A() 632 633 if !g.locktmp && a0 >= g.nlocals { 634 if a0 == b { // tmp x = lexical y; local z = tmp x => local z = lexical y 635 b0 := i0.B() 636 637 i = opcode.AB(op0, a, b0) 638 639 offset++ 640 641 continue 642 } 643 } 644 case opcode.GETTABLE: 645 a0 := i0.A() 646 647 if !g.locktmp && a0 >= g.nlocals { 648 if a0 == b { // tmp x = y.foo; local z = tmp x => local z = y.foo 649 b0 := i0.B() 650 c0 := i0.C() 651 652 i = opcode.ABC(op0, a, b0, c0) 653 654 offset++ 655 656 continue 657 } 658 } 659 case opcode.GETTABUP: 660 a0 := i0.A() 661 662 if !g.locktmp && a0 >= g.nlocals { 663 if a0 == b { // tmp x = global y; local z = tmp x => local z = global y 664 b0 := i0.B() 665 c0 := i0.C() 666 667 i = opcode.ABC(op0, a, b0, c0) 668 669 offset++ 670 671 continue 672 } 673 } 674 case opcode.NEWTABLE: 675 a0 := i0.A() 676 677 if !g.locktmp && a0 >= g.nlocals { 678 if a0 == b { // tmp x = <table>; local z = tmp x => local z = <table> 679 b0 := i0.B() 680 c0 := i0.C() 681 682 i = opcode.ABC(op0, a, b0, c0) 683 684 offset++ 685 686 continue 687 } 688 } 689 case opcode.CLOSURE: 690 a0 := i0.A() 691 692 if !g.locktmp && a0 >= g.nlocals { 693 if a0 == b { // tmp x = <func>; local z = tmp x => local z = <func> 694 bx0 := i0.Bx() 695 696 i = opcode.ABx(op0, a, bx0) 697 698 offset++ 699 700 continue 701 } 702 } 703 case opcode.UNM, opcode.BNOT, opcode.NOT, opcode.LEN: 704 a0 := i0.A() 705 706 if !g.locktmp && a0 >= g.nlocals { 707 if a0 == b { // tmp x = - local y; local z = tmp x => local z = - local y 708 b0 := i0.B() 709 710 i = opcode.AB(op0, a, b0) 711 712 offset++ 713 714 continue 715 } 716 } 717 case opcode.ADD, opcode.SUB, opcode.MUL, opcode.MOD, opcode.POW, opcode.DIV, 718 opcode.IDIV, opcode.BAND, opcode.BOR, opcode.BXOR, opcode.SHL, opcode.SHR: 719 a0 := i0.A() 720 721 if !g.locktmp && a0 >= g.nlocals { 722 if a0 == b { // tmp x = tmp y + tmp z; local w = tmp x => local w = tmp y + tmp z 723 b0 := i0.B() 724 c0 := i0.C() 725 726 i = opcode.ABC(op0, a, b0, c0) 727 728 offset++ 729 730 continue 731 } 732 } 733 case opcode.CONCAT: 734 a0 := i0.A() 735 736 if !g.locktmp && a0 >= g.nlocals { 737 if a0 == b { // tmp x = - local y; local z = tmp x => local z = - local y 738 b0 := i0.B() 739 c0 := i0.C() 740 741 i = opcode.ABC(op0, a, b0, c0) 742 743 offset++ 744 745 continue 746 } 747 } 748 } 749 case opcode.LOADBOOL: 750 c0 := i0.C() 751 752 if c0 == 0 { 753 if g.peepLoad(i0, i) { 754 offset++ 755 756 continue 757 } 758 } 759 case opcode.LOADK, opcode.NEWTABLE, opcode.CLOSURE: 760 if g.peepLoad(i0, i) { 761 offset++ 762 763 continue 764 } 765 case opcode.GETUPVAL: 766 if g.peepLoad(i0, i) { 767 offset++ 768 769 continue 770 } 771 772 a := i.A() 773 b := i.B() 774 775 switch op0 { 776 case opcode.SETUPVAL: 777 a0 := i0.A() 778 b0 := i0.B() 779 780 if a0 == a && b0 == b { // lexical x = local y; local y = lexical x => lexical x = local y 781 g.Code = g.Code[:len(g.Code)-offset] 782 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 783 784 return 785 } 786 } 787 case opcode.GETTABUP: 788 a := i.A() 789 c := i.C() 790 791 if a != c { 792 if g.peepLoad(i0, i) { 793 offset++ 794 795 continue 796 } 797 } 798 case opcode.GETTABLE: 799 a := i.A() 800 b := i.B() 801 c := i.C() 802 803 if a != b && a != c { 804 if g.peepLoad(i0, i) { 805 offset++ 806 807 continue 808 } 809 } 810 811 switch op0 { 812 case opcode.GETUPVAL: 813 a0 := i0.A() 814 815 if a0 == a { 816 b0 := i0.B() 817 818 i = opcode.ABC(opcode.GETTABUP, a, b0, c) 819 820 offset++ 821 822 continue 823 } 824 825 if !g.locktmp && a0 >= g.nlocals { 826 if a0 == b { // tmp x = lexical env; local z = (tmp x).foo => local z = global foo 827 b0 := i0.B() 828 829 i = opcode.ABC(opcode.GETTABUP, a, b0, c) 830 831 offset++ 832 833 continue 834 } 835 } 836 } 837 case opcode.ADD, opcode.SUB, opcode.MUL, opcode.MOD, opcode.POW, 838 opcode.DIV, opcode.IDIV, opcode.BAND, opcode.BOR, opcode.BXOR, opcode.SHL, opcode.SHR: 839 a := i.A() 840 b := i.B() 841 c := i.C() 842 843 if a != b && a != c { 844 if g.peepLoad(i0, i) { 845 offset++ 846 847 continue 848 } 849 } 850 case opcode.UNM, opcode.BNOT, opcode.NOT, opcode.LEN: 851 a := i.A() 852 b := i.B() 853 854 if a != b { 855 if g.peepLoad(i0, i) { 856 offset++ 857 858 continue 859 } 860 } 861 case opcode.SETUPVAL: 862 a := i.A() 863 b := i.B() 864 865 switch op0 { 866 case opcode.MOVE: 867 a0 := i0.A() 868 869 if a == a0 { 870 if !g.locktmp && a >= g.nlocals { 871 b0 := i0.B() 872 873 i = opcode.AB(opcode.SETUPVAL, b0, b) 874 875 offset++ 876 877 continue 878 } 879 } 880 case opcode.SETUPVAL: 881 b0 := i0.B() 882 883 if b0 == b { // lexical x = local y; lexical x = local z => lexical x = local z 884 offset++ 885 886 continue 887 } 888 case opcode.GETUPVAL: 889 a0 := i0.A() 890 b0 := i0.B() 891 892 if a0 == a && b0 == b { // lexical x = local y; local y = lexical x => lexical x = local y 893 g.Code = g.Code[:len(g.Code)-offset] 894 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 895 896 return 897 } 898 } 899 case opcode.SETTABLE: 900 a := i.A() 901 b := i.B() 902 c := i.C() 903 904 switch op0 { 905 case opcode.MOVE: 906 a0 := i0.A() 907 908 if a0 == c { 909 a := i.A() 910 b := i.B() 911 b0 := i0.B() 912 913 i = opcode.ABC(op, a, b, b0) 914 915 offset++ 916 917 continue 918 } 919 case opcode.LOADK: 920 a0 := i0.A() 921 bx0 := i0.Bx() 922 923 if bx0 <= opcode.MaxRKIndex && a0 == c { 924 a := i.A() 925 b := i.B() 926 927 i = opcode.ABC(op, a, b, bx0|opcode.BitRK) 928 929 offset++ 930 931 continue 932 } 933 case opcode.GETUPVAL: 934 a0 := i0.A() 935 936 if !g.locktmp && a0 >= g.nlocals { 937 if a0 == a { // tmp x = lexical env; (tmp x).foo = local z => global foo = local z 938 b0 := i0.B() 939 940 i = opcode.ABC(opcode.SETTABUP, b0, b, c) 941 942 offset++ 943 944 continue 945 } 946 } 947 } 948 case opcode.SETTABUP: 949 c := i.C() 950 951 switch op0 { 952 case opcode.MOVE: 953 a0 := i0.A() 954 955 if a0 == c { 956 a := i.A() 957 b := i.B() 958 b0 := i0.B() 959 960 i = opcode.ABC(op, a, b, b0) 961 962 offset++ 963 964 continue 965 } 966 case opcode.LOADK: 967 a0 := i0.A() 968 bx0 := i0.Bx() 969 970 if bx0 <= opcode.MaxRKIndex && a0 == c { 971 a := i.A() 972 b := i.B() 973 974 i = opcode.ABC(op, a, b, bx0|opcode.BitRK) 975 976 offset++ 977 978 continue 979 } 980 } 981 case opcode.JMP: 982 a := i.A() 983 b := i.B() 984 985 if a == 0 && b == 0 { 986 g.Code = g.Code[:len(g.Code)-offset] 987 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset] 988 989 return 990 } 991 } 992 993 if offset == 0 { 994 g.Code = append(g.Code, i) 995 g.LineInfo = append(g.LineInfo, line) 996 } else { 997 g.Code[len(g.Code)-offset] = i 998 g.LineInfo[len(g.LineInfo)-offset] = line 999 1000 g.Code = g.Code[:len(g.Code)-offset+1] 1001 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset+1] 1002 } 1003 1004 return 1005 1006 } 1007 1008 if offset == 0 { 1009 g.Code = append(g.Code, i) 1010 g.LineInfo = append(g.LineInfo, line) 1011 } else { 1012 g.Code[len(g.Code)-offset] = i 1013 g.LineInfo[len(g.LineInfo)-offset] = line 1014 1015 g.Code = g.Code[:len(g.Code)-offset+1] 1016 g.LineInfo = g.LineInfo[:len(g.LineInfo)-offset+1] 1017 } 1018 1019 return 1020 } 1021 }