Skip to content

Instantly share code, notes, and snippets.

@MDFL64
Created August 17, 2014 02:21
Show Gist options
  • Save MDFL64/228474c4ec949390cddf to your computer and use it in GitHub Desktop.
Save MDFL64/228474c4ec949390cddf to your computer and use it in GitHub Desktop.
o god why
if CLIENT then return end
/* jit.util library functions
funcbc = function: builtin#142
funck = function: builtin#143
funcinfo = function: builtin#141
traceinfo = function: builtin#145
tracek = function: builtin#147
tracesnap = function: builtin#148
traceir = function: builtin#146
tracemc = function: builtin#149
ircalladdr = function: builtin#151
traceexitstub = function: builtin#150
funcuvname = function: builtin#144
*/
local MAX_EXECUTION_TIME = .1
local OPCODE_NAMES = {
"ISGE","ISLE","ISGT",
"ISEQV","ISNEV","ISEQS","ISNES","ISEQN","ISNEN","ISEQP","ISNEP",
"ISTC","ISFC","IST","ISF",
"MOV","NOT","UNM","LEN",
"ADDVN","SUBVN","MULVN","DIVVN","MODVN",
"ADDNV","SUBNV","MULNV","DIVNV","MODNV",
"ADDVV","SUBVV","MULVV","DIVVV","MODVV",
"POW","CAT",
"KSTR","KCDATA","KSHORT","KNUM","KPRI","KNIL",
"UGET","USETV","USETS","USETN","USETP","UCLO","FNEW",
"TNEW","TDUP","GGET","GSET","TGETV","TGETS","TGETB","TSETV","TSETS","TSETB","TSETM",
"CALLM","CALL","CALLMT","CALLT","ITERC","ITERN","VARG","ISNEXT",
"RETM","RET","RET0","RET1",
"FORI","JFORI",
"FORL","IFORL","JFORL",
"ITERL","IITERL","JITERL",
"LOOP","ILOOP","JLOOP",
"JMP",
"FUNCF","IFUNCF","JFUNCF","FUNCV","IFUNCV","JFUNCV","FUNCC","FUNCCW"
}
OPCODE_NAMES[0]="ISLT"
local function INS_GET_A(ins)
return bit.band(bit.rshift(ins,8),255)
end
local function INS_GET_B(ins)
return bit.rshift(ins,24)
end
local function INS_GET_C(ins)
return bit.band(bit.rshift(ins,16),255)
end
local function INS_GET_D(ins)
return bit.rshift(ins,16)
end
local PRIMTYPES = {}
PRIMTYPES[0]=nil
PRIMTYPES[1]=false
PRIMTYPES[2]=true
function func2scode(func)
//Read code
local code = {}
local pc=0
while true do
local ins,m = jit.util.funcbc(func,pc)
if (ins==nil) then break end
code[pc]= ins
pc=pc+1
end
//Read constants
local consts = {}
local cc=0
while true do
local const = jit.util.funck(func,cc)
if (const==nil) then break end
consts[cc]=const
cc=cc+1
end
cc=-1
while true do
local const = jit.util.funck(func,cc)
if (const==nil) then break end
if type(const)=="proto" then
const = func2scode(const)
end
consts[cc]=const
cc=cc-1
end
//Get function info
local info = jit.util.funcinfo(func)
return {___IS_SLAG_CODE___=true,code=code,consts=consts,arg_count=info.params}
end
function scode2blob(scodeTab)
end
local function formatError(err)
return err:gsub("^[^:]+:%d+: ","",1):gsub("^%l",string.upper):gsub("[^!?.]$",function(s) return s.."." end)
end
function VM(scode)
local vm={}
vm.data={}
vm.code=scode.code
vm.consts=scode.consts
vm.arg_count=scode.arg_count
vm.pc = 0
vm.multres = 0
vm.vargs={}
function vm:step()
if self.called_vm then
local status, error_or_retval = self.called_vm:step()
if status==true then
//handle returned stuff
elseif status==false then
return status, error_or_retval
end
end
local ins = self.code[self.pc]
if !ins then return false, "Reached end of code, no return!" end
local op = bit.band(ins,255)
local a = INS_GET_A(ins)
/*
* GreaterThan/LessThan tests. Catch errors because they happen a lot when comparing disparate types.
*/
if op==0 then //ISLT
local d = INS_GET_D(ins)
local _,err = pcall(function() if !(self.data[a]<self.data[d]) then self.pc=self.pc+1 end end)
if err then return false, formatError(err) end
elseif op==1 then //ISGE
local d = INS_GET_D(ins)
local _,err = pcall(function() if !(self.data[a]>=self.data[d]) then self.pc=self.pc+1 end end)
if err then return false, formatError(err) end
elseif op==2 then //ISLE
local d = INS_GET_D(ins)
local _,err = pcall(function() if !(self.data[a]<=self.data[d]) then self.pc=self.pc+1 end end)
if err then return false, formatError(err) end
elseif op==3 then //ISGT
local d = INS_GET_D(ins)
local _,err = pcall(function() if !(self.data[a]>self.data[d]) then self.pc=self.pc+1 end end)
if err then return false, formatError(err) end
/*
* Equivalence tests. Don't catch errors, they're probably the result of shitty metamethod implementations.
*/
elseif op==4 then //ISEQV
local d = INS_GET_D(ins)
if !(self.data[a]==self.data[d]) then self.pc=self.pc+1 end
elseif op==5 then //ISNEV
local d = INS_GET_D(ins)
if !(self.data[a]!=self.data[d]) then self.pc=self.pc+1 end
elseif op==6 then //ISEQS
local str = self:getConst(INS_GET_D(ins))
if !(self.data[a]==str) then self.pc=self.pc+1 end
elseif op==7 then //ISNES
local str = self:getConst(INS_GET_D(ins))
if !(self.data[a]!=str) then self.pc=self.pc+1 end
elseif op==8 then //ISEQN
local num = self:getConstNum(INS_GET_D(ins))
if !(self.data[a]==num) then self.pc=self.pc+1 end
elseif op==9 then //ISNEN
local num = self:getConstNum(INS_GET_D(ins))
if !(self.data[a]!=num) then self.pc=self.pc+1 end
elseif op==10 then //ISEQP
local pri = PRIMTYPES[INS_GET_D(ins)]
if !(self.data[a]==pri) then self.pc=self.pc+1 end
elseif op==11 then //ISNEP
local pri = PRIMTYPES[INS_GET_D(ins)]
if !(self.data[a]!=pri) then self.pc=self.pc+1 end
/*
* Unary tests. Don't catch errors, these are dead simple and should never generate them.
*/
elseif op==12 then //ISTC
local d = self.data[INS_GET_D(ins)]
if d then
self.data[a]=d
else
self.pc=self.pc+1
end
elseif op==13 then //ISFC
local d = self.data[INS_GET_D(ins)]
if !d then
self.data[a]=d
else
self.pc=self.pc+1
end
elseif op==14 then //IST
local d = self.data[INS_GET_D(ins)]
if !d then
self.pc=self.pc+1
end
elseif op==15 then //ISF
local d = self.data[INS_GET_D(ins)]
if d then
self.pc=self.pc+1
end
/*
* Unary Operators. Catch errors for negate and length ops.
*/
elseif op==16 then //MOV
local src = self.data[INS_GET_D(ins)]
self.data[a]= src
elseif op==17 then //NOT
local src = self.data[INS_GET_D(ins)]
self.data[a]= !src
elseif op==18 then //UNM
local d = INS_GET_D(ins)
local _,err = pcall(function() self.data[a]= -self.data[d] end)
if err then return false, formatError(err) end
elseif op==19 then //LEN
local d = INS_GET_D(ins)
local _,err = pcall(function() self.data[a]= #self.data[d] end)
if err then return false, formatError(err) end
/*
* Binary Operators. Catch all errors, lots of stuff can go wrong.
*/
elseif op==20 then //ADDVN
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= self.data[b]+n end)
if err then return false, formatError(err) end
elseif op==21 then //SUBVN
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= self.data[b]-n end)
if err then return false, formatError(err) end
elseif op==22 then //MULVN
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= self.data[b]*n end)
if err then return false, formatError(err) end
elseif op==23 then //DIVVN
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= self.data[b]/n end)
if err then return false, formatError(err) end
elseif op==24 then //MODVN
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= self.data[b]%n end)
if err then return false, formatError(err) end
elseif op==25 then //ADDNV
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= n+self.data[b] end)
if err then return false, formatError(err) end
elseif op==26 then //SUBNV
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= n-self.data[b] end)
if err then return false, formatError(err) end
elseif op==27 then //MULNV
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= n*self.data[b] end)
if err then return false, formatError(err) end
elseif op==28 then //DIVNV
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= n/self.data[b] end)
if err then return false, formatError(err) end
elseif op==29 then //MODNV
local b = INS_GET_B(ins)
local n = self:getConstNum(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]= n%self.data[b] end)
if err then return false, formatError(err) end
elseif op==30 then //ADDVV
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]+self.data[c] end)
if err then return false, formatError(err) end
elseif op==31 then //SUBVV
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]-self.data[c] end)
if err then return false, formatError(err) end
elseif op==32 then //MULVV
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]*self.data[c] end)
if err then return false, formatError(err) end
elseif op==33 then //DIVVV
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]/self.data[c] end)
if err then return false, formatError(err) end
elseif op==34 then //MODVV
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]%self.data[c] end)
if err then return false, formatError(err) end
elseif op==35 then //POW
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]^self.data[c] end)
if err then return false, formatError(err) end
elseif op==36 then //CAT
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]= self.data[b]..self.data[c] end)
if err then return false, formatError(err) end
/*
* Constants. No possibility of errors.
*/
elseif op==37 then //KSTR
local str = self:getConst(INS_GET_D(ins))
self.data[a]=str
elseif op==38 then //KCDATA
return false,"KCDATA OP CALLED. PLEASE INFORM PARAKEET."
elseif op==39 then //KSHORT
local int = INS_GET_D(ins)
self.data[a]=int
elseif op==40 then //KNUM
local num = self:getConstNum(INS_GET_D(ins))
self.data[a]=num
elseif op==41 then //KPRI
local pri = PRIMTYPES[INS_GET_D(ins)]
self.data[a]=pri
elseif op==42 then //KNIL
local last_slot = INS_GET_D(ins)
if last_slot<a then return false,"KNIL END<START. PLEASE INFORM PARAKEET." end
while a<=last_slot do
self.data[a]=nil
a=a+1
end
/*
* Upvalue and Functions.
*/
//SKIP FOR NOW, K?
/*
* Table Ops. Some need error handling.
*/
elseif op==50 then //TNEW
self.data[a]={}
elseif op==51 then //TDUP
local d = INS_GET_D(ins)
self.data[a]=table.Copy(self:getConst(d))
elseif op==52 then //GGET
local name = self:getConst(INS_GET_D(ins))
self.data[a]=_G[name]
elseif op==53 then //GSET
local name = self:getConst(INS_GET_D(ins))
_G[name]=self.data[a]
elseif op==54 then //TGETV
local b = INS_GET_B(ins)
local key = self.data[INS_GET_C(ins)]
local _,err = pcall(function() self.data[a]=self.data[b][key] end)
if err then return false, formatError(err) end
elseif op==55 then //TGETS
local b = INS_GET_B(ins)
local key = self:getConst(INS_GET_C(ins))
local _,err = pcall(function() self.data[a]=self.data[b][key] end)
if err then return false, formatError(err) end
elseif op==56 then //TGETB
local b = INS_GET_B(ins)
local key = INS_GET_C(ins)
local _,err = pcall(function() self.data[a]=self.data[b][key] end)
if err then return false, formatError(err) end
elseif op==57 then //TSETV
local b = INS_GET_B(ins)
local key = self.data[INS_GET_C(ins)]
local _,err = pcall(function() self.data[b][key]=self.data[a] end)
if err then return false, formatError(err) end
elseif op==58 then //TSETS
local b = INS_GET_B(ins)
local key = self:getConst(INS_GET_C(ins))
local _,err = pcall(function() self.data[b][key]=self.data[a] end)
if err then return false, formatError(err) end
elseif op==59 then //TSETB
local b = INS_GET_B(ins)
local key = INS_GET_C(ins)
local _,err = pcall(function() self.data[b][key]=self.data[a] end)
if err then return false, formatError(err) end
elseif op==60 then //TSETM
local tbl = self.data[a-1]
local items = self:getRange(a,self.multres)
//local n = self:getConstNum(INS_GET_D(ins))
//local dingus_offset = bit.band((math.frexp(self:getConstNum(INS_GET_D(ins))) * 2 - 1) * math.ldexp(.5,53),4095)
local tbl_offset = bit.band(self:getConstNum(INS_GET_D(ins))*2,4095)
for k,v in pairs(items) do
tbl[tbl_offset+k-1]=v
end
//local bullshit_magic_indexer, teemo = math.frexp(1000000)
/*print(">>",INS_GET_D(ins),n,frac,dec)
print("AA:",3*(2^52))
print("++",bit.tobit(3*(2^52)))
print("--",bit.band(3*(2^52),2^32-1))
print("##",string.len(dingus_double(n)))*/
print(tbl_offset)
/*
* Calls and Varargs. Handle errors of calls.
*/
elseif op==61 then //CALLM
local func = self.data[a]
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local returns
local _,err = pcall(function() returns = {func(unpack(self:getRange(a+1,c+self.multres)))} end)
if err then return false, formatError(err) end
self:handleReturns(returns,a,b)
elseif op==62 then //CALL
local func = self.data[a]
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
local returns
local _,err = pcall(function() returns = {func(unpack(self:getRange(a+1,c-1)))} end)
if err then return false, formatError(err) end
self:handleReturns(returns,a,b)
elseif op==67 then //VARG
local b = INS_GET_B(ins)
local c = INS_GET_C(ins)
self:handleReturns(self.vargs,a,b)
/*
* Returns.
*/
elseif op==71 then //ret0
return true, {}
elseif op==72 then
local retval = self.data[a]
return true, {retval}
/*
* Loops, Jumps.
*/
elseif op==81 then //LOOP
//EFFECTIVE NOP
elseif op==82 then //ILOOP
//EFFECTIVE NOP
elseif op==83 then //JLOOP
//EFFECTIVE NOP
elseif op==84 then //JMP
self.pc=self.pc+INS_GET_D(ins)-32768
/*
* Function headers. "FUNCF","IFUNCF","JFUNCF","FUNCV","IFUNCV","JFUNCV","FUNCC","FUNCCW"
*/
elseif op==85 then //FUNCF
/*
This passes informations about how big our stack is.
We don't care, since we're a shit VM and just use lau tables for everything.
Maybe will need for upvalues?
*/
elseif op==86 then //IFUNCF
//...
elseif op==87 then //JFUNCF
//...
elseif op==88 then //FUNCV
//NUMBER 88!
elseif op==89 then //IFUNCV
//NOT NUMBER 88!
elseif op==90 then //JFUNCV
//...
elseif op==91 then //FUNCC
//C function header... can this even be called?
elseif op==92 then //FUNCCW
//C wrapped function header... can this even be called?
//There may be some more header opcodes after this!
else
return false, ">> "..OPCODE_NAMES[op].."("..op..")"
end
self.pc=self.pc+1
end
function vm:run(args)
if args then
for k,v in pairs(args) do
if !isnumber(k) then error("SlagVM received malformed arguments table.") end
if k>self.arg_count then
self.vargs[k-self.arg_count]=v
else
self.data[k-1]=v
end
end
end
local start = SysTime()
while true do
local status, error_or_retval = self:step()
if start+MAX_EXECUTION_TIME<SysTime() then
status=false
error_or_retval= "Script timed out."
end
if status==true then
return error_or_retval
elseif status==false then
MsgC(Color(255,100,100),"[SlagVM Error] "..error_or_retval.."\n")
error("SlagVM Halted.",0)
end
end
end
function vm:getConst(i)
return self.consts[-1-i]
end
function vm:getConstNum(i)
return self.consts[i]
end
function vm:getRange(i,count)
local range={}
while true do
if count<=0 then return range end
table.insert(range,self.data[i])
count=count-1
i=i+1
end
end
function vm:handleReturns(returns,a,b)
if b==0 then
self.multres = #returns
for _,v in pairs(returns) do
self.data[a]=v
a=a+1
end
elseif b>1 then
local last_ret_slot = a+b-2
local i=0
while a+i<=last_ret_slot do
self.data[a+i]= returns[i+1]
i=i+1
end
end
end
return vm
end
//Our test function.
local function asshole(a,b,c,...)
print(...)
local dingus = {6,6,6,string.find("dingus mah zingus", "zing")}
PrintTable(dingus)
return 1337
end
local function run_slag(func,...)
MsgC(Color(100,255,100),"[SlagVM] Running function...\n")
local codez = func2scode(asshole)
local machine = VM(codez)
local returned = machine:run{...}
MsgC(Color(100,255,100),"[SlagVM] Returned: ",string.Implode(", ", returned),"\n")
end
run_slag(asshole,"arg1","arg2","arg3","varg1","varg2","varg3")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment