Пример #1
0
        public static void Transform(ILBlock method)
        {
            // TODO: move this somewhere else
            // Eliminate 'dups':
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
                for (int i = 0; i < expr.Arguments.Count; i++) {
                    if (expr.Arguments[i].Code == ILCode.Dup)
                        expr.Arguments[i] = expr.Arguments[i].Arguments[0];
                }
            }

            var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand)));
            var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
            var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
            var initializeArrayPattern = new ILCall(
                "System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
                new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
                for (int i = block.Body.Count - 1; i >= 0; i--) {
                    if (!newArrPattern.Match(block.Body[i]))
                        continue;
                    ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
                    int arrayLength = (int)newArrInst.Arguments[0].Operand;
                    if (arrayLength == 0)
                        continue;
                    if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
                        if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
                            if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
                                i -= ILInlining.InlineInto(block, i + 1, method) - 1;
                            }
                            continue;
                        }
                    }
                    if (i + 1 + arrayLength > block.Body.Count)
                        continue;
                    List<ILExpression> operands = new List<ILExpression>();
                    for (int j = 0; j < arrayLength; j++) {
                        ILExpression expr = block.Body[i + 1 + j] as ILExpression;
                        if (expr == null || !IsStoreToArray(expr.Code))
                            break;
                        if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable))
                            break;
                        if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j))
                            break;
                        operands.Add(expr.Arguments[2]);
                    }
                    if (operands.Count == arrayLength) {
                        ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
                            ILCode.InitArray, newArrInst.Operand, operands.ToArray());
                        block.Body.RemoveRange(i + 1, arrayLength);
                        i -= ILInlining.InlineInto(block, i + 1, method) - 1;
                    }
                }
            }
        }
Пример #2
0
 void AddBlockToLocals(ILBlock block)
 {
     lock (locals)
     {
         foreach (var e in block.GetSelfAndChildrenRecursive <ILExpression>(x => x.Code == GMCode.Var))
         {
             ILVariable v = e.Operand as ILVariable;
             if (v.isGlobal)
             {
                 continue;
             }
             locals.AddOrUpdate(v.Name,
                                (key) => {
                 var info = new LocalInfo(v);
                 //  v.UserData = info;
                 return(info);
             },
                                (key, existingVal) =>
             {
                 //  v.UserData = existingVal;
                 existingVal.Add(v);
                 return(existingVal);
             });
         }
     }
     lock (assignments)
     {
         foreach (var e in block.GetSelfAndChildrenRecursive <ILExpression>(x => x.Code == GMCode.Assign))
         {
             ILVariable          vr = e.Arguments[0].Operand as ILVariable;
             List <ILExpression> vs;
             if (!assignments.TryGetValue(vr.Name, out vs))
             {
                 assignments.Add(vr.Name, vs = new List <ILExpression>());
             }
             vs.Add(e);
         }
     }
     lock (funcCalls)
     {
         foreach (var e in block.GetSelfAndChildrenRecursive <ILExpression>(x => x.Code == GMCode.Call))
         {
             ILCall c = e.Operand as ILCall;
             List <ILExpression> vs;
             if (!funcCalls.TryGetValue(c.Name, out vs))
             {
                 funcCalls.Add(c.Name, vs = new List <ILExpression>());
             }
             vs.Add(e);
         }
     }
 }
Пример #3
0
        // This pass accepts index or instance values being
        protected override ILExpression CreateExpression(List <ILNode> list)
        {
            ILExpression e       = null;
            OldCode      nOpCode = (OldCode)(CurrentRaw >> 24);

            GM_Type[] types = ReadTypes(CurrentRaw);
            switch (nOpCode) // the bit switch
            {
            case OldCode.Conv: e = CreateExpression(GMCode.Conv, types); break;

            case OldCode.Popz: e = CreateExpression(GMCode.Popz, types); break;

            case OldCode.Mul: e = CreateExpression(GMCode.Mul, types); break;

            case OldCode.Div: e = CreateExpression(GMCode.Div, types); break;

            case OldCode.Rem: e = CreateExpression(GMCode.Rem, types); break;

            case OldCode.Mod: e = CreateExpression(GMCode.Mod, types); break;

            case OldCode.Add: e = CreateExpression(GMCode.Add, types); break;

            case OldCode.Sub: e = CreateExpression(GMCode.Sub, types); break;

            case OldCode.And: e = CreateExpression(GMCode.And, types); break;

            case OldCode.Or: e = CreateExpression(GMCode.Or, types); break;

            case OldCode.Xor: e = CreateExpression(GMCode.Xor, types); break;

            case OldCode.Neg: e = CreateExpression(GMCode.Neg, types); break;

            case OldCode.Not: e = CreateExpression(GMCode.Not, types); break;

            case OldCode.Sal: e = CreateExpression(GMCode.Sal, types); break;

            //    case GMCode.S: e = CreateExpression(GMCode.Sal, types); break;
            //    case GMCode.S: e = CreateExpression(GMCode.Sal, types); break;
            //  case GMCode.shr:     e = CreateExpression(GMCode.Saa, types); break; // hack, handle shift right
            case OldCode.Slt: e = CreateExpression(GMCode.Slt, types); break;

            case OldCode.Sle: e = CreateExpression(GMCode.Sle, types); break;

            case OldCode.Seq: e = CreateExpression(GMCode.Seq, types); break;

            case OldCode.Sne: e = CreateExpression(GMCode.Sne, types); break;

            case OldCode.Sge: e = CreateExpression(GMCode.Sge, types); break;

            case OldCode.Sgt: e = CreateExpression(GMCode.Sgt, types); break;


            case OldCode.Dup:
                e         = CreateExpression(GMCode.Dup, types);
                e.Operand = (int)(CurrentRaw & 0xFFFF);     // dup type
                break;

            case OldCode.Call:
                e         = CreateExpression(GMCode.CallUnresolved, types);
                e.Operand = ILCall.CreateCall(File.Strings[r.ReadInt32()].String, (int)(CurrentRaw & 0xFFFF));

                break;

            case OldCode.Ret: e = CreateExpression(GMCode.Ret, types); break;

            case OldCode.Exit: e = CreateExpression(GMCode.Exit, types); break;

            case OldCode.B: e = CreateLabeledExpression(GMCode.B); break;

            case OldCode.Bt: e = CreateLabeledExpression(GMCode.Bt); break;

            case OldCode.Bf: e = CreateLabeledExpression(GMCode.Bf); break;

            // We have to fix these to a lopp to emulate a while latter
            case OldCode.Pushenv:
            {
                //    Debug.WriteLine("Popenv: Address: {0}, Extra: {1} {1:X8}  Calc: {2}", CurrentPC, CurrentRaw, GMCodeUtil.getBranchOffset(CurrentRaw));
                int sextra = CurrentPC + GMCodeUtil.getBranchOffset(CurrentRaw);
                e = CreateExpression(GMCode.Pushenv, types, GetLabel(sextra + 1)); // we are one instruction after the pop
                pushEnviroment.Add(sextra, GetLabel(CurrentPC));                   // record the pop position
            }
            break;

            case OldCode.Popenv:
            {
                // We convert this to a Branch so the loop detecter will find it
                e = CreateExpression(GMCode.Popenv, types);
                // e = CreateExpression(GMCode.Popenv, types);
                if (CurrentRaw == 0xbcf00000)        // its a break, ugh, old break code ugh
                {
                    foreach (var last in list.Reverse <ILNode>().OfType <ILExpression>())
                    {
                        if (last.Code == GMCode.Pushenv)
                        {
                            e.Operand = last.Operand;
                            return(e);
                        }
                    }
                    Debug.Assert(false);
                }
                else
                {
                    // some reason its the negitive offset?
                    // int offset = GMCodeUtil.getBranchOffset(CurrentRaw) - currentPC;
                    ILLabel endOfEnviroment;
                    if (pushEnviroment.TryGetValue(CurrentPC, out endOfEnviroment)) // this is the code
                    {
                        e.Operand = endOfEnviroment;                                // not a break, set the label BACK to the push as we are simulating a loop
                    }
                    else
                    {
                        throw new Exception("This MUST be a break");
                    }
                }
            }
            break;

            case OldCode.Pop:
                e         = CreateExpression(GMCode.Pop, types);
                e.Operand = BuildUnresolvedVar(r.ReadInt32());

                break;

            case OldCode.Push:
                e = CreatePushExpression(GMCode.Push, types);
                break;

            case OldCode.Break: e = CreateExpression(GMCode.Break, types); break;

            default:
                throw new Exception("Bad opcode");
            }
            return(e);
        }
Пример #4
0
        public virtual void Write(ILExpression expr)
        {
            InsertLineInfo(expr);

            //  if (Code.isExpression())
            //      WriteExpressionLua(output);
            // ok, big one here, important to get this right
            switch (expr.Code)
            {
            case GMCode.Not: WritePreExpresion("!", expr); break;

            case GMCode.Neg: WritePreExpresion("-", expr); break;

            case GMCode.Mul: WriteTreeExpression("*", expr); break;

            case GMCode.Div: WriteTreeExpression("/", expr); break;

            case GMCode.Mod: WriteTreeExpression("%", expr); break;

            case GMCode.Add: WriteTreeExpression("+", expr); break;

            case GMCode.Sub: WriteTreeExpression("-", expr); break;

            case GMCode.Concat: WriteTreeExpression("+", expr); break;

            // in lua, these have all the same prec
            case GMCode.Sne: WriteTreeExpression("!=", expr); break;

            case GMCode.Sge: WriteTreeExpression(">=", expr); break;

            case GMCode.Slt: WriteTreeExpression("<", expr); break;

            case GMCode.Sgt: WriteTreeExpression(">", expr); break;

            case GMCode.Seq: WriteTreeExpression("==", expr); break;

            case GMCode.Sle: WriteTreeExpression("<=", expr); break;

            case GMCode.LogicAnd: WriteTreeExpression("&&", expr); break;

            case GMCode.LogicOr: WriteTreeExpression("||", expr); break;

            case GMCode.Call:
            {
                ILCall call = expr.Operand as ILCall;
                Write(call.Name);
                Write('(');         // self is normaly the first of eveything
                WriteNodesComma(expr.Arguments);
                Write(')');
            }
            break;

            case GMCode.Constant:     // primitive c# type
                Write(expr.Operand as ILValue);
                break;

            case GMCode.Var:      // should be ILVariable
                WriteVariable(expr);
                break;

            case GMCode.Exit:
                Write("return // exit");
                break;

            case GMCode.Ret:
                Write("return ");
                Write(expr.Arguments.Single());
                break;

            case GMCode.LoopOrSwitchBreak:
                Write("break");
                break;

            case GMCode.LoopContinue:
                Write("continue");
                break;

            case GMCode.Assign:
                WriteAssign(expr.Arguments[0], expr.Arguments[1]);

                break;

            // These shouldn't print, debugging
            default:
                Write("ExprError: ");
                Write(expr.ToString());
                Flush();
                error.Error("Expression error on line " + this.LineNumber);

                /*
                 * //  Close(); // we die here
                 * var root = expr.Root;
                 * using (StreamWriter sw = new StreamWriter("bad_write.txt"))
                 * {
                 *  sw.Write(root.ToString());
                 *  sw.Flush();
                 * }
                 * throw new Exception("Not Implmented! ugh");
                 */
                break;
            }
            if (expr.Comment != null)
            {
                Write(BlockCommentStart);
                Write(' ');
                Write(expr.Comment);
                Write(' ');
                Write(BlockCommentEnd);
            }
        }
Пример #5
0
        protected override ILExpression CreateExpression(List <ILNode> list)
        {
            ILExpression e       = null;
            NewOpcode    nOpCode = (NewOpcode)(CurrentRaw >> 24);

            GM_Type[] types = ReadTypes(CurrentRaw);
            switch (nOpCode) // the bit switch
            {
            case NewOpcode.conv: e = CreateExpression(GMCode.Conv, types); break;

            case NewOpcode.popz: e = CreateExpression(GMCode.Popz, types); break;

            case NewOpcode.mul: e = CreateExpression(GMCode.Mul, types); break;

            case NewOpcode.div: e = CreateExpression(GMCode.Div, types); break;

            case NewOpcode.rem: e = CreateExpression(GMCode.Rem, types); break;

            case NewOpcode.mod: e = CreateExpression(GMCode.Mod, types); break;

            case NewOpcode.@add: e = CreateExpression(GMCode.Add, types); break;

            case NewOpcode.sub: e = CreateExpression(GMCode.Sub, types); break;

            case NewOpcode.and: e = CreateExpression(GMCode.And, types); break;

            case NewOpcode.or: e = CreateExpression(GMCode.Or, types); break;

            case NewOpcode.xor: e = CreateExpression(GMCode.Xor, types); break;

            case NewOpcode.neg: e = CreateExpression(GMCode.Neg, types); break;

            case NewOpcode.not: e = CreateExpression(GMCode.Not, types); break;

            case NewOpcode.shl: e = CreateExpression(GMCode.Sal, types); break;

            //  case NewOpcode.shr:     e = CreateExpression(GMCode.Saa, types); break; // hack, handle shift right
            case NewOpcode.@set:
                switch ((CurrentRaw >> 8) & 0xFF)
                {
                case 1: e = CreateExpression(GMCode.Slt, types); break;

                case 2: e = CreateExpression(GMCode.Sle, types); break;

                case 3: e = CreateExpression(GMCode.Seq, types); break;

                case 4: e = CreateExpression(GMCode.Sne, types); break;

                case 5: e = CreateExpression(GMCode.Sge, types); break;

                case 6: e = CreateExpression(GMCode.Sgt, types); break;

                default:
                    throw new Exception("Bad condition");
                }
                break;

            case NewOpcode.dup:
                e         = CreateExpression(GMCode.Dup, types);
                e.Operand = (int)(CurrentRaw & 0xFFFF);     // dup type
                break;

            case NewOpcode.call:
                e         = CreateExpression(GMCode.CallUnresolved, types);
                e.Operand = ILCall.CreateCall(File.Strings[r.ReadInt32()].String, (int)(CurrentRaw & 0xFFFF));
                // since we can have var args on alot of functions, extra is used
                break;

            case NewOpcode.ret: e = CreateExpression(GMCode.Ret, types); break;

            case NewOpcode.exit: e = CreateExpression(GMCode.Exit, types); break;

            case NewOpcode.b: e = CreateLabeledExpression(GMCode.B); break;

            case NewOpcode.bt: e = CreateLabeledExpression(GMCode.Bt); break;

            case NewOpcode.bf: e = CreateLabeledExpression(GMCode.Bf); break;

            // We have to fix these to a lopp to emulate a while latter
            case NewOpcode.pushenv:
            {
                //  Debug.WriteLine("Popenv: Address: {0}, Extra: {1} {1:X8}  Calc: {2}",i.Address, raw, GMCodeUtil.getBranchOffset(raw));
                int sextra = CurrentPC + GMCodeUtil.getBranchOffset(CurrentRaw);
                e = CreateExpression(GMCode.Pushenv, types, GetLabel(sextra + 1)); // we are one instruction after the pop
                pushEnviroment.Add(sextra, GetLabel(CurrentPC));                   // record the pop position
            }
            break;

            case NewOpcode.popenv:
            {
                // We convert this to a Branch so the loop detecter will find it
                e = CreateExpression(GMCode.B, types);
                // e = CreateExpression(GMCode.Popenv, types);
                if (CurrentRaw == 0xBBF00000)        // its a break, ugh
                {
                    foreach (var last in list.Reverse <ILNode>().OfType <ILExpression>())
                    {
                        if (last.Code == GMCode.Pushenv)
                        {
                            e.Operand = last.Operand;
                            return(e);
                        }
                    }
                    Debug.Assert(false);
                }
                else
                {
                    // some reason its the negitive offset?
                    // int offset = GMCodeUtil.getBranchOffset(CurrentRaw) - currentPC;
                    ILLabel endOfEnviroment;
                    if (pushEnviroment.TryGetValue(CurrentPC, out endOfEnviroment)) // this is the code
                    {
                        e.Operand = endOfEnviroment;                                // not a break, set the label BACK to the push as we are simulating a loop
                    }
                    else
                    {
                        throw new Exception("This MUST be a break");
                    }
                }
            }
            break;

            case NewOpcode.pop:
                e         = CreateExpression(GMCode.Pop, types);
                e.Operand = BuildUnresolvedVar(r.ReadInt32());
                break;

            case NewOpcode.pushi:
                Debug.Assert(types[0] == GM_Type.Short);
                e = CreatePushExpression(GMCode.Push, types);
                break;    // push int? ah like a pushe

            case NewOpcode.push:
                e = CreatePushExpression(GMCode.Push, types);
                break;            // generic push is fine right?

            case NewOpcode.pushl: // local
                e = CreatePushExpression(GMCode.Push, types);

                break;            // local? -7

            case NewOpcode.pushg: // Global
                e = CreatePushExpression(GMCode.Push, types);
                break;            // global? -5 // id is the last bit?

            case NewOpcode.pushb: // builtin .. seeing a patern hummmm
                                  // Built in vars?  always -1?
                e = CreatePushExpression(GMCode.Push, types);
                break;

            //      case NewOpcode.call2: e = CreateExpression(GMCode.Sal, types, operand); break;
            case NewOpcode.@break: e = CreateExpression(GMCode.Break, types); break;

            default:
                throw new Exception("Bad opcode");
            }
            return(e);
        }