github.com/tul/gopher-lua@v0.0.0-20181008131706-f6fcaab0c612/vm.go (about) 1 package lua 2 3 //////////////////////////////////////////////////////// 4 // This file was generated by go-inline. DO NOT EDIT. // 5 //////////////////////////////////////////////////////// 6 7 import ( 8 "fmt" 9 "math" 10 "strings" 11 ) 12 13 func mainLoop(L *LState, baseframe *callFrame) { 14 var inst uint32 15 var cf *callFrame 16 17 if L.stack.IsEmpty() { 18 return 19 } 20 21 L.currentFrame = L.stack.Last() 22 if L.currentFrame.Fn.IsG { 23 callGFunction(L, false) 24 return 25 } 26 27 for { 28 cf = L.currentFrame 29 inst = cf.Fn.Proto.Code[cf.Pc] 30 cf.Pc++ 31 if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { 32 return 33 } 34 } 35 } 36 37 func mainLoopWithContext(L *LState, baseframe *callFrame) { 38 var inst uint32 39 var cf *callFrame 40 41 if L.stack.IsEmpty() { 42 return 43 } 44 45 L.currentFrame = L.stack.Last() 46 if L.currentFrame.Fn.IsG { 47 callGFunction(L, false) 48 return 49 } 50 51 for { 52 cf = L.currentFrame 53 inst = cf.Fn.Proto.Code[cf.Pc] 54 cf.Pc++ 55 select { 56 case <-L.ctx.Done(): 57 L.RaiseError(L.ctx.Err().Error()) 58 return 59 default: 60 if jumpTable[int(inst>>26)](L, inst, baseframe) == 1 { 61 return 62 } 63 } 64 } 65 } 66 67 func copyReturnValues(L *LState, regv, start, n, b int) { // +inline-start 68 if b == 1 { 69 // this section is inlined by go-inline 70 // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' 71 { 72 rg := L.reg 73 regm := regv 74 for i := 0; i < n; i++ { 75 rg.array[regm+i] = LNil 76 } 77 rg.top = regm + n 78 } 79 } else { 80 // this section is inlined by go-inline 81 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 82 { 83 rg := L.reg 84 limit := -1 85 for i := 0; i < n; i++ { 86 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 87 rg.array[regv+i] = LNil 88 } else { 89 rg.array[regv+i] = rg.array[tidx] 90 } 91 } 92 rg.top = regv + n 93 } 94 } 95 } // +inline-end 96 97 func switchToParentThread(L *LState, nargs int, haserror bool, kill bool) { 98 parent := L.Parent 99 if parent == nil { 100 L.RaiseError("can not yield from outside of a coroutine") 101 } 102 L.G.CurrentThread = parent 103 L.Parent = nil 104 if !L.wrapped { 105 if haserror { 106 parent.Push(LFalse) 107 } else { 108 parent.Push(LTrue) 109 } 110 } 111 L.XMoveTo(parent, nargs) 112 L.stack.Pop() 113 offset := L.currentFrame.LocalBase - L.currentFrame.ReturnBase 114 L.currentFrame = L.stack.Last() 115 L.reg.SetTop(L.reg.Top() - offset) // remove 'yield' function(including tailcalled functions) 116 if kill { 117 L.kill() 118 } 119 } 120 121 func callGFunction(L *LState, tailcall bool) bool { 122 frame := L.currentFrame 123 gfnret := frame.Fn.GFunction(L) 124 if tailcall { 125 L.stack.Remove(L.stack.Sp() - 2) // remove caller lua function frame 126 L.currentFrame = L.stack.Last() 127 } 128 129 if gfnret < 0 { 130 switchToParentThread(L, L.GetTop(), false, false) 131 return true 132 } 133 134 wantret := frame.NRet 135 if wantret == MultRet { 136 wantret = gfnret 137 } 138 139 if tailcall && L.Parent != nil && L.stack.Sp() == 1 { 140 switchToParentThread(L, wantret, false, true) 141 return true 142 } 143 144 // this section is inlined by go-inline 145 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 146 { 147 rg := L.reg 148 regv := frame.ReturnBase 149 start := L.reg.Top() - gfnret 150 limit := -1 151 n := wantret 152 for i := 0; i < n; i++ { 153 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 154 rg.array[regv+i] = LNil 155 } else { 156 rg.array[regv+i] = rg.array[tidx] 157 } 158 } 159 rg.top = regv + n 160 } 161 L.stack.Pop() 162 L.currentFrame = L.stack.Last() 163 return false 164 } 165 166 func threadRun(L *LState) { 167 if L.stack.IsEmpty() { 168 return 169 } 170 171 defer func() { 172 if rcv := recover(); rcv != nil { 173 var lv LValue 174 if v, ok := rcv.(*ApiError); ok { 175 lv = v.Object 176 } else { 177 lv = LString(fmt.Sprint(rcv)) 178 } 179 if parent := L.Parent; parent != nil { 180 if L.wrapped { 181 L.Push(lv) 182 parent.Panic(L) 183 } else { 184 L.SetTop(0) 185 L.Push(lv) 186 switchToParentThread(L, 1, true, true) 187 } 188 } else { 189 panic(rcv) 190 } 191 } 192 }() 193 L.mainLoop(L, nil) 194 } 195 196 type instFunc func(*LState, uint32, *callFrame) int 197 198 var jumpTable [opCodeMax + 1]instFunc 199 200 func init() { 201 jumpTable = [opCodeMax + 1]instFunc{ 202 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVE 203 reg := L.reg 204 cf := L.currentFrame 205 lbase := cf.LocalBase 206 A := int(inst>>18) & 0xff //GETA 207 RA := lbase + A 208 B := int(inst & 0x1ff) //GETB 209 reg.Set(RA, reg.Get(lbase+B)) 210 return 0 211 }, 212 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_MOVEN 213 reg := L.reg 214 cf := L.currentFrame 215 lbase := cf.LocalBase 216 A := int(inst>>18) & 0xff //GETA 217 B := int(inst & 0x1ff) //GETB 218 C := int(inst>>9) & 0x1ff //GETC 219 reg.Set(lbase+A, reg.Get(lbase+B)) 220 code := cf.Fn.Proto.Code 221 pc := cf.Pc 222 for i := 0; i < C; i++ { 223 inst = code[pc] 224 pc++ 225 A = int(inst>>18) & 0xff //GETA 226 B = int(inst & 0x1ff) //GETB 227 reg.Set(lbase+A, reg.Get(lbase+B)) 228 } 229 cf.Pc = pc 230 return 0 231 }, 232 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADK 233 reg := L.reg 234 cf := L.currentFrame 235 lbase := cf.LocalBase 236 A := int(inst>>18) & 0xff //GETA 237 RA := lbase + A 238 Bx := int(inst & 0x3ffff) //GETBX 239 reg.Set(RA, cf.Fn.Proto.Constants[Bx]) 240 return 0 241 }, 242 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADBOOL 243 reg := L.reg 244 cf := L.currentFrame 245 lbase := cf.LocalBase 246 A := int(inst>>18) & 0xff //GETA 247 RA := lbase + A 248 B := int(inst & 0x1ff) //GETB 249 C := int(inst>>9) & 0x1ff //GETC 250 if B != 0 { 251 reg.Set(RA, LTrue) 252 } else { 253 reg.Set(RA, LFalse) 254 } 255 if C != 0 { 256 cf.Pc++ 257 } 258 return 0 259 }, 260 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LOADNIL 261 reg := L.reg 262 cf := L.currentFrame 263 lbase := cf.LocalBase 264 A := int(inst>>18) & 0xff //GETA 265 RA := lbase + A 266 B := int(inst & 0x1ff) //GETB 267 for i := RA; i <= lbase+B; i++ { 268 reg.Set(i, LNil) 269 } 270 return 0 271 }, 272 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETUPVAL 273 reg := L.reg 274 cf := L.currentFrame 275 lbase := cf.LocalBase 276 A := int(inst>>18) & 0xff //GETA 277 RA := lbase + A 278 B := int(inst & 0x1ff) //GETB 279 reg.Set(RA, cf.Fn.Upvalues[B].Value()) 280 return 0 281 }, 282 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETGLOBAL 283 reg := L.reg 284 cf := L.currentFrame 285 lbase := cf.LocalBase 286 A := int(inst>>18) & 0xff //GETA 287 RA := lbase + A 288 Bx := int(inst & 0x3ffff) //GETBX 289 //reg.Set(RA, L.getField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx])) 290 reg.Set(RA, L.getFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx])) 291 return 0 292 }, 293 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLE 294 reg := L.reg 295 cf := L.currentFrame 296 lbase := cf.LocalBase 297 A := int(inst>>18) & 0xff //GETA 298 RA := lbase + A 299 B := int(inst & 0x1ff) //GETB 300 C := int(inst>>9) & 0x1ff //GETC 301 reg.Set(RA, L.getField(reg.Get(lbase+B), L.rkValue(C))) 302 return 0 303 }, 304 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_GETTABLEKS 305 reg := L.reg 306 cf := L.currentFrame 307 lbase := cf.LocalBase 308 A := int(inst>>18) & 0xff //GETA 309 RA := lbase + A 310 B := int(inst & 0x1ff) //GETB 311 C := int(inst>>9) & 0x1ff //GETC 312 reg.Set(RA, L.getFieldString(reg.Get(lbase+B), L.rkString(C))) 313 return 0 314 }, 315 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETGLOBAL 316 reg := L.reg 317 cf := L.currentFrame 318 lbase := cf.LocalBase 319 A := int(inst>>18) & 0xff //GETA 320 RA := lbase + A 321 Bx := int(inst & 0x3ffff) //GETBX 322 //L.setField(cf.Fn.Env, cf.Fn.Proto.Constants[Bx], reg.Get(RA)) 323 L.setFieldString(cf.Fn.Env, cf.Fn.Proto.stringConstants[Bx], reg.Get(RA)) 324 return 0 325 }, 326 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETUPVAL 327 reg := L.reg 328 cf := L.currentFrame 329 lbase := cf.LocalBase 330 A := int(inst>>18) & 0xff //GETA 331 RA := lbase + A 332 B := int(inst & 0x1ff) //GETB 333 cf.Fn.Upvalues[B].SetValue(reg.Get(RA)) 334 return 0 335 }, 336 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLE 337 reg := L.reg 338 cf := L.currentFrame 339 lbase := cf.LocalBase 340 A := int(inst>>18) & 0xff //GETA 341 RA := lbase + A 342 B := int(inst & 0x1ff) //GETB 343 C := int(inst>>9) & 0x1ff //GETC 344 L.setField(reg.Get(RA), L.rkValue(B), L.rkValue(C)) 345 return 0 346 }, 347 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETTABLEKS 348 reg := L.reg 349 cf := L.currentFrame 350 lbase := cf.LocalBase 351 A := int(inst>>18) & 0xff //GETA 352 RA := lbase + A 353 B := int(inst & 0x1ff) //GETB 354 C := int(inst>>9) & 0x1ff //GETC 355 L.setFieldString(reg.Get(RA), L.rkString(B), L.rkValue(C)) 356 return 0 357 }, 358 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NEWTABLE 359 reg := L.reg 360 cf := L.currentFrame 361 lbase := cf.LocalBase 362 A := int(inst>>18) & 0xff //GETA 363 RA := lbase + A 364 B := int(inst & 0x1ff) //GETB 365 C := int(inst>>9) & 0x1ff //GETC 366 reg.Set(RA, newLTable(B, C)) 367 return 0 368 }, 369 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SELF 370 reg := L.reg 371 cf := L.currentFrame 372 lbase := cf.LocalBase 373 A := int(inst>>18) & 0xff //GETA 374 RA := lbase + A 375 B := int(inst & 0x1ff) //GETB 376 C := int(inst>>9) & 0x1ff //GETC 377 selfobj := reg.Get(lbase + B) 378 reg.Set(RA, L.getFieldString(selfobj, L.rkString(C))) 379 reg.Set(RA+1, selfobj) 380 return 0 381 }, 382 opArith, // OP_ADD 383 opArith, // OP_SUB 384 opArith, // OP_MUL 385 opArith, // OP_DIV 386 opArith, // OP_MOD 387 opArith, // OP_POW 388 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_UNM 389 reg := L.reg 390 cf := L.currentFrame 391 lbase := cf.LocalBase 392 A := int(inst>>18) & 0xff //GETA 393 RA := lbase + A 394 B := int(inst & 0x1ff) //GETB 395 unaryv := L.rkValue(B) 396 if nm, ok := unaryv.(LNumber); ok { 397 reg.SetNumber(RA, -nm) 398 } else { 399 op := L.metaOp1(unaryv, "__unm") 400 if op.Type() == LTFunction { 401 reg.Push(op) 402 reg.Push(unaryv) 403 L.Call(1, 1) 404 reg.Set(RA, reg.Pop()) 405 } else if str, ok1 := unaryv.(LString); ok1 { 406 if num, err := parseNumber(string(str)); err == nil { 407 reg.Set(RA, -num) 408 } else { 409 L.RaiseError("__unm undefined") 410 } 411 } else { 412 L.RaiseError("__unm undefined") 413 } 414 } 415 return 0 416 }, 417 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOT 418 reg := L.reg 419 cf := L.currentFrame 420 lbase := cf.LocalBase 421 A := int(inst>>18) & 0xff //GETA 422 RA := lbase + A 423 B := int(inst & 0x1ff) //GETB 424 if LVIsFalse(reg.Get(lbase + B)) { 425 reg.Set(RA, LTrue) 426 } else { 427 reg.Set(RA, LFalse) 428 } 429 return 0 430 }, 431 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LEN 432 reg := L.reg 433 cf := L.currentFrame 434 lbase := cf.LocalBase 435 A := int(inst>>18) & 0xff //GETA 436 RA := lbase + A 437 B := int(inst & 0x1ff) //GETB 438 switch lv := L.rkValue(B).(type) { 439 case LString: 440 reg.SetNumber(RA, LNumber(len(lv))) 441 default: 442 op := L.metaOp1(lv, "__len") 443 if op.Type() == LTFunction { 444 reg.Push(op) 445 reg.Push(lv) 446 L.Call(1, 1) 447 ret := reg.Pop() 448 if ret.Type() == LTNumber { 449 reg.SetNumber(RA, ret.(LNumber)) 450 } else { 451 reg.SetNumber(RA, LNumber(0)) 452 } 453 } else if lv.Type() == LTTable { 454 reg.SetNumber(RA, LNumber(lv.(*LTable).Len())) 455 } else { 456 L.RaiseError("__len undefined") 457 } 458 } 459 return 0 460 }, 461 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CONCAT 462 reg := L.reg 463 cf := L.currentFrame 464 lbase := cf.LocalBase 465 A := int(inst>>18) & 0xff //GETA 466 RA := lbase + A 467 B := int(inst & 0x1ff) //GETB 468 C := int(inst>>9) & 0x1ff //GETC 469 RC := lbase + C 470 RB := lbase + B 471 reg.Set(RA, stringConcat(L, RC-RB+1, RC)) 472 return 0 473 }, 474 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_JMP 475 cf := L.currentFrame 476 Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX 477 cf.Pc += Sbx 478 return 0 479 }, 480 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_EQ 481 cf := L.currentFrame 482 A := int(inst>>18) & 0xff //GETA 483 B := int(inst & 0x1ff) //GETB 484 C := int(inst>>9) & 0x1ff //GETC 485 ret := equals(L, L.rkValue(B), L.rkValue(C), false) 486 v := 1 487 if ret { 488 v = 0 489 } 490 if v == A { 491 cf.Pc++ 492 } 493 return 0 494 }, 495 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LT 496 cf := L.currentFrame 497 A := int(inst>>18) & 0xff //GETA 498 B := int(inst & 0x1ff) //GETB 499 C := int(inst>>9) & 0x1ff //GETC 500 ret := lessThan(L, L.rkValue(B), L.rkValue(C)) 501 v := 1 502 if ret { 503 v = 0 504 } 505 if v == A { 506 cf.Pc++ 507 } 508 return 0 509 }, 510 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_LE 511 cf := L.currentFrame 512 A := int(inst>>18) & 0xff //GETA 513 B := int(inst & 0x1ff) //GETB 514 C := int(inst>>9) & 0x1ff //GETC 515 lhs := L.rkValue(B) 516 rhs := L.rkValue(C) 517 ret := false 518 519 if v1, ok1 := lhs.assertFloat64(); ok1 { 520 if v2, ok2 := rhs.assertFloat64(); ok2 { 521 ret = v1 <= v2 522 } else { 523 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 524 } 525 } else { 526 if lhs.Type() != rhs.Type() { 527 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 528 } 529 switch lhs.Type() { 530 case LTString: 531 ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) <= 0 532 default: 533 switch objectRational(L, lhs, rhs, "__le") { 534 case 1: 535 ret = true 536 case 0: 537 ret = false 538 default: 539 ret = !objectRationalWithError(L, rhs, lhs, "__lt") 540 } 541 } 542 } 543 544 v := 1 545 if ret { 546 v = 0 547 } 548 if v == A { 549 cf.Pc++ 550 } 551 return 0 552 }, 553 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TEST 554 reg := L.reg 555 cf := L.currentFrame 556 lbase := cf.LocalBase 557 A := int(inst>>18) & 0xff //GETA 558 RA := lbase + A 559 C := int(inst>>9) & 0x1ff //GETC 560 if LVAsBool(reg.Get(RA)) == (C == 0) { 561 cf.Pc++ 562 } 563 return 0 564 }, 565 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TESTSET 566 reg := L.reg 567 cf := L.currentFrame 568 lbase := cf.LocalBase 569 A := int(inst>>18) & 0xff //GETA 570 RA := lbase + A 571 B := int(inst & 0x1ff) //GETB 572 C := int(inst>>9) & 0x1ff //GETC 573 if value := reg.Get(lbase + B); LVAsBool(value) != (C == 0) { 574 reg.Set(RA, value) 575 } else { 576 cf.Pc++ 577 } 578 return 0 579 }, 580 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CALL 581 reg := L.reg 582 cf := L.currentFrame 583 lbase := cf.LocalBase 584 A := int(inst>>18) & 0xff //GETA 585 RA := lbase + A 586 B := int(inst & 0x1ff) //GETB 587 C := int(inst>>9) & 0x1ff //GETC 588 nargs := B - 1 589 if B == 0 { 590 nargs = reg.Top() - (RA + 1) 591 } 592 lv := reg.Get(RA) 593 nret := C - 1 594 var callable *LFunction 595 var meta bool 596 if fn, ok := lv.assertFunction(); ok { 597 callable = fn 598 meta = false 599 } else { 600 callable, meta = L.metaCall(lv) 601 } 602 // this section is inlined by go-inline 603 // source function is 'func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) ' in '_state.go' 604 { 605 ls := L 606 cf := callFrame{Fn: callable, Pc: 0, Base: RA, LocalBase: RA + 1, ReturnBase: RA, NArgs: nargs, NRet: nret, Parent: cf, TailCall: 0} 607 fn := lv 608 if meta { 609 cf.NArgs++ 610 ls.reg.Insert(fn, cf.LocalBase) 611 } 612 if cf.Fn == nil { 613 ls.RaiseError("attempt to call a non-function object") 614 } 615 if ls.stack.sp == ls.Options.CallStackSize { 616 ls.RaiseError("stack overflow") 617 } 618 // this section is inlined by go-inline 619 // source function is 'func (cs *callFrameStack) Push(v callFrame) ' in '_state.go' 620 { 621 cs := ls.stack 622 v := cf 623 cs.array[cs.sp] = v 624 cs.array[cs.sp].Idx = cs.sp 625 cs.sp++ 626 } 627 newcf := ls.stack.Last() 628 // this section is inlined by go-inline 629 // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' 630 { 631 cf := newcf 632 if cf.Fn.IsG { 633 ls.reg.SetTop(cf.LocalBase + cf.NArgs) 634 } else { 635 proto := cf.Fn.Proto 636 nargs := cf.NArgs 637 np := int(proto.NumParameters) 638 for i := nargs; i < np; i++ { 639 ls.reg.array[cf.LocalBase+i] = LNil 640 nargs = np 641 } 642 643 if (proto.IsVarArg & VarArgIsVarArg) == 0 { 644 if nargs < int(proto.NumUsedRegisters) { 645 nargs = int(proto.NumUsedRegisters) 646 } 647 for i := np; i < nargs; i++ { 648 ls.reg.array[cf.LocalBase+i] = LNil 649 } 650 ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) 651 } else { 652 /* swap vararg positions: 653 closure 654 namedparam1 <- lbase 655 namedparam2 656 vararg1 657 vararg2 658 659 TO 660 661 closure 662 nil 663 nil 664 vararg1 665 vararg2 666 namedparam1 <- lbase 667 namedparam2 668 */ 669 nvarargs := nargs - np 670 if nvarargs < 0 { 671 nvarargs = 0 672 } 673 674 ls.reg.SetTop(cf.LocalBase + nargs + np) 675 for i := 0; i < np; i++ { 676 //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) 677 ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] 678 //ls.reg.Set(cf.LocalBase+i, LNil) 679 ls.reg.array[cf.LocalBase+i] = LNil 680 } 681 682 if CompatVarArg { 683 ls.reg.SetTop(cf.LocalBase + nargs + np + 1) 684 if (proto.IsVarArg & VarArgNeedsArg) != 0 { 685 argtb := newLTable(nvarargs, 0) 686 for i := 0; i < nvarargs; i++ { 687 argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) 688 } 689 argtb.RawSetString("n", LNumber(nvarargs)) 690 //ls.reg.Set(cf.LocalBase+nargs+np, argtb) 691 ls.reg.array[cf.LocalBase+nargs+np] = argtb 692 } else { 693 ls.reg.array[cf.LocalBase+nargs+np] = LNil 694 } 695 } 696 cf.LocalBase += nargs 697 maxreg := cf.LocalBase + int(proto.NumUsedRegisters) 698 ls.reg.SetTop(maxreg) 699 } 700 } 701 } 702 ls.currentFrame = newcf 703 } 704 if callable.IsG && callGFunction(L, false) { 705 return 1 706 } 707 return 0 708 }, 709 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TAILCALL 710 reg := L.reg 711 cf := L.currentFrame 712 lbase := cf.LocalBase 713 A := int(inst>>18) & 0xff //GETA 714 RA := lbase + A 715 B := int(inst & 0x1ff) //GETB 716 nargs := B - 1 717 if B == 0 { 718 nargs = reg.Top() - (RA + 1) 719 } 720 lv := reg.Get(RA) 721 var callable *LFunction 722 var meta bool 723 if fn, ok := lv.assertFunction(); ok { 724 callable = fn 725 meta = false 726 } else { 727 callable, meta = L.metaCall(lv) 728 } 729 if callable == nil { 730 L.RaiseError("attempt to call a non-function object") 731 } 732 // this section is inlined by go-inline 733 // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' 734 { 735 ls := L 736 idx := lbase 737 if ls.uvcache != nil { 738 var prev *Upvalue 739 for uv := ls.uvcache; uv != nil; uv = uv.next { 740 if uv.index >= idx { 741 if prev != nil { 742 prev.next = nil 743 } else { 744 ls.uvcache = nil 745 } 746 uv.Close() 747 } 748 prev = uv 749 } 750 } 751 } 752 if callable.IsG { 753 luaframe := cf 754 L.pushCallFrame(callFrame{ 755 Fn: callable, 756 Pc: 0, 757 Base: RA, 758 LocalBase: RA + 1, 759 ReturnBase: cf.ReturnBase, 760 NArgs: nargs, 761 NRet: cf.NRet, 762 Parent: cf, 763 TailCall: 0, 764 }, lv, meta) 765 if callGFunction(L, true) { 766 return 1 767 } 768 if L.currentFrame == nil || L.currentFrame.Fn.IsG || luaframe == baseframe { 769 return 1 770 } 771 } else { 772 base := cf.Base 773 cf.Fn = callable 774 cf.Pc = 0 775 cf.Base = RA 776 cf.LocalBase = RA + 1 777 // cf.ReturnBase = cf.ReturnBase 778 cf.NArgs = nargs 779 // cf.NRet = cf.NRet 780 cf.TailCall++ 781 lbase := cf.LocalBase 782 if meta { 783 cf.NArgs++ 784 L.reg.Insert(lv, cf.LocalBase) 785 } 786 // this section is inlined by go-inline 787 // source function is 'func (ls *LState) initCallFrame(cf *callFrame) ' in '_state.go' 788 { 789 ls := L 790 if cf.Fn.IsG { 791 ls.reg.SetTop(cf.LocalBase + cf.NArgs) 792 } else { 793 proto := cf.Fn.Proto 794 nargs := cf.NArgs 795 np := int(proto.NumParameters) 796 for i := nargs; i < np; i++ { 797 ls.reg.array[cf.LocalBase+i] = LNil 798 nargs = np 799 } 800 801 if (proto.IsVarArg & VarArgIsVarArg) == 0 { 802 if nargs < int(proto.NumUsedRegisters) { 803 nargs = int(proto.NumUsedRegisters) 804 } 805 for i := np; i < nargs; i++ { 806 ls.reg.array[cf.LocalBase+i] = LNil 807 } 808 ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters) 809 } else { 810 /* swap vararg positions: 811 closure 812 namedparam1 <- lbase 813 namedparam2 814 vararg1 815 vararg2 816 817 TO 818 819 closure 820 nil 821 nil 822 vararg1 823 vararg2 824 namedparam1 <- lbase 825 namedparam2 826 */ 827 nvarargs := nargs - np 828 if nvarargs < 0 { 829 nvarargs = 0 830 } 831 832 ls.reg.SetTop(cf.LocalBase + nargs + np) 833 for i := 0; i < np; i++ { 834 //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i)) 835 ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i] 836 //ls.reg.Set(cf.LocalBase+i, LNil) 837 ls.reg.array[cf.LocalBase+i] = LNil 838 } 839 840 if CompatVarArg { 841 ls.reg.SetTop(cf.LocalBase + nargs + np + 1) 842 if (proto.IsVarArg & VarArgNeedsArg) != 0 { 843 argtb := newLTable(nvarargs, 0) 844 for i := 0; i < nvarargs; i++ { 845 argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i)) 846 } 847 argtb.RawSetString("n", LNumber(nvarargs)) 848 //ls.reg.Set(cf.LocalBase+nargs+np, argtb) 849 ls.reg.array[cf.LocalBase+nargs+np] = argtb 850 } else { 851 ls.reg.array[cf.LocalBase+nargs+np] = LNil 852 } 853 } 854 cf.LocalBase += nargs 855 maxreg := cf.LocalBase + int(proto.NumUsedRegisters) 856 ls.reg.SetTop(maxreg) 857 } 858 } 859 } 860 // this section is inlined by go-inline 861 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 862 { 863 rg := L.reg 864 regv := base 865 start := RA 866 limit := -1 867 n := reg.Top() - RA - 1 868 for i := 0; i < n; i++ { 869 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 870 rg.array[regv+i] = LNil 871 } else { 872 rg.array[regv+i] = rg.array[tidx] 873 } 874 } 875 rg.top = regv + n 876 } 877 cf.Base = base 878 cf.LocalBase = base + (cf.LocalBase - lbase + 1) 879 } 880 return 0 881 }, 882 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_RETURN 883 reg := L.reg 884 cf := L.currentFrame 885 lbase := cf.LocalBase 886 A := int(inst>>18) & 0xff //GETA 887 RA := lbase + A 888 B := int(inst & 0x1ff) //GETB 889 // this section is inlined by go-inline 890 // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' 891 { 892 ls := L 893 idx := lbase 894 if ls.uvcache != nil { 895 var prev *Upvalue 896 for uv := ls.uvcache; uv != nil; uv = uv.next { 897 if uv.index >= idx { 898 if prev != nil { 899 prev.next = nil 900 } else { 901 ls.uvcache = nil 902 } 903 uv.Close() 904 } 905 prev = uv 906 } 907 } 908 } 909 nret := B - 1 910 if B == 0 { 911 nret = reg.Top() - RA 912 } 913 n := cf.NRet 914 if cf.NRet == MultRet { 915 n = nret 916 } 917 918 if L.Parent != nil && L.stack.Sp() == 1 { 919 // this section is inlined by go-inline 920 // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' 921 { 922 regv := reg.Top() 923 start := RA 924 b := B 925 if b == 1 { 926 // this section is inlined by go-inline 927 // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' 928 { 929 rg := L.reg 930 regm := regv 931 for i := 0; i < n; i++ { 932 rg.array[regm+i] = LNil 933 } 934 rg.top = regm + n 935 } 936 } else { 937 // this section is inlined by go-inline 938 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 939 { 940 rg := L.reg 941 limit := -1 942 for i := 0; i < n; i++ { 943 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 944 rg.array[regv+i] = LNil 945 } else { 946 rg.array[regv+i] = rg.array[tidx] 947 } 948 } 949 rg.top = regv + n 950 } 951 } 952 } 953 switchToParentThread(L, n, false, true) 954 return 1 955 } 956 islast := baseframe == L.stack.Pop() || L.stack.IsEmpty() 957 // this section is inlined by go-inline 958 // source function is 'func copyReturnValues(L *LState, regv, start, n, b int) ' in '_vm.go' 959 { 960 regv := cf.ReturnBase 961 start := RA 962 b := B 963 if b == 1 { 964 // this section is inlined by go-inline 965 // source function is 'func (rg *registry) FillNil(regm, n int) ' in '_state.go' 966 { 967 rg := L.reg 968 regm := regv 969 for i := 0; i < n; i++ { 970 rg.array[regm+i] = LNil 971 } 972 rg.top = regm + n 973 } 974 } else { 975 // this section is inlined by go-inline 976 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 977 { 978 rg := L.reg 979 limit := -1 980 for i := 0; i < n; i++ { 981 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 982 rg.array[regv+i] = LNil 983 } else { 984 rg.array[regv+i] = rg.array[tidx] 985 } 986 } 987 rg.top = regv + n 988 } 989 } 990 } 991 L.currentFrame = L.stack.Last() 992 if islast || L.currentFrame == nil || L.currentFrame.Fn.IsG { 993 return 1 994 } 995 return 0 996 }, 997 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORLOOP 998 reg := L.reg 999 cf := L.currentFrame 1000 lbase := cf.LocalBase 1001 A := int(inst>>18) & 0xff //GETA 1002 RA := lbase + A 1003 if init, ok1 := reg.Get(RA).assertFloat64(); ok1 { 1004 if limit, ok2 := reg.Get(RA + 1).assertFloat64(); ok2 { 1005 if step, ok3 := reg.Get(RA + 2).assertFloat64(); ok3 { 1006 init += step 1007 reg.SetNumber(RA, LNumber(init)) 1008 if (step > 0 && init <= limit) || (step <= 0 && init >= limit) { 1009 Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX 1010 cf.Pc += Sbx 1011 reg.SetNumber(RA+3, LNumber(init)) 1012 } else { 1013 reg.SetTop(RA + 1) 1014 } 1015 } else { 1016 L.RaiseError("for statement step must be a number") 1017 } 1018 } else { 1019 L.RaiseError("for statement limit must be a number") 1020 } 1021 } else { 1022 L.RaiseError("for statement init must be a number") 1023 } 1024 return 0 1025 }, 1026 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_FORPREP 1027 reg := L.reg 1028 cf := L.currentFrame 1029 lbase := cf.LocalBase 1030 A := int(inst>>18) & 0xff //GETA 1031 RA := lbase + A 1032 Sbx := int(inst&0x3ffff) - opMaxArgSbx //GETSBX 1033 if init, ok1 := reg.Get(RA).assertFloat64(); ok1 { 1034 if step, ok2 := reg.Get(RA + 2).assertFloat64(); ok2 { 1035 reg.SetNumber(RA, LNumber(init-step)) 1036 } else { 1037 L.RaiseError("for statement step must be a number") 1038 } 1039 } else { 1040 L.RaiseError("for statement init must be a number") 1041 } 1042 cf.Pc += Sbx 1043 return 0 1044 }, 1045 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_TFORLOOP 1046 reg := L.reg 1047 cf := L.currentFrame 1048 lbase := cf.LocalBase 1049 A := int(inst>>18) & 0xff //GETA 1050 RA := lbase + A 1051 C := int(inst>>9) & 0x1ff //GETC 1052 nret := C 1053 reg.SetTop(RA + 3 + 2) 1054 reg.Set(RA+3+2, reg.Get(RA+2)) 1055 reg.Set(RA+3+1, reg.Get(RA+1)) 1056 reg.Set(RA+3, reg.Get(RA)) 1057 L.callR(2, nret, RA+3) 1058 if value := reg.Get(RA + 3); value != LNil { 1059 reg.Set(RA+2, value) 1060 pc := cf.Fn.Proto.Code[cf.Pc] 1061 cf.Pc += int(pc&0x3ffff) - opMaxArgSbx 1062 } 1063 cf.Pc++ 1064 return 0 1065 }, 1066 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_SETLIST 1067 reg := L.reg 1068 cf := L.currentFrame 1069 lbase := cf.LocalBase 1070 A := int(inst>>18) & 0xff //GETA 1071 RA := lbase + A 1072 B := int(inst & 0x1ff) //GETB 1073 C := int(inst>>9) & 0x1ff //GETC 1074 if C == 0 { 1075 C = int(cf.Fn.Proto.Code[cf.Pc]) 1076 cf.Pc++ 1077 } 1078 offset := (C - 1) * FieldsPerFlush 1079 table := reg.Get(RA).(*LTable) 1080 nelem := B 1081 if B == 0 { 1082 nelem = reg.Top() - RA - 1 1083 } 1084 for i := 1; i <= nelem; i++ { 1085 table.RawSetInt(offset+i, reg.Get(RA+i)) 1086 } 1087 return 0 1088 }, 1089 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSE 1090 cf := L.currentFrame 1091 lbase := cf.LocalBase 1092 A := int(inst>>18) & 0xff //GETA 1093 RA := lbase + A 1094 // this section is inlined by go-inline 1095 // source function is 'func (ls *LState) closeUpvalues(idx int) ' in '_state.go' 1096 { 1097 ls := L 1098 idx := RA 1099 if ls.uvcache != nil { 1100 var prev *Upvalue 1101 for uv := ls.uvcache; uv != nil; uv = uv.next { 1102 if uv.index >= idx { 1103 if prev != nil { 1104 prev.next = nil 1105 } else { 1106 ls.uvcache = nil 1107 } 1108 uv.Close() 1109 } 1110 prev = uv 1111 } 1112 } 1113 } 1114 return 0 1115 }, 1116 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_CLOSURE 1117 reg := L.reg 1118 cf := L.currentFrame 1119 lbase := cf.LocalBase 1120 A := int(inst>>18) & 0xff //GETA 1121 RA := lbase + A 1122 Bx := int(inst & 0x3ffff) //GETBX 1123 proto := cf.Fn.Proto.FunctionPrototypes[Bx] 1124 closure := newLFunctionL(proto, cf.Fn.Env, int(proto.NumUpvalues)) 1125 reg.Set(RA, closure) 1126 for i := 0; i < int(proto.NumUpvalues); i++ { 1127 inst = cf.Fn.Proto.Code[cf.Pc] 1128 cf.Pc++ 1129 B := opGetArgB(inst) 1130 switch opGetOpCode(inst) { 1131 case OP_MOVE: 1132 closure.Upvalues[i] = L.findUpvalue(lbase + B) 1133 case OP_GETUPVAL: 1134 closure.Upvalues[i] = cf.Fn.Upvalues[B] 1135 } 1136 } 1137 return 0 1138 }, 1139 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_VARARG 1140 reg := L.reg 1141 cf := L.currentFrame 1142 lbase := cf.LocalBase 1143 A := int(inst>>18) & 0xff //GETA 1144 RA := lbase + A 1145 B := int(inst & 0x1ff) //GETB 1146 nparams := int(cf.Fn.Proto.NumParameters) 1147 nvarargs := cf.NArgs - nparams 1148 if nvarargs < 0 { 1149 nvarargs = 0 1150 } 1151 nwant := B - 1 1152 if B == 0 { 1153 nwant = nvarargs 1154 } 1155 // this section is inlined by go-inline 1156 // source function is 'func (rg *registry) CopyRange(regv, start, limit, n int) ' in '_state.go' 1157 { 1158 rg := reg 1159 regv := RA 1160 start := cf.Base + nparams + 1 1161 limit := cf.LocalBase 1162 n := nwant 1163 for i := 0; i < n; i++ { 1164 if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 { 1165 rg.array[regv+i] = LNil 1166 } else { 1167 rg.array[regv+i] = rg.array[tidx] 1168 } 1169 } 1170 rg.top = regv + n 1171 } 1172 return 0 1173 }, 1174 func(L *LState, inst uint32, baseframe *callFrame) int { //OP_NOP 1175 return 0 1176 }, 1177 } 1178 } 1179 1180 func opArith(L *LState, inst uint32, baseframe *callFrame) int { //OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POW 1181 reg := L.reg 1182 cf := L.currentFrame 1183 lbase := cf.LocalBase 1184 A := int(inst>>18) & 0xff //GETA 1185 RA := lbase + A 1186 opcode := int(inst >> 26) //GETOPCODE 1187 B := int(inst & 0x1ff) //GETB 1188 C := int(inst>>9) & 0x1ff //GETC 1189 lhs := L.rkValue(B) 1190 rhs := L.rkValue(C) 1191 v1, ok1 := lhs.assertFloat64() 1192 v2, ok2 := rhs.assertFloat64() 1193 if ok1 && ok2 { 1194 reg.SetNumber(RA, numberArith(L, opcode, LNumber(v1), LNumber(v2))) 1195 } else { 1196 reg.Set(RA, objectArith(L, opcode, lhs, rhs)) 1197 } 1198 return 0 1199 } 1200 1201 func luaModulo(lhs, rhs LNumber) LNumber { 1202 flhs := float64(lhs) 1203 frhs := float64(rhs) 1204 v := math.Mod(flhs, frhs) 1205 if flhs < 0 || frhs < 0 && !(flhs < 0 && frhs < 0) { 1206 v += frhs 1207 } 1208 return LNumber(v) 1209 } 1210 1211 func numberArith(L *LState, opcode int, lhs, rhs LNumber) LNumber { 1212 switch opcode { 1213 case OP_ADD: 1214 return lhs + rhs 1215 case OP_SUB: 1216 return lhs - rhs 1217 case OP_MUL: 1218 return lhs * rhs 1219 case OP_DIV: 1220 return lhs / rhs 1221 case OP_MOD: 1222 return luaModulo(lhs, rhs) 1223 case OP_POW: 1224 flhs := float64(lhs) 1225 frhs := float64(rhs) 1226 return LNumber(math.Pow(flhs, frhs)) 1227 } 1228 panic("should not reach here") 1229 } 1230 1231 func objectArith(L *LState, opcode int, lhs, rhs LValue) LValue { 1232 event := "" 1233 switch opcode { 1234 case OP_ADD: 1235 event = "__add" 1236 case OP_SUB: 1237 event = "__sub" 1238 case OP_MUL: 1239 event = "__mul" 1240 case OP_DIV: 1241 event = "__div" 1242 case OP_MOD: 1243 event = "__mod" 1244 case OP_POW: 1245 event = "__pow" 1246 } 1247 op := L.metaOp2(lhs, rhs, event) 1248 if op.Type() == LTFunction { 1249 L.reg.Push(op) 1250 L.reg.Push(lhs) 1251 L.reg.Push(rhs) 1252 L.Call(2, 1) 1253 return L.reg.Pop() 1254 } 1255 if str, ok := lhs.(LString); ok { 1256 if lnum, err := parseNumber(string(str)); err == nil { 1257 lhs = lnum 1258 } 1259 } 1260 if str, ok := rhs.(LString); ok { 1261 if rnum, err := parseNumber(string(str)); err == nil { 1262 rhs = rnum 1263 } 1264 } 1265 if v1, ok1 := lhs.assertFloat64(); ok1 { 1266 if v2, ok2 := rhs.assertFloat64(); ok2 { 1267 return numberArith(L, opcode, LNumber(v1), LNumber(v2)) 1268 } 1269 } 1270 L.RaiseError(fmt.Sprintf("cannot perform %v operation between %v and %v", 1271 strings.TrimLeft(event, "_"), lhs.Type().String(), rhs.Type().String())) 1272 1273 return LNil 1274 } 1275 1276 func stringConcat(L *LState, total, last int) LValue { 1277 rhs := L.reg.Get(last) 1278 total-- 1279 for i := last - 1; total > 0; { 1280 lhs := L.reg.Get(i) 1281 if !(LVCanConvToString(lhs) && LVCanConvToString(rhs)) { 1282 op := L.metaOp2(lhs, rhs, "__concat") 1283 if op.Type() == LTFunction { 1284 L.reg.Push(op) 1285 L.reg.Push(lhs) 1286 L.reg.Push(rhs) 1287 L.Call(2, 1) 1288 rhs = L.reg.Pop() 1289 total-- 1290 i-- 1291 } else { 1292 L.RaiseError("cannot perform concat operation between %v and %v", lhs.Type().String(), rhs.Type().String()) 1293 return LNil 1294 } 1295 } else { 1296 buf := make([]string, total+1) 1297 buf[total] = LVAsString(rhs) 1298 for total > 0 { 1299 lhs = L.reg.Get(i) 1300 if !LVCanConvToString(lhs) { 1301 break 1302 } 1303 buf[total-1] = LVAsString(lhs) 1304 i-- 1305 total-- 1306 } 1307 rhs = LString(strings.Join(buf, "")) 1308 } 1309 } 1310 return rhs 1311 } 1312 1313 func lessThan(L *LState, lhs, rhs LValue) bool { 1314 // optimization for numbers 1315 if v1, ok1 := lhs.assertFloat64(); ok1 { 1316 if v2, ok2 := rhs.assertFloat64(); ok2 { 1317 return v1 < v2 1318 } 1319 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 1320 } 1321 if lhs.Type() != rhs.Type() { 1322 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 1323 return false 1324 } 1325 ret := false 1326 switch lhs.Type() { 1327 case LTString: 1328 ret = strCmp(string(lhs.(LString)), string(rhs.(LString))) < 0 1329 default: 1330 ret = objectRationalWithError(L, lhs, rhs, "__lt") 1331 } 1332 return ret 1333 } 1334 1335 func equals(L *LState, lhs, rhs LValue, raw bool) bool { 1336 if lhs.Type() != rhs.Type() { 1337 return false 1338 } 1339 1340 ret := false 1341 switch lhs.Type() { 1342 case LTNil: 1343 ret = true 1344 case LTNumber: 1345 v1, _ := lhs.assertFloat64() 1346 v2, _ := rhs.assertFloat64() 1347 ret = v1 == v2 1348 case LTBool: 1349 ret = bool(lhs.(LBool)) == bool(rhs.(LBool)) 1350 case LTString: 1351 ret = string(lhs.(LString)) == string(rhs.(LString)) 1352 case LTUserData, LTTable: 1353 if lhs == rhs { 1354 ret = true 1355 } else if !raw { 1356 switch objectRational(L, lhs, rhs, "__eq") { 1357 case 1: 1358 ret = true 1359 default: 1360 ret = false 1361 } 1362 } 1363 default: 1364 ret = lhs == rhs 1365 } 1366 return ret 1367 } 1368 1369 func objectRationalWithError(L *LState, lhs, rhs LValue, event string) bool { 1370 switch objectRational(L, lhs, rhs, event) { 1371 case 1: 1372 return true 1373 case 0: 1374 return false 1375 } 1376 L.RaiseError("attempt to compare %v with %v", lhs.Type().String(), rhs.Type().String()) 1377 return false 1378 } 1379 1380 func objectRational(L *LState, lhs, rhs LValue, event string) int { 1381 m1 := L.metaOp1(lhs, event) 1382 m2 := L.metaOp1(rhs, event) 1383 if m1.Type() == LTFunction && m1 == m2 { 1384 L.reg.Push(m1) 1385 L.reg.Push(lhs) 1386 L.reg.Push(rhs) 1387 L.Call(2, 1) 1388 if LVAsBool(L.reg.Pop()) { 1389 return 1 1390 } 1391 return 0 1392 } 1393 return -1 1394 }