public static void SetList(FuncState fs, int t, int nelems, int tostore) { int c = (nelems - 1) / LuaDef.LFIELDS_PER_FLUSH + 1; int b = (tostore == LuaDef.LUA_MULTRET) ? 0 : tostore; Utl.Assert(tostore != 0); if (c <= Instruction.MAXARG_C) { CodeABC(fs, OpCode.OP_SETLIST, t, b, c); } else if (c <= Instruction.MAXARG_Ax) { CodeABC(fs, OpCode.OP_SETLIST, t, b, 0); CodeExtraArg(fs, c); } else { fs.Lexer.SyntaxError("constructor too long"); } // free registers with list values fs.FreeReg = t + 1; }
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); } }
private static int CondJump( FuncState fs, OpCode op, int a, int b, int c ) { CodeABC( fs, op, a, b, c ); return Jump( fs ); }
public static void JumpTo( FuncState fs, int target ) { PatchList( fs, Jump(fs), target ); }
public static void Posfix( FuncState fs, BinOpr op, ExpDesc e1, ExpDesc e2, int line ) { // Debug.Log(">> POSFIX op:" + op); 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; } }
public static void ReserveRegs(FuncState fs, int n) { CheckStack(fs, n); fs.FreeReg += n; }
public static void ReserveRegs( FuncState fs, int n ) { // Debug.Log("===================================== FREEREG + " + n); CheckStack( fs, n ); fs.FreeReg += n; }
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; }
public static int NumberK( FuncState fs, double r ) { var o = new TValue(); o.SetNValue(r); return AddK( fs, ref o, ref o ); }
public static void FixLine(FuncState fs, int line) { fs.Proto.LineInfo[fs.Pc - 1] = line; }
public static int CodeABC(FuncState fs, OpCode op, int a, int b, int c) { return(Code(fs, Instruction.CreateABC(op, a, b, c))); }
public static int CodeAsBx(FuncState fs, OpCode op, int a, int sBx) { return(CodeABx(fs, op, a, ((uint)sBx) + Instruction.MAXARG_sBx)); }
private static int CodeExtraArg(FuncState fs, int a) { Utl.Assert(a <= Instruction.MAXARG_Ax); return(Code(fs, Instruction.CreateAx(OpCode.OP_EXTRAARG, a))); }
public static void SetMultiRet(FuncState fs, ExpDesc e) { SetReturns(fs, e, LuaDef.LUA_MULTRET); }
public static void PatchClose( FuncState fs, int list, int level ) { level++; // argument is +1 to reserve 0 as non-op while( list != NO_JUMP ) { int next = GetJump( fs, list ); var pi = new InstructionPtr( fs.Proto.Code, list );; Utl.Assert( pi.Value.GET_OPCODE() == OpCode.OP_JMP && ( pi.Value.GETARG_A() == 0 || pi.Value.GETARG_A() >= level ) ); pi.Value = pi.Value.SETARG_A( level ); list = next; } }
public static int Concat( FuncState fs, int l1, int l2 ) { // Debug.Log("======== Concat l1:" + l1 + " l2:" + l2); if( l2 == NO_JUMP ) return l1; else if( l1 == NO_JUMP ) return l2; else { int list = l1; // Debug.Log("Concat list:" + list); int next = GetJump( fs, list ); // find last element while( next != NO_JUMP ) { list = next; // Debug.Log("Concat list:" + list); next = GetJump( fs, list ); } FixJump( fs, list, l2 ); return l1; } }
// returns current `pc' and mark it as a jump target // (to avoid wrong optimizations with consecutive // instructions not in the same basic block) public static int GetLabel(FuncState fs) { fs.LastTarget = fs.Pc; return(fs.Pc); }
private static int NilK( FuncState fs ) { // // cannot use nil as key; // // instead use table itself to represent nil // var k = fs.H; // var o = new LuaNil(); // return AddK( fs, k, o ); var o = new TValue(); o.SetNilValue(); return AddK( fs, ref o, ref o ); }
private static void DischargeJpc(FuncState fs) { PatchListAux(fs, fs.Jpc, fs.Pc, NO_REG, fs.Pc); fs.Jpc = NO_JUMP; }
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; }
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: throw new NotImplementedException(string.Format("opcode {0}({1}, {2}) @line:{3}", op, e1, e2, line)); } }
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; }
public static void JumpTo(FuncState fs, int target) { PatchList(fs, Jump(fs), target); }
public static void Infix( FuncState fs, BinOpr op, ExpDesc e ) { // Debug.Log(">> INFIX op:" + op); 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; } }
public static void Ret(FuncState fs, int first, int nret) { CodeABC(fs, OpCode.OP_RETURN, first, nret + 1, 0); }
public static int Jump( FuncState fs ) { int jpc = fs.Jpc; // save list of jumps to here fs.Jpc = NO_JUMP; int j = CodeAsBx( fs, OpCode.OP_JMP, 0, NO_JUMP ); j = Concat( fs, j, jpc ); return j; }
private static int CondJump(FuncState fs, OpCode op, int a, int b, int c) { CodeABC(fs, op, a, b, c); return(Jump(fs)); }
public static void Ret( FuncState fs, int first, int nret ) { CodeABC( fs, OpCode.OP_RETURN, first, nret+1, 0 ); }
public static void PatchToHere(FuncState fs, int list) { GetLabel(fs); fs.Jpc = Concat(fs, fs.Jpc, list); }
public static void PatchList( FuncState fs, int list, int target ) { if( target == fs.Pc ) PatchToHere( fs, list ); else { Utl.Assert( target < fs.Pc ); PatchListAux( fs, list, target, NO_REG, target ); } }
private static int CodeLabel(FuncState fs, int a, int b, int jump) { GetLabel(fs); // those instructions may be jump targets return(CodeABC(fs, OpCode.OP_LOADBOOL, a, b, jump)); }
public static void PatchToHere( FuncState fs, int list ) { GetLabel( fs ); fs.Jpc = Concat( fs, fs.Jpc, list ); }
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 int StringK( FuncState fs, string s ) { // Debug.Log(" STRING K >>>> " + s ); var o = new TValue(); o.SetSValue(s); return AddK( fs, ref o, ref o ); }
private static int JumpOnCond( FuncState fs, ExpDesc e, bool cond ) { // Debug.Log("--------------- 2 ----------JumpOnCond k:" + e.Kind ); 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 int BoolK( FuncState fs, bool b ) { var o = new TValue(); o.SetBValue(b); return AddK( fs, ref o, ref o ); }
public static void GoIfTrue( FuncState fs, ExpDesc e ) { // Debug.Log("--------------- 1 ----------GoIfTrue k:" + e.Kind ); 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 int AddK( FuncState fs, ref TValue key, ref TValue v ) { int idx; if( fs.H.TryGetValue( key, out idx ) ) return idx; idx = fs.Proto.K.Count; fs.H.Add( key, idx ); var newItem = new StkId(); newItem.V.SetObj(ref v); fs.Proto.K.Add(newItem); // Debug.Log("--------- ADD K ------- " + fs.Proto.K.Count + " line:" + fs.Lexer.LineNumber + " key:" + key); return idx; }
public static void GoIfFalse( FuncState fs, ExpDesc e ) { // Debug.Log("GoIfFalse k:" + e.Kind ); 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; }
private static int CodeLabel( FuncState fs, int a, int b, int jump ) { GetLabel( fs ); // those instructions may be jump targets return CodeABC( fs, OpCode.OP_LOADBOOL, a, b, jump ); }
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 CheckStack( FuncState fs, int n ) { int newStack = fs.FreeReg + n; if( newStack > fs.Proto.MaxStackSize ) { if( newStack >= LuaLimits.MAXSTACK ) { fs.Lexer.SyntaxError("function or expression too complex"); } fs.Proto.MaxStackSize = (byte)newStack; } }
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; }
private static void Discharge2AnyReg( FuncState fs, ExpDesc e ) { if( e.Kind != ExpKind.VNONRELOC ) { ReserveRegs( fs, 1 ); Discharge2Reg( fs, e, fs.FreeReg-1 ); } }
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 static void Exp2NextReg( FuncState fs, ExpDesc e ) { DischargeVars( fs, e ); FreeExp( fs, e ); ReserveRegs( fs, 1 ); Exp2Reg( fs, e, fs.FreeReg-1 ); }
public static int CodeAsBx(FuncState fs, OpCode op, int a, int sBx) { //FIXME:System.OverflowException: 算术运算导致溢出。 //return CodeABx( fs, op, a, ((uint)sBx)+Instruction.MAXARG_sBx); return(CodeABx(fs, op, a, (uint)(sBx + Instruction.MAXARG_sBx))); }