local function p(p,g)return function(F)local s=g(F.source,F.index)F.index=F.index+p return s end end local function g(p)local g=p:s_int()local F=table.create(g)for g=1,g,1 do local s=p:s_ins()local r=bit.band(s,63)local u=OPCODE_T[r]local n=OPCODE_M[r]local m={value=s;op=OPCODE_RM[r];A=bit.band(bit.rshift(s,6),255)}if u=="\065\066\067"then m.B=bit.band(bit.rshift(s,23),511)m.C=bit.band(bit.rshift(s,14),511)m.is_KB=n.b=="\079\112\065\114\103\075"and m.B>255 m.is_KC=n.c=="\079\112\065\114\103\075"and m.C>255 elseif u=="\065\066\120"then m.Bx=bit.band(bit.rshift(s,14),262143)m.is_K=n.b=="\079\112\065\114\103\075"elseif u=="\065\115\066\120"then m.sBx=bit.band(bit.rshift(s,14),262143)-131071 end F[g]=m end return F end local function F(p)local g=p:s_int()local F=table.create(g)for g=1,g,1 do local s=stm_byte(p)local r if s==1 then r=stm_byte(p)~=0 elseif s==3 then r=p:s_num()elseif s==4 then r=stm_lstring(p)end F[g]=r end return F end local function s(p,g)local F=p:s_int()local s=table.create(F)for F=1,F,1 do s[F]=stm_lua_func(p,g)end return s end local function r(p)local g=p:s_int()local F=table.create(g)for g=1,g,1 do F[g]=p:s_int()end return F end local function u(p)local g=p:s_int()local F=table.create(g)for g=1,g,1 do F[g]={varname=stm_lstring(p);startpc=p:s_int();endpc=p:s_int()}end return F end local function n(p)local g=p:s_int()local F=table.create(g)for g=1,g,1 do F[g]=stm_lstring(p)end return F end function stm_lua_func(p,m)local R={}local i=stm_lstring(p)or m R.source=i p:s_int()p:s_int()R.num_upval=stm_byte(p)R.num_param=stm_byte(p)stm_byte(p)R.max_stack=stm_byte(p)R.code=g(p)R.const=F(p)R.subs=s(p,i)R.lines=r(p)u(p)n(p)for p,g in ipairs(R.code)do if g.is_K then g.const=R.const[g.Bx+1]else if g.is_KB then g.const_B=R.const[g.B-255]end if g.is_KC then g.const_C=R.const[g.C-255]end end end return R end function lua_bc_to_state(g)local F local s local r local u local n local m local R local i={index=1;source=g}assert(stm_string(i,4)=="\027\076\117\097","\105\110\118\097\108\105\100 \076\117\097 \115\105\103\110\097\116\117\114\101")assert(stm_byte(i)==81,"\105\110\118\097\108\105\100 \076\117\097 \118\101\114\115\105\111\110")assert(stm_byte(i)==0,"\105\110\118\097\108\105\100 \076\117\097 \102\111\114\109\097\116")s=stm_byte(i)~=0 r=stm_byte(i)u=stm_byte(i)n=stm_byte(i)m=stm_byte(i)R=stm_byte(i)~=0 F=s and rd_int_le or rd_int_be i.s_int=cst_int_rdr(r,F)i.s_szt=cst_int_rdr(u,F)i.s_ins=cst_int_rdr(n,F)if R then i.s_num=cst_int_rdr(m,F)elseif float_types[m]then i.s_num=p(m,float_types[m][s and"\108\105\116\116\108\101"or"\098\105\103"])else error("\117\110\115\117\112\112\111\114\116\101\100 \102\108\111\097\116 \115\105\122\101")end return stm_lua_func(i,"\064\118\105\114\116\117\097\108")end local function m(p,g)for F,s in pairs(p)do if s.index>=g then s.value=s.store[s.index]s.store=s s.index="\118\097\108\117\101"p[F]=nil end end end local function R(p,g,F)local s=p[g]if not s then s={index=g;store=F}p[g]=s end return s end local function i(p,g)local F=p.source local s=p.lines[p.pc-1]error(string.format("\037\115\058\037\105\058 \037\115",F,s,g),0)end local function h(p,g,F)local s=p.code local r=p.subs local u=p.vararg local n=-1 local i={}local h=p.memory local U=p.pc while true do local v=s[U]local T=v.op U=U+1 if T<18 then if T<8 then if T<3 then if T<1 then for p=v.A,v.B,1 do h[p]=nil end elseif T>1 then local p=F[v.B]h[v.A]=p.store[p.index]else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p+g end elseif T>3 then if T<6 then if T>4 then local p=v.A local g=v.B local F if v.is_KC then F=v.const_C else F=h[v.C]end h[p+1]=h[g]h[p]=h[g][F]else h[v.A]=g[v.const]end elseif T>6 then local p if v.is_KC then p=v.const_C else p=h[v.C]end h[v.A]=h[v.B][p]else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p-g end else h[v.A]=h[v.B]end elseif T>8 then if T<13 then if T<10 then g[v.const]=h[v.A]elseif T>10 then if T<12 then local p=v.A local g=v.B local F=v.C local s if g==0 then s=n-p else s=g-1 end local r=table.pack(h[p](table.unpack(h,p+1,p+s)))local u=r.n if F==0 then n=(p+u)-1 else u=F-1 end table.move(r,1,u,p,h)else local p=F[v.B]p.store[p.index]=h[v.A]end else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p*g end elseif T>13 then if T<16 then if T>14 then local p=v.A local g=v.B local F if g==0 then F=n-p else F=g-1 end m(i,0)return h[p](table.unpack(h,p+1,p+F))else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A][p]=g end elseif T>16 then h[v.A]={}else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p/g end else h[v.A]=v.const end else local p=v.A local g=h[p+2]local F=h[p]+g local s=h[p+1]local r if g==math.abs(g)then r=F<=s else r=F>=s end if r then h[p]=F h[p+3]=F U=U+v.sBx end end elseif T>18 then if T<28 then if T<23 then if T<20 then h[v.A]=#h[v.B]elseif T>20 then if T<22 then local p=v.A local g=v.B local F if g==0 then F=(n-p)+1 else F=g-1 end m(i,0)return table.unpack(h,p,(p+F)-1)else local p=v.B local g=h[p]for p=p+1,v.C,1 do g=g..h[p]end h[v.A]=g end else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p%g end elseif T>23 then if T<26 then if T>24 then m(i,v.A)else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end if(p==g)==(v.A~=0)then U=U+s[U].sBx end U=U+1 end elseif T>26 then local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end if(p<g)==(v.A~=0)then U=U+s[U].sBx end U=U+1 else local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end h[v.A]=p^g end else h[v.A]=v.B~=0 if v.C~=0 then U=U+1 end end elseif T>28 then if T<33 then if T<30 then local p,g if v.is_KB then p=v.const_B else p=h[v.B]end if v.is_KC then g=v.const_C else g=h[v.C]end if(p<=g)==(v.A~=0)then U=U+s[U].sBx end U=U+1 elseif T>30 then if T<32 then local p=r[v.Bx+1]local u=p.num_upval local n if u~=0 then n={}for p=1,u,1 do local g=s[(U+p)-1]if g.op==OPCODE_RM[0]then n[p-1]=R(i,g.B,h)elseif g.op==OPCODE_RM[4]then n[p-1]=F[g.B]end end U=U+u end h[v.A]=lua_wrap_state(p,g,n)else local p=v.A local g=v.B if not h[g]~=(v.C~=0)then h[p]=h[g]U=U+s[U].sBx end U=U+1 end else h[v.A]=-h[v.B]end elseif T>33 then if T<36 then if T>34 then local p=v.A local g=v.B if g==0 then g=u.len n=(p+g)-1 end table.move(u.list,1,g,p,h)else local p=v.A local g,F,s g=assert(tonumber(h[p]),"\096\102\111\114\096 \105\110\105\116\105\097\108 \118\097\108\117\101 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")F=assert(tonumber(h[p+1]),"\096\102\111\114\096 \108\105\109\105\116 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")s=assert(tonumber(h[p+2]),"\096\102\111\114\096 \115\116\101\112 \109\117\115\116 \098\101 \097 \110\117\109\098\101\114")h[p]=g-s h[p+1]=F h[p+2]=s U=U+v.sBx end elseif T>36 then local p=v.A local g=v.C local F=v.B local s=h[p]local r if F==0 then F=n-p end if g==0 then g=v[U].value U=U+1 end r=(g-1)*FIELDS_PER_FLUSH table.move(h,p+1,p+F,r+1,s)else h[v.A]=not h[v.B]end else if not h[v.A]~=(v.C~=0)then U=U+s[U].sBx end U=U+1 end else local p=v.A local g=p+3 local F={h[p](h[p+1],h[p+2])}table.move(F,1,v.C,g,h)if h[g]~=nil then h[p+2]=h[g]U=U+s[U].sBx end U=U+1 end else U=U+v.sBx end p.pc=U end end function lua_wrap_state(p,g,F)local function s(...)local s=table.pack(...)local r=table.create(p.max_stack)local u={len=0;list={}}table.move(s,1,p.num_param,0,r)if p.num_param<s.n then local g=p.num_param+1 local F=s.n-p.num_param u.len=F table.move(s,g,(g+F)-1,1,u.list)end local n={vararg=u,memory=r;code=p.code;subs=p.subs;pc=1}local m=table.pack(pcall(h,n,g,F))if m[1]then return table.unpack(m,2,m.n)else local g={pc=n.pc;source=p.source,lines=p.lines}i(g,m[2])return end end return s end return function(p,g)return lua_wrap_state(lua_bc_to_state(p),g or getfenv(0))end

local function cst_flt_rdr(len, func)
	return function(S)
		local flt = func(S.source, S.index)
		S.index = S.index + len

		return flt
	end
end

local function stm_inst_list(S)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do
		local ins = S:s_ins()
		local op = bit.band(ins, 0x3F)
		local args = OPCODE_T[op]
		local mode = OPCODE_M[op]
		local data = {value = ins, op = OPCODE_RM[op], A = bit.band(bit.rshift(ins, 6), 0xFF)}

		if args == 'ABC' then
			data.B = bit.band(bit.rshift(ins, 23), 0x1FF)
			data.C = bit.band(bit.rshift(ins, 14), 0x1FF)
			data.is_KB = mode.b == 'OpArgK' and data.B > 0xFF -- post process optimization
			data.is_KC = mode.c == 'OpArgK' and data.C > 0xFF
		elseif args == 'ABx' then
			data.Bx = bit.band(bit.rshift(ins, 14), 0x3FFFF)
			data.is_K = mode.b == 'OpArgK'
		elseif args == 'AsBx' then
			data.sBx = bit.band(bit.rshift(ins, 14), 0x3FFFF) - 131071
		end

		list[i] = data
	end

	return list
end

local function stm_const_list(S)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do
		local tt = stm_byte(S)
		local k

		if tt == 1 then
			k = stm_byte(S) ~= 0
		elseif tt == 3 then
			k = S:s_num()
		elseif tt == 4 then
			k = stm_lstring(S)
		end

		list[i] = k -- offset +1 during instruction decode
	end

	return list
end

local function stm_sub_list(S, src)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do
		list[i] = stm_lua_func(S, src) -- offset +1 in CLOSURE
	end

	return list
end

local function stm_line_list(S)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do list[i] = S:s_int() end

	return list
end

local function stm_loc_list(S)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do list[i] = {varname = stm_lstring(S), startpc = S:s_int(), endpc = S:s_int()} end

	return list
end

local function stm_upval_list(S)
	local len = S:s_int()
	local list = table.create(len)

	for i = 1, len do list[i] = stm_lstring(S) end

	return list
end

function stm_lua_func(S, psrc)
	local proto = {}
	local src = stm_lstring(S) or psrc -- source is propagated

	proto.source = src -- source name

	S:s_int() -- line defined
	S:s_int() -- last line defined

	proto.num_upval = stm_byte(S) -- num upvalues
	proto.num_param = stm_byte(S) -- num params

	stm_byte(S) -- vararg flag
	proto.max_stack = stm_byte(S) -- max stack size

	proto.code = stm_inst_list(S)
	proto.const = stm_const_list(S)
	proto.subs = stm_sub_list(S, src)
	proto.lines = stm_line_list(S)

	stm_loc_list(S)
	stm_upval_list(S)

	-- post process optimization
	for _, v in ipairs(proto.code) do
		if v.is_K then
			v.const = proto.const[v.Bx + 1] -- offset for 1 based index
		else
			if v.is_KB then v.const_B = proto.const[v.B - 0xFF] end

			if v.is_KC then v.const_C = proto.const[v.C - 0xFF] end
		end
	end

	return proto
end

function lua_bc_to_state(src)
	-- func reader
	local rdr_func

	-- header flags
	local little
	local size_int
	local size_szt
	local size_ins
	local size_num
	local flag_int

	-- stream object
	local stream = {
		-- data
		index = 1,
		source = src,
	}

	assert(stm_string(stream, 4) == '\27Lua', 'invalid Lua signature')
	assert(stm_byte(stream) == 0x51, 'invalid Lua version')
	assert(stm_byte(stream) == 0, 'invalid Lua format')

	little = stm_byte(stream) ~= 0
	size_int = stm_byte(stream)
	size_szt = stm_byte(stream)
	size_ins = stm_byte(stream)
	size_num = stm_byte(stream)
	flag_int = stm_byte(stream) ~= 0

	rdr_func = little and rd_int_le or rd_int_be
	stream.s_int = cst_int_rdr(size_int, rdr_func)
	stream.s_szt = cst_int_rdr(size_szt, rdr_func)
	stream.s_ins = cst_int_rdr(size_ins, rdr_func)

	if flag_int then
		stream.s_num = cst_int_rdr(size_num, rdr_func)
	elseif float_types[size_num] then
		stream.s_num = cst_flt_rdr(size_num, float_types[size_num][little and 'little' or 'big'])
	else
		error('unsupported float size')
	end

	return stm_lua_func(stream, '@virtual')
end

local function close_lua_upvalues(list, index)
	for i, uv in pairs(list) do
		if uv.index >= index then
			uv.value = uv.store[uv.index] -- store value
			uv.store = uv
			uv.index = 'value' -- self reference
			list[i] = nil
		end
	end
end

local function open_lua_upvalue(list, index, memory)
	local prev = list[index]

	if not prev then
		prev = {index = index, store = memory}
		list[index] = prev
	end

	return prev
end

local function on_lua_error(failed, err)
	local src = failed.source
	local line = failed.lines[failed.pc - 1]

	error(string.format('%s:%i: %s', src, line, err), 0)
end

local function run_lua_func(state, env, upvals)
	local code = state.code
	local subs = state.subs
	local vararg = state.vararg

	local top_index = -1
	local open_list = {}
	local memory = state.memory
	local pc = state.pc

	while true do
		local inst = code[pc]
		local op = inst.op
		pc = pc + 1

		if op < 18 then
			if op < 8 then
				if op < 3 then
					if op < 1 then
						--[[LOADNIL]]
						for i = inst.A, inst.B do memory[i] = nil end
					elseif op > 1 then
						--[[GETUPVAL]]
						local uv = upvals[inst.B]

						memory[inst.A] = uv.store[uv.index]
					else
						--[[ADD]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs + rhs
					end
				elseif op > 3 then
					if op < 6 then
						if op > 4 then
							--[[SELF]]
							local A = inst.A
							local B = inst.B
							local index

							if inst.is_KC then
								index = inst.const_C
							else
								index = memory[inst.C]
							end

							memory[A + 1] = memory[B]
							memory[A] = memory[B][index]
						else
							--[[GETGLOBAL]]
							memory[inst.A] = env[inst.const]
						end
					elseif op > 6 then
						--[[GETTABLE]]
						local index

						if inst.is_KC then
							index = inst.const_C
						else
							index = memory[inst.C]
						end

						memory[inst.A] = memory[inst.B][index]
					else
						--[[SUB]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs - rhs
					end
				else --[[MOVE]]
					memory[inst.A] = memory[inst.B]
				end
			elseif op > 8 then
				if op < 13 then
					if op < 10 then
						--[[SETGLOBAL]]
						env[inst.const] = memory[inst.A]
					elseif op > 10 then
						if op < 12 then
							--[[CALL]]
							local A = inst.A
							local B = inst.B
							local C = inst.C
							local params

							if B == 0 then
								params = top_index - A
							else
								params = B - 1
							end

							local ret_list = table.pack(memory[A](table.unpack(memory, A + 1, A + params)))
							local ret_num = ret_list.n

							if C == 0 then
								top_index = A + ret_num - 1
							else
								ret_num = C - 1
							end

							table.move(ret_list, 1, ret_num, A, memory)
						else
							--[[SETUPVAL]]
							local uv = upvals[inst.B]

							uv.store[uv.index] = memory[inst.A]
						end
					else
						--[[MUL]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs * rhs
					end
				elseif op > 13 then
					if op < 16 then
						if op > 14 then
							--[[TAILCALL]]
							local A = inst.A
							local B = inst.B
							local params

							if B == 0 then
								params = top_index - A
							else
								params = B - 1
							end

							close_lua_upvalues(open_list, 0)

							return memory[A](table.unpack(memory, A + 1, A + params))
						else
							--[[SETTABLE]]
							local index, value

							if inst.is_KB then
								index = inst.const_B
							else
								index = memory[inst.B]
							end

							if inst.is_KC then
								value = inst.const_C
							else
								value = memory[inst.C]
							end

							memory[inst.A][index] = value
						end
					elseif op > 16 then
						--[[NEWTABLE]]
						memory[inst.A] = {}
					else
						--[[DIV]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs / rhs
					end
				else
					--[[LOADK]]
					memory[inst.A] = inst.const
				end
			else
				--[[FORLOOP]]
				local A = inst.A
				local step = memory[A + 2]
				local index = memory[A] + step
				local limit = memory[A + 1]
				local loops

				if step == math.abs(step) then
					loops = index <= limit
				else
					loops = index >= limit
				end

				if loops then
					memory[A] = index
					memory[A + 3] = index
					pc = pc + inst.sBx
				end
			end
		elseif op > 18 then
			if op < 28 then
				if op < 23 then
					if op < 20 then
						--[[LEN]]
						memory[inst.A] = #memory[inst.B]
					elseif op > 20 then
						if op < 22 then
							--[[RETURN]]
							local A = inst.A
							local B = inst.B
							local len

							if B == 0 then
								len = top_index - A + 1
							else
								len = B - 1
							end

							close_lua_upvalues(open_list, 0)

							return table.unpack(memory, A, A + len - 1)
						else
							--[[CONCAT]]
							local B = inst.B
							local str = memory[B]

							for i = B + 1, inst.C do str = str .. memory[i] end

							memory[inst.A] = str
						end
					else
						--[[MOD]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs % rhs
					end
				elseif op > 23 then
					if op < 26 then
						if op > 24 then
							--[[CLOSE]]
							close_lua_upvalues(open_list, inst.A)
						else
							--[[EQ]]
							local lhs, rhs

							if inst.is_KB then
								lhs = inst.const_B
							else
								lhs = memory[inst.B]
							end

							if inst.is_KC then
								rhs = inst.const_C
							else
								rhs = memory[inst.C]
							end

							if (lhs == rhs) == (inst.A ~= 0) then pc = pc + code[pc].sBx end

							pc = pc + 1
						end
					elseif op > 26 then
						--[[LT]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						if (lhs < rhs) == (inst.A ~= 0) then pc = pc + code[pc].sBx end

						pc = pc + 1
					else
						--[[POW]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						memory[inst.A] = lhs ^ rhs
					end
				else
					--[[LOADBOOL]]
					memory[inst.A] = inst.B ~= 0

					if inst.C ~= 0 then pc = pc + 1 end
				end
			elseif op > 28 then
				if op < 33 then
					if op < 30 then
						--[[LE]]
						local lhs, rhs

						if inst.is_KB then
							lhs = inst.const_B
						else
							lhs = memory[inst.B]
						end

						if inst.is_KC then
							rhs = inst.const_C
						else
							rhs = memory[inst.C]
						end

						if (lhs <= rhs) == (inst.A ~= 0) then pc = pc + code[pc].sBx end

						pc = pc + 1
					elseif op > 30 then
						if op < 32 then
							--[[CLOSURE]]
							local sub = subs[inst.Bx + 1] -- offset for 1 based index
							local nups = sub.num_upval
							local uvlist

							if nups ~= 0 then
								uvlist = {}

								for i = 1, nups do
									local pseudo = code[pc + i - 1]

									if pseudo.op == OPCODE_RM[0] then -- @MOVE
										uvlist[i - 1] = open_lua_upvalue(open_list, pseudo.B, memory)
									elseif pseudo.op == OPCODE_RM[4] then -- @GETUPVAL
										uvlist[i - 1] = upvals[pseudo.B]
									end
								end

								pc = pc + nups
							end

							memory[inst.A] = lua_wrap_state(sub, env, uvlist)
						else
							--[[TESTSET]]
							local A = inst.A
							local B = inst.B

							if (not memory[B]) ~= (inst.C ~= 0) then
								memory[A] = memory[B]
								pc = pc + code[pc].sBx
							end
							pc = pc + 1
						end
					else
						--[[UNM]]
						memory[inst.A] = -memory[inst.B]
					end
				elseif op > 33 then
					if op < 36 then
						if op > 34 then
							--[[VARARG]]
							local A = inst.A
							local len = inst.B

							if len == 0 then
								len = vararg.len
								top_index = A + len - 1
							end

							table.move(vararg.list, 1, len, A, memory)
						else
							--[[FORPREP]]
							local A = inst.A
							local init, limit, step

							init = assert(tonumber(memory[A]), '`for` initial value must be a number')
							limit = assert(tonumber(memory[A + 1]), '`for` limit must be a number')
							step = assert(tonumber(memory[A + 2]), '`for` step must be a number')

							memory[A] = init - step
							memory[A + 1] = limit
							memory[A + 2] = step

							pc = pc + inst.sBx
						end
					elseif op > 36 then
						--[[SETLIST]]
						local A = inst.A
						local C = inst.C
						local len = inst.B
						local tab = memory[A]
						local offset

						if len == 0 then len = top_index - A end

						if C == 0 then
							C = inst[pc].value
							pc = pc + 1
						end

						offset = (C - 1) * FIELDS_PER_FLUSH

						table.move(memory, A + 1, A + len, offset + 1, tab)
					else
						--[[NOT]]
						memory[inst.A] = not memory[inst.B]
					end
				else
					--[[TEST]]
					if (not memory[inst.A]) ~= (inst.C ~= 0) then pc = pc + code[pc].sBx end
					pc = pc + 1
				end
			else
				--[[TFORLOOP]]
				local A = inst.A
				local base = A + 3

				local vals = {memory[A](memory[A + 1], memory[A + 2])}

				table.move(vals, 1, inst.C, base, memory)

				if memory[base] ~= nil then
					memory[A + 2] = memory[base]
					pc = pc + code[pc].sBx
				end

				pc = pc + 1
			end
		else
			--[[JMP]]
			pc = pc + inst.sBx
		end

		state.pc = pc
	end
end

function lua_wrap_state(proto, env, upval)
	local function wrapped(...)
		local passed = table.pack(...)
		local memory = table.create(proto.max_stack)
		local vararg = {len = 0, list = {}}

		table.move(passed, 1, proto.num_param, 0, memory)

		if proto.num_param < passed.n then
			local start = proto.num_param + 1
			local len = passed.n - proto.num_param

			vararg.len = len
			table.move(passed, start, start + len - 1, 1, vararg.list)
		end

		local state = {vararg = vararg, memory = memory, code = proto.code, subs = proto.subs, pc = 1}

		local result = table.pack(pcall(run_lua_func, state, env, upval))

		if result[1] then
			return table.unpack(result, 2, result.n)
		else
			local failed = {pc = state.pc, source = proto.source, lines = proto.lines}

			on_lua_error(failed, result[2])

			return
		end
	end

	return wrapped
end

return function(bCode, env)
	return lua_wrap_state(lua_bc_to_state(bCode), env or getfenv(0))
end
