protected override void TraverseNode(Node node) { if (Stack.Count() == 1) { _retlabel = _ptx.def_label("ret"); base.TraverseNode(node); _ptx.label(_retlabel); _ptx.emit(new exit{}); _ptx._stk.AssertEmpty(); } else { var stmt = !(node is Expression); var top_level_expr = node is Expression && !(node.Parent is Expression); top_level_expr &= (node.Parent != null); // rule out synthetic expressions (e.g. see TraverseOperator for AndAlso) if (stmt || top_level_expr) { // note. we comment only top-level expressions // since there's a discrepancy in visit time and emit time // so that typically all comments for intermediate expressions // get emitted much earlier than instructions they refer to _ptx.comment(Environment.NewLine); var i_indent = node.Parents().Count() - 1; var s_indent = i_indent.Times(" "); _ptx.comment(s_indent + node.ToDebugString_WithoutParentInfo()); } base.TraverseNode(node); } }
private void PutIntoCache(Node stmt) { double? index = null; _vertices.TakeWhile(_ => index == null).ForEach((cfb, i) => { var united = cfb.BalancedCode.Concat(cfb.Residue.Cast<Node>()).ToReadOnly(); var iof = united.IndexOf(stmt); if (iof == -1) return; Node before = null; if (iof > 0) before = united[iof - 1]; else { before = (i - 1).DownTo(0).Select(j => _vertices[j].Residue.LastOrDefault() ?? _vertices[j].BalancedCode.LastOrDefault()).Where(n => n != null).FirstOrDefault(); } Node after = null; if (iof < united.Count() - 1) after = united[iof + 1]; else { after = (i + 1).UpTo(_vertices.Count() - 1).Select(j => _vertices[j].BalancedCode.FirstOrDefault() ?? _vertices[j].Residue.FirstOrDefault()).Where(n => n != null).FirstOrDefault(); } var i_before = before == null ? _execOrders.Values.MinOrDefault() - 1 : _execOrders[before]; var i_after = after == null ? _execOrders.Values.MaxOrDefault() + 1 : _execOrders[after]; index = (i_before + i_after) / 2; }); index.AssertNotNull(); PutIntoCache(stmt, index.Value); }
public ArrayLayout(Node node, space space, Address ptr, ReadOnlyCollection<Reg> dims) { Node = node; Space = space; Ptr = ptr; Dims = dims; }
public static Operator CreateOpPostAssign(this Node lhs, OperatorType op, Node rhs) { var e_lhs = lhs as Expression; var e_rhs = rhs as Expression; if (e_lhs == null || e_rhs == null) return null; OperatorType opAssign; if (EnumHelper.TryParse(op + "Assign", out opAssign)) { if (op == OperatorType.Add && e_rhs.IsConstOne()) { return Operator.PostIncrement(e_lhs); } else if (op == OperatorType.Subtract && e_rhs.IsConstOne()) { return Operator.PostDecrement(e_lhs); } else { return null; } } else { return null; } }
public static void Remove(this ControlFlowGraph cfg, Node toDelete) { var parent = cfg.Vertices.SingleOrDefault(cfb => cfb.BalancedCode.Contains(toDelete) || cfb.Residue.Contains(toDelete as Expression)); if (parent != null) { parent.BalancedCode.Remove(toDelete); parent.Residue.Remove(toDelete as Expression); } }
public static void Replace(this ControlFlowGraph cfg, Node replacee, Node replacer) { var parent = cfg.Vertices.SingleOrDefault(cfb => cfb.BalancedCode.Contains(replacee) || cfb.Residue.Contains(replacee as Expression)); if (parent != null) { parent.BalancedCode.ReplaceElements(replacee, replacer); parent.Residue.ReplaceElements(replacee as Expression, replacer as Expression); } }
public void ReplaceWith(Node node) { if (node == null) RemoveSelf(); var blk = node as Block; if (blk != null && blk.IsEmpty()) RemoveSelf(); else { Parent.AssertNotNull(); Parent.Children[Index] = node; } }
public NodeSnippet(Node node) { Node = node.AssertNotNull(); }
public void ReplaceRecursive(Node root, Func<Node, bool> find, Func<Node, Node> replace) { EvictFromCache(root.Stmt()); root.ReplaceRecursive(find, replace); PutIntoCache(root.Stmt()); }
private Node Filter(Node node) { return node; }
public void Replace(Node replacee, Node replacer) { _cfg.Replace(replacee, replacer); EvictFromCache(replacee); PutIntoCache(replacer); }
public static void ReplaceRecursive(this Node root, Node find, Func<Node, Node> replace) { root.ReplaceRecursive(n => ReferenceEquals(find, n), replace); }
public ReadOnlyCollection<Expression> Reads(Node atom) { return _usages[atom.AssertCast<Expression>()].Where(u => !(u is Assign)).ToReadOnly(); }
private static void Traverse(Node n, List<Node> log) { // this is a child-first traversal if (n == null) { // do nothing - nowhere to drill into } else if (n is Addr) { var addr = (Addr)n; Traverse(addr.Target, log); } else if (n is Assign) { var ass = (Assign)n; Traverse(ass.Rhs, log); Traverse(ass.Lhs, log); } else if (n is Operator) { var op = (Operator)n; op.Args.ForEach(a => Traverse(a, log)); } else if (n is Conditional) { var cond = (Conditional)n; Traverse(cond.Test, log); Traverse(cond.IfTrue, log); Traverse(cond.IfFalse, log); } else if (n is Const) { // do nothing - nowhere to drill into } else if (n is Convert) { var cvt = (Convert)n; Traverse(cvt.Source, log); } else if (n is Deref) { var deref = (Deref)n; Traverse(deref.Target, log); } else if (n is Slot) { var slot = (Slot)n; Traverse(slot.This, log); } else if (n is Loophole) { // do nothing - nowhere to drill into } else if (n is Ref) { // do nothing - nowhere to drill into } else if (n is SizeOf) { // do nothing - nowhere to drill into } else if (n is TypeAs) { var typeAs = (TypeAs)n; Traverse(typeAs.Target, log); } else if (n is TypeIs) { var typeIs = (TypeIs)n; Traverse(typeIs.Target, log); } else if (n is Default) { // do nothing - nowhere to drill into } else if (n is CollectionInit) { var ci = (CollectionInit)n; ci.Elements.ForEach(el => Traverse(el, log)); Traverse(ci.Ctor, log); } else if (n is ObjectInit) { var oi = (ObjectInit)n; oi.Members.ForEach(mi => Traverse(oi.MemberInits[mi], log)); Traverse(oi.Ctor, log); } else if (n is Apply) { var app = (Apply)n; app.Args.ForEach(a => Traverse(a, log)); Traverse(app.Callee, log); } else if (n is Eval) { var eval = (Eval)n; Traverse(eval.Callee, log); } else if (n is Lambda) { // do nothing - nowhere to drill into } else if (n is Catch) { var @catch = (Catch)n; Traverse(@catch.Filter, log); @catch.ForEach(c => Traverse(c, log)); } else if (n is Block) { var block = (Block)n; block.ForEach(c => Traverse(c, log)); } else if (n is If) { var @if = (If)n; Traverse(@if.Test, log); Traverse(@if.IfTrue, log); Traverse(@if.IfFalse, log); } else if (n is Loop) { var loop = (Loop)n; Traverse(loop.Init, log); if (loop.IsWhileDo) Traverse(loop.Test, log); Traverse(loop.Body, log); Traverse(loop.Iter, log); if (loop.IsDoWhile) Traverse(loop.Test, log); } else if (n is Break) { // do nothing - nowhere to drill into } else if (n is Continue) { // do nothing - nowhere to drill into } else if (n is Goto) { // todo. I don't really have time to implement this right now // neither I can think about the case in the near future when this will be useful // throw new NotImplementedException(); } else if (n is Label) { // do nothing - nowhere to drill into } else if (n is Return) { var @return = (Return)n; Traverse(@return.Value, log); } else if (n is Throw) { var @throw = (Throw)n; Traverse(@throw.Exception, log); } else if (n is Try) { var @try = (Try)n; Traverse(@try.Body, log); @try.Clauses.ForEach(c => Traverse(c, log)); } else if (n is Using) { var @using = (Using)n; Traverse(@using.Init, log); Traverse(@using.Body, log); } else if (n is Iter) { var iter = (Iter)n; Traverse(iter.Seq, log); Traverse(iter.Body, log); } else { throw AssertionHelper.Fail(); } // this is a child-first traversal log.Add(n); }
public static void ReplaceRecursive(this Node root, Node find, Node replace) { root.ReplaceRecursive(n => find.Equiv(n), _ => replace); }
private void PutIntoCache(Node stmt, double execOrder) { _execOrders.Add(stmt, execOrder); // todo. use Family instead of ChildrenRecursive and make this not crash var usages = stmt.ChildrenRecursive().Where(n => n.IsAtom()).ToReadOnly(); foreach (Expression u in usages) { _atoms.Add(u); var cache = _usages.GetOrCreate(u, () => new List<Expression>()); var ins = cache.TakeWhile((u2, i) => _execOrders[u2.Stmt()] <= execOrder).Count(); var isAssignToAtom = u.Parent is Assign && ((Assign)u.Parent).Lhs == u; cache.Insert(ins, isAssignToAtom ? u.Parent.AssertCast<Assign>() : u); } }
public double ExecOrderOfStmt(Node anyNode) { return _execOrders[anyNode.Stmt()]; }
public ReadOnlyCollection<Assign> Writes(Node atom) { return _usages[atom.AssertCast<Expression>()].OfType<Assign>().ToReadOnly(); }
public void ReplaceRecursive(Node root, Node find, Node replace) { EvictFromCache(root.Stmt()); root.ReplaceRecursive(find, replace); PutIntoCache(root.Stmt()); }
// note. unlike most transformations in Truesight, this one works in-place private static void StripOffRedundanciesInPlace(Node root) { Action<Node> defaultTraverse = node => node.Children.ForEach(c => { var deref = c as Deref; if (deref != null) { var t = deref.Target.Type(); if (t != null && t.IsByRef) c.ReplaceWith(deref.Target); c = deref.Target; } c.Traverse(); }); root.Traverse(defaultTraverse, (Assign ass) => { defaultTraverse(ass); var ass_prop = ass.Lhs as Prop; var ass_app = ass.Lhs as Apply; if (ass_app != null) ass_prop = ass_app.Callee as Prop; if (ass_prop != null) { var addr = ass_prop.This as Addr; if (addr != null) ass_prop.This = addr.Target; } var ass_deref = ass.Lhs as Deref; if (ass_deref != null) { var t = ass_deref.Target.Type(); if (t != null && t.IsByRef) ass.Lhs = ass_deref.Target; } }, (Fld fld) => { var addr = fld.This as Addr; if (addr != null) fld.This = addr.Target; defaultTraverse(fld); }, (Prop prop) => { var addr = prop.This as Addr; if (addr != null) prop.This = addr.Target; defaultTraverse(prop); }, (Deref deref) => { var t = deref.Target.Type(); if (t != null && t.IsByRef) throw AssertionHelper.Fail(); defaultTraverse(deref); }, (Apply app) => { var callee_addr = app.Callee as Addr; if (callee_addr != null) app.Callee = callee_addr.Target; defaultTraverse(app); app.ArgsInfo.Zip((arg, pi, i) => { var addr = arg as Addr; var arg_byref = addr != null; var p_byref = pi != null && pi.Type.IsByRef; if (arg_byref && p_byref) app.Args[i] = addr.Target; var p_is_this = i == 0 && pi != null && pi.Name == "this"; if (arg_byref && p_is_this) app.Args[i] = addr.Target; }); } ); }
public NodeDebugView(Node node) : this(node, null) {}
public ReadOnlyCollection<Expression> Usages(Node atom) { return _usages[atom.AssertCast<Expression>()].ToReadOnly(); }
public static void ReplaceRecursive(this Node root, Func<Node, bool> find, Node replace) { root.ReplaceRecursive(find, _ => replace); }
public NodeDebugView_NoParent(Node node) : this(node, null) { }
private void Expand(Node node) { if (node is Expression) { var expr = (Expression)node; var inlined = expr.Expand(Ctx); inlined.Stmts.ForEach(Stmts.Add); if (inlined.Result != null) Stmts.Add(inlined.Result); } else if (node is Block) { var block = (Block)node; Stmts.Add(block.Expand(Ctx.SpinOff())); } else if (node is Break) { Stmts.Add(node); } else if (node is Continue) { Stmts.Add(node); } else if (node is Goto) { Stmts.Add(node); } else if (node is Label) { Stmts.Add(node); } else if (node is If) { var @if = (If)node; var test = @if.Test.Expand(Ctx); test.Stmts.ForEach(Stmts.Add); test.Result.AssertNotNull(); var if_true = @if.IfTrue.Expand(Ctx.SpinOff()); var if_false = @if.IfFalse.Expand(Ctx.SpinOff()); var expanded = new If(test.Result, if_true, if_false); Stmts.Add(expanded); } else if (node is Loop) { var loop = (Loop)node; var test = loop.Test.Expand(Ctx); test.Result.AssertNotNull(); var init = loop.Init.Expand(Ctx.SpinOff()); var iter = loop.Iter.Expand(Ctx.SpinOff()); var body = loop.Body.Expand(Ctx.SpinOff()); var prepend_test = loop.IsWhileDo && test.Stmts.IsNotEmpty(); if (init.IsNotEmpty() && prepend_test) { Stmts.Add(init); init = new Block(); } if (prepend_test) test.Stmts.ForEach(Stmts.Add); test.Stmts.ForEach(iter.Add); var xloop = new Loop(test.Result, body, loop.IsWhileDo){Init = init, Iter = iter}; var cloned_locals = loop.Locals.Select(l => l.DeepClone()); cloned_locals.ForEach(local => xloop.Locals.Add(local)); Stmts.Add(xloop); } else if (node is Return) { var ret = (Return)node; (ret.Value == null).AssertEquiv(Ret == null); if (ret.Value != null) Expand(new Assign(Ret, ret.Value)); Stmts.Add(new Goto(RetLabel)); } else if (node is Try || node is Clause || node is Throw || node is Using || node is Iter) { // todo. implement support for non-linear control flow // this is only possible when we fully implement decompilation of tries // until now I leave this marked as "to be implemented" throw AssertionHelper.Fail(); } else { throw AssertionHelper.Fail(); } }
public NodeDebugView_NoParent(Node node, Object parentProxy) : this(node, parentProxy, NodeDebuggabilityHelper.InferDebugProxyNameFromStackTrace()) {}
public NodeDebugView_NoParent(Node node, Object parentProxy, String name) { _node = node; _parentProxy = parentProxy; _name = name; }
private void Qualify(Node node) { var pp_node = Filter(node); _map.Add(pp_node, _currentOp); var dbg = _currentOp.Source.DebugInfo; if (dbg != null) pp_node.Family().Where(n => n != null).ForEach(n => n.Src = n.Src ?? dbg[_currentOp.Offset]); _qualified.Enqueue(pp_node); }
public SlotLayout(Node node, Slot slot) { Node = node; Slot = slot; }
public void Remove(Node toDelete) { _cfg.Remove(toDelete); EvictFromCache(toDelete); }