[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Bytecode hacks [fixed]
- From: "Soni L." <fakedme@...>
- Date: Thu, 7 Sep 2017 20:25:10 -0300
On 2017-09-03 11:10 AM, Soni L. wrote:
On 2017-09-02 02:28 PM, Soni L. wrote:
On 2014-05-24 06:24 PM, Mike Nelson wrote:
The bytecode hack that works:
replace the case ':' clause in suffixedexp in lparser.c with:
case ':': { /* `:' NAME funcargs */
expdesc key;
int flag=0;
luaX_next(ls);
if (ls->t.token=='[') {
luaK_exp2anyregup(fs, v);
yindex(ls, &key);
if (key.k==VNONRELOC){flag=1;}
}
else
checkname(ls, &key);
luaK_self(fs, v, &key);
if (flag) ls->fs->freereg++;
funcargs(ls, v, line);
break;
}
This will detect and correct the pathological cases of bytecode
generation.
Special thanks to Luiz for the original patch and to Roberto for
pointing me in the right direction.
Is some kind of error checking in order for the line if (flag)
ls->fs->freereg++;? I don't see the need based on the source code of
yindex, etc., but I could be overlooking something.
If anyone finds a case in which this fails, please let me know, the
detection clause may need to be more complex.
Sorry to bump an old thread, but this appears to no longer work, in
Lua 5.3.4.
Would anyone know of a fix?
Update: I noticed this
https://github.com/lua/lua/commit/257961c601fdec1ea1f9640d460e0d31c39333a1
But even after reverting the commit, I still get "Assertion `reg ==
fs->freereg' failed".
Update: "<Soni> All I [could] think of [was] just getting rid of
luaK_self entirely":
(bonus: includes component syntax)
/* lparser.c:suffixedexp: */
case ':': { /* ':' NAME funcargs */
expdesc key;
int ereg;
luaK_exp2anyreg(fs, v);
ereg = v->u.info; /* register where 'e' was placed */
luaK_freeexp(fs, v);
v->u.info = fs->freereg; /* base register for op_self */
v->k = VNONRELOC; /* self expression has a fixed register */
luaK_reserveregs(fs, 2); /* function and 'self' produced by
op_self */
luaX_next(ls);
if (ls->t.token == '[') {
yindex(ls, &key);
}
else
checkname(ls, &key);
luaK_codeABC(fs, OP_SELF, v->u.info, ereg, luaK_exp2RK(fs, &key));
luaK_freeexp(fs, &key);
if (ls->t.token == '.') { /* component syntax */
expdesc key2;
int rg;
luaX_next(ls); /* skip the dot or colon */
checkname(ls, &key2);
rg = luaK_exp2RK(fs, &key2);
luaK_codeABC(fs, OP_GETTABLE, v->u.info, v->u.info, rg);
if (!ISK(rg) && rg >= fs->nactvar) {
fs->freereg--;
lua_assert(rg == fs->freereg);
}
}
funcargs(ls, v, line);
break;
}
/* lcode.c:freeexp: */
/*
** Free register used by expression 'e' (if any)
*/
static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
}
void luaK_freeexp (FuncState *fs, expdesc *e) {
freeexp(fs, e);
}
/* lcode.h:anywhere: */
LUAI_FUNC void luaK_freeexp (FuncState *fs, expdesc *e);
This compiles, doesn't throw any asserts, and handles all edge-cases
gracefully!
-- tests.lua
local t = setmetatable({}, { __tostring=function()return"t"end})
local F = {}
local T = {}
t.t = t
t.tt = t
t[T] = t
t.f = print
t.ff = print
t[F] = print
local _f="f"
local _t="t"
print("------ t:[k]()")
t:f(1) -- plain old lua
t:[_f](2) -- simple string key in register
t:[string.char(string.byte("f"))](3,32,33) -- string key from function
t:["f".."f"](4) -- string key from concatenation
t:["f"..string.sub("afun",2,2)](5,52,53) -- concatenation with function
result
t:[(string.sub("afun",2,2))](6,62,63) -- function result in parentheses
t:[(function()return"f"end)()](7) -- closure in key
-- be careful with the ambiguous function call!!!
;(function()return t end)():[(function()return"f"end)()](8) -- closure
in object and in key
t:[F](9) -- object key
print("------ t:[k].f()")
t:t.f(1) -- string identifier
t:[_t].f(2) -- string key in register
t:[string.char(string.byte("t"))].f(3,32,33) -- string key from function
t:["t".."t"].f(4) -- string key from concatenation
t:["t"..string.sub("atable",2,2)].f(5,52,53) -- concatenation with
function result
t:[(string.sub("atable",2,2))].f(6,62,63) -- function result in parentheses
t:[(function()return"t"end)()].f(7) -- closure in key
-- be careful with the ambiguous function call!!!
;(function()return t end)():[(function()return"t"end)()].f(8) -- closure
in object and in key
t:[T].f(9) -- object key
-- some fun with ECS/runtime traits
entity = {}
inventory = {get=false, set=false, size=false}
inventory.new=function(size)
local t = {size=function() return size end}
function t.set(e, i, o)
if i <= 0 or i > e:[inventory].size() then error() end
e[inventory][i] = o
end
function t.get(e, i)
if i <= 0 or i > e:[inventory].size() then error() end
return e[inventory][i]
end
return t
end
inventory.of=function(e) -- helper for passing standalone inventories around
return {get=function(...)return e:[inventory].get(...)end,
set=function(...)return e:[inventory].set(...)end,
size=function(...)return e:[inventory].size(...)end}
end
entity[inventory] = inventory.new(5)
entity:[inventory].set(1, "Hello World!")
print(entity:[inventory].get(1))
for i=1, entity:[inventory].size() do
print(i, entity:[inventory].get(i))
end
local myinv = inventory.of(entity)
for i=1, myinv.size() do
print("wrapped", i, myinv.get(i))
end
-- Mike
--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.