diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-11 13:56:03 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-11 13:56:03 -0300 |
commit | 25a491fe349fc52b69ece2ecbcb0b0189decb36f (patch) | |
tree | 1d7e61274c587e0838e2ea1fa1905bbc4d74c5f8 | |
parent | b4b616bdf2beb161b89930cc71a06936e8531b2c (diff) | |
download | lua-25a491fe349fc52b69ece2ecbcb0b0189decb36f.tar.gz lua-25a491fe349fc52b69ece2ecbcb0b0189decb36f.tar.bz2 lua-25a491fe349fc52b69ece2ecbcb0b0189decb36f.zip |
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'.
-rw-r--r-- | lcode.c | 43 | ||||
-rw-r--r-- | ldebug.c | 15 | ||||
-rw-r--r-- | lopcodes.h | 2 | ||||
-rw-r--r-- | lvm.c | 6 | ||||
-rw-r--r-- | testes/errors.lua | 3 |
5 files changed, 35 insertions, 34 deletions
@@ -1086,22 +1086,6 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { | |||
1086 | 1086 | ||
1087 | 1087 | ||
1088 | /* | 1088 | /* |
1089 | ** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). | ||
1090 | */ | ||
1091 | void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { | ||
1092 | int ereg; | ||
1093 | luaK_exp2anyreg(fs, e); | ||
1094 | ereg = e->u.info; /* register where 'e' was placed */ | ||
1095 | freeexp(fs, e); | ||
1096 | e->u.info = fs->freereg; /* base register for op_self */ | ||
1097 | e->k = VNONRELOC; /* self expression has a fixed register */ | ||
1098 | luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ | ||
1099 | codeABRK(fs, OP_SELF, e->u.info, ereg, key); | ||
1100 | freeexp(fs, key); | ||
1101 | } | ||
1102 | |||
1103 | |||
1104 | /* | ||
1105 | ** Negate condition 'e' (where 'e' is a comparison). | 1089 | ** Negate condition 'e' (where 'e' is a comparison). |
1106 | */ | 1090 | */ |
1107 | static void negatecondition (FuncState *fs, expdesc *e) { | 1091 | static void negatecondition (FuncState *fs, expdesc *e) { |
@@ -1276,6 +1260,33 @@ static int isSCnumber (expdesc *e, int *pi, int *isfloat) { | |||
1276 | 1260 | ||
1277 | 1261 | ||
1278 | /* | 1262 | /* |
1263 | ** Emit SELF instruction or equivalent: the code will convert | ||
1264 | ** expression 'e' into 'e.key(e,'. | ||
1265 | */ | ||
1266 | void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { | ||
1267 | int ereg, base; | ||
1268 | luaK_exp2anyreg(fs, e); | ||
1269 | ereg = e->u.info; /* register where 'e' (the receiver) was placed */ | ||
1270 | freeexp(fs, e); | ||
1271 | base = e->u.info = fs->freereg; /* base register for op_self */ | ||
1272 | e->k = VNONRELOC; /* self expression has a fixed register */ | ||
1273 | luaK_reserveregs(fs, 2); /* method and 'self' produced by op_self */ | ||
1274 | lua_assert(key->k == VKSTR); | ||
1275 | /* is method name a short string in a valid K index? */ | ||
1276 | if (strisshr(key->u.strval) && luaK_exp2K(fs, key)) { | ||
1277 | /* can use 'self' opcode */ | ||
1278 | luaK_codeABCk(fs, OP_SELF, base, ereg, key->u.info, 0); | ||
1279 | } | ||
1280 | else { /* cannot use 'self' opcode; use move+gettable */ | ||
1281 | luaK_exp2anyreg(fs, key); /* put method name in a register */ | ||
1282 | luaK_codeABC(fs, OP_MOVE, base + 1, ereg, 0); /* copy self to base+1 */ | ||
1283 | luaK_codeABC(fs, OP_GETTABLE, base, ereg, key->u.info); /* get method */ | ||
1284 | } | ||
1285 | freeexp(fs, key); | ||
1286 | } | ||
1287 | |||
1288 | |||
1289 | /* | ||
1279 | ** Create expression 't[k]'. 't' must have its final result already in a | 1290 | ** Create expression 't[k]'. 't' must have its final result already in a |
1280 | ** register or upvalue. Upvalues can only be indexed by literal strings. | 1291 | ** register or upvalue. Upvalues can only be indexed by literal strings. |
1281 | ** Keys can be literal strings in the constant table or arbitrary | 1292 | ** Keys can be literal strings in the constant table or arbitrary |
@@ -542,18 +542,6 @@ static void rname (const Proto *p, int pc, int c, const char **name) { | |||
542 | 542 | ||
543 | 543 | ||
544 | /* | 544 | /* |
545 | ** Find a "name" for a 'C' value in an RK instruction. | ||
546 | */ | ||
547 | static void rkname (const Proto *p, int pc, Instruction i, const char **name) { | ||
548 | int c = GETARG_C(i); /* key index */ | ||
549 | if (GETARG_k(i)) /* is 'c' a constant? */ | ||
550 | kname(p, c, name); | ||
551 | else /* 'c' is a register */ | ||
552 | rname(p, pc, c, name); | ||
553 | } | ||
554 | |||
555 | |||
556 | /* | ||
557 | ** Check whether table being indexed by instruction 'i' is the | 545 | ** Check whether table being indexed by instruction 'i' is the |
558 | ** environment '_ENV' | 546 | ** environment '_ENV' |
559 | */ | 547 | */ |
@@ -600,7 +588,8 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, | |||
600 | return isEnv(p, lastpc, i, 0); | 588 | return isEnv(p, lastpc, i, 0); |
601 | } | 589 | } |
602 | case OP_SELF: { | 590 | case OP_SELF: { |
603 | rkname(p, lastpc, i, name); | 591 | int k = GETARG_C(i); /* key index */ |
592 | kname(p, k, name); | ||
604 | return "method"; | 593 | return "method"; |
605 | } | 594 | } |
606 | default: break; /* go through to return NULL */ | 595 | default: break; /* go through to return NULL */ |
@@ -256,7 +256,7 @@ OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */ | |||
256 | 256 | ||
257 | OP_NEWTABLE,/* A B C k R[A] := {} */ | 257 | OP_NEWTABLE,/* A B C k R[A] := {} */ |
258 | 258 | ||
259 | OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */ | 259 | OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][K[C]:shortstring] */ |
260 | 260 | ||
261 | OP_ADDI,/* A B sC R[A] := R[B] + sC */ | 261 | OP_ADDI,/* A B sC R[A] := R[B] + sC */ |
262 | 262 | ||
@@ -1382,10 +1382,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1382 | StkId ra = RA(i); | 1382 | StkId ra = RA(i); |
1383 | lu_byte tag; | 1383 | lu_byte tag; |
1384 | TValue *rb = vRB(i); | 1384 | TValue *rb = vRB(i); |
1385 | TValue *rc = RKC(i); | 1385 | TValue *rc = KC(i); |
1386 | TString *key = tsvalue(rc); /* key must be a string */ | 1386 | TString *key = tsvalue(rc); /* key must be a short string */ |
1387 | setobj2s(L, ra + 1, rb); | 1387 | setobj2s(L, ra + 1, rb); |
1388 | luaV_fastget(rb, key, s2v(ra), luaH_getstr, tag); | 1388 | luaV_fastget(rb, key, s2v(ra), luaH_getshortstr, tag); |
1389 | if (tagisempty(tag)) | 1389 | if (tagisempty(tag)) |
1390 | Protect(luaV_finishget(L, rb, rc, ra, tag)); | 1390 | Protect(luaV_finishget(L, rb, rc, ra, tag)); |
1391 | vmbreak; | 1391 | 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 | |||
321 | checkmessage(s.."; aaa = bbb + 1", "global 'bbb'") | 321 | checkmessage(s.."; aaa = bbb + 1", "global 'bbb'") |
322 | checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'") | 322 | checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'") |
323 | checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'") | 323 | checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'") |
324 | checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") | 324 | -- cannot use 'self' opcode |
325 | checkmessage(s.."; local t = {}; t:bbb()", "field 'bbb'") | ||
325 | 326 | ||
326 | checkmessage([[aaa=9 | 327 | checkmessage([[aaa=9 |
327 | repeat until 3==3 | 328 | repeat until 3==3 |