private static void FreeExp(FuncState fs, ExpDesc e) { if (e.Kind == ExpKind.VNONRELOC) { FreeReg(fs, e.Info); } }
public static void StoreVar(FuncState fs, ExpDesc v, ExpDesc e) { switch (v.Kind) { case ExpKind.VLOCAL: { FreeExp(fs, e); Exp2Reg(fs, e, v.Info); break; } case ExpKind.VUPVAL: { int c = Exp2AnyReg(fs, e); CodeABC(fs, OpCode.OP_SETUPVAL, c, v.Info, 0); break; } case ExpKind.VINDEXED: { OpCode op = (v.Ind.Vt == ExpKind.VLOCAL) ? OpCode.OP_SETTABLE : OpCode.OP_SETTABUP; int c = Exp2RK(fs, e); CodeABC(fs, op, v.Ind.T, v.Ind.Idx, c); break; } default: { throw new NotImplementedException("invalid var kind to store"); } } FreeExp(fs, e); }
public static void GoIfFalse(FuncState fs, ExpDesc e) { int pc; // pc of last jump DischargeVars(fs, e); switch (e.Kind) { case ExpKind.VJMP: pc = e.Info; break; case ExpKind.VNIL: case ExpKind.VFALSE: pc = NO_JUMP; break; default: pc = JumpOnCond(fs, e, true); break; } // insert last jump in `t' list e.ExitTrue = Concat(fs, e.ExitTrue, pc); PatchToHere(fs, e.ExitFalse); e.ExitFalse = NO_JUMP; }
public static void GoIfTrue(FuncState fs, ExpDesc e) { int pc; // pc of last jump DischargeVars(fs, e); switch (e.Kind) { case ExpKind.VJMP: InvertJump(fs, e); pc = e.Info; break; case ExpKind.VK: case ExpKind.VKNUM: case ExpKind.VTRUE: pc = NO_JUMP; break; default: pc = JumpOnCond(fs, e, false); break; } // insert last jump in `f' list e.ExitFalse = Concat(fs, e.ExitFalse, pc); PatchToHere(fs, e.ExitTrue); e.ExitTrue = NO_JUMP; }
public static void Exp2AnyRegUp(FuncState fs, ExpDesc e) { if (e.Kind != ExpKind.VUPVAL || HasJumps(e)) { Exp2AnyReg(fs, e); } }
public static void DischargeVars(FuncState fs, ExpDesc e) { switch (e.Kind) { case ExpKind.VLOCAL: e.Kind = ExpKind.VNONRELOC; break; case ExpKind.VUPVAL: e.Info = CodeABC(fs, OpCode.OP_GETUPVAL, 0, e.Info, 0); e.Kind = ExpKind.VRELOCABLE; break; case ExpKind.VINDEXED: OpCode op = OpCode.OP_GETTABUP; FreeReg(fs, e.Ind.Idx); if (e.Ind.Vt == ExpKind.VLOCAL) { FreeReg(fs, e.Ind.T); op = OpCode.OP_GETTABLE; } e.Info = CodeABC(fs, op, 0, e.Ind.T, e.Ind.Idx); e.Kind = ExpKind.VRELOCABLE; break; case ExpKind.VVARARG: case ExpKind.VCALL: SetOneRet(fs, e); break; default: break; } }
public static void Exp2NextReg(FuncState fs, ExpDesc e) { DischargeVars(fs, e); FreeExp(fs, e); ReserveRegs(fs, 1); Exp2Reg(fs, e, fs.FreeReg - 1); }
public static void Infix(FuncState fs, BinOpr op, ExpDesc e) { switch (op) { case BinOpr.AND: { GoIfTrue(fs, e); } break; case BinOpr.OR: { GoIfFalse(fs, e); } break; case BinOpr.CONCAT: { Exp2NextReg(fs, e); // operand must be on the `stack' } break; case BinOpr.ADD: case BinOpr.SUB: case BinOpr.MUL: case BinOpr.DIV: case BinOpr.MOD: case BinOpr.POW: { if (!IsNumeral(e)) { Exp2RK(fs, e); } } break; default: { Exp2RK(fs, e); } break; } }
private static void Exp2Reg(FuncState fs, ExpDesc e, int reg) { Discharge2Reg(fs, e, reg); if (e.Kind == ExpKind.VJMP) { e.ExitTrue = Concat(fs, e.ExitTrue, e.Info); } if (HasJumps(e)) { int p_f = NO_JUMP; int p_t = NO_JUMP; if (NeedValue(fs, e.ExitTrue) || NeedValue(fs, e.ExitFalse)) { int fj = (e.Kind == ExpKind.VJMP) ? NO_JUMP : Jump(fs); p_f = CodeLabel(fs, reg, 0, 1); p_t = CodeLabel(fs, reg, 1, 0); PatchToHere(fs, fj); } // position after whole expression int final = GetLabel(fs); PatchListAux(fs, e.ExitFalse, final, reg, p_f); PatchListAux(fs, e.ExitTrue, final, reg, p_t); } e.ExitFalse = NO_JUMP; e.ExitTrue = NO_JUMP; e.Info = reg; e.Kind = ExpKind.VNONRELOC; }
private static void CodeArith(FuncState fs, OpCode op, ExpDesc e1, ExpDesc e2, int line) { if (ConstFolding(op, e1, e2)) { return; } int o2 = (op != OpCode.OP_UNM && op != OpCode.OP_LEN) ? Exp2RK(fs, e2) : 0; int o1 = Exp2RK(fs, e1); if (o1 > o2) { FreeExp(fs, e1); FreeExp(fs, e2); } else { FreeExp(fs, e2); FreeExp(fs, e1); } e1.Info = CodeABC(fs, op, 0, o1, o2); e1.Kind = ExpKind.VRELOCABLE; FixLine(fs, line); }
public static void Indexed(FuncState fs, ExpDesc t, ExpDesc k) { t.Ind.T = t.Info; t.Ind.Idx = Exp2RK(fs, k); t.Ind.Vt = (t.Kind == ExpKind.VUPVAL) ? ExpKind.VUPVAL : ExpKind.VLOCAL; // FIXME t.Kind = ExpKind.VINDEXED; }
private static void Discharge2AnyReg(FuncState fs, ExpDesc e) { if (e.Kind != ExpKind.VNONRELOC) { ReserveRegs(fs, 1); Discharge2Reg(fs, e, fs.FreeReg - 1); } }
private static void InvertJump(FuncState fs, ExpDesc e) { InstructionPtr pc = GetJumpControl(fs, e.Info); Utl.Assert(TestTMode(pc.Value.GET_OPCODE()) && pc.Value.GET_OPCODE() != OpCode.OP_TESTSET && pc.Value.GET_OPCODE() != OpCode.OP_TEST); pc.Value = pc.Value.SETARG_A(pc.Value.GETARG_A() == 0 ? 1 : 0); }
public static void Exp2Val(FuncState fs, ExpDesc e) { if (HasJumps(e)) { Exp2AnyReg(fs, e); } else { DischargeVars(fs, e); } }
public static void Self(FuncState fs, ExpDesc e, ExpDesc key) { Exp2AnyReg(fs, e); int ereg = e.Info; // register where `e' is placed FreeExp(fs, e); e.Info = fs.FreeReg; // base register for op_self e.Kind = ExpKind.VNONRELOC; ReserveRegs(fs, 2); CodeABC(fs, OpCode.OP_SELF, e.Info, ereg, Coder.Exp2RK(fs, key)); FreeExp(fs, key); }
public void CopyFrom(ExpDesc e) { this.Kind = e.Kind; this.Info = e.Info; // this.Ind.T = e.Ind.T; // this.Ind.Idx = e.Ind.Idx; // this.Ind.Vt = e.Ind.Vt; this.Ind = e.Ind; this.NumberValue = e.NumberValue; this.ExitTrue = e.ExitTrue; this.ExitFalse = e.ExitFalse; }
public static void SetReturns(FuncState fs, ExpDesc e, int nResults) { if (e.Kind == ExpKind.VCALL) // expression is an open function call? { var pi = fs.GetCode(e); pi.Value = pi.Value.SETARG_C(nResults + 1); } else if (e.Kind == ExpKind.VVARARG) { var pi = fs.GetCode(e); pi.Value = pi.Value.SETARG_B(nResults + 1).SETARG_A(fs.FreeReg); ReserveRegs(fs, 1); } }
private static void Discharge2Reg(FuncState fs, ExpDesc e, int reg) { DischargeVars(fs, e); switch (e.Kind) { case ExpKind.VNIL: { CodeNil(fs, reg, 1); break; } case ExpKind.VFALSE: case ExpKind.VTRUE: { CodeABC(fs, OpCode.OP_LOADBOOL, reg, (e.Kind == ExpKind.VTRUE ? 1 : 0), 0); break; } case ExpKind.VK: { CodeK(fs, reg, e.Info); break; } case ExpKind.VKNUM: { CodeK(fs, reg, NumberK(fs, e.NumberValue)); break; } case ExpKind.VRELOCABLE: { InstructionPtr pi = fs.GetCode(e); pi.Value = pi.Value.SETARG_A(reg); break; } case ExpKind.VNONRELOC: { if (reg != e.Info) { CodeABC(fs, OpCode.OP_MOVE, reg, e.Info, 0); } break; } default: { Utl.Assert(e.Kind == ExpKind.VVOID || e.Kind == ExpKind.VJMP); return; // nothing to do... } } e.Info = reg; e.Kind = ExpKind.VNONRELOC; }
private static bool ConstFolding(OpCode op, ExpDesc e1, ExpDesc e2) { if (!IsNumeral(e1) || !IsNumeral(e2)) { return(false); } if ((op == OpCode.OP_DIV || op == OpCode.OP_MOD) && e2.NumberValue == 0.0) { return(false); // do not attempt to divide by 0 } switch (op) { case OpCode.OP_ADD: e1.NumberValue = e1.NumberValue + e2.NumberValue; break; case OpCode.OP_SUB: e1.NumberValue = e1.NumberValue - e2.NumberValue; break; case OpCode.OP_MUL: e1.NumberValue = e1.NumberValue * e2.NumberValue; break; case OpCode.OP_DIV: e1.NumberValue = e1.NumberValue / e2.NumberValue; break; case OpCode.OP_MOD: e1.NumberValue = e1.NumberValue % e2.NumberValue; break; case OpCode.OP_POW: e1.NumberValue = Math.Pow(e1.NumberValue, e2.NumberValue); break; case OpCode.OP_UNM: e1.NumberValue = -e1.NumberValue; break; default: throw new Exception("ConstFolding unknown op" + op); } return(true); }
public static void SetOneRet(FuncState fs, ExpDesc e) { // expression is an open function call? if (e.Kind == ExpKind.VCALL) { e.Kind = ExpKind.VNONRELOC; e.Info = (fs.GetCode(e)).Value.GETARG_A(); } else if (e.Kind == ExpKind.VVARARG) { var pi = fs.GetCode(e); pi.Value = pi.Value.SETARG_B(2); e.Kind = ExpKind.VRELOCABLE; // can relocate its simple result } }
public static int Exp2RK(FuncState fs, ExpDesc e) { Exp2Val(fs, e); switch (e.Kind) { case ExpKind.VTRUE: case ExpKind.VFALSE: case ExpKind.VNIL: { // constant fits in RK operand? if (fs.Proto.K.Count <= Instruction.MAXINDEXRK) { e.Info = (e.Kind == ExpKind.VNIL) ? NilK(fs) : BoolK(fs, (e.Kind == ExpKind.VTRUE)); e.Kind = ExpKind.VK; return(Instruction.RKASK(e.Info)); } else { break; } } case ExpKind.VKNUM: case ExpKind.VK: { if (e.Kind == ExpKind.VKNUM) { e.Info = NumberK(fs, e.NumberValue); e.Kind = ExpKind.VK; } if (e.Info <= Instruction.MAXINDEXRK) { return(Instruction.RKASK(e.Info)); } else { break; } } default: break; } return(Exp2AnyReg(fs, e)); }
private static int JumpOnCond(FuncState fs, ExpDesc e, bool cond) { if (e.Kind == ExpKind.VRELOCABLE) { Instruction ie = fs.GetCode(e).Value; if (ie.GET_OPCODE() == OpCode.OP_NOT) { fs.Pc--; // remove previous OP_NOT return(CondJump(fs, OpCode.OP_TEST, ie.GETARG_B(), 0, (cond ? 0 : 1))); } // else go through } Discharge2AnyReg(fs, e); FreeExp(fs, e); return(CondJump(fs, OpCode.OP_TESTSET, NO_REG, e.Info, (cond ? 1 : 0))); }
private static void CodeComp(FuncState fs, OpCode op, int cond, ExpDesc e1, ExpDesc e2) { int o1 = Exp2RK(fs, e1); int o2 = Exp2RK(fs, e2); FreeExp(fs, e2); FreeExp(fs, e1); // exchange args to replace by `<' or `<=' if (cond == 0 && op != OpCode.OP_EQ) { int temp; temp = o1; o1 = o2; o2 = temp; // o1 <==> o2 cond = 1; } e1.Info = CondJump(fs, op, cond, o1, o2); e1.Kind = ExpKind.VJMP; }
public static int Exp2AnyReg(FuncState fs, ExpDesc e) { DischargeVars(fs, e); if (e.Kind == ExpKind.VNONRELOC) { // exp is already in a register if (!HasJumps(e)) { return(e.Info); } // reg. is not a local? if (e.Info >= fs.NumActVar) { Exp2Reg(fs, e, e.Info); return(e.Info); } } Exp2NextReg(fs, e); // default return(e.Info); }
private static void CodeNot(FuncState fs, ExpDesc e) { DischargeVars(fs, e); switch (e.Kind) { case ExpKind.VNIL: case ExpKind.VFALSE: e.Kind = ExpKind.VTRUE; break; case ExpKind.VK: case ExpKind.VKNUM: case ExpKind.VTRUE: e.Kind = ExpKind.VFALSE; break; case ExpKind.VJMP: InvertJump(fs, e); break; case ExpKind.VRELOCABLE: case ExpKind.VNONRELOC: Discharge2AnyReg(fs, e); FreeExp(fs, e); e.Info = CodeABC(fs, OpCode.OP_NOT, 0, e.Info, 0); e.Kind = ExpKind.VRELOCABLE; break; default: throw new Exception("CodeNot unknown e.Kind:" + e.Kind); } // interchange true and false lists { int temp = e.ExitFalse; e.ExitFalse = e.ExitTrue; e.ExitTrue = temp; } RemoveValues(fs, e.ExitFalse); RemoveValues(fs, e.ExitTrue); }
public static void Prefix(FuncState fs, UnOpr op, ExpDesc e, int line) { ExpDesc e2 = new ExpDesc(); e2.ExitTrue = NO_JUMP; e2.ExitFalse = NO_JUMP; e2.Kind = ExpKind.VKNUM; e2.NumberValue = 0.0; switch (op) { case UnOpr.MINUS: { if (IsNumeral(e)) // minus constant? { e.NumberValue = -e.NumberValue; } else { Exp2AnyReg(fs, e); CodeArith(fs, OpCode.OP_UNM, e, e2, line); } } break; case UnOpr.NOT: { CodeNot(fs, e); } break; case UnOpr.LEN: { Exp2AnyReg(fs, e); // cannot operate on constants CodeArith(fs, OpCode.OP_LEN, e, e2, line); } break; default: throw new Exception("[Coder]Prefix Unknown UnOpr:" + op); } }
public ConstructorControl() { ExpLastItem = new ExpDesc(); }
public LHSAssign() { Prev = null; Exp = new ExpDesc(); }
private static bool HasJumps(ExpDesc e) { return(e.ExitTrue != e.ExitFalse); }
public static void Posfix(FuncState fs, BinOpr op, ExpDesc e1, ExpDesc e2, int line) { switch (op) { case BinOpr.AND: { Utl.Assert(e1.ExitTrue == NO_JUMP); DischargeVars(fs, e2); e2.ExitFalse = Concat(fs, e2.ExitFalse, e1.ExitFalse); e1.CopyFrom(e2); break; } case BinOpr.OR: { Utl.Assert(e1.ExitFalse == NO_JUMP); DischargeVars(fs, e2); e2.ExitTrue = Concat(fs, e2.ExitTrue, e1.ExitTrue); e1.CopyFrom(e2); break; } case BinOpr.CONCAT: { Exp2Val(fs, e2); var pe2 = fs.GetCode(e2); if (e2.Kind == ExpKind.VRELOCABLE && pe2.Value.GET_OPCODE() == OpCode.OP_CONCAT) { Utl.Assert(e1.Info == pe2.Value.GETARG_B() - 1); FreeExp(fs, e1); pe2.Value = pe2.Value.SETARG_B(e1.Info); e1.Kind = ExpKind.VRELOCABLE; e1.Info = e2.Info; } else { // operand must be on the `stack' Exp2NextReg(fs, e2); CodeArith(fs, OpCode.OP_CONCAT, e1, e2, line); } break; } case BinOpr.ADD: { CodeArith(fs, OpCode.OP_ADD, e1, e2, line); break; } case BinOpr.SUB: { CodeArith(fs, OpCode.OP_SUB, e1, e2, line); break; } case BinOpr.MUL: { CodeArith(fs, OpCode.OP_MUL, e1, e2, line); break; } case BinOpr.DIV: { CodeArith(fs, OpCode.OP_DIV, e1, e2, line); break; } case BinOpr.MOD: { CodeArith(fs, OpCode.OP_MOD, e1, e2, line); break; } case BinOpr.POW: { CodeArith(fs, OpCode.OP_POW, e1, e2, line); break; } case BinOpr.EQ: { CodeComp(fs, OpCode.OP_EQ, 1, e1, e2); break; } case BinOpr.LT: { CodeComp(fs, OpCode.OP_LT, 1, e1, e2); break; } case BinOpr.LE: { CodeComp(fs, OpCode.OP_LE, 1, e1, e2); break; } case BinOpr.NE: { CodeComp(fs, OpCode.OP_EQ, 0, e1, e2); break; } case BinOpr.GT: { CodeComp(fs, OpCode.OP_LT, 0, e1, e2); break; } case BinOpr.GE: { CodeComp(fs, OpCode.OP_LE, 0, e1, e2); break; } default: Utl.Assert(false); break; } }