- load and call
from lua_stack import LuaStack
from lua_type import LuaType
from lua_value import LuaValue
from arith_op import ArithOp
from arithmetic import Arithmetic
from cmp_op import CmpOp
from compare import Compare
from lua_table import LuaTable
from binary_chunk import BinaryChunk
from closure import Closure
from opcode import Instruction
from opcode import OpCode
from thread_state import ThreadStatus
class LuaState:
def __init__(self):
self.stack = LuaStack()
# ...
# vm
def get_pc(self):
return self.stack.pc
def add_pc(self, n):
self.stack.pc += n
def fetch(self):
code = self.stack.closure.proto.get_code()[self.stack.pc]
self.stack.pc += 1
return code
def get_const(self, idx):
self.stack.push(self.stack.closure.proto.get_constants()[idx])
def get_rk(self, rk):
if rk > 0xff: # constant
self.get_const(rk & 0xff)
else: # register
self.push_value(rk + 1)
# ...
def load(self, chunk):
bc = BinaryChunk(chunk)
proto = bc.undump()
closure = Closure(proto)
self.stack.push(closure)
return ThreadStatus.OK
def call(self, nargs, nresults):
val = self.stack.get(-(nargs+1))
if isinstance(val, Closure):
print(\'call %s<%d,%d>\' % (val.proto.get_source(), val.proto.get_line_defined(),
val.proto.get_last_line_defined()))
self.call_lua_closure(nargs, nresults, val)
else:
raise Exception(\'not function\')
def call_lua_closure(self, nargs, nresults, c):
nregs = c.proto.get_max_stack_size()
nparams = c.proto.get_num_params()
is_vararg = c.proto.get_is_vararg()
# create new lua stack
new_stack = LuaStack()
new_stack.closure = c
# pass args, pop func
func_and_args = self.stack.popn(nargs+1)
new_stack.pushn(func_and_args[1:], nparams)
if nargs > nparams and is_vararg:
new_stack.varargs = func_and_args[nparams+1:]
# run closure
self.push_lua_stack(new_stack)
self.set_top(nregs)
self.run_lua_closure()
self.pop_lua_stack()
# return results
if nresults != 0:
results = new_stack.popn(new_stack.top() - nregs)
self.stack.check(len(results))
self.stack.pushn(results, nresults)
def run_lua_closure(self):
while True:
pc = self.get_pc() + 1
inst = Instruction(self.fetch())
inst.execute(self)
print(\'[%02d] %-12s \' % (pc, inst.op_name()), end=\'\')
self.print_stack()
if inst.op_code() == OpCode.RETURN:
break
def push_lua_stack(self, s):
s.caller = self.stack
self.stack = s
def pop_lua_stack(self):
s = self.stack
self.stack = s.caller
s.caller = None
def register_count(self):
return self.stack.closure.proto.get_max_stack_size()
def load_vararg(self, n):
if n < 0:
n = len(self.stack.varargs)
self.stack.check(n)
self.stack.pushn(self.stack.varargs, n)
def load_proto(self, idx):
proto = self.stack.closure.proto.get_protos()[idx]
c = Closure(proto)
self.stack.push(c)
- instructions
# R(A)[(C-1)*LFIELDS_PER_FLUSH+i] := R(A+i), 1 <= i <= B
def setlist(inst, vm):
a, b, c = inst.a_b_c()
a += 1
c = c - 1 if c > 0 else inst.ax(vm.fetch())
is_zero = b == 0
if is_zero:
b = vm.to_integer(-1) - a - 1
vm.pop(1)
vm.check_stack(1)
idx = c * LFIELDS_PER_FLUSH
for i in range(1, b+1):
idx += 1
vm.push_value(a+i)
vm.set_i(a, idx)
if is_zero:
for i in range(vm.register_count() + 1, vm.get_top()+1):
idx += 1
vm.push_value(i)
vm.set_i(a, idx)
vm.set_top(vm.register_count())
# R(A+1) := R(B); R(A) := R(B)[RK(C)]
def luaself(inst, vm):
a, b, c = inst.a_b_c()
a += 1
b += 1
vm.copy(b, a+1)
vm.get_rk(c)
vm.get_table(b)
vm.replace(a)
# R(A) := closure(KPROTO[Bx])
def closure(inst, vm):
a, bx = inst.a_bx()
a += 1
vm.load_proto(bx)
vm.replace(a)
def vararg(inst, vm):
a, b, _ = inst.a_b_c()
a += 1
if b != 1:
vm.load_vararg(b-1)
pop_results(a, b, vm)
def tailcall(inst, vm):
a, b, _ = inst.a_b_c()
a += 1
c = 0
nargs = push_func_and_args(a, b, vm)
vm.call(nargs, c-1)
pop_results(a, c, vm)
def call(inst, vm):
a, b, c = inst.a_b_c()
a += 1
nargs = push_func_and_args(a, b, vm)
vm.call(nargs, c-1)
pop_results(a, c, vm)
def luaret(inst, vm):
a, b, _ = inst.a_b_c()
a += 1
if b == 1:
pass
elif b > 1:
vm.check_stack(b-1)
for i in range(a, a+b-1):
vm.push_value(i)
else:
fix_stack(a, vm)
def push_func_and_args(a, b, vm):
if b >= 1:
vm.check_stack(b)
for i in range(a, a+b):
vm.push_value(i)
return b-1
else:
fix_stack(a, vm)
return vm.get_top() - vm.register_count() - 1
def fix_stack(a, vm):
x = vm.to_integer(-1)
vm.pop(1)
vm.check_stack(x-a)
for i in range(a, x):
vm.push_value(i)
vm.rotate(vm.register_count()+1, x-a)
def pop_results(a, c, vm):
if c == 1:
pass
elif c > 1:
for i in range(a+c-2, a-1, -1):
vm.replace(i)
else:
vm.check_stack(1)
vm.push_integer(a)
op_codes = [
# T A B C mode name action
OpCode(0, 1, OpArgR, OpArgN, IABC, \"MOVE \", move), # R(A) := R(B)
OpCode(0, 1, OpArgK, OpArgN, IABx, \"LOADK \", loadk), # R(A) := Kst(Bx)
OpCode(0, 1, OpArgN, OpArgN, IABx, \"LOADKX \", loadkx), # R(A) := Kst(extra arg)
OpCode(0, 1, OpArgU, OpArgU, IABC, \"LOADBOOL\", loadbool), # R(A) := (bool)B; if (C) pc++
OpCode(0, 1, OpArgU, OpArgN, IABC, \"LOADNIL \", loadnil), # R(A), R(A+1), ..., R(A+B) := nil
OpCode(0, 1, OpArgU, OpArgN, IABC, \"GETUPVAL\", None), # R(A) := UpValue[B]
OpCode(0, 1, OpArgU, OpArgK, IABC, \"GETTABUP\", None), # R(A) := UpValue[B][RK(C)]
OpCode(0, 1, OpArgR, OpArgK, IABC, \"GETTABLE\", gettable), # R(A) := R(B)[RK(C)]
OpCode(0, 0, OpArgK, OpArgK, IABC, \"SETTABUP\", None), # UpValue[A][RK(B)] := RK(C)
OpCode(0, 0, OpArgU, OpArgN, IABC, \"SETUPVAL\", None), # UpValue[B] := R(A)
OpCode(0, 0, OpArgK, OpArgK, IABC, \"SETTABLE\", settable), # R(A)[RK(B)] := RK(C)
OpCode(0, 1, OpArgU, OpArgU, IABC, \"NEWTABLE\", newtable), # R(A) := {} (size = B,C)
OpCode(0, 1, OpArgR, OpArgK, IABC, \"SELF \", luaself), # R(A+1) := R(B); R(A) := R(B)[RK(C)]
OpCode(0, 1, OpArgK, OpArgK, IABC, \"ADD \", add), # R(A) := RK(B) + RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"SUB \", sub), # R(A) := RK(B) - RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"MUL \", mul), # R(A) := RK(B) * RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"MOD \", mod), # R(A) := RK(B) % RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"POW \", luapow), # R(A) := RK(B) ^ RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"DIV \", div), # R(A) := RK(B) / RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"IDIV \", idiv), # R(A) := RK(B) // RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"BAND \", band), # R(A) := RK(B) & RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"BOR \", bor), # R(A) := RK(B) | RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"BXOR \", bxor), # R(A) := RK(B) ~ RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"SHL \", shl), # R(A) := RK(B) << RK(C)
OpCode(0, 1, OpArgK, OpArgK, IABC, \"SHR \", shr), # R(A) := RK(B) >> RK(C)
OpCode(0, 1, OpArgR, OpArgN, IABC, \"UNM \", unm), # R(A) := -R(B)
OpCode(0, 1, OpArgR, OpArgN, IABC, \"BNOT \", bnot), # R(A) := ~R(B)
OpCode(0, 1, OpArgR, OpArgN, IABC, \"NOT \", luanot), # R(A) := not R(B)
OpCode(0, 1, OpArgR, OpArgN, IABC, \"LEN \", length), # R(A) := length of R(B)
OpCode(0, 1, OpArgR, OpArgR, IABC, \"CONCAT \", concat), # R(A) := R(B).. ... ..R(C)
OpCode(0, 0, OpArgR, OpArgN, IAsBx, \"JMP \", jmp), # pc+=sBx; if (A) close all upvalues >= R(A - 1)
OpCode(1, 0, OpArgK, OpArgK, IABC, \"EQ \", eq), # if ((RK(B) == RK(C)) ~= A) then pc++
OpCode(1, 0, OpArgK, OpArgK, IABC, \"LT \", lt), # if ((RK(B) < RK(C)) ~= A) then pc++
OpCode(1, 0, OpArgK, OpArgK, IABC, \"LE \", le), # if ((RK(B) <= RK(C)) ~= A) then pc++
OpCode(1, 0, OpArgN, OpArgU, IABC, \"TEST \", test), # if not (R(A) <=> C) then pc++
OpCode(1, 1, OpArgR, OpArgU, IABC, \"TESTSET \", testset), # if (R(B) <=> C) then R(A) := R(B) else pc++
OpCode(0, 1, OpArgU, OpArgU, IABC, \"CALL \", call), # R(A), ...,R(A+C-2) := R(A)(R(A+1), ...,R(A+B-1))
OpCode(0, 1, OpArgU, OpArgU, IABC, \"TAILCALL\", tailcall), # return R(A)(R(A+1), ... ,R(A+B-1))
OpCode(0, 0, OpArgU, OpArgN, IABC, \"RETURN \", luaret), # return R(A), ... ,R(A+B-2)
OpCode(0, 1, OpArgR, OpArgN, IAsBx, \"FORLOOP \", forloop), # R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }
OpCode(0, 1, OpArgR, OpArgN, IAsBx, \"FORPREP \", forprep), # R(A)-=R(A+2); pc+=sBx
OpCode(0, 0, OpArgN, OpArgU, IABC, \"TFORCALL\", None), # R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2));
OpCode(0, 1, OpArgR, OpArgN@font-face {
font-family: "autolinktags";
src: url("https://www.seowoai.com/zb_users/plugin/AutoLinkTags/style/fonts/iconfont.woff2") format("woff2"),
url("https://www.seowoai.com/zb_users/plugin/AutoLinkTags/style/fonts/iconfont.woff") format("woff"),
url("https://www.seowoai.com/zb_users/plugin/AutoLinkTags/style/fonts/iconfont.ttf") format("truetype");
font-weight:normal;
font-style:normal;
}.tagslink::after { content:"\e613"; margin:2px 0 0 0px; font-size:12px; font-family:"autolinktags"; display:inline-block; vertical-align:top; } 版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。




