Пример #1
0
        private static void CgForNumStat(FuncInfo fi, ForNumStat node)
        {
            fi.EnterScope(true);

            CgLocalVarDeclStat(fi, new LocalVarDeclStat
            {
                NameList = new List <string> {
                    "(for index)", "(for limit)", "(for step)"
                },
                ExpList = new List <Exp> {
                    node.InitExp, node.LimitExp, node.StepExp
                }
            });
            fi.AddLocVar(node.VarName);

            var a         = fi.UsedRegs - 4;
            var pcForPrep = fi.EmitForPrep(a, 0);

            CgBlock(fi, node.Block);
            fi.CloseOpenUpvals();
            var pcForLoop = fi.EmitForLoop(a, 0);

            fi.FixsBx(pcForPrep, pcForLoop - pcForPrep - 1);
            fi.FixsBx(pcForLoop, pcForPrep - pcForLoop);

            fi.ExitScope();
        }
Пример #2
0
        private static void CgForInStat(FuncInfo fi, ForInStat node)
        {
            fi.EnterScope(true);

            CgLocalVarDeclStat(fi, new LocalVarDeclStat
            {
                NameList = new List <string> {
                    "(for generator)", "(for state)", "(for control)"
                },
                ExpList = node.ExpList
            });

            foreach (var name in node.NameList)
            {
                fi.AddLocVar(name);
            }

            var pcJmpToTfc = fi.EmitJmp(0, 0);

            CgBlock(fi, node.Block);
            fi.CloseOpenUpvals();
            fi.FixsBx(pcJmpToTfc, fi.PC() - pcJmpToTfc);

            var rGenerator = fi.SlotOfLocVar("(for generator)");

            fi.EmitTForCall(rGenerator, node.NameList.Count);
            fi.EmitTForLoop(rGenerator + 2, pcJmpToTfc - fi.PC() - 1);
            fi.ExitScope();
        }
Пример #3
0
        private static ProtoType ToProto(FuncInfo fi)
        {
            var proto = new ProtoType
            {
                NumParams    = (byte)fi.NumParams,
                MaxStackSize = (byte)fi.MaxRegs,
                Code         = fi.Insts.ToArray(),
                Constatns    = GetConstants(fi),
                Upvalues     = GetUpvalues(fi),
                Protos       = ToProtos(fi.SubFuncs),
                LineInfo     = new uint[0],
                LocVars      = new LocVar[0],
                UpvalueNames = new string[0]
            };

            if (proto.MaxStackSize < 2)
            {
                proto.MaxStackSize = 2;
            }

            if (fi.IsVararg)
            {
                proto.IsVararg = 1;
            }

            return(proto);
        }
Пример #4
0
        private static void CgNameExp(FuncInfo fi, NameExp node, int a)
        {
            var r = fi.SlotOfLocVar(node.Name);

            if (r >= 0)
            {
                fi.EmitMove(a, r);
            }
            else
            {
                var idx = fi.IndexOfUpval(node.Name);
                if (idx >= 0)
                {
                    fi.EmitGetUpval(a, idx);
                }
                else
                {
                    var taExp = new TableAccessExp
                    {
                        PrefixExp = new NameExp
                        {
                            Line = 0,
                            Name = "_ENV"
                        },
                        KeyExp = new StringExp
                        {
                            Line = 0,
                            Str  = node.Name
                        }
                    };
                    CgTableAccessExp(fi, taExp, a);
                }
            }
        }
Пример #5
0
        private static Upvalue[] GetUpvalues(FuncInfo fi)
        {
            var upvals = new Upvalue[fi.Upvalues.Count];

            foreach (var kv in fi.Upvalues)
            {
                if (kv.Value.LocVarSlot >= 0)
                {
                    upvals[kv.Value.Index] = new Upvalue
                    {
                        Instack = 1,
                        Idx     = (byte)kv.Value.LocVarSlot
                    };
                }
                else
                {
                    upvals[kv.Value.Index] = new Upvalue
                    {
                        Instack = 0,
                        Idx     = (byte)kv.Value.UpvalIndex
                    };
                }
            }

            return(upvals);
        }
Пример #6
0
        private static void CgFuncCallStat(FuncInfo fi, FuncCallStat node)
        {
            var r = fi.AllocReg();

            CgFuncCallExp(fi, node, r, 0);
            fi.FreeReg();
        }
Пример #7
0
 private static void CgDoStat(FuncInfo fi, DoStat node)
 {
     fi.EnterScope(false);
     CgBlock(fi, node.Block);
     fi.CloseOpenUpvals();
     fi.ExitScope();
 }
Пример #8
0
        private static void CgUnopExp(FuncInfo fi, UnopExp node, int a)
        {
            var b = fi.AllocReg();

            CgExp(fi, node.Exp, b, 1);
            fi.EmitUnaryOp(node.GetOpCode(), a, b);
            fi.FreeReg();
        }
Пример #9
0
        private static void CgTableConstructorExp(FuncInfo fi, TableConstructorExp node, int a)
        {
            var nArr    = node.KeyExps?.Count(exp => exp is null) ?? 0;
            var nExps   = node.KeyExps?.Count ?? 0;
            var multRet = nExps > 0 && IsVarargOrFuncCall(node.ValExps[nExps - 1]);

            fi.EmitNewTable(a, nArr, nExps - nArr);
            var arrIdx = 0;

            for (var i = 0; i < nExps; i++)
            {
                var keyExp = node.KeyExps[i];
                var valExp = node.ValExps[i];

                if (keyExp == null)
                {
                    arrIdx++;
                    var tmp = fi.AllocReg();
                    if (i == nExps - 1 && multRet)
                    {
                        CgExp(fi, valExp, tmp, -1);
                    }
                    else
                    {
                        CgExp(fi, valExp, tmp, 1);
                    }

                    if (arrIdx % 50 == 0 || arrIdx == nArr)
                    {
                        var n = arrIdx % 50;
                        if (n == 0)
                        {
                            n = 50;
                        }

                        fi.FreeRegs(n);
                        var c = (arrIdx - 1) / 50 + 1;
                        if (i == nExps - 1 && multRet)
                        {
                            fi.EmitSetList(a, 0, c);
                        }
                        else
                        {
                            fi.EmitSetList(a, n, c);
                        }
                    }

                    continue;
                }

                var b = fi.AllocReg();
                CgExp(fi, keyExp, b, 1);
                var d = fi.AllocReg();
                CgExp(fi, valExp, d, 1);
                fi.FreeRegs(2);
                fi.EmitSetTable(a, b, d);
            }
        }
Пример #10
0
        private static void CgVarargExp(FuncInfo fi, VarargExp node, int a, int n)
        {
            if (!fi.IsVararg)
            {
                Debug.Panic("cannot use '...' outside a vararg function");
                return;
            }

            fi.EmitVararg(a, n);
        }
Пример #11
0
        private static void CgStat(FuncInfo fi, Stat node)
        {
            switch (node)
            {
            case FuncCallStat fs:
                CgFuncCallStat(fi, fs);
                break;

            case BreakStat bs:
                CgBreakStat(fi, bs);
                break;

            case DoStat ds:
                CgDoStat(fi, ds);
                break;

            case WhileStat ws:
                CgWhileStat(fi, ws);
                break;

            case RepeatStat rs:
                CgRepeatStat(fi, rs);
                break;

            case IfStat ifs:
                CgIfStat(fi, ifs);
                break;

            case ForNumStat fns:
                CgForNumStat(fi, fns);
                break;

            case ForInStat fis:
                CgForInStat(fi, fis);
                break;

            case AssignStat ass:
                CgAssignStat(fi, ass);
                break;

            case LocalVarDeclStat lvds:
                CgLocalVarDeclStat(fi, lvds);
                break;

            case LocalFuncDefStat lfds:
                CgLocalFuncDefStat(fi, lfds);
                break;

            case LabelStat _:
            case GotoStat _:
                Debug.Panic("label and goto statements are not supported!");
                break;
            }
        }
Пример #12
0
        private static void CgTableAccessExp(FuncInfo fi, TableAccessExp node, int a)
        {
            var b = fi.AllocReg();

            CgExp(fi, node.PrefixExp, b, 1);
            var c = fi.AllocReg();

            CgExp(fi, node.KeyExp, c, 1);
            fi.EmitGetTable(a, b, c);
            fi.FreeRegs(2);
        }
Пример #13
0
        private static void CgBlock(FuncInfo fi, Block node)
        {
            foreach (var stat in node.Stats)
            {
                CgStat(fi, stat);
            }

            if (node.RetExps != null)
            {
                CgRetStat(fi, node.RetExps);
            }
        }
Пример #14
0
 public FuncInfo(FuncInfo parent, FuncDefExp fd)
 {
     _parent   = parent;
     SubFuncs  = new List <FuncInfo>();
     _locVars  = new List <LocVarInfo>(8);
     _locNames = new Dictionary <string, LocVarInfo>();
     Upvalues  = new Dictionary <string, UpvalInfo>();
     Constants = new Dictionary <object, int>();
     _breaks   = new List <List <int> >(1);
     Insts     = new List <uint>(8);
     NumParams = fd.ParList.Count;
     IsVararg  = fd.IsVararg;
 }
Пример #15
0
        public static ProtoType GenProto(Block chunk)
        {
            var fd = new FuncDefExp
            {
                IsVararg = true,
                Block    = chunk,
                ParList  = new List <string>()
            };
            var fi = new FuncInfo(null, fd);

            fi.AddLocVar("_ENV");
            CgFuncDefExp(fi, fd, 0);
            return(ToProto(fi.SubFuncs[0]));
        }
Пример #16
0
        private static void CgConcatExp(FuncInfo fi, ConcatExp node, int a)
        {
            foreach (var subExp in node.Exps)
            {
                var tmp = fi.AllocReg();
                CgExp(fi, subExp, tmp, 1);
            }

            var c = fi.UsedRegs - 1;
            var b = c - node.Exps.Count + 1;

            fi.FreeRegs(c - b + 1);
            fi.EmitABC(EOpCode.OP_CONCAT, a, b, c);
        }
Пример #17
0
        private static object[] GetConstants(FuncInfo fi)
        {
            var consts = new object[fi.Constants.Count];

            foreach (var kv in fi.Constants)
            {
                if (kv.Key == FuncInfo.NilObj)
                {
                    consts[kv.Value] = null;
                }
                else
                {
                    consts[kv.Value] = kv.Key;
                }
            }

            return(consts);
        }
Пример #18
0
        private static void CgFuncDefExp(FuncInfo fi, FuncDefExp node, int a)
        {
            var subFi = new FuncInfo(fi, node);

            fi.SubFuncs.Add(subFi);

            foreach (var param in node.ParList)
            {
                subFi.AddLocVar(param);
            }

            CgBlock(subFi, node.Block);
            subFi.ExitScope();
            subFi.EmitReturn(0, 0);
            var bx = fi.SubFuncs.Count - 1;

            fi.EmitClosure(a, bx);
        }
Пример #19
0
        private static void CgRepeatStat(FuncInfo fi, RepeatStat node)
        {
            fi.EnterScope(true);

            var pcBeforeBlock = fi.PC();

            CgBlock(fi, node.Block);

            var r = fi.AllocReg();

            CgExp(fi, node.Exp, r, 1);
            fi.FreeReg();

            fi.EmitTest(r, 0);
            fi.EmitJmp(fi.GetJmpArgA(), pcBeforeBlock - fi.PC() - 1);
            fi.CloseOpenUpvals();

            fi.ExitScope();
        }
Пример #20
0
        private static void CgBinopExp(FuncInfo fi, BinopExp node, int a)
        {
            switch (node.Op)
            {
            case ETokenType.OpAnd:
            case ETokenType.OpOr:
            {
                var b = fi.AllocReg();
                CgExp(fi, node.Exp1, b, 1);
                fi.FreeReg();

                if (node.Op == ETokenType.OpAnd)
                {
                    fi.EmitTestSet(a, b, 0);
                }
                else
                {
                    fi.EmitTestSet(a, b, 1);
                }

                var pcOfJmp = fi.EmitJmp(0, 0);
                b = fi.AllocReg();
                CgExp(fi, node.Exp2, b, 1);
                fi.FreeReg();
                fi.EmitMove(a, b);
                fi.FixsBx(pcOfJmp, fi.PC() - pcOfJmp);

                break;
            }

            default:
            {
                var b = fi.AllocReg();
                CgExp(fi, node.Exp1, b, 1);
                var c = fi.AllocReg();
                CgExp(fi, node.Exp2, c, 1);
                fi.EmitBinaryOp(node.Op, a, b, c);
                fi.FreeRegs(2);
                break;
            }
            }
        }
Пример #21
0
        private static int PrepFuncCall(FuncInfo fi, FuncCallExp node, int a)
        {
            var nArgs = node.Args?.Count ?? 0;
            var lastArgIsVarargsOrFuncCall = false;

            CgExp(fi, node.PrefixExp, a, 1);
            if (node.NameExp != null)
            {
                fi.IndexOfConstant(node.NameExp.Str, out var idx);
                var c = 0x100 + idx;
                fi.EmitSelf(a, a, c);
            }

            for (var i = 0; i < nArgs; i++)
            {
                var arg = node.Args[i];
                var tmp = fi.AllocReg();
                if (i == nArgs - 1 && IsVarargOrFuncCall(arg))
                {
                    lastArgIsVarargsOrFuncCall = true;
                    CgExp(fi, arg, tmp, -1);
                }
                else
                {
                    CgExp(fi, arg, tmp, 1);
                }
            }

            fi.FreeRegs(nArgs);

            if (node.NameExp != null)
            {
                nArgs++;
            }

            if (lastArgIsVarargsOrFuncCall)
            {
                nArgs = -1;
            }

            return(nArgs);
        }
Пример #22
0
        private static void CgWhileStat(FuncInfo fi, WhileStat node)
        {
            var pcBeforeExp = fi.PC();

            var r = fi.AllocReg();

            CgExp(fi, node.Exp, r, 1);
            fi.FreeReg();

            fi.EmitTest(r, 0);
            var pcJmpToEnd = fi.EmitJmp(0, 0);

            fi.EnterScope(true);
            CgBlock(fi, node.Block);
            fi.CloseOpenUpvals();
            fi.EmitJmp(0, pcBeforeExp - fi.PC() - 1);
            fi.ExitScope();

            fi.FixsBx(pcJmpToEnd, fi.PC() - pcJmpToEnd);
        }
Пример #23
0
        private static void CgIfStat(FuncInfo fi, IfStat node)
        {
            var pcJmpToEnds    = new int[node.Exps.Count];
            var pcJmpToNextExp = -1;

            for (var i = 0; i < node.Exps.Count; i++)
            {
                var exp = node.Exps[i];

                if (pcJmpToNextExp >= 0)
                {
                    fi.FixsBx(pcJmpToNextExp, fi.PC() - pcJmpToNextExp);
                }

                var r = fi.AllocReg();
                CgExp(fi, exp, r, 1);
                fi.FreeReg();

                fi.EmitTest(r, 0);
                pcJmpToNextExp = fi.EmitJmp(0, 0);

                fi.EnterScope(false);
                CgBlock(fi, node.Blocks[i]);
                fi.CloseOpenUpvals();
                fi.ExitScope();

                if (i < node.Exps.Count - 1)
                {
                    pcJmpToEnds[i] = fi.EmitJmp(0, 0);
                }
                else
                {
                    pcJmpToEnds[i] = pcJmpToNextExp;
                }
            }

            foreach (var pc in pcJmpToEnds)
            {
                fi.FixsBx(pc, fi.PC() - pc);
            }
        }
Пример #24
0
        private static void CgBreakStat(FuncInfo fi, BreakStat node)
        {
            var pc = fi.EmitJmp(0, 0);

            fi.AddBreakJump(pc);
        }
Пример #25
0
        private static void CgTailCallExp(FuncInfo fi, FuncCallExp node, int a)
        {
            var nArgs = PrepFuncCall(fi, node, a);

            fi.EmitTailCall(a, nArgs);
        }
Пример #26
0
        private static void CgFuncCallExp(FuncInfo fi, FuncCallExp node, int a, int n)
        {
            var nArgs = PrepFuncCall(fi, node, a);

            fi.EmitCall(a, nArgs, n);
        }
Пример #27
0
        private static void CgExp(FuncInfo fi, Exp node, int a, int n)
        {
            switch (node)
            {
            case NilExp _:
                fi.EmitLoadNil(a, n);
                break;

            case FalseExp _:
                fi.EmitLoadBool(a, 0, 0);
                break;

            case TrueExp _:
                fi.EmitLoadBool(a, 1, 0);
                break;

            case IntegerExp integerExp:
                fi.EmitLoadK(a, integerExp.Val);
                break;

            case FloatExp floatExp:
                fi.EmitLoadK(a, floatExp.Val);
                break;

            case StringExp stringExp:
                fi.EmitLoadK(a, stringExp.Str);
                break;

            case ParensExp parensExp:
                CgExp(fi, parensExp.Exp, a, 1);
                break;

            case VarargExp varargExp:
                CgVarargExp(fi, varargExp, a, n);
                break;

            case FuncDefExp funcDefExp:
                CgFuncDefExp(fi, funcDefExp, a);
                break;

            case TableConstructorExp tableConstructorExp:
                CgTableConstructorExp(fi, tableConstructorExp, a);
                break;

            case UnopExp unopExp:
                CgUnopExp(fi, unopExp, a);
                break;

            case BinopExp binopExp:
                CgBinopExp(fi, binopExp, a);
                break;

            case ConcatExp concatExp:
                CgConcatExp(fi, concatExp, a);
                break;

            case NameExp nameExp:
                CgNameExp(fi, nameExp, a);
                break;

            case TableAccessExp tableAccessExp:
                CgTableAccessExp(fi, tableAccessExp, a);
                break;

            case FuncCallExp funcCallExp:
                CgFuncCallExp(fi, funcCallExp, a, n);
                break;
            }
        }
Пример #28
0
        private static void CgAssignStat(FuncInfo fi, AssignStat node)
        {
            var exps  = RemoveTailNil(node.ExpList);
            var nExps = exps.Count;
            var nVars = node.VarList.Count;

            var tRegs   = new int[nVars];
            var kRegs   = new int[nVars];
            var vRegs   = new int[nVars];
            var oldRegs = fi.UsedRegs;

            for (var i = 0; i < node.VarList.Count; i++)
            {
                var exp = node.VarList[i];

                if (exp is TableAccessExp tableAccessExp)
                {
                    tRegs[i] = fi.AllocReg();
                    CgExp(fi, tableAccessExp.PrefixExp, tRegs[i], 1);
                    kRegs[i] = fi.AllocReg();
                    CgExp(fi, tableAccessExp.KeyExp, kRegs[i], 1);
                }
                else if (exp is NameExp nameExp)
                {
                    var name = nameExp.Name;

                    if (fi.SlotOfLocVar(name) < 0 && fi.IndexOfUpval(name) < 0)
                    {
                        kRegs[i] = -1;
                        fi.IndexOfConstant(name, out var constIdx);
                        if (constIdx > 0xff)
                        {
                            kRegs[i] = fi.AllocReg();
                        }
                    }
                }
            }

            for (var i = 0; i < nVars; i++)
            {
                vRegs[i] = fi.UsedRegs + i;
            }

            if (nExps >= nVars)
            {
                for (var i = 0; i < exps.Count; i++)
                {
                    var exp = exps[i];
                    var a   = fi.AllocReg();
                    if (i >= nVars && i == nExps - 1 && IsVarargOrFuncCall(exp))
                    {
                        CgExp(fi, exp, a, 0);
                    }
                    else
                    {
                        CgExp(fi, exp, a, 1);
                    }
                }
            }
            else
            {
                var multRet = false;

                for (var i = 0; i < exps.Count; i++)
                {
                    var exp = exps[i];
                    var a   = fi.AllocReg();
                    if (i == nExps - 1 && IsVarargOrFuncCall(exp))
                    {
                        multRet = true;
                        var n = nVars - nExps + 1;
                        CgExp(fi, exp, a, n);
                        fi.AllocRegs(n - 1);
                    }
                    else
                    {
                        CgExp(fi, exp, a, 1);
                    }
                }

                if (!multRet)
                {
                    var n = nVars - nExps;
                    var a = fi.AllocRegs(n);
                    fi.EmitLoadNil(a, n);
                }
            }

            for (var i = 0; i < node.VarList.Count; i++)
            {
                var exp = node.VarList[i];

                if (exp is NameExp nameExp)
                {
                    var varName = nameExp.Name;
                    var a       = fi.SlotOfLocVar(varName);

                    if (a >= 0)
                    {
                        fi.EmitMove(a, vRegs[i]);
                    }
                    else
                    {
                        var b = fi.IndexOfUpval(varName);
                        if (b >= 0)
                        {
                            fi.EmitSetUpval(vRegs[i], b);
                        }
                        else
                        {
                            a = fi.SlotOfLocVar("_ENV");
                            if (a >= 0)
                            {
                                if (kRegs[i] < 0)
                                {
                                    fi.IndexOfConstant(varName, out var constIdx);
                                    b = 0x100 + constIdx;
                                    fi.EmitSetTable(a, b, vRegs[i]);
                                }
                                else
                                {
                                    fi.EmitSetTable(a, kRegs[i], vRegs[i]);
                                }
                            }
                            else
                            {
                                a = fi.IndexOfUpval("_ENV");
                                if (kRegs[i] < 0)
                                {
                                    fi.IndexOfConstant(varName, out var idx);
                                    b = 0x100 + idx;
                                    fi.EmitSetTabUp(a, b, vRegs[i]);
                                }
                                else
                                {
                                    fi.EmitSetTable(a, kRegs[i], vRegs[i]);
                                }
                            }
                        }
                    }
                }
                else
                {
                    fi.EmitSetTable(tRegs[i], kRegs[i], vRegs[i]);
                }
            }

            fi.UsedRegs = oldRegs;
        }
Пример #29
0
        private static void CgLocalFuncDefStat(FuncInfo fi, LocalFuncDefStat node)
        {
            var r = fi.AddLocVar(node.Name);

            CgFuncDefExp(fi, node.Exp, r);
        }
Пример #30
0
        private static void CgLocalVarDeclStat(FuncInfo fi, LocalVarDeclStat node)
        {
            var exps    = RemoveTailNil(node.ExpList);
            var nExps   = exps.Count;
            var nNames  = node.NameList.Count;
            var oldRegs = fi.UsedRegs;

            if (nExps == nNames)
            {
                foreach (var exp in exps)
                {
                    var a = fi.AllocReg();
                    CgExp(fi, exp, a, 1);
                }
            }
            else if (nExps > nNames)
            {
                for (var i = 0; i < exps.Count; i++)
                {
                    var exp = exps[i];
                    var a   = fi.AllocReg();
                    if (i == nExps - 1 && IsVarargOrFuncCall(exp))
                    {
                        CgExp(fi, exp, a, 0);
                    }
                    else
                    {
                        CgExp(fi, exp, a, 1);
                    }
                }
            }
            else
            {
                var multRet = false;
                for (var i = 0; i < exps.Count; i++)
                {
                    var exp = exps[i];
                    var a   = fi.AllocReg();
                    if (i == nExps - 1 && IsVarargOrFuncCall(exp))
                    {
                        multRet = true;
                        var n = nNames - nExps + 1;
                        CgExp(fi, exp, a, n);
                        fi.AllocRegs(n - 1);
                    }
                    else
                    {
                        CgExp(fi, exp, a, 1);
                    }
                }

                if (!multRet)
                {
                    var n = nNames - nExps;
                    var a = fi.AllocRegs(n);
                    fi.EmitLoadNil(a, n);
                }
            }

            fi.UsedRegs = oldRegs;
            foreach (var name in node.NameList)
            {
                fi.AddLocVar(name);
            }
        }