1 Star 0 Fork 0

Jaesoon/luaEngine

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
lcode.c 51.58 KB
一键复制 编辑 原始数据 按行查看 历史
jaesonzhang 提交于 2024-07-16 20:56 . 注释代码提交
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
/*
** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#define lcode_c
#define LUA_CORE
#include "lprefix.h"
#include <math.h>
#include <stdlib.h>
#include "lua.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
/* Maximum number of registers in a Lua function (must fit in 8 bits) */
#define MAXREGS 255
#define hasjumps(e) ((e)->t != (e)->f)
/*
** If expression is a numeric constant, fills 'v' with its value
** and returns 1. Otherwise, returns 0.
*/
static int tonumeral(const expdesc *e, TValue *v) {
if (hasjumps(e))
return 0; /* not a numeral */
switch (e->k) {
case VKINT:
if (v) setivalue(v, e->u.ival);
return 1;
case VKFLT:
if (v) setfltvalue(v, e->u.nval);
return 1;
default:
return 0;
}
}
/*
** Create a OP_LOADNIL instruction, but try to optimize: if the previous
** instruction is also OP_LOADNIL and ranges are compatible, adjust
** range of previous instruction instead of emitting a new one. (For
** instance, 'local a; local b' will generate a single opcode.)
*/
void luaK_nil(FuncState *fs, int from, int n) {
Instruction *previous;
int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->code[fs->pc - 1];
if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
int pfrom = GETARG_A(*previous); /* get previous range */
int pl = pfrom + GETARG_B(*previous);
if ((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
if (pl > l) l = pl; /* l = max(l, pl) */
SETARG_A(*previous, from);
SETARG_B(*previous, l - from);
return;
}
} /* else go through */
}
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
}
/*
** Gets the destination address of a jump instruction. Used to traverse
** a list of jumps.
*/
static int getjump(FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */
return NO_JUMP; /* end of list */
else
return (pc + 1) + offset; /* turn offset into absolute position */
}
/*
** Fix jump instruction at position 'pc' to jump to 'dest'.
** (Jump addresses are relative in Lua)
*/
static void fixjump(FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc];
int offset = dest - (pc + 1);
lua_assert(dest != NO_JUMP);
if (abs(offset) > MAXARG_sBx)
luaX_syntaxerror(fs->ls, "control structure too long");
SETARG_sBx(*jmp, offset);
}
/*
** Concatenate jump-list 'l2' into jump-list 'l1'
*/
void luaK_concat(FuncState *fs, int *l1, int l2) {
if (l2 == NO_JUMP) return; /* nothing to concatenate? */
else if (*l1 == NO_JUMP) /* no original list? */
*l1 = l2; /* 'l1' points to 'l2' */
else {
int list = *l1;
int next;
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
list = next;
fixjump(fs, list, l2); /* last element links to 'l2' */
}
}
/*
** Create a jump instruction and return its position, so its destination
** can be fixed later (with 'fixjump'). If there are jumps to
** this position (kept in 'jpc'), link them all together so that
** 'patchlistaux' will fix all them directly to the final destination.
*/
int luaK_jump(FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
fs->jpc = NO_JUMP; /* no more jumps to here */
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
/*
** Code a 'return' instruction
*/
void luaK_ret(FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret + 1, 0);
}
/*
** Code a "conditional jump", that is, a test or comparison opcode
** followed by a jump. Return jump position.
*/
static int condjump(FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs);
}
/*
** returns current 'pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
*/
int luaK_getlabel(FuncState *fs) {
fs->lasttarget = fs->pc;
return fs->pc;
}
/*
** Returns the position of the instruction "controlling" a given
** jump (that is, its condition), or the jump itself if it is
** unconditional.
*/
static Instruction *getjumpcontrol(FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi - 1))))
return pi - 1;
else
return pi;
}
/*
** Patch destination register for a TESTSET instruction.
** If instruction in position 'node' is not a TESTSET, return 0 ("fails").
** Otherwise, if 'reg' is not 'NO_REG', set it as the destination
** register. Otherwise, change instruction to a simple 'TEST' (produces
** no register value)
*/
static int patchtestreg(FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
else {
/* no register to put value or register already has the value;
change instruction to simple test */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
}
return 1;
}
/*
** Traverse a list of tests ensuring no one produces a value
*/
static void removevalues(FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
/*
** Traverse a list of tests, patching their destination address and
** registers: tests producing values jump to 'vtarget' (and put their
** values in 'reg'), other tests jump to 'dtarget'.
*/
static void patchlistaux(FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
int next = getjump(fs, list);
if (patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget);
else
fixjump(fs, list, dtarget); /* jump to default target */
list = next;
}
}
/*
** Ensure all pending jumps to current position are fixed (jumping
** to current position with no values) and reset list of pending
** jumps
*/
static void dischargejpc(FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
/*
** Add elements in 'list' to list of pending jumps to "here"
** (current position)
*/
void luaK_patchtohere(FuncState *fs, int list) {
luaK_getlabel(fs); /* mark "here" as a jump target */
luaK_concat(fs, &fs->jpc, list);
}
/*
** Path all jumps in 'list' to jump to 'target'.
** (The assert means that we cannot fix a jump to a forward address
** because we only know addresses once code is generated.)
*/
void luaK_patchlist(FuncState *fs, int list, int target) {
if (target == fs->pc) /* 'target' is current position? */
luaK_patchtohere(fs, list); /* add list to pending jumps */
else {
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
}
}
/*
** Path all jumps in 'list' to close upvalues up to given 'level'
** (The assertion checks that jumps either were closing nothing
** or were closing higher levels, from inner blocks.)
*/
void luaK_patchclose(FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
for (; list != NO_JUMP; list = getjump(fs, list)) {
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
}
}
/*
** Emit instruction 'i', checking for array sizes and saving also its
** line information. Return 'i' position.
*/
static int luaK_code(FuncState *fs, Instruction i) {
Proto *f = fs->f; // 获取当前函数的原型结构体
// 确保任何待处理的跳转(jump control points)都已解决,因为 pc 即将改变
dischargejpc(fs); /* 'pc' will change */
/* 在代码数组中放入新的指令 */
/* put new instruction in code array */
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT, "opcodes");
// 将指令 i 放入代码数组的当前位置
f->code[fs->pc] = i;
/* 保存对应指令的行号信息(用于lua代码调试)*/
/* save corresponding line information */
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
MAX_INT, "opcodes");
// 将当前的行号信息存储在行号数组的当前位置
f->lineinfo[fs->pc] = fs->ls->lastline;
// 返回当前指令的位置,并准备下一个指令的位置
return fs->pc++;
}
/*
** Format and emit an 'iABC' instruction. (Assertions check consistency
** of parameters versus opcode.)
*/
int luaK_codeABC(FuncState *fs, OpCode o, int a, int b, int c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
lua_assert(getCMode(o) != OpArgN || c == 0);
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
return luaK_code(fs, CREATE_ABC(o, a, b, c));
}
/*
** Format and emit an 'iABx' instruction.
*/
int luaK_codeABx(FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, bc));
}
/*
** Emit an "extra argument" instruction (format 'iAx')
*/
static int codeextraarg(FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
/*
** Emit a "load constant" instruction, using either 'OP_LOADK'
** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'
** instruction with "extra argument".
*/
int luaK_codek(FuncState *fs, int reg, int k) {
if (k <= MAXARG_Bx)
return luaK_codeABx(fs, OP_LOADK, reg, k);
else {
int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
codeextraarg(fs, k);
return p;
}
}
/*
** Check register-stack level, keeping track of its maximum size
** in field 'maxstacksize'
*/
void luaK_checkstack(FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXREGS)
luaX_syntaxerror(fs->ls,
"function or expression needs too many registers");
fs->f->maxstacksize = cast_byte(newstack);
}
}
/*
** Reserve 'n' registers in register stack
*/
void luaK_reserveregs(FuncState *fs, int n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
/*
** Free register 'reg', if it is neither a constant index nor
** a local variable.
*/
static void freereg(FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
}
}
/*
** Free register used by expression 'e' (if any)
*/
static void freeexp(FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
}
/*
** Free registers used by expressions 'e1' and 'e2' (if any) in proper
** order.
*/
static void freeexps(FuncState *fs, expdesc *e1, expdesc *e2) {
int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;
int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;
if (r1 > r2) {
freereg(fs, r1);
freereg(fs, r2);
} else {
freereg(fs, r2);
freereg(fs, r1);
}
}
/*
** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list
** and try to reuse constants. Because some values should not be used
** as keys (nil cannot be a key, integer keys can collapse with float
** keys), the caller must provide a useful 'key' for indexing the cache.
* 用于将常量值 v 添加到函数原型 f 的常量表中。这个函数使用词法分析器的哈希表 h 来缓存常量的索引,
* 以便于重用已有的常量,避免重复添加相同的常量。这在编译时常量折叠(constant folding)和优化中很有用。
* addk 函数的主要步骤包括:
* 获取当前 Lua 状态和函数原型:从 FuncState 结构体中获取 lua_State 和 Proto 结构体指针。
* 在词法分析器的哈希表中查找常量索引:使用 luaH_set 函数在词法分析器的哈希表中查找给定 key 对应的常量索引。
* 检查是否已经有相同的常量:如果找到了索引,并且该索引处的常量与 v 相等,则重用这个索引。
* 创建新的常量条目:如果没有找到相同的常量,使用 luaM_growvector 扩展常量表以容纳新的常量。
* 初始化新条目并添加常量:将新分配的常量表条目初始化为 nil,然后将常量 v 添加到常量表中。
* 更新常量数量:增加 FuncState 中记录的常量数量 nk。
* 更新垃圾收集器屏障:调用 luaC_barrier 更新垃圾收集器的屏障,因为常量表可能指向了一个新的垃圾收集对象。
* 返回新常量的索引:函数返回新添加常量的索引,这个索引可以用于字节码中的常量引用。
* 通过使用 addk 函数,Lua 编译器能够有效地管理常量表,避免重复添加相同的常量,从而优化了内存使用和字节码大小。同时,它还确保了垃圾收集器能够正确跟踪新添加的常量对象。
*/
static int addk(FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
Proto *f = fs->f;
TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */
int k, oldsize;
if (ttisinteger(idx)) { /* is there an index there? */
k = cast_int(ivalue(idx));
/* correct value? (warning: must distinguish floats from integers!) */
if (k < fs->nk && ttype(&f->k[k]) == ttype(v) &&
luaV_rawequalobj(&f->k[k], v))
return k; /* reuse index */
}
/* constant not found; create a new entry */
oldsize = f->sizek;
k = fs->nk;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
// 保存到 proto.k 中
setobj(L, &f->k[k], v);
fs->nk++;
luaC_barrier(L, f, v);
return k;
}
/*
** Add a string to list of constants and return its index.
* 添加一个String到FuncState的常量表中,并返回它在常量表中的索引
*/
int luaK_stringK(FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
return addk(fs, &o, &o); /* use string itself as key */
}
/*
** Add an integer to list of constants and return its index.
** Integers use userdata as keys to avoid collision with floats with
** same value; conversion to 'void*' is used only for hashing, so there
** are no "precision" problems.
*/
int luaK_intK(FuncState *fs, lua_Integer n) {
TValue k, o;
// setpvalue 是一个宏,用于设置一个 TValue 类型的值(Lua 中的一个值)的指针部分,并指定其类型。
// 使用宏 setpvalue 设置 k 的指针值为 n 的 void* 类型表示。
// 这里通过 size_t 中转是为了避免直接将 lua_Integer 转换为 void* 可能引起的精度问题。
// 这里根据 n, 构造了一个 k,k和n一一映射绑定。目的是为了重复利用数字类型的敞亮
setpvalue(&k, cast(void*, cast(size_t, n)));
setivalue(&o, n);
return addk(fs, &k, &o);
}
/*
** Add a float to list of constants and return its index.
** 将一个浮点数字加到常量池中,并返回他在常量池中的索引
*/
static int luaK_numberK(FuncState *fs, lua_Number r) {
TValue o;
setfltvalue(&o, r);
return addk(fs, &o, &o); /* use number itself as key */
}
/*
** Add a boolean to list of constants and return its index.
*/
static int boolK(FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
return addk(fs, &o, &o); /* use boolean itself as key */
}
/*
** Add nil to list of constants and return its index.
*/
static int nilK(FuncState *fs) {
TValue k, v;
setnilvalue(&v);
/* cannot use nil as key; instead use table itself to represent nil */
sethvalue(fs->ls->L, &k, fs->ls->h);
return addk(fs, &k, &v);
}
/*
** Fix an expression to return the number of results 'nresults'.
** Either 'e' is a multi-ret expression (function call or vararg)
** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
*/
void luaK_setreturns(FuncState *fs, expdesc *e, int nresults) {
if (e->k == VCALL) { /* expression is an open function call? */
SETARG_C(getinstruction(fs, e), nresults + 1);
} else if (e->k == VVARARG) {
Instruction *pc = &getinstruction(fs, e);
SETARG_B(*pc, nresults + 1);
SETARG_A(*pc, fs->freereg);
luaK_reserveregs(fs, 1);
} else
lua_assert(nresults == LUA_MULTRET);
}
/*
** Fix an expression to return one result.
** If expression is not a multi-ret expression (function call or
** vararg), it already returns one result, so nothing needs to be done.
** Function calls become VNONRELOC expressions (as its result comes
** fixed in the base register of the call), while vararg expressions
** become VRELOCABLE (as OP_VARARG puts its results where it wants).
** (Calls are created returning one result, so that does not need
** to be fixed.)
*/
void luaK_setoneret(FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */
/* already returns 1 value */
lua_assert(GETARG_C(getinstruction(fs, e)) == 2);
e->k = VNONRELOC; /* result has fixed position */
e->u.info = GETARG_A(getinstruction(fs, e));
} else if (e->k == VVARARG) {
SETARG_B(getinstruction(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */
}
}
/*
** Ensure that expression 'e' is not a variable.
* 用于确保表达式 e 不再是一个变量,即它不依赖于任何未解决的变量或上值。
* 这个函数通过生成适当的字节码指令来“放电”变量,将其值移动到一个寄存器中,或者生成一个可以立即执行的指令。
* 函数的主要任务是处理以下几种情况:
* 局部变量(VLOCAL):如果表达式是一个局部变量,它已经是在寄存器中的,函数将其标记为 VNONRELOC(非可重定位值)。
* 上值(VUPVAL):如果表达式是一个上值,函数生成一个 OP_GETUPVAL 指令来获取上值,并将其标记为 VRELOCABLE(可重定位值)。
* 索引变量(VINDEXED):如果表达式是一个索引操作(例如,访问表中的元素),
* 函数生成一个 OP_GETTABLE 或 OP_GETTABUP 指令来获取索引值,并将其标记为 VRELOCABLE。
* 可变参数(VVARARG)和函数调用(VCALL):这些情况需要特殊处理,因为它们可能产生多个返回值。
* luaK_setoneret 函数确保这些表达式只产生一个返回值。
* 在每种情况下,函数都通过调用 luaK_codeABC 来生成相应的字节码指令,该指令的 A、B、C 字段分别对应操作码的参数。
* freereg 函数用于释放不再需要的寄存器。
* 通过这种方式,luaK_dischargevars 确保表达式 e 不再包含任何变量引用,这有助于编译器生成更高效的代码,
* 因为变量的值已经被移动到了寄存器中,或者可以立即通过字节码指令获取。
*/
void luaK_dischargevars(FuncState *fs, expdesc *e) {
// 根据表达式 e 的类型,进行不同的处理
switch (e->k) {
case VLOCAL: { /* already in a register */ /* 已经是在寄存器中的局部变量 */
// 将表达式标记为非可重定位值
e->k = VNONRELOC; /* becomes a non-relocatable value */
break;
}
case VUPVAL: { /* move value to some (pending) register */ /* 将上值移动到某个(待处理的)寄存器 */
// 生成获取上值的字节码指令,并得到指令在字节码中的位置,并更新 e 为可重定位值
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
case VINDEXED: {
OpCode op;
// 释放索引寄存器
freereg(fs, e->u.ind.idx);
// 检查表是在局部变量还是上值中
if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */
// 如果表是局部变量,释放表的寄存器,并生成 gettable 指令
// 如果是一个 local 变量,则直接生成一个 gettable 指令,从变量表中获取变量
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
} else {
lua_assert(e->u.ind.vt == VUPVAL);
/* 表示在一个上值中 */
op = OP_GETTABUP; /* 't' is in an upvalue */
}
// 生成获取表中元素的字节码指令,并更新 e 为当前指令PC
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break;
}
case VVARARG:
case VCALL: {
// 对于可变参数和函数调用,确保它们只有一个返回值
luaK_setoneret(fs, e);
break;
}
default:
break; /* there is one value available (somewhere) */
}
}
/*
** Ensures expression value is in register 'reg' (and therefore
** 'e' will become a non-relocatable expression).
** 生成代码,将指定表达式e的值,加载到指定寄存器中
** 用于确保表达式 e 的值被加载到指定的寄存器 reg 中。
** 这样做的目的是使表达式 e 成为一个非可重定位(non-relocatable)表达式,
** 即其结果不再依赖于运行时的某些动态状态,而是直接存储在一个固定的寄存器中。
** discharge2reg 函数通过 switch 语句根据表达式 e 的当前类型,调用不同的 luaK_ 系列函数来生成相应的字节码指令,
** 将表达式的值放入指定的寄存器 reg 中。这些指令包括:
** luaK_nil:生成一个将空值序列放入寄存器的指令。
** luaK_codeABC:生成一个 ABC 格式的指令,用于加载布尔值、移动寄存器值等。
** luaK_codek:生成一个将字面量值放入寄存器的指令。
** luaK_numberK 和 luaK_intK:将浮点数或整数字面量转换为 Lua 可以处理的形式,并请求一个寄存器来存储这个字面量。
** 函数的最后,它更新了 expdesc 结构体 e,将 e->u.info 设置为 reg,表示表达式的值现在位于寄存器 reg 中,
** 并将 e->k 设置为 VNONRELOC,表示表达式现在是非可重定位的。
** 这允许后续的代码生成步骤直接引用这个寄存器,而不需要考虑表达式的原始形式。
*/
static void discharge2reg(FuncState *fs, expdesc *e, int reg) {
// 首先,放电表达式中的任何变量,确保它们已经在寄存器中
luaK_dischargevars(fs, e);
// 根据表达式的类型,生成相应的代码将值放入寄存器 reg 中
switch (e->k) {
case VNIL: {
// 如果表达式的类型是 VNIL(空值),则生成一个将空值放入寄存器的指令
luaK_nil(fs, reg, 1);
break;
}
case VFALSE:
case VTRUE: {
// 如果表达式的类型是 VFALSE 或 VTRUE(布尔值),则生成一个加载布尔值的指令
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
break;
}
case VK: {
// 如果表达式的类型是 VK(表明位于常量池中),则生成一个加载常量池常量到寄存器中的指令
luaK_codek(fs, reg, e->u.info);
break;
}
case VKFLT: {
// 如果表达式的类型是 VKFLT(常量池中的浮点字面量),生成加载该浮点数到指定寄存器中的指令
luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
break;
}
case VKINT: {
// 如果表达式的类型是 VKINT(常量池中的整数字面量),生成加载该整数到指定寄存器中指令
luaK_codek(fs, reg, luaK_intK(fs, e->u.ival));
break;
}
case VRELOCABLE: {
// 如果表达式的类型是 VRELOCABLE(可重定位值),则直接修改原来的指令,使其结果放入 reg
Instruction *pc = &getinstruction(fs, e);
SETARG_A(*pc, reg); /* instruction will put result in 'reg' */
break;
}
case VNONRELOC: {
// 如果表达式的类型是 VNONRELOC(非可重定位值),并且目标寄存器不是当前寄存器,则生成一个移动指令(本质上是一个复制指令)
if (reg != e->u.info)
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
break;
}
default: {
// 如果表达式的类型是 VJMP(跳转),则不需要做任何事情,因为跳转已经处理完毕
lua_assert(e->k == VJMP);
return; /* nothing to do... */
}
}
// 更新表达式描述,记录值现在所在的寄存器,并将类型设置为 VNONRELOC
e->u.info = reg;
e->k = VNONRELOC;
}
/*
** Ensures expression value is in any register.
*/
static void discharge2anyreg(FuncState *fs, expdesc *e) {
if (e->k != VNONRELOC) { /* no fixed register yet? */
luaK_reserveregs(fs, 1); /* get a register */
discharge2reg(fs, e, fs->freereg - 1); /* put value there */
}
}
static int code_loadbool(FuncState *fs, int A, int b, int jump) {
luaK_getlabel(fs); /* those instructions may be jump targets */
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}
/*
** check whether list has any jump that do not produce a value
** or produce an inverted value
*/
static int need_value(FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) {
Instruction i = *getjumpcontrol(fs, list);
if (GET_OPCODE(i) != OP_TESTSET) return 1;
}
return 0; /* not found */
}
/*
** Ensures final expression result (including results from its jump
** lists) is in register 'reg'.
** If expression has jumps, need to patch these jumps either to
** its final position or to "load" instructions (for those tests
** that do not produce values).
** exp2reg 函数的主要职责是确保表达式 e 的结果值位于一个寄存器中,并且处理与该表达式相关的所有跳转。这包括:
** 使用 discharge2reg 将表达式的值移动到指定的寄存器中。
** 如果表达式本身是一个跳转,将其添加到跳转列表 e->t 中。
** 检查表达式是否包含跳转,如果是,则为 false 和 true 的情况生成 LOAD 指令,并使用 patchlistaux 将跳转列表中的所有跳转目标修改为表达式之后的代码位置。
** 清理表达式描述,确保它不再引用任何跳转,并将表达式的类型设置为 VNONRELOC,表示结果是一个固定的寄存器值。
*/
static void exp2reg(FuncState *fs, expdesc *e, int reg) {
// 首先,将表达式 e 的值(如果还不是寄存器)移动到寄存器 reg 中
discharge2reg(fs, e, reg);
// 如果表达式本身是一个跳转(例如,一个条件表达式的结果),则将该跳转添加到 e->t 列表中
if (e->k == VJMP) {
/* expression itself is a test? */
luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */
}
// 如果表达式 e 包含跳转,处理这些跳转
if (hasjumps(e)) {
// 最终位置,即整个表达式之后的代码位置
int final; /* position after whole expression */
// 用于 LOAD false 的跳转位置
int p_f = NO_JUMP; /* position of an eventual LOAD false */
// 用于 LOAD true 的跳转位置
int p_t = NO_JUMP; /* position of an eventual LOAD true */
// 如果表达式的真值或假值被需要,则生成一个跳转,并为 false 和 true 分别创建 LOAD 指令
if (need_value(fs, e->t) || need_value(fs, e->f)) {
// 如果 e 本身不是跳转,则创建一个新跳转
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
// 生成一个 LOAD false 的指令
p_f = code_loadbool(fs, reg, 0, 1);
// 生成一个 LOAD true 的指令
p_t = code_loadbool(fs, reg, 1, 0);
// 将之前创建的跳转(如果存在)指向当前位置
luaK_patchtohere(fs, fj);
}
// 获取当前表达式之后的标签
final = luaK_getlabel(fs);
// 将 e->f 列表中的所有跳转修改为目标位置 final,并将结果值存入寄存器 reg
patchlistaux(fs, e->f, final, reg, p_f);
// 将 e->t 列表中的所有跳转修改为目标位置 final,并将结果值存入寄存器 reg
patchlistaux(fs, e->t, final, reg, p_t);
}
// 清理 e,确保它不再引用任何跳转
e->f = e->t = NO_JUMP;
// 记录表达式值所在的寄存器
e->u.info = reg;
// 设置表达式的类型为 VNONRELOC,表示结果值现在是一个固定的寄存器值,不需要进一步的处理
e->k = VNONRELOC;
}
/*
** Ensures final expression result (including results from its jump
** lists) is in next available register.
* 这个函数的作用就是:生成一段代码,将一个表达式表达的内容,复制到下一个寄存器中
* 简单来说,就是将解析到expdesc中值,变成一个寄存器中的值,确定到某一个具体的寄存器中
** 用于确保表达式的结果(包括来自其跳转列表的结果)位于下一个可用的寄存器中。
** 这个函数对于生成高效的字节码非常重要,因为它确保了表达式的结果可以直接在寄存器中访问,而不是散布在栈上。
*/
void luaK_exp2nextreg(FuncState *fs, expdesc *e) {
// 调用 luaK_dischargevars 函数,它的目的是将表达式 e 中的所有变量(如果有的话)“放电”,
// 即将它们从原来可能的上值或寄存器中加载到新的寄存器中。这样做是为了确保表达式的结果不会依赖于任何未解决的上值或变量状态。
luaK_dischargevars(fs, e);
// 它的目的是“释放”表达式 e,即清理 expdesc 结构体,使其不再指向任何特定的变量或寄存器。
// 这通常意味着将 expdesc 的类型设置为 VVOID,表示它不包含有效的表达式。
freeexp(fs, e);
// 调用 luaK_reserveregs 函数,为表达式的结果预留一个寄存器。参数 1 表示需要预留一个寄存器。
luaK_reserveregs(fs, 1);
// 调用 exp2reg 函数,生成一段代码,将表达式 e 的结果移动到刚刚预留的寄存器中。参数 fs->freereg - 1 表示预留的寄存器的索引。
exp2reg(fs, e, fs->freereg - 1);
}
/*
** Ensures final expression result (including results from its jump
** lists) is in some (any) register and return that register.
* 用于确保表达式 e 的结果位于任意一个寄存器中,并返回该寄存器的索引。
* 如果表达式已经在某个寄存器中,并且没有相关的跳转(即没有多个执行路径),函数将返回该寄存器。
* 否则,它会使用 luaK_exp2nextreg 函数将表达式的结果移动到下一个可用的寄存器中。
* luaK_exp2anyreg 函数的主要步骤包括:
* 放电变量:luaK_dischargevars(fs, e); 确保表达式 e 中的任何变量都已经在寄存器中。
* 检查是否已有寄存器:如果表达式 e 已经是 VNONRELOC 类型(即已经在寄存器中),函数继续检查:
* 如果没有跳转(!hasjumps(e)),直接返回该寄存器的索引 e->u.info。
* 如果寄存器索引不是局部变量的索引(e->u.info >= fs->nactvar),则使用 exp2reg 函数将表达式的结果移动到该寄存器,并返回索引。
* 使用下一个寄存器:如果表达式不在寄存器中,或者不能重用当前寄存器,
* 函数调用 luaK_exp2nextreg(fs, e); 来确保表达式的结果在下一个可用的寄存器中,并返回该寄存器的索引。
* 通过这种方式,luaK_exp2anyreg 函数确保了表达式的结果可以在 Lua 字节码中作为一个寄存器值被引用,
* 这有助于优化代码生成,因为它避免了在运行时对变量的重复查找和加载。
*/
int luaK_exp2anyreg(FuncState *fs, expdesc *e) {
// 首先,放电表达式中的任何变量,确保它们已经在寄存器中
luaK_dischargevars(fs, e);
/* 表达式已经在寄存器中? */
if (e->k == VNONRELOC) { /* expression already has a register? */
/* 没有跳转? */
if (!hasjumps(e)) /* no jumps? */
return e->u.info; /* result is already in a register */
/* 寄存器不是局部变量? */
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
// 将最终结果放入该寄存器中
exp2reg(fs, e, e->u.info); /* put final result in it */
return e->u.info;
}
}
// 否则,使用下一个可用的寄存器
luaK_exp2nextreg(fs, e); /* otherwise, use next available register */
// 返回表达式结果所在的寄存器索引
return e->u.info;
}
/*
** Ensures final expression result is either in a register or in an
** upvalue.
*/
void luaK_exp2anyregup(FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
/*
** Ensures final expression result is either in a register or it is
** a constant.
*/
void luaK_exp2val(FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
else
luaK_dischargevars(fs, e);
}
/*
** Ensures final expression result is in a valid R/K index
** (that is, it is either in a register or in 'k' with an index
** in the range of R/K indices).
** Returns R/K index.
* luaK_exp2RK函数的目的是将一个表达式转换成一个有效的R/K索引。
* R/K索引是一种优化手段,用于在Lua字节码中表示常量和寄存器。
* 函数首先尝试将表达式转换为一个常量索引(如果可能),
* 如果表达式的值是一个常量并且其索引在R/K索引的范围内,
* 则可以直接使用这个索引。如果表达式不是常量,或者常量索引超出了范围,
* 则需要将表达式放入一个寄存器中,并返回该寄存器的索引。
*/
int luaK_exp2RK(FuncState *fs, expdesc *e) {
// 将表达式所表达的内容,放到寄存器或常量中
luaK_exp2val(fs, e);
switch (e->k) { /* move constants to 'k' */
case VTRUE:
e->u.info = boolK(fs, 1);
goto vk;
case VFALSE:
e->u.info = boolK(fs, 0);
goto vk;
case VNIL:
e->u.info = nilK(fs);
goto vk;
case VKINT:
e->u.info = luaK_intK(fs, e->u.ival); // 添加到常量表中,然后返回它在常量表中的索引
goto vk;
case VKFLT:
e->u.info = luaK_numberK(fs, e->u.nval);
goto vk;
case VK:
vk:
e->k = VK;
if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
return RKASK(e->u.info); // RKASK用于加一个标识,标识这个索引位于R或K中
else break;
default:
break;
}
/* not a constant in the right range: put it in a register */
return luaK_exp2anyreg(fs, e);
}
/*
** Generate code to store result of expression 'ex' into variable 'var'.
* 生成代码来加载ex的值到var中。
*/
void luaK_storevar(FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) {
case VLOCAL: {
freeexp(fs, ex);
exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */
return;
}
case VUPVAL: {
int e = luaK_exp2anyreg(fs, ex);
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
break;
}
case VINDEXED: {
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int e = luaK_exp2RK(fs, ex); // 经过这步处理,ex的值只会在寄存器或常量池中, 所以e表示寄存器索引或者函数常量池索引
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); // 生成将寄存器或常量池中的值设置到table中(即 table[var] 中)的指令
break;
}
default:
lua_assert(0); /* invalid var kind to store */
}
freeexp(fs, 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 */
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
freeexp(fs, key);
}
/*
** Negate condition 'e' (where 'e' is a comparison).
*/
static void negatecondition(FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
SETARG_A(*pc, !(GETARG_A(*pc)));
}
/*
** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'
** is true, code will jump if 'e' is true.) Return jump position.
** Optimize when 'e' is 'not' something, inverting the condition
** and removing the 'not'.
*/
static int jumponcond(FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) {
Instruction ie = getinstruction(fs, e);
if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
}
/* else go through */
}
discharge2anyreg(fs, e);
freeexp(fs, e);
return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
}
/*
** Emit code to go through if 'e' is true, jump otherwise.
*/
void luaK_goiftrue(FuncState *fs, expdesc *e) {
int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: { /* condition? */
negatecondition(fs, e); /* jump when it is false */
pc = e->u.info; /* save jump position */
break;
}
case VK:
case VKFLT:
case VKINT:
case VTRUE: {
pc = NO_JUMP; /* always true; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 0); /* jump when false */
break;
}
}
luaK_concat(fs, &e->f, pc); /* insert new jump in false list */
luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */
e->t = NO_JUMP;
}
/*
** Emit code to go through if 'e' is false, jump otherwise.
*/
void luaK_goiffalse(FuncState *fs, expdesc *e) {
int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
pc = e->u.info; /* already jump if true */
break;
}
case VNIL:
case VFALSE: {
pc = NO_JUMP; /* always false; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 1); /* jump if true */
break;
}
}
luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */
luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */
e->f = NO_JUMP;
}
/*
** Code 'not e', doing constant folding.
*/
static void codenot(FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL:
case VFALSE: {
e->k = VTRUE; /* true == not nil == not false */
break;
}
case VK:
case VKFLT:
case VKINT:
case VTRUE: {
e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */
break;
}
case VJMP: {
negatecondition(fs, e);
break;
}
case VRELOCABLE:
case VNONRELOC: {
discharge2anyreg(fs, e);
freeexp(fs, e);
e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
default:
lua_assert(0); /* cannot happen */
}
/* interchange true and false lists */
{
int temp = e->f;
e->f = e->t;
e->t = temp;
}
removevalues(fs, e->f); /* values are useless when negated */
removevalues(fs, e->t);
}
/**
** Create expression 't[k]'. 't' must have its final result already in a
** register or upvalue.
* 创建表达式 't[k]'。't' 的最终结果必须已经在寄存器或上值中。
* 这句话中的“必须”怎么理解?必须的意思是,这个函数一定会给指定key的变量安排一个位置,这个位置或者是在常量池中或者寄存器上
*/
void luaK_indexed(FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
t->u.ind.t = t->u.info; /* register or upvalue index */
// luaK_exp2RK 将会根据key,确定分配一个寄存器还是一个常量,并返回其索引
t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
t->k = VINDEXED;
}
/*
** Return false if folding can raise an error.
** Bitwise operations need operands convertible to integers; division
** operations cannot have 0 as divisor.
*/
static int validop(int op, TValue *v1, TValue *v2) {
switch (op) {
case LUA_OPBAND:
case LUA_OPBOR:
case LUA_OPBXOR:
case LUA_OPSHL:
case LUA_OPSHR:
case LUA_OPBNOT: { /* conversion errors */
lua_Integer i;
return (tointeger(v1, &i) && tointeger(v2, &i));
}
case LUA_OPDIV:
case LUA_OPIDIV:
case LUA_OPMOD: /* division by 0 */
return (nvalue(v2) != 0);
default:
return 1; /* everything else is valid */
}
}
/*
** Try to "constant-fold" an operation; return 1 iff successful.
** (In this case, 'e1' has the final result.)
*/
static int constfolding(FuncState *fs, int op, expdesc *e1,
const expdesc *e2) {
TValue v1, v2, res;
if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
return 0; /* non-numeric operands or not safe to fold */
luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */
if (ttisinteger(&res)) {
e1->k = VKINT;
e1->u.ival = ivalue(&res);
} else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */
lua_Number n = fltvalue(&res);
if (luai_numisnan(n) || n == 0)
return 0;
e1->k = VKFLT;
e1->u.nval = n;
}
return 1;
}
/*
** Emit code for unary expressions that "produce values"
** (everything but 'not').
** Expression to produce final result will be encoded in 'e'.
*/
static void codeunexpval(FuncState *fs, OpCode op, expdesc *e, int line) {
int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
freeexp(fs, e);
e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
e->k = VRELOCABLE; /* all those operations are relocatable */
luaK_fixline(fs, line);
}
/*
** Emit code for binary expressions that "produce values"
** (everything but logical operators 'and'/'or' and comparison
** operators).
** Expression to produce final result will be encoded in 'e1'.
** Because 'luaK_exp2RK' can free registers, its calls must be
** in "stack order" (that is, first on 'e2', which may have more
** recent registers to be released).
*/
static void codebinexpval(FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
int rk1 = luaK_exp2RK(fs, e1);
freeexps(fs, e1, e2);
e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
e1->k = VRELOCABLE; /* all those operations are relocatable */
luaK_fixline(fs, line);
}
/*
** Emit code for comparisons.
** 'e1' was already put in R/K form by 'luaK_infix'.
*/
static void codecomp(FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int rk1 = (e1->k == VK) ? RKASK(e1->u.info)
: check_exp(e1->k == VNONRELOC, e1->u.info);
int rk2 = luaK_exp2RK(fs, e2);
freeexps(fs, e1, e2);
switch (opr) {
case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */
e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);
break;
}
case OPR_GT:
case OPR_GE: {
/* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */
break;
}
default: { /* '==', '<', '<=' use their own opcodes */
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
e1->u.info = condjump(fs, op, 1, rk1, rk2);
break;
}
}
e1->k = VJMP;
}
/*
** Apply prefix operation 'op' to expression 'e'.
*/
void luaK_prefix(FuncState *fs, UnOpr op, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
switch (op) {
case OPR_MINUS:
case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef))
break;
/* FALLTHROUGH */
case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
break;
case OPR_NOT:
codenot(fs, e);
break;
default:
lua_assert(0);
}
}
/*
** Process 1st operand 'v' of binary operation 'op' before reading
** 2nd operand.
*/
void luaK_infix(FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
break;
}
case OPR_OR: {
luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */
break;
}
case OPR_CONCAT: {
luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */
break;
}
case OPR_ADD:
case OPR_SUB:
case OPR_MUL:
case OPR_DIV:
case OPR_IDIV:
case OPR_MOD:
case OPR_POW:
case OPR_BAND:
case OPR_BOR:
case OPR_BXOR:
case OPR_SHL:
case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2RK(fs, v);
/* else keep numeral, which may be folded with 2nd operand */
break;
}
default: {
luaK_exp2RK(fs, v);
break;
}
}
}
/*
** Finalize code for binary operation, after reading 2nd operand.
** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
** concatenation is right associative), merge second CONCAT into first
** one.
*/
void luaK_posfix(FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
}
case OPR_OR: {
lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
break;
}
case OPR_CONCAT: {
luaK_exp2val(fs, e2);
if (e2->k == VRELOCABLE &&
GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2)) - 1);
freeexp(fs, e1);
SETARG_B(getinstruction(fs, e2), e1->u.info);
e1->k = VRELOCABLE;
e1->u.info = e2->u.info;
} else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
codebinexpval(fs, OP_CONCAT, e1, e2, line);
}
break;
}
case OPR_ADD:
case OPR_SUB:
case OPR_MUL:
case OPR_DIV:
case OPR_IDIV:
case OPR_MOD:
case OPR_POW:
case OPR_BAND:
case OPR_BOR:
case OPR_BXOR:
case OPR_SHL:
case OPR_SHR: {
if (!constfolding(fs, op + LUA_OPADD, e1, e2))
codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
break;
}
case OPR_EQ:
case OPR_LT:
case OPR_LE:
case OPR_NE:
case OPR_GT:
case OPR_GE: {
codecomp(fs, op, e1, e2);
break;
}
default:
lua_assert(0);
}
}
/*
** Change line information associated with current position.
*/
void luaK_fixline(FuncState *fs, int line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
/*
** Emit a SETLIST instruction.
** 'base' is register that keeps table;
** 'nelems' is #table plus those to be stored now;
** 'tostore' is number of values (in registers 'base + 1',...) to add to
** table (or LUA_MULTRET to add up to stack top).
*/
void luaK_setlist(FuncState *fs, int base, int nelems, int tostore) {
int c = (nelems - 1) / LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else if (c <= MAXARG_Ax) {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
codeextraarg(fs, c);
} else
luaX_syntaxerror(fs->ls, "constructor too long");
fs->freereg = base + 1; /* free registers with list values */
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/jaesoon/lua-engine.git
[email protected]:jaesoon/lua-engine.git
jaesoon
lua-engine
luaEngine
master

搜索帮助