github.com/enotodden/gopher-lua@v1.1.2/_vm.go (about) 1 package lua 2 3 import ( 4 "fmt" 5 "math" 6 "strings" 7 ) 8 9 func mainLoop(L *LState, baseframe *callFrame) { 10 var inst uint32 11 var cf *callFrame 12 13 if L.stack.IsEmpty() { 14 return 15 } 16 17 L.currentFrame = L.stack.Last() 18 if L.currentFrame.Fn.IsG { 19 callGFunction(L, false) 20 return 21 } 22 23 for { 24 cf = L.currentFrame 25 inst = cf.Fn.Proto.Code[cf.Pc] 26 cf.Pc++ 27 if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { 28 return 29 } 30 } 31 } 32 33 func mainLoopWithContext(L *LState, baseframe *callFrame) { 34 var inst uint32 35 var cf *callFrame 36 37 if L.stack.IsEmpty() { 38 return 39 } 40 41 L.currentFrame = L.stack.Last() 42 if L.currentFrame.Fn.IsG { 43 callGFunction(L, false) 44 return 45 } 46 47 for { 48 cf = L.currentFrame 49 inst = cf.Fn.Proto.Code[cf.Pc] 50 cf.Pc++ 51 select { 52 case <-L.ctx.Done(): 53 L.RaiseError(L.ctx.Err().Error()) 54 return 55 default: 56 if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { 57 return 58 } 59 } 60 } 61 } 62 63 // regv is the first target register to copy the return values to. 64 // It can be reg.top, indicating that the copied values are going into new registers, or it can be below reg.top 65 // Indicating that the values should be within the existing registers. 66 // b is the available number of return values + 1. 67 // n is the desired number of return values. 68 // If n more than the available return values then the extra values are set to nil. 69 // When this function returns the top of the registry will be set to regv+n. 70 func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start 71 if b == 1 { 72 // +inline-call L.reg.FillNil regv n 73 } else { 74 // +inline-call L.reg.CopyRange regv start -1 n 75 if b > 1 && n > (b-1) { 76 // +inline-call L.reg.FillNil regv+b-1 n-(b-1) 77 } 78 } 79 } // +inline-end 80 81 func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) { 82 parent := L.Parent 83 if parent == nil { 84 L.RaiseError("can not yield from outside of a coroutine") 85 } 86 L.G.CurrentThread = parent 87 L.Parent = nil 88 if !L.wrapped { 89 if haserror { 90 parent.Push(LFalse) 91 } else { 92 parent.Push(LTrue) 93 } 94 } 95 L.XMoveTo(parent, nargs) 96 L.stack.Pop() 97 offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase 98 L.currentFrame = L.stack.Last() 99 L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions) 100 if kill { 101 L.kill() 102 } 103 } 104 105 func callGFunction(L *LState, tailcall bool) bool { 106 frame := L.currentFrame 107 gfnret := frame.Fn.GFunction(L) 108 if tailcall { 109 L.currentFrame = L.RemoveCallerFrame() 110 } 111 112 if gfnret < 0 { 113 switchToParentThread(L, L.GetTop(), false, false) 114 return true 115 } 116 117 wantret := frame.NRet 118 if wantret == MultRet { 119 wantret = gfnret 120 } 121 122 if tailcall && L.Parent != nil && L.stack.Sp() == 1 { 123 switchToParentThread(L, wantret, false, true) 124 return true 125 } 126 127 // +inline-call L.reg.CopyRange frame.ReturnBase L.reg.Top()-gfnret -1 wantret 128 L.stack.Pop() 129 L.currentFrame = L.stack.Last() 130 return false 131 } 132 133 func threadRun(L *LState) { 134 if L.stack.IsEmpty() { 135 return 136 } 137 138 defer func() { 139 if rcv := recover(); rcv != nil { 140 var lv LValue 141 if v, ok := rcv.(*ApiError); ok { 142 lv = v.Object 143 } else { 144 lv = LString(fmt.Sprint(rcv)) 145 } 146 if parent := L.Parent; parent != nil { 147 if L.wrapped { 148 L.Push(lv) 149 parent.Panic(L) 150 } else { 151 L.SetTop(0) 152 L.Push(lv) 153 switchToParentThread(L, 1, true, true) 154 } 155 } else { 156 panic(rcv) 157 } 158 } 159 }() 160 L.mainLoop(L, nil) 161 } 162 163 type instFunc func(*LState, uint32, *callFrame) int 164 165 var jumpTable [opCodeMax + 1]instFunc 166 167 func init() { 168 jumpTable = [opCodeMax + 1]instFunc{ 169 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_MOVE 170 reg := L.reg 171 cf := L.currentFrame 172 lbase := cf.LocalBase 173 A := int(inst>>18) & 0xff // GETA 174 RA := lbase + A 175 B := int(inst & 0x1ff) // GETB 176 v := reg.Get(lbase + B) 177 // +inline-call reg.Set RA v 178 return 0 179 }, 180 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_MOVEN 181 reg := L.reg 182 cf := L.currentFrame 183 lbase := cf.LocalBase 184 A := int(inst>>18) & 0xff // GETA 185 B := int(inst & 0x1ff) // GETB 186 C := int(inst>>9) & 0x1ff // GETC 187 v := reg.Get(lbase + B) 188 // +inline-call reg.Set lbase+A v 189 code := cf.Fn.Proto.Code 190 pc := cf.Pc 191 for i := 0; i < C; i++ { 192 inst = code[pc] 193 pc++ 194 A = int(inst>>18) & 0xff // GETA 195 B = int(inst & 0x1ff) // GETB 196 v := reg.Get(lbase + B) 197 // +inline-call reg.Set lbase+A v 198 } 199 cf.Pc = pc 200 return 0 201 }, 202 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LOADK 203 reg := L.reg 204 cf := L.currentFrame 205 lbase := cf.LocalBase 206 A := int(inst>>18) & 0xff // GETA 207 RA := lbase + A 208 Bx := int(inst & 0x3ffff) // GETBX 209 v := cf.Fn.Proto.Constants[Bx] 210 // +inline-call reg.Set RA v 211 return 0 212 }, 213 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LOADBOOL 214 reg := L.reg 215 cf := L.currentFrame 216 lbase := cf.LocalBase 217 A := int(inst>>18) & 0xff // GETA 218 RA := lbase + A 219 B := int(inst & 0x1ff) // GETB 220 C := int(inst>>9) & 0x1ff // GETC 221 if B != 0 { 222 // +inline-call reg.Set RA LTrue 223 } else { 224 // +inline-call reg.Set RA LFalse 225 } 226 if C != 0 { 227 cf.Pc++ 228 } 229 return 0 230 }, 231 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LOADNIL 232 reg := L.reg 233 cf := L.currentFrame 234 lbase := cf.LocalBase 235 A := int(inst>>18) & 0xff // GETA 236 RA := lbase + A 237 B := int(inst & 0x1ff) // GETB 238 for i := RA; i <= lbase+B; i++ { 239 // +inline-call reg.Set i LNil 240 } 241 return 0 242 }, 243 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_GETUPVAL 244 reg := L.reg 245 cf := L.currentFrame 246 lbase := cf.LocalBase 247 A := int(inst>>18) & 0xff // GETA 248 RA := lbase + A 249 B := int(inst & 0x1ff) // GETB 250 v := cf.Fn.Upvalues[B].Value() 251 // +inline-call reg.Set RA v 252 return 0 253 }, 254 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_GETGLOBAL 255 reg := L.reg 256 cf := L.currentFrame 257 lbase := cf.LocalBase 258 A := int(inst>>18) & 0xff // GETA 259 RA := lbase + A 260 Bx := int(inst & 0x3ffff) // GETBX 261 // reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) 262 v := L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx]) 263 // +inline-call reg.Set RA v 264 return 0 265 }, 266 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_GETTABLE 267 reg := L.reg 268 cf := L.currentFrame 269 lbase := cf.LocalBase 270 A := int(inst>>18) & 0xff // GETA 271 RA := lbase + A 272 B := int(inst & 0x1ff) // GETB 273 C := int(inst>>9) & 0x1ff // GETC 274 v := L.getField(reg.Get(lbase+B), L.rkValue(C)) 275 // +inline-call reg.Set RA v 276 return 0 277 }, 278 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_GETTABLEKS 279 reg := L.reg 280 cf := L.currentFrame 281 lbase := cf.LocalBase 282 A := int(inst>>18) & 0xff // GETA 283 RA := lbase + A 284 B := int(inst & 0x1ff) // GETB 285 C := int(inst>>9) & 0x1ff // GETC 286 v := L.getFieldString(reg.Get(lbase+B), L.rkString(C)) 287 // +inline-call reg.Set RA v 288 return 0 289 }, 290 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SETGLOBAL 291 reg := L.reg 292 cf := L.currentFrame 293 lbase := cf.LocalBase 294 A := int(inst>>18) & 0xff // GETA 295 RA := lbase + A 296 Bx := int(inst & 0x3ffff) // GETBX 297 // L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) 298 L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) 299 return 0 300 }, 301 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SETUPVAL 302 reg := L.reg 303 cf := L.currentFrame 304 lbase := cf.LocalBase 305 A := int(inst>>18) & 0xff // GETA 306 RA := lbase + A 307 B := int(inst & 0x1ff) // GETB 308 cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) 309 return 0 310 }, 311 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SETTABLE 312 reg := L.reg 313 cf := L.currentFrame 314 lbase := cf.LocalBase 315 A := int(inst>>18) & 0xff // GETA 316 RA := lbase + A 317 B := int(inst & 0x1ff) // GETB 318 C := int(inst>>9) & 0x1ff // GETC 319 L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) 320 return 0 321 }, 322 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SETTABLEKS 323 reg := L.reg 324 cf := L.currentFrame 325 lbase := cf.LocalBase 326 A := int(inst>>18) & 0xff // GETA 327 RA := lbase + A 328 B := int(inst & 0x1ff) // GETB 329 C := int(inst>>9) & 0x1ff // GETC 330 L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) 331 return 0 332 }, 333 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_NEWTABLE 334 reg := L.reg 335 cf := L.currentFrame 336 lbase := cf.LocalBase 337 A := int(inst>>18) & 0xff // GETA 338 RA := lbase + A 339 B := int(inst & 0x1ff) // GETB 340 C := int(inst>>9) & 0x1ff // GETC 341 v := newLTable(B, C) 342 // +inline-call reg.Set RA v 343 return 0 344 }, 345 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SELF 346 reg := L.reg 347 cf := L.currentFrame 348 lbase := cf.LocalBase 349 A := int(inst>>18) & 0xff // GETA 350 RA := lbase + A 351 B := int(inst & 0x1ff) // GETB 352 C := int(inst>>9) & 0x1ff // GETC 353 selfobj := reg.Get(lbase + B) 354 v := L.getFieldString(selfobj, L.rkString(C)) 355 // +inline-call reg.Set RA v 356 // +inline-call reg.Set RA+1 selfobj 357 return 0 358 }, 359 opArith, // OP_ADD 360 opArith, // OP_SUB 361 opArith, // OP_MUL 362 opArith, // OP_DIV 363 opArith, // OP_BITOR 364 opArith, // OP_MOD 365 opArith, // OP_POW 366 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_UNM 367 reg := L.reg 368 cf := L.currentFrame 369 lbase := cf.LocalBase 370 A := int(inst>>18) & 0xff // GETA 371 RA := lbase + A 372 B := int(inst & 0x1ff) // GETB 373 unaryv := L.rkValue(B) 374 if nm, ok := unaryv.(LNumber); ok { 375 // +inline-call reg.Set RA -nm 376 } else { 377 op := L.metaOp1(unaryv, "__unm") 378 if op.Type() == LTFunction { 379 reg.Push(op) 380 reg.Push(unaryv) 381 L.Call(1, 1) 382 // +inline-call reg.Set RA reg.Pop() 383 } else if str, ok1 := unaryv.(LString); ok1 { 384 if num, err := parseNumber(string(str)); err == nil { 385 // +inline-call reg.Set RA -num 386 } else { 387 L.RaiseError("__unm undefined") 388 } 389 } else { 390 L.RaiseError("__unm undefined") 391 } 392 } 393 return 0 394 }, 395 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_NOT 396 reg := L.reg 397 cf := L.currentFrame 398 lbase := cf.LocalBase 399 A := int(inst>>18) & 0xff // GETA 400 RA := lbase + A 401 B := int(inst & 0x1ff) // GETB 402 if LVIsFalse(reg.Get(lbase + B)) { 403 // +inline-call reg.Set RA LTrue 404 } else { 405 // +inline-call reg.Set RA LFalse 406 } 407 return 0 408 }, 409 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LEN 410 reg := L.reg 411 cf := L.currentFrame 412 lbase := cf.LocalBase 413 A := int(inst>>18) & 0xff // GETA 414 RA := lbase + A 415 B := int(inst & 0x1ff) // GETB 416 switch lv := L.rkValue(B).(type) { 417 case LString: 418 // +inline-call reg.SetNumber RA LNumber(len(lv)) 419 default: 420 op := L.metaOp1(lv, "__len") 421 if op.Type() == LTFunction { 422 reg.Push(op) 423 reg.Push(lv) 424 L.Call(1, 1) 425 ret := reg.Pop() 426 if ret.Type() == LTNumber { 427 v, _ := ret.(LNumber) 428 // +inline-call reg.SetNumber RA v 429 } else { 430 // +inline-call reg.Set RA ret 431 } 432 } else if lv.Type() == LTTable { 433 // +inline-call reg.SetNumber RA LNumber(lv.(*LTable).Len()) 434 } else { 435 L.RaiseError("__len undefined") 436 } 437 } 438 return 0 439 }, 440 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_CONCAT 441 reg := L.reg 442 cf := L.currentFrame 443 lbase := cf.LocalBase 444 A := int(inst>>18) & 0xff // GETA 445 RA := lbase + A 446 B := int(inst & 0x1ff) // GETB 447 C := int(inst>>9) & 0x1ff // GETC 448 RC := lbase + C 449 RB := lbase + B 450 v := stringConcat(L, RC-RB+1, RC) 451 // +inline-call reg.Set RA v 452 return 0 453 }, 454 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_JMP 455 cf := L.currentFrame 456 Sbx := int(inst&0x3ffff) - opMaxArgSbx // GETSBX 457 cf.Pc += Sbx 458 return 0 459 }, 460 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_EQ 461 cf := L.currentFrame 462 A := int(inst>>18) & 0xff // GETA 463 B := int(inst & 0x1ff) // GETB 464 C := int(inst>>9) & 0x1ff // GETC 465 ret := equals(L, L.rkValue(B), L.rkValue(C), false) 466 v := 1 467 if ret { 468 v = 0 469 } 470 if v == A { 471 cf.Pc++ 472 } 473 return 0 474 }, 475 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LT 476 cf := L.currentFrame 477 A := int(inst>>18) & 0xff // GETA 478 B := int(inst & 0x1ff) // GETB 479 C := int(inst>>9) & 0x1ff // GETC 480 ret := lessThan(L, L.rkValue(B), L.rkValue(C)) 481 v := 1 482 if ret { 483 v = 0 484 } 485 if v == A { 486 cf.Pc++ 487 } 488 return 0 489 }, 490 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_LE 491 cf := L.currentFrame 492 A := int(inst>>18) & 0xff // GETA 493 B := int(inst & 0x1ff) // GETB 494 C := int(inst>>9) & 0x1ff // GETC 495 lhs := L.rkValue(B) 496 rhs := L.rkValue(C) 497 ret := false 498 499 if v1, ok1 := lhs.(LNumber); ok1 { 500 if v2, ok2 := rhs.(LNumber); ok2 { 501 ret = v1 <= v2 502 } else { 503 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 504 } 505 } else { 506 if lhs.Type() != rhs.Type() { 507 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 508 } 509 switch lhs.Type() { 510 case LTString: 511 ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 512 default: 513 switch objectRational(L, lhs, rhs, "__le") { 514 case 1: 515 ret = true 516 case 0: 517 ret = false 518 default: 519 ret = !objectRationalWithError(L, rhs, lhs, "__lt") 520 } 521 } 522 } 523 524 v := 1 525 if ret { 526 v = 0 527 } 528 if v == A { 529 cf.Pc++ 530 } 531 return 0 532 }, 533 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_TEST 534 reg := L.reg 535 cf := L.currentFrame 536 lbase := cf.LocalBase 537 A := int(inst>>18) & 0xff // GETA 538 RA := lbase + A 539 C := int(inst>>9) & 0x1ff // GETC 540 if LVAsBool(reg.Get(RA)) == (C == 0) { 541 cf.Pc++ 542 } 543 return 0 544 }, 545 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_TESTSET 546 reg := L.reg 547 cf := L.currentFrame 548 lbase := cf.LocalBase 549 A := int(inst>>18) & 0xff // GETA 550 RA := lbase + A 551 B := int(inst & 0x1ff) // GETB 552 C := int(inst>>9) & 0x1ff // GETC 553 if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { 554 // +inline-call reg.Set RA value 555 } else { 556 cf.Pc++ 557 } 558 return 0 559 }, 560 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_CALL 561 reg := L.reg 562 cf := L.currentFrame 563 lbase := cf.LocalBase 564 A := int(inst>>18) & 0xff // GETA 565 RA := lbase + A 566 B := int(inst & 0x1ff) // GETB 567 C := int(inst>>9) & 0x1ff // GETC 568 nargs := B - 1 569 if B == 0 { 570 nargs = reg.Top() - (RA + 1) 571 } 572 lv := reg.Get(RA) 573 nret := C - 1 574 var callable *LFunction 575 var meta bool 576 if fn, ok := lv.(*LFunction); ok { 577 callable = fn 578 meta = false 579 } else { 580 callable, meta = L.metaCall(lv) 581 } 582 // +inline-call L.pushCallFrame callFrame{Fn:callable,Pc:0,Base:RA,LocalBase:RA+1,ReturnBase:RA,NArgs:nargs,NRet:nret,Parent:cf,TailCall:0} lv meta 583 if callable.IsG && callGFunction(L, false) { 584 return 1 585 } 586 return 0 587 }, 588 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_TAILCALL 589 reg := L.reg 590 cf := L.currentFrame 591 lbase := cf.LocalBase 592 A := int(inst>>18) & 0xff // GETA 593 RA := lbase + A 594 B := int(inst & 0x1ff) // GETB 595 nargs := B - 1 596 if B == 0 { 597 nargs = reg.Top() - (RA + 1) 598 } 599 lv := reg.Get(RA) 600 var callable *LFunction 601 var meta bool 602 if fn, ok := lv.(*LFunction); ok { 603 callable = fn 604 meta = false 605 } else { 606 callable, meta = L.metaCall(lv) 607 } 608 if callable == nil { 609 L.RaiseError("attempt to call a non-function object") 610 } 611 // +inline-call L.closeUpvalues lbase 612 if callable.IsG { 613 luaframe := cf 614 L.pushCallFrame(callFrame{ 615 Fn: callable, 616 Pc: 0, 617 Base: RA, 618 LocalBase: RA + 1, 619 ReturnBase: cf.ReturnBase, 620 NArgs: nargs, 621 NRet: cf.NRet, 622 Parent: cf, 623 TailCall: 0, 624 }, lv, meta) 625 if callGFunction(L, true) { 626 return 1 627 } 628 if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { 629 return 1 630 } 631 } else { 632 base := cf.Base 633 cf.Fn = callable 634 cf.Pc = 0 635 cf.Base = RA 636 cf.LocalBase = RA + 1 637 cf.ReturnBase = cf.ReturnBase 638 cf.NArgs = nargs 639 cf.NRet = cf.NRet 640 cf.TailCall++ 641 lbase := cf.LocalBase 642 if meta { 643 cf.NArgs++ 644 L.reg.Insert(lv, cf.LocalBase) 645 } 646 // +inline-call L.initCallFrame cf 647 // +inline-call L.reg.CopyRange base RA -1 reg.Top()-RA-1 648 cf.Base = base 649 cf.LocalBase = base + (cf.LocalBase - lbase + 1) 650 } 651 return 0 652 }, 653 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_RETURN 654 reg := L.reg 655 cf := L.currentFrame 656 lbase := cf.LocalBase 657 A := int(inst>>18) & 0xff // GETA 658 RA := lbase + A 659 B := int(inst & 0x1ff) // GETB 660 // +inline-call L.closeUpvalues lbase 661 nret := B - 1 662 if B == 0 { 663 nret = reg.Top() - RA 664 } 665 n := cf.NRet 666 if cf.NRet == MultRet { 667 n = nret 668 } 669 670 if L.Parent != nil && L.stack.Sp() == 1 { 671 // +inline-call copyReturnValues L reg.Top() RA n B 672 switchToParentThread(L, n, false, true) 673 return 1 674 } 675 islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() 676 // +inline-call copyReturnValues L cf.ReturnBase RA n B 677 L.currentFrame = L.stack.Last() 678 if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { 679 return 1 680 } 681 return 0 682 }, 683 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_FORLOOP 684 reg := L.reg 685 cf := L.currentFrame 686 lbase := cf.LocalBase 687 A := int(inst>>18) & 0xff // GETA 688 RA := lbase + A 689 if init, ok1 := reg.Get(RA).(LNumber); ok1 { 690 if limit, ok2 := reg.Get(RA + 1).(LNumber); ok2 { 691 if step, ok3 := reg.Get(RA + 2).(LNumber); ok3 { 692 init += step 693 v := LNumber(init) 694 // +inline-call reg.SetNumber RA v 695 if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { 696 Sbx := int(inst&0x3ffff) - opMaxArgSbx // GETSBX 697 cf.Pc += Sbx 698 // +inline-call reg.SetNumber RA+3 v 699 } else { 700 // +inline-call reg.SetTop RA+1 701 } 702 } else { 703 L.RaiseError("for statement step must be a number") 704 } 705 } else { 706 L.RaiseError("for statement limit must be a number") 707 } 708 } else { 709 L.RaiseError("for statement init must be a number") 710 } 711 return 0 712 }, 713 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_FORPREP 714 reg := L.reg 715 cf := L.currentFrame 716 lbase := cf.LocalBase 717 A := int(inst>>18) & 0xff // GETA 718 RA := lbase + A 719 Sbx := int(inst&0x3ffff) - opMaxArgSbx // GETSBX 720 if init, ok1 := reg.Get(RA).(LNumber); ok1 { 721 if step, ok2 := reg.Get(RA + 2).(LNumber); ok2 { 722 // +inline-call reg.SetNumber RA LNumber(init-step) 723 } else { 724 L.RaiseError("for statement step must be a number") 725 } 726 } else { 727 L.RaiseError("for statement init must be a number") 728 } 729 cf.Pc += Sbx 730 return 0 731 }, 732 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_TFORLOOP 733 reg := L.reg 734 cf := L.currentFrame 735 lbase := cf.LocalBase 736 A := int(inst>>18) & 0xff // GETA 737 RA := lbase + A 738 C := int(inst>>9) & 0x1ff // GETC 739 nret := C 740 // +inline-call reg.SetTop RA+3+2 741 // +inline-call reg.Set RA+3+2 reg.Get(RA+2) 742 // +inline-call reg.Set RA+3+1 reg.Get(RA+1) 743 // +inline-call reg.Set RA+3 reg.Get(RA) 744 L.callR(2, nret, RA+3) 745 if value := reg.Get(RA + 3); value != LNil { 746 // +inline-call reg.Set RA+2 value 747 pc := cf.Fn.Proto.Code[cf.Pc] 748 cf.Pc += int(pc&0x3ffff) - opMaxArgSbx 749 } 750 cf.Pc++ 751 return 0 752 }, 753 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_SETLIST 754 reg := L.reg 755 cf := L.currentFrame 756 lbase := cf.LocalBase 757 A := int(inst>>18) & 0xff // GETA 758 RA := lbase + A 759 B := int(inst & 0x1ff) // GETB 760 C := int(inst>>9) & 0x1ff // GETC 761 if C == 0 { 762 C = int(cf.Fn.Proto.Code[cf.Pc]) 763 cf.Pc++ 764 } 765 offset := (C - 1) * FieldsPerFlush 766 table := reg.Get(RA).(*LTable) 767 nelem := B 768 if B == 0 { 769 nelem = reg.Top() - RA - 1 770 } 771 for i := 1; i <= nelem; i++ { 772 table.RawSetInt(offset+i, reg.Get(RA+i)) 773 } 774 return 0 775 }, 776 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_CLOSE 777 cf := L.currentFrame 778 lbase := cf.LocalBase 779 A := int(inst>>18) & 0xff // GETA 780 RA := lbase + A 781 // +inline-call L.closeUpvalues RA 782 return 0 783 }, 784 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_CLOSURE 785 reg := L.reg 786 cf := L.currentFrame 787 lbase := cf.LocalBase 788 A := int(inst>>18) & 0xff // GETA 789 RA := lbase + A 790 Bx := int(inst & 0x3ffff) // GETBX 791 proto := cf.Fn.Proto.FunctionPrototypes[Bx] 792 closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) 793 // +inline-call reg.Set RA closure 794 for i := 0; i < int(proto.NumUpvalues); i++ { 795 inst = cf.Fn.Proto.Code[cf.Pc] 796 cf.Pc++ 797 B := opGetArgB(inst) 798 switch opGetOpCode(inst) { 799 case OP_MOVE: 800 closure.Upvalues[i] = L.findUpvalue(lbase + B) 801 case OP_GETUPVAL: 802 closure.Upvalues[i] = cf.Fn.Upvalues[B] 803 } 804 } 805 return 0 806 }, 807 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_VARARG 808 reg := L.reg 809 cf := L.currentFrame 810 lbase := cf.LocalBase 811 A := int(inst>>18) & 0xff // GETA 812 RA := lbase + A 813 B := int(inst & 0x1ff) // GETB 814 nparams := int(cf.Fn.Proto.NumParameters) 815 nvarargs := cf.NArgs - nparams 816 if nvarargs < 0 { 817 nvarargs = 0 818 } 819 nwant := B - 1 820 if B == 0 { 821 nwant = nvarargs 822 } 823 // +inline-call reg.CopyRange RA cf.Base+nparams+1 cf.LocalBase nwant 824 return 0 825 }, 826 func(L *LState, inst uint32, baseframe *callFrame) int { // OP_NOP 827 return 0 828 }, 829 } 830 } 831 832 func opArith( 833 L *LState, 834 inst uint32, 835 baseframe *callFrame, 836 ) int { // OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_BITOR, OP_MOD, OP_POW 837 reg := L.reg 838 cf := L.currentFrame 839 lbase := cf.LocalBase 840 A := int(inst>>18) & 0xff // GETA 841 RA := lbase + A 842 opcode := int(inst >> 26) // GETOPCODE 843 B := int(inst & 0x1ff) // GETB 844 C := int(inst>>9) & 0x1ff // GETC 845 lhs := L.rkValue(B) 846 rhs := L.rkValue(C) 847 v1, ok1 := lhs.(LNumber) 848 v2, ok2 := rhs.(LNumber) 849 if ok1 && ok2 { 850 v := numberArith(L, opcode, LNumber(v1), LNumber(v2)) 851 // +inline-call reg.SetNumber RA v 852 } else { 853 v := objectArith(L, opcode, lhs, rhs) 854 // +inline-call reg.Set RA v 855 } 856 return 0 857 } 858 859 func luaModulo(lhs, rhs LNumber) LNumber { 860 flhs := float64(lhs) 861 frhs := float64(rhs) 862 v := math.Mod(flhs, frhs) 863 if frhs > 0 && v < 0 || frhs < 0 && v > 0 { 864 v += frhs 865 } 866 return LNumber(v) 867 } 868 869 func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber { 870 switch opcode { 871 case OP_ADD: 872 return lhs + rhs 873 case OP_SUB: 874 return lhs - rhs 875 case OP_MUL: 876 return lhs * rhs 877 case OP_DIV: 878 return lhs / rhs 879 case OP_BITOR: 880 return lhs | rhs 881 case OP_MOD: 882 return luaModulo(lhs, rhs) 883 case OP_POW: 884 flhs := float64(lhs) 885 frhs := float64(rhs) 886 return LNumber(math.Pow(flhs, frhs)) 887 } 888 panic("should not reach here") 889 return LNumber(0) 890 } 891 892 func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue { 893 event := "" 894 switch opcode { 895 case OP_ADD: 896 event = "__add" 897 case OP_SUB: 898 event = "__sub" 899 case OP_MUL: 900 event = "__mul" 901 case OP_DIV: 902 event = "__div" 903 case OP_BITOR: 904 event = "__bitor" 905 case OP_MOD: 906 event = "__mod" 907 case OP_POW: 908 event = "__pow" 909 } 910 op := L.metaOp2(lhs, rhs, event) 911 if _, ok := op.(*LFunction); ok { 912 L.reg.Push(op) 913 L.reg.Push(lhs) 914 L.reg.Push(rhs) 915 L.Call(2, 1) 916 return L.reg.Pop() 917 } 918 if str, ok := lhs.(LString); ok { 919 if lnum, err := parseNumber(string(str)); err == nil { 920 lhs = lnum 921 } 922 } 923 if str, ok := rhs.(LString); ok { 924 if rnum, err := parseNumber(string(str)); err == nil { 925 rhs = rnum 926 } 927 } 928 if v1, ok1 := lhs.(LNumber); ok1 { 929 if v2, ok2 := rhs.(LNumber); ok2 { 930 return numberArith(L, opcode, LNumber(v1), LNumber(v2)) 931 } 932 } 933 L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v", 934 strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String())) 935 936 return LNil 937 } 938 939 func stringConcat(L *LState, total, last int) LValue { 940 rhs := L.reg.Get(last) 941 total-- 942 for i := last - 1; total > 0; { 943 lhs := L.reg.Get(i) 944 if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) { 945 op := L.metaOp2(lhs, rhs, "__concat") 946 if op.Type() == LTFunction { 947 L.reg.Push(op) 948 L.reg.Push(lhs) 949 L.reg.Push(rhs) 950 L.Call(2, 1) 951 rhs = L.reg.Pop() 952 total-- 953 i-- 954 } else { 955 L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String()) 956 return LNil 957 } 958 } else { 959 buf := make([]string, total+1) 960 buf[total] = LVAsString(rhs) 961 for total > 0 { 962 lhs = L.reg.Get(i) 963 if !LVCanConvToString(lhs) { 964 break 965 } 966 buf[total-1] = LVAsString(lhs) 967 i-- 968 total-- 969 } 970 rhs = LString(strings.Join(buf, "")) 971 } 972 } 973 return rhs 974 } 975 976 func lessThan(L *LState, lhs, rhs LValue) bool { 977 // optimization for numbers 978 if v1, ok1 := lhs.(LNumber); ok1 { 979 if v2, ok2 := rhs.(LNumber); ok2 { 980 return v1 < v2 981 } 982 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 983 } 984 if lhs.Type() != rhs.Type() { 985 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 986 return false 987 } 988 ret := false 989 switch lhs.Type() { 990 case LTString: 991 ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0 992 default: 993 ret = objectRationalWithError(L, lhs, rhs, "__lt") 994 } 995 return ret 996 } 997 998 func equals(L *LState, lhs, rhs LValue, raw bool) bool { 999 lt := lhs.Type() 1000 if lt != rhs.Type() { 1001 return false 1002 } 1003 1004 ret := false 1005 switch lt { 1006 case LTNil: 1007 ret = true 1008 case LTNumber: 1009 v1, _ := lhs.(LNumber) 1010 v2, _ := rhs.(LNumber) 1011 ret = v1 == v2 1012 case LTBool: 1013 ret = bool(lhs.(LBool)) == bool(rhs.(LBool)) 1014 case LTString: 1015 ret = string(lhs.(LString)) == string(rhs.(LString)) 1016 case LTUserData, LTTable: 1017 if lhs == rhs { 1018 ret = true 1019 } else if !raw { 1020 switch objectRational(L, lhs, rhs, "__eq") { 1021 case 1: 1022 ret = true 1023 default: 1024 ret = false 1025 } 1026 } 1027 default: 1028 ret = lhs == rhs 1029 } 1030 return ret 1031 } 1032 1033 func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool { 1034 switch objectRational(L, lhs, rhs, event) { 1035 case 1: 1036 return true 1037 case 0: 1038 return false 1039 } 1040 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 1041 return false 1042 } 1043 1044 func objectRational(L *LState, lhs, rhs LValue, event string) int { 1045 m1 := L.metaOp1(lhs, event) 1046 m2 := L.metaOp1(rhs, event) 1047 if m1.Type() == LTFunction && m1 == m2 { 1048 L.reg.Push(m1) 1049 L.reg.Push(lhs) 1050 L.reg.Push(rhs) 1051 L.Call(2, 1) 1052 if LVAsBool(L.reg.Pop()) { 1053 return 1 1054 } 1055 return 0 1056 } 1057 return -1 1058 }