commit 722bdbe17d0192baf72978f88069d12a921e9bfb
parent 1b100335839e13021b4731f0407b87e4f7544dc0
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Thu, 28 Sep 2017 13:53:02 -0300
no more 'getBMode'-'getCMode' (imprecise + we will need more space
for op mode) + better control of op modes
Diffstat:
M | lcode.c | | | 18 | +++++++++++++----- |
M | lcode.h | | | 4 | ++-- |
M | lopcodes.c | | | 116 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | lopcodes.h | | | 57 | +++++++++++++++++++++++++++------------------------------ |
M | lparser.c | | | 4 | ++-- |
M | lvm.c | | | 19 | ++++++++----------- |
6 files changed, 109 insertions(+), 109 deletions(-)
diff --git a/lcode.c b/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.124 2017/09/26 17:10:49 roberto Exp roberto $
+** $Id: lcode.c,v 2.125 2017/09/26 18:14:45 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -367,8 +367,6 @@ static int luaK_code (FuncState *fs, Instruction i) {
*/
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));
}
@@ -378,14 +376,24 @@ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int 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(getOpMode(o) == iABx);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, bc));
}
/*
+** Format and emit an 'iAsBx' instruction.
+*/
+int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) {
+ unsigned int b = bc + MAXARG_sBx;
+ lua_assert(getOpMode(o) == iAsBx);
+ lua_assert(a <= MAXARG_A && b <= MAXARG_Bx);
+ return luaK_code(fs, CREATE_ABx(o, a, b));
+}
+
+
+/*
** Emit an "extra argument" instruction (format 'iAx')
*/
static int codeextraarg (FuncState *fs, int a) {
diff --git a/lcode.h b/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.65 2017/04/20 19:53:55 roberto Exp roberto $
+** $Id: lcode.h,v 1.66 2017/09/13 19:50:08 roberto Exp roberto $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -43,13 +43,13 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
-#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
+LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
diff --git a/lopcodes.c b/lopcodes.c
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.c,v 1.63 2017/09/19 18:38:14 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.64 2017/09/26 18:14:45 roberto Exp roberto $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -77,64 +77,62 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
};
-#define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m))
-
LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
-/* T A B C mode opcode */
- opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */
- ,opmode(0, 1, OpArgU, OpArgN, iAsBx) /* OP_LOADI */
- ,opmode(0, 1, OpArgU, OpArgN, iAsBx) /* OP_LOADF */
- ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */
- ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */
- ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */
- ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */
- ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */
- ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_GETTABLE */
- ,opmode(0, 1, OpArgR, OpArgU, iABC) /* OP_GETI */
- ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETFIELD */
- ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */
- ,opmode(0, 0, OpArgR, OpArgK, iABC) /* OP_SETTABLE */
- ,opmode(0, 0, OpArgU, OpArgK, iABC) /* OP_SETI */
- ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETFIELD */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */
- ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */
- ,opmode(0, 1, OpArgR, OpArgU, iABC) /* OP_ADDI */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_ADD */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_SUB */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_MUL */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_MOD */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_POW */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_DIV */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_IDIV */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_BAND */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_BOR */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_BXOR */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_SHL */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_SHR */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */
- ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */
- ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */
- ,opmode(0, 0, OpArgN, OpArgN, iABC) /* OP_CLOSE */
- ,opmode(0, 0, OpArgU, OpArgN, iAsBx) /* OP_JMP */
- ,opmode(1, 0, OpArgR, OpArgR, iABC) /* OP_EQ */
- ,opmode(1, 0, OpArgR, OpArgR, iABC) /* OP_LT */
- ,opmode(1, 0, OpArgR, OpArgR, iABC) /* OP_LE */
- ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */
- ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */
- ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */
- ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */
- ,opmode(0, 1, OpArgR, OpArgN, iABx) /* OP_FORLOOP */
- ,opmode(0, 1, OpArgR, OpArgN, iABx) /* OP_FORPREP */
- ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */
- ,opmode(0, 1, OpArgR, OpArgN, iABx) /* OP_TFORLOOP */
- ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */
- ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */
- ,opmode(0, 1, OpArgU, OpArgR, iABC) /* OP_VARARG */
- ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */
+/* T A mode opcode */
+ opmode(0, 1, iABC) /* OP_MOVE */
+ ,opmode(0, 1, iAsBx) /* OP_LOADI */
+ ,opmode(0, 1, iAsBx) /* OP_LOADF */
+ ,opmode(0, 1, iABx) /* OP_LOADK */
+ ,opmode(0, 1, iABx) /* OP_LOADKX */
+ ,opmode(0, 1, iABC) /* OP_LOADBOOL */
+ ,opmode(0, 1, iABC) /* OP_LOADNIL */
+ ,opmode(0, 1, iABC) /* OP_GETUPVAL */
+ ,opmode(0, 0, iABC) /* OP_SETUPVAL */
+ ,opmode(0, 1, iABC) /* OP_GETTABUP */
+ ,opmode(0, 1, iABC) /* OP_GETTABLE */
+ ,opmode(0, 1, iABC) /* OP_GETI */
+ ,opmode(0, 1, iABC) /* OP_GETFIELD */
+ ,opmode(0, 0, iABC) /* OP_SETTABUP */
+ ,opmode(0, 0, iABC) /* OP_SETTABLE */
+ ,opmode(0, 0, iABC) /* OP_SETI */
+ ,opmode(0, 0, iABC) /* OP_SETFIELD */
+ ,opmode(0, 1, iABC) /* OP_NEWTABLE */
+ ,opmode(0, 1, iABC) /* OP_SELF */
+ ,opmode(0, 1, iABC) /* OP_ADDI */
+ ,opmode(0, 1, iABC) /* OP_ADD */
+ ,opmode(0, 1, iABC) /* OP_SUB */
+ ,opmode(0, 1, iABC) /* OP_MUL */
+ ,opmode(0, 1, iABC) /* OP_MOD */
+ ,opmode(0, 1, iABC) /* OP_POW */
+ ,opmode(0, 1, iABC) /* OP_DIV */
+ ,opmode(0, 1, iABC) /* OP_IDIV */
+ ,opmode(0, 1, iABC) /* OP_BAND */
+ ,opmode(0, 1, iABC) /* OP_BOR */
+ ,opmode(0, 1, iABC) /* OP_BXOR */
+ ,opmode(0, 1, iABC) /* OP_SHL */
+ ,opmode(0, 1, iABC) /* OP_SHR */
+ ,opmode(0, 1, iABC) /* OP_UNM */
+ ,opmode(0, 1, iABC) /* OP_BNOT */
+ ,opmode(0, 1, iABC) /* OP_NOT */
+ ,opmode(0, 1, iABC) /* OP_LEN */
+ ,opmode(0, 1, iABC) /* OP_CONCAT */
+ ,opmode(0, 0, iABC) /* OP_CLOSE */
+ ,opmode(0, 0, iAsBx) /* OP_JMP */
+ ,opmode(1, 0, iABC) /* OP_EQ */
+ ,opmode(1, 0, iABC) /* OP_LT */
+ ,opmode(1, 0, iABC) /* OP_LE */
+ ,opmode(1, 0, iABC) /* OP_TEST */
+ ,opmode(1, 1, iABC) /* OP_TESTSET */
+ ,opmode(0, 1, iABC) /* OP_CALL */
+ ,opmode(0, 1, iABC) /* OP_TAILCALL */
+ ,opmode(0, 0, iABC) /* OP_RETURN */
+ ,opmode(0, 1, iABx) /* OP_FORLOOP */
+ ,opmode(0, 1, iABx) /* OP_FORPREP */
+ ,opmode(0, 0, iABC) /* OP_TFORCALL */
+ ,opmode(0, 1, iABx) /* OP_TFORLOOP */
+ ,opmode(0, 0, iABC) /* OP_SETLIST */
+ ,opmode(0, 1, iABx) /* OP_CLOSURE */
+ ,opmode(0, 1, iABC) /* OP_VARARG */
+ ,opmode(0, 0, iAx) /* OP_EXTRAARG */
};
diff --git a/lopcodes.h b/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.160 2017/09/19 18:38:14 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.161 2017/09/26 18:14:45 roberto Exp roberto $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -89,6 +89,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
+#define checkopm(i,m) (getOpMode(GET_OPCODE(i)) == m)
+
+
#define getarg(i,pos,size) (cast(int, ((i)>>(pos)) & MASK1(size,0)))
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
@@ -96,25 +99,28 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
-#define GETARG_B(i) getarg(i, POS_B, SIZE_B)
+#define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B))
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
-#define GETARG_Br(i) getarg(i, POS_B, SIZE_B - 1)
+#define GETARG_Br(i) \
+ check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B - 1))
#define GETARG_Bk(i) getarg(i, (POS_B + SIZE_B - 1), 1)
-#define GETARG_C(i) getarg(i, POS_C, SIZE_C)
+#define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C))
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
-#define GETARG_Cr(i) getarg(i, POS_C, SIZE_C - 1)
+#define GETARG_Cr(i) \
+ check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C - 1))
#define GETARG_Ck(i) getarg(i, (POS_C + SIZE_C - 1), 1)
-#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx)
+#define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx))
#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx)
-#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax)
+#define GETARG_Ax(i) check_exp(checkopm(i, iAx), getarg(i, POS_Ax, SIZE_Ax))
#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax)
-#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
+#define GETARG_sBx(i) \
+ check_exp(checkopm(i, iAsBx), getarg(i, POS_Bx, SIZE_Bx) - MAXARG_sBx)
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
@@ -160,8 +166,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/*
** R(x) - register
-** Kst(x) - constant (in constant table)
-** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
+** K(x) - constant (in constant table)
+** RK(x) == if ISK(x) then K(INDEXK(x)) else R(x)
*/
@@ -176,8 +182,8 @@ name args description
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADI,/* A sBx R(A) := sBx */
OP_LOADF,/* A sBx R(A) := (lua_Number)sBx */
-OP_LOADK,/* A Bx R(A) := Kst(Bx) */
-OP_LOADKX,/* A R(A) := Kst(extra arg) */
+OP_LOADK,/* A Bx R(A) := K(Bx) */
+OP_LOADKX,/* A R(A) := K(extra arg) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
@@ -186,7 +192,7 @@ OP_SETUPVAL,/* A B UpValue[B] := R(A) */
OP_GETTABUP,/* A B C R(A) := UpValue[B][K(C):string] */
OP_GETTABLE,/* A B C R(A) := R(B)[R(C)] */
OP_GETI,/* A B C R(A) := R(B)[C] */
-OP_GETFIELD,/* A B C R(A) := R(B)[Kst(C):string] */
+OP_GETFIELD,/* A B C R(A) := R(B)[K(C):string] */
OP_SETTABUP,/* A B C UpValue[A][K(B):string] := RK(C) */
OP_SETTABLE,/* A B C R(A)[R(B)] := RK(C) */
@@ -277,27 +283,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
/*
** masks for instruction properties. The format is:
-** bits 0-1: op mode
-** bits 2-3: C arg mode
-** bits 4-5: B arg mode
-** bit 6: instruction set register A
-** bit 7: operator is a test (next instruction must be a jump)
+** bits 0-2: op mode
+** bit 3: instruction set register A
+** bit 4: operator is a test (next instruction must be a jump)
*/
-enum OpArgMask {
- OpArgN, /* argument is not used */
- OpArgU, /* argument is used */
- OpArgR, /* argument is a register or a jump offset */
- OpArgK /* argument is a constant or register/constant */
-};
-
LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
-#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
-#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
-#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
-#define testAMode(m) (luaP_opmodes[m] & (1 << 6))
-#define testTMode(m) (luaP_opmodes[m] & (1 << 7))
+#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7))
+#define testAMode(m) (luaP_opmodes[m] & (1 << 3))
+#define testTMode(m) (luaP_opmodes[m] & (1 << 4))
+
+#define opmode(t,a,m) (((t)<<4) | ((a)<<3) | (m))
LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
diff --git a/lparser.c b/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.164 2017/08/14 18:33:14 roberto Exp roberto $
+** $Id: lparser.c,v 2.165 2017/09/13 19:50:08 roberto Exp roberto $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -1373,7 +1373,7 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
luaK_patchtohere(fs, prep);
luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars);
luaK_fixline(fs, line);
- endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP);
+ endfor = luaK_codeABx(fs, OP_TFORLOOP, base + 2, 0);
}
fixforjump(fs, endfor, prep + 1, 1);
luaK_fixline(fs, line);
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.294 2017/09/26 18:14:45 roberto Exp roberto $
+** $Id: lvm.c,v 2.295 2017/09/27 18:59:08 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -733,14 +733,13 @@ void luaV_finishOp (lua_State *L) {
#define RA(i) (base+GETARG_A(i))
-#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_Br(i))
+#define RB(i) (base+GETARG_Br(i))
#define vRB(i) s2v(RB(i))
-#define KB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_B(i))
-#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
+#define KB(i) (k+GETARG_B(i))
+#define RC(i) (base+GETARG_C(i))
#define vRC(i) s2v(RC(i))
-#define KC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, k+GETARG_C(i))
-#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
- (GETARG_Ck(i)) ? k + GETARG_Cr(i) : s2v(base + GETARG_Cr(i)))
+#define KC(i) (k+GETARG_C(i))
+#define RKC(i) ((GETARG_Ck(i)) ? k + GETARG_Cr(i) : s2v(base + GETARG_Cr(i)))
@@ -834,8 +833,7 @@ void luaV_execute (lua_State *L) {
}
vmcase(OP_LOADKX) {
TValue *rb;
- lua_assert(GET_OPCODE(*pc) == OP_EXTRAARG);
- rb = k + GETARG_Ax(*pc++);
+ rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb);
vmbreak;
}
@@ -1409,8 +1407,7 @@ void luaV_execute (lua_State *L) {
Table *h;
if (n == 0) n = cast_int(L->top - ra) - 1;
if (c == 0) {
- lua_assert(GET_OPCODE(*pc) == OP_EXTRAARG);
- c = GETARG_Ax(*pc++);
+ c = GETARG_Ax(*pc); pc++;
}
h = hvalue(s2v(ra));
last = ((c-1)*LFIELDS_PER_FLUSH) + n;