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; } } } }
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); } } }
// 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); }
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); } }
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); }