From 25a491fe349fc52b69ece2ecbcb0b0189decb36f Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 11 Dec 2024 13:56:03 -0300 Subject: [PATCH] OP_SELF restricted to constant short strings Optimize this opcode for the common case. For long names or method calls after too many constants, operation can be coded as a move followed by 'gettable'. --- lcode.c | 43 +++++++++++++++++++++++++++---------------- ldebug.c | 15 ++------------- lopcodes.h | 2 +- lvm.c | 6 +++--- testes/errors.lua | 3 ++- 5 files changed, 35 insertions(+), 34 deletions(-) diff --git a/lcode.c b/lcode.c index 42670794..6c124ff6 100644 --- a/lcode.c +++ b/lcode.c @@ -1085,22 +1085,6 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { } -/* -** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). -*/ -void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { - int ereg; - luaK_exp2anyreg(fs, e); - ereg = e->u.info; /* register where 'e' was placed */ - freeexp(fs, e); - e->u.info = fs->freereg; /* base register for op_self */ - e->k = VNONRELOC; /* self expression has a fixed register */ - luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ - codeABRK(fs, OP_SELF, e->u.info, ereg, key); - freeexp(fs, key); -} - - /* ** Negate condition 'e' (where 'e' is a comparison). */ @@ -1275,6 +1259,33 @@ static int isSCnumber (expdesc *e, int *pi, int *isfloat) { } +/* +** Emit SELF instruction or equivalent: the code will convert +** expression 'e' into 'e.key(e,'. +*/ +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { + int ereg, base; + luaK_exp2anyreg(fs, e); + ereg = e->u.info; /* register where 'e' (the receiver) was placed */ + freeexp(fs, e); + base = e->u.info = fs->freereg; /* base register for op_self */ + e->k = VNONRELOC; /* self expression has a fixed register */ + luaK_reserveregs(fs, 2); /* method and 'self' produced by op_self */ + lua_assert(key->k == VKSTR); + /* is method name a short string in a valid K index? */ + if (strisshr(key->u.strval) && luaK_exp2K(fs, key)) { + /* can use 'self' opcode */ + luaK_codeABCk(fs, OP_SELF, base, ereg, key->u.info, 0); + } + else { /* cannot use 'self' opcode; use move+gettable */ + luaK_exp2anyreg(fs, key); /* put method name in a register */ + luaK_codeABC(fs, OP_MOVE, base + 1, ereg, 0); /* copy self to base+1 */ + luaK_codeABC(fs, OP_GETTABLE, base, ereg, key->u.info); /* get method */ + } + freeexp(fs, key); +} + + /* ** Create expression 't[k]'. 't' must have its final result already in a ** register or upvalue. Upvalues can only be indexed by literal strings. diff --git a/ldebug.c b/ldebug.c index ee3ac17f..09ec197c 100644 --- a/ldebug.c +++ b/ldebug.c @@ -541,18 +541,6 @@ static void rname (const Proto *p, int pc, int c, const char **name) { } -/* -** Find a "name" for a 'C' value in an RK instruction. -*/ -static void rkname (const Proto *p, int pc, Instruction i, const char **name) { - int c = GETARG_C(i); /* key index */ - if (GETARG_k(i)) /* is 'c' a constant? */ - kname(p, c, name); - else /* 'c' is a register */ - rname(p, pc, c, name); -} - - /* ** Check whether table being indexed by instruction 'i' is the ** environment '_ENV' @@ -600,7 +588,8 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, return isEnv(p, lastpc, i, 0); } case OP_SELF: { - rkname(p, lastpc, i, name); + int k = GETARG_C(i); /* key index */ + kname(p, k, name); return "method"; } default: break; /* go through to return NULL */ diff --git a/lopcodes.h b/lopcodes.h index 31f6fac0..7511eb22 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -256,7 +256,7 @@ OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */ OP_NEWTABLE,/* A B C k R[A] := {} */ -OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */ +OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][K[C]:shortstring] */ OP_ADDI,/* A B sC R[A] := R[B] + sC */ diff --git a/lvm.c b/lvm.c index 1c564a71..b6b18a69 100644 --- a/lvm.c +++ b/lvm.c @@ -1382,10 +1382,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { StkId ra = RA(i); lu_byte tag; TValue *rb = vRB(i); - TValue *rc = RKC(i); - TString *key = tsvalue(rc); /* key must be a string */ + TValue *rc = KC(i); + TString *key = tsvalue(rc); /* key must be a short string */ setobj2s(L, ra + 1, rb); - luaV_fastget(rb, key, s2v(ra), luaH_getstr, tag); + luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, tag); if (tagisempty(tag)) Protect(luaV_finishget(L, rb, rc, ra, tag)); vmbreak; diff --git a/testes/errors.lua b/testes/errors.lua index 0925fe58..027e1b03 100644 --- a/testes/errors.lua +++ b/testes/errors.lua @@ -321,7 +321,8 @@ t = nil checkmessage(s.."; aaa = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'") checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'") -checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") +-- cannot use 'self' opcode +checkmessage(s.."; local t = {}; t:bbb()", "field 'bbb'") checkmessage([[aaa=9 repeat until 3==3