protected virtual ILCondition VisitCondition(ILCondition condition) { foreach (var child in condition.GetChildren()) { Visit(child); } return(condition); }
bool MatchFixedInitializer(List <ILNode> body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos) { if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) { initValue = (ILExpression)body[i]; nextPos = i + 1; HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue); return(true); } ILCondition ifStmt = body[i] as ILCondition; ILExpression arrayLoadingExpr; if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) { ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand; ILExpression trueValue; if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue) && pinnedVar.IsPinned && IsNullOrZero(trueValue)) { if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1 && ifStmt.FalseBlock.Body[0] is ILFixedStatement) { ILFixedStatement fixedStmt = (ILFixedStatement)ifStmt.FalseBlock.Body[0]; ILVariable stlocVar; ILExpression falseValue; if (fixedStmt.Initializers.Count == 1 && fixedStmt.BodyBlock.Body.Count == 0 && fixedStmt.Initializers[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar) { ILVariable loadedVariable; if (falseValue.Code == ILCode.Ldelema && falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable && IsNullOrZero(falseValue.Arguments[1])) { // OK, we detected the pattern for fixing an array. // Now check whether the loading expression was a store ot a temp. var // that can be eliminated. if (arrayLoadingExpr.Code == ILCode.Stloc) { ILInlining inlining = new ILInlining(method); if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 && inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0) { arrayLoadingExpr = arrayLoadingExpr.Arguments[0]; } } initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr); nextPos = i + 1; return(true); } } } } } initValue = null; nextPos = -1; return(false); }
private void CompileTernaryOp(ILExpression e, ExpectType expect) { ILCondition conditionNode = new ILCondition(); conditionNode.Condition = e.Arguments[0]; conditionNode.TrueBlock = new ILBlock(e.Arguments[1]); conditionNode.FalseBlock = new ILBlock(e.Arguments[2]); CompileCondition(conditionNode, expect); TranslateType(resolver.Resolve(e.InferredType, thisMethod.FullGenericArguments), expect, e); }
/// <summary> /// Reduce the nesting of conditions. /// It should be done on flat data that already had most gotos removed /// </summary> void ReduceIfNesting(ILNode node) { ILBlock block = node as ILBlock; if (block != null) { for (int i = 0; i < block.Body.Count; i++) { ILCondition cond = block.Body[i] as ILCondition; if (cond != null) { bool trueExits = cond.TrueBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); bool falseExits = cond.FalseBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); if (trueExits) { // Move the false block after the condition block.Body.InsertRange(i + 1, cond.FalseBlock.GetChildren()); cond.FalseBlock = new ILBlock(); } else if (falseExits) { // Move the true block after the condition block.Body.InsertRange(i + 1, cond.TrueBlock.GetChildren()); cond.TrueBlock = new ILBlock(); } // Eliminate empty true block if (!cond.TrueBlock.GetChildren().Any() && cond.FalseBlock.GetChildren().Any()) { // Swap bodies ILBlock tmp = cond.TrueBlock; cond.TrueBlock = cond.FalseBlock; cond.FalseBlock = tmp; cond.Condition = new ILExpression(ILCode.LogicNot, null, cond.Condition); } } } } // We are changing the number of blocks so we use plain old recursion to get all blocks foreach (ILNode child in node.GetChildren()) { if (child != null && !(child is ILExpression)) { ReduceIfNesting(child); } } }
public virtual void Write(ILCondition condition) { InsertLineInfo(condition); Write("if("); Write(condition.Condition); // want to make sure we are using the debug Write(")"); WriteSingleLineOrBlock(condition.TrueBlock); if (condition.FalseBlock != null && condition.FalseBlock.Body.Count > 0) { if (this.Column > 0 && this.CurrentLine != "}") { WriteLine(); } Write(" else "); WriteSingleLineOrBlock(condition.FalseBlock); } }
private List <ILVariable> PreprocessorCheckUninitializedLocalVarsBranch(ILBlock branch, List <ILVariable> initializedVars) { List <ILVariable> result = new List <ILVariable>(initializedVars); foreach (ILNode node in branch.Body) { if (node is ILExpression) { PreprocessorCheckUninitializedLocalVarsExpression((ILExpression)node, result); } else if (node is ILBlock) { result = PreprocessorCheckUninitializedLocalVarsBranch((ILBlock)node, result); } else if (node is ILTryCatchBlock) { ILTryCatchBlock block = (ILTryCatchBlock)node; List <ILVariable> newResult = new List <ILVariable>(result); if (block.TryBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.TryBlock, result)).ToList(); } if (block.FaultBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FaultBlock, result)).ToList(); } if (block.FinallyBlock != null) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(block.FinallyBlock, result)).ToList(); } if (block.CatchBlocks != null) { foreach (ILTryCatchBlock.CatchBlock c in block.CatchBlocks) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(c, result)).ToList(); } } result = newResult; } else if (node is ILWhileLoop) { PreprocessorCheckUninitializedLocalVarsExpression(((ILWhileLoop)node).Condition, result); result = PreprocessorCheckUninitializedLocalVarsBranch(((ILWhileLoop)node).BodyBlock, result); } else if (node is ILCondition) { ILCondition cond = (ILCondition)node; PreprocessorCheckUninitializedLocalVarsExpression(cond.Condition, result); List <ILVariable> fromTrue = PreprocessorCheckUninitializedLocalVarsBranch(cond.TrueBlock, result); List <ILVariable> fromFalse = PreprocessorCheckUninitializedLocalVarsBranch(cond.FalseBlock, result); result = fromTrue.Union(fromFalse).ToList(); } else if (node is ILSwitch) { ILSwitch sw = (ILSwitch)node; PreprocessorCheckUninitializedLocalVarsExpression(sw.Condition, result); List <ILVariable> newResult = new List <ILVariable>(result); foreach (var cas in sw.CaseBlocks) { newResult = newResult.Union(PreprocessorCheckUninitializedLocalVarsBranch(cas, result)).ToList(); } result = newResult; } } return(result); }
/// <summary> /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node. /// Try blocks may not be entered in any way. If possible, the try block is returned as the node to be executed. /// </summary> ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes) { if (node == null) { throw new ArgumentNullException(); } if (!visitedNodes.Add(node)) { return(null); // Infinite loop } ILLabel label = node as ILLabel; if (label != null) { return(Exit(label, visitedNodes)); } ILExpression expr = node as ILExpression; if (expr != null) { if (expr.Code == GMCode.B) { ILLabel target = (ILLabel)expr.Operand; return(Enter(target, visitedNodes)); } else if (expr.Code == GMCode.BadOp || expr.Code == GMCode.Constant || expr.Code == GMCode.Var) { return(Exit(expr, visitedNodes)); } else if (expr.Code == GMCode.LoopOrSwitchBreak) { ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch || n is ILWithStatement); return(Exit(breakBlock, new HashSet <ILNode>() { expr })); } else if (expr.Code == GMCode.LoopContinue) { ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILWithStatement); return(Enter(continueBlock, new HashSet <ILNode>() { expr })); } else { return(expr); } } ILBlock block = node as ILBlock; if (block != null) { if (block.EntryGoto != null) { return(Enter(block.EntryGoto, visitedNodes)); } else if (block.Body.Count > 0) { return(Enter(block.Body[0], visitedNodes)); } else { return(Exit(block, visitedNodes)); } } ILCondition cond = node as ILCondition; if (cond != null) { return(cond.Condition); } ILWhileLoop loop = node as ILWhileLoop; if (loop != null) { if (loop.Condition != null) { return(loop.Condition); } else { return(Enter(loop.Body, visitedNodes)); } } ILSwitch ilSwitch = node as ILSwitch; if (ilSwitch != null) { return(ilSwitch.Condition); } throw new NotSupportedException(node.GetType().ToString()); }
/// <summary> /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node. /// Try blocks may not be entered in any way. If possible, the try block is returned as the node to be executed. /// </summary> ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes) { if (node == null) { throw new ArgumentNullException(); } if (!visitedNodes.Add(node)) { return(null); // Infinite loop } ILLabel label = node as ILLabel; if (label != null) { return(Exit(label, visitedNodes)); } ILExpression expr = node as ILExpression; if (expr != null) { if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave) { ILLabel target = (ILLabel)expr.Operand; // Early exit - same try-block if (GetParents(expr).OfType <ILTryCatchBlock>().FirstOrDefault() == GetParents(target).OfType <ILTryCatchBlock>().FirstOrDefault()) { return(Enter(target, visitedNodes)); } // Make sure we are not entering any try-block var srcTryBlocks = GetParents(expr).OfType <ILTryCatchBlock>().Reverse().ToList(); var dstTryBlocks = GetParents(target).OfType <ILTryCatchBlock>().Reverse().ToList(); // Skip blocks that we are already in int i = 0; while (i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i]) { i++; } if (i == dstTryBlocks.Count) { return(Enter(target, visitedNodes)); } else { ILTryCatchBlock dstTryBlock = dstTryBlocks[i]; // Check that the goto points to the start ILTryCatchBlock current = dstTryBlock; while (current != null) { foreach (ILNode n in current.TryBlock.Body) { if (n is ILLabel) { if (n == target) { return(dstTryBlock); } } else if (!n.Match(ILCode.Nop)) { current = n as ILTryCatchBlock; break; } } } return(null); } } else if (expr.Code == ILCode.Nop) { return(Exit(expr, visitedNodes)); } else if (expr.Code == ILCode.LoopOrSwitchBreak) { ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch); return(Exit(breakBlock, new HashSet <ILNode>() { expr })); } else if (expr.Code == ILCode.LoopContinue) { ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop); return(Enter(continueBlock, new HashSet <ILNode>() { expr })); } else { return(expr); } } ILBlock block = node as ILBlock; if (block != null) { if (block.EntryGoto != null) { return(Enter(block.EntryGoto, visitedNodes)); } else if (block.Body.Count > 0) { return(Enter(block.Body[0], visitedNodes)); } else { return(Exit(block, visitedNodes)); } } ILCondition cond = node as ILCondition; if (cond != null) { return(cond.Condition); } ILWhileLoop loop = node as ILWhileLoop; if (loop != null) { if (loop.Condition != null) { return(loop.Condition); } else { return(Enter(loop.BodyBlock, visitedNodes)); } } ILTryCatchBlock tryCatch = node as ILTryCatchBlock; if (tryCatch != null) { return(tryCatch); } ILSwitch ilSwitch = node as ILSwitch; if (ilSwitch != null) { return(ilSwitch.Condition); } throw new NotSupportedException(node.GetType().ToString()); }
void CachedDelegateInitializationWithField(ILBlock block, ref int i) { // if (logicnot(ldsfld(field))) { // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) // } else { // } // ...(..., ldsfld(field), ...) ILCondition c = block.Body[i] as ILCondition; if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) { return; } if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) { return; } if (!c.Condition.Match(ILCode.LogicNot)) { return; } ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldsfld) { return; } FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule(); // field is defined in current assembly if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) { return; } ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression; if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field)) { return; } ILExpression newObj = stsfld.Arguments[0]; if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) { return; } if (newObj.Arguments[0].Code != ILCode.Ldnull) { return; } if (newObj.Arguments[1].Code != ILCode.Ldftn) { return; } MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) { return; } ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); int ldfldResolvingWithinSameMethodCount = followingNode .EnumerateSelfAndChildrenRecursive() .OfType <ILExpression>() .Count( e => e.Code == ILCode.Ldsfld && ((FieldReference)e.Operand).ResolveWithinSameModule() == field); if (followingNode != null && ldfldResolvingWithinSameMethodCount == 1) { foreach (ILExpression parent in followingNode.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>()) { for (int j = 0; j < parent.Arguments.Count; j++) { if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field) { parent.Arguments[j] = newObj; block.Body.RemoveAt(i); i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false); return; } } } } }
private void ProcessMethodDecencies(InterMethod method, ILNode node, List <InterGenericArgument> genericArgs) { if (node is ILBlock) { ILBlock block = node as ILBlock; foreach (ILNode n in block.Body) { ProcessMethodDecencies(method, n, genericArgs); } } else if (node is ILBasicBlock) { ILBasicBlock block = node as ILBasicBlock; foreach (ILNode n in block.Body) { ProcessMethodDecencies(method, n, genericArgs); } } else if (node is ILTryCatchBlock) { ILTryCatchBlock block = node as ILTryCatchBlock; foreach (ILNode n in block.TryBlock.Body) { ProcessMethodDecencies(method, n, genericArgs); } if (block.FaultBlock != null) { foreach (ILNode n in block.FaultBlock.Body) { ProcessMethodDecencies(method, n, genericArgs); } } if (block.FinallyBlock != null) { foreach (ILNode n in block.FinallyBlock.Body) { ProcessMethodDecencies(method, n, genericArgs); } } foreach (var catchBlock in block.CatchBlocks) { ((IResolver)this).Resolve(catchBlock.ExceptionType, genericArgs); ProcessMethodDecencies(method, catchBlock, genericArgs); } } else if (node is ILExpression) { ILExpression e = node as ILExpression; foreach (var n in e.Arguments) { ProcessMethodDecencies(method, n, genericArgs); } if ((e.Code == ILCode.Mkrefany) || (e.Code == ILCode.Refanyval)) { ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName); } if (e.Code == ILCode.Refanytype) { ((IResolver)this).Resolve(ClassNames.SystemTypedReference.ClassName); ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName); } if (e.Code == ILCode.Arglist) { ((IResolver)this).Resolve(ClassNames.SystemRuntimeArgumentHandle.ClassName); } if (e.Code.IsExternalRealization()) { ((IResolver)this).Resolve(ClassNames.CIL2JavaVESInstructions.ClassName); } if (e.Code == ILCode.Ldc_Decimal) { ((IResolver)this).Resolve(ClassNames.SystemDecimal.ClassNames); } if (e.Code == ILCode.Ldtoken) { if (e.Operand is TypeReference) { ((IResolver)this).Resolve(ClassNames.SystemRuntimeTypeHandle.ClassName); } else if (e.Operand is FieldReference) { ((IResolver)this).Resolve(ClassNames.SystemRuntimeFieldHandle.ClassName); } else if (e.Operand is MethodReference) { ((IResolver)this).Resolve(ClassNames.SystemRuntimeMethodHandle.ClassName); } } if (e.Operand is ILVariable) { ((IResolver)this).Resolve(((ILVariable)e.Operand).Type, genericArgs); } if (e.Operand is TypeReference) { ((IResolver)this).Resolve((TypeReference)e.Operand, genericArgs); } if (e.Operand is MethodReference) { ((IResolver)this).Resolve((MethodReference)e.Operand, genericArgs); } if (e.Operand is FieldReference) { InterField fld = ((IResolver)this).Resolve((FieldReference)e.Operand, genericArgs); bool needAccessor = false; if ((fld.IsPrivate) && (fld.DeclaringType != method.DeclaringType)) { needAccessor = true; } else if ((fld.IsProtected) && (fld.DeclaringType != method.DeclaringType) && (!method.DeclaringType.IsSuper(fld.DeclaringType))) { needAccessor = true; } if (needAccessor) { switch (e.Code) { case ILCode.Ldflda: case ILCode.Ldsflda: if (fld.FieldType.IsValueType) { fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld)); } break; case ILCode.Ldfld: case ILCode.Ldsfld: fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Getter, fld)); break; case ILCode.Stfld: case ILCode.Stsfld: fld.DeclaringType.AddFieldAccessor(new FieldAccessor(FieldAccessorType.Setter, fld)); break; } } } InterType expected = null; InterType inferred = null; if (e.ExpectedType != null) { expected = ((IResolver)this).Resolve(e.ExpectedType, genericArgs); } if (e.InferredType != null) { inferred = ((IResolver)this).Resolve(e.InferredType, genericArgs); } if ((expected != null) && (expected.IsInterface) && (inferred != null) && (inferred.IsArray)) { ((IResolver)this).Resolve(ClassNames.ArraysInterfaceAdapterTypeName, new List <InterGenericArgument>() { new InterGenericArgument(GenericArgumentOwnerType.Type, 0, inferred.ElementType) }); } } else if (node is ILWhileLoop) { ILWhileLoop loop = node as ILWhileLoop; ProcessMethodDecencies(method, loop.Condition, genericArgs); ProcessMethodDecencies(method, loop.BodyBlock, genericArgs); } else if (node is ILCondition) { ILCondition cond = node as ILCondition; ProcessMethodDecencies(method, cond.Condition, genericArgs); ProcessMethodDecencies(method, cond.TrueBlock, genericArgs); ProcessMethodDecencies(method, cond.FalseBlock, genericArgs); } else if (node is ILSwitch) { ILSwitch sw = node as ILSwitch; ProcessMethodDecencies(method, sw.Condition, genericArgs); foreach (var c in sw.CaseBlocks) { ProcessMethodDecencies(method, c, genericArgs); } } else if (node is ILFixedStatement) { ILFixedStatement fs = node as ILFixedStatement; foreach (var n in fs.Initializers) { ProcessMethodDecencies(method, n, genericArgs); } ProcessMethodDecencies(method, fs.BodyBlock, genericArgs); } }
List<ILNode> FindConditions(HashSet<ControlFlowNode> nodes, ControlFlowNode entryNode) { List<ILNode> result = new List<ILNode>(); Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>(); agenda.Enqueue(entryNode); while(agenda.Count > 0) { ControlFlowNode node = agenda.Dequeue(); // Find a block that represents a simple condition if (nodes.Contains(node)) { ILMoveableBlock block = node.UserData as ILMoveableBlock; if (block != null && block.Body.Count == 3) { ILLabel label = block.Body[0] as ILLabel; ILExpression condBranch = block.Body[1] as ILExpression; ILExpression statBranch = block.Body[2] as ILExpression; // Switch if (label != null && condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0 && statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0) { ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch }; // Replace the two branches with a conditional structure - this preserves the node label block.Body.Remove(condBranch); block.Body.Remove(statBranch); block.Body.Add(ilSwitch); ControlFlowNode statTarget = null; labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget); // Pull in the conditional code HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (statTarget != null) frontiers.UnionWith(statTarget.DominanceFrontier); foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier); } foreach(ILLabel condLabel in (ILLabel[])condBranch.Operand) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); ILBlock caseBlock = new ILBlock() { EntryPoint = condLabel }; if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget); nodes.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); } ilSwitch.CaseBlocks.Add(caseBlock); } // The labels will not be used - kill them condBranch.Operand = null; result.Add(block); nodes.Remove(node); } // Two-way branch if (label != null && condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0 && statBranch != null && statBranch.Operand is ILLabel && statBranch.Arguments.Count == 0) { ControlFlowNode statTarget = null; labelToCfNode.TryGetValue((ILLabel)statBranch.Operand, out statTarget); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue((ILLabel)condBranch.Operand, out condTarget); ILCondition condition = new ILCondition() { Condition = condBranch, TrueBlock = new ILBlock() { EntryPoint = (ILLabel)condBranch.Operand }, FalseBlock = new ILBlock() { EntryPoint = (ILLabel)statBranch.Operand } }; // Replace the two branches with a conditional structure - this preserves the node label block.Body.Remove(condBranch); block.Body.Remove(statBranch); block.Body.Add(condition); // Pull in the conditional code HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (statTarget != null) frontiers.UnionWith(statTarget.DominanceFrontier); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, condTarget); nodes.ExceptWith(content); condition.TrueBlock.Body.AddRange(FindConditions(content, condTarget)); } if (statTarget != null && !frontiers.Contains(statTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(nodes, statTarget); nodes.ExceptWith(content); condition.FalseBlock.Body.AddRange(FindConditions(content, statTarget)); } // The label will not be used - kill it condBranch.Operand = null; result.Add(block); nodes.Remove(node); } } // Add the node now so that we have good ordering if (nodes.Contains(node)) { result.Add((ILNode)node.UserData); nodes.Remove(node); } } // Using the dominator tree should ensure we find the the widest loop first foreach(var child in node.DominatorTreeChildren) { agenda.Enqueue(child); } } // Add whatever is left foreach(var node in nodes) { result.Add((ILNode)node.UserData); } return result; }
protected bool TranslateCallSiteConstruction(ILCondition condition, out JSStatement result) { var cond = condition.Condition; if ( (cond.Code == ILCode.LogicNot) && (cond.Arguments.Count > 0) && (cond.Arguments[0].Code == ILCode.GetCallSite) && (condition.TrueBlock != null) && (condition.TrueBlock.Body.Count == 1) && (condition.TrueBlock.Body[0] is ILExpression) ) { var callSiteExpression = (ILExpression)condition.TrueBlock.Body[0]; var callSiteType = callSiteExpression.Arguments[0].ExpectedType; var binderExpression = callSiteExpression.Arguments[0].Arguments[0]; var binderMethod = (MethodReference)binderExpression.Operand; var arguments = Translate(binderExpression.Arguments); var targetType = ((IGenericInstance)callSiteType).GenericArguments[0]; DynamicCallSites.InitializeCallSite( (FieldReference)cond.Arguments[0].Operand, binderMethod.Name, targetType, arguments ); result = new JSNullStatement(); return true; } result = null; return false; }
List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode) { List<ILNode> result = new List<ILNode>(); // Do not modify entry data scope = new HashSet<ControlFlowNode>(scope); HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(); agenda.Add(entryNode); while(agenda.Any()) { ControlFlowNode node = agenda.First(); // Attempt for a good order while(agenda.Contains(node.ImmediateDominator)) { node = node.ImmediateDominator; } agenda.Remove(node); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = node.UserData as ILBasicBlock; if (block != null && block.Body.Count == 1) { ILExpression condBranch = block.Body[0] as ILExpression; // Switch if (condBranch != null && condBranch.Operand is ILLabel[] && condBranch.Arguments.Count > 0) { ILLabel[] caseLabels = (ILLabel[])condBranch.Operand; // The labels will not be used - kill them condBranch.Operand = null; ILSwitch ilSwitch = new ILSwitch() { Condition = condBranch, DefaultGoto = block.FallthoughGoto }; result.Add(new ILBasicBlock() { EntryLabel = block.EntryLabel, // Keep the entry label Body = { ilSwitch } }); // Remove the item so that it is not picked up as content if (!scope.Remove(node)) throw new Exception("Item is not in set"); // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue((ILLabel)block.FallthoughGoto.Operand, out fallTarget); HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (fallTarget != null) frontiers.UnionWith(fallTarget.DominanceFrontier); foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier); } foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); ILBlock caseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, condLabel) }; if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); } ilSwitch.CaseBlocks.Add(caseBlock); } } // Two-way branch ILExpression branchExpr = null; ILLabel trueLabel = null; ILLabel falseLabel = null; if(IsConditionalBranch(block, ref branchExpr, ref trueLabel, ref falseLabel)) { // The branch label will not be used - kill it branchExpr.Operand = null; // Convert the basic block to ILCondition ILCondition ilCond = new ILCondition() { Condition = branchExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } }; result.Add(new ILBasicBlock() { EntryLabel = block.EntryLabel, // Keep the entry label Body = { ilCond } }); // Remove the item immediately so that it is not picked up as content if (!scope.Remove(node)) throw new Exception("Item is not in set"); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (trueTarget != null) frontiers.UnionWith(trueTarget.DominanceFrontier); if (falseTarget != null) frontiers.UnionWith(falseTarget.DominanceFrontier); if (trueTarget != null && !frontiers.Contains(trueTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget)); } if (falseTarget != null && !frontiers.Contains(falseTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); } if (scope.Count == 0) { // We have removed the whole scope - eliminte one of the condition bodies int trueSize = ilCond.TrueBlock.GetSelfAndChildrenRecursive<ILNode>().Count(); int falseSize = ilCond.FalseBlock.GetSelfAndChildrenRecursive<ILNode>().Count(); // The block are protected Debug.Assert(ilCond.TrueBlock.EntryGoto != null); Debug.Assert(ilCond.FalseBlock.EntryGoto != null); if (falseSize > trueSize) { // Move the false body out result.AddRange(ilCond.FalseBlock.Body); ilCond.FalseBlock.Body.Clear(); } else { // Move the true body out result.AddRange(ilCond.TrueBlock.Body); ilCond.TrueBlock.Body.Clear(); } } // If true body is empty, swap bodies. // Might happend because there was not any to start with or we moved it out. if (ilCond.TrueBlock.Body.Count == 0 && ilCond.FalseBlock.Body.Count > 0) { ILBlock tmp = ilCond.TrueBlock; ilCond.TrueBlock = ilCond.FalseBlock; ilCond.FalseBlock = tmp; ilCond.Condition = new ILExpression(ILCode.LogicNot, null, ilCond.Condition); } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // Using the dominator tree should ensure we find the the widest loop first foreach(var child in node.DominatorTreeChildren) { agenda.Add(child); } } // Add whatever is left foreach(var node in scope) { result.Add((ILNode)node.UserData); } return result; }
List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode) { List <ILNode> result = new List <ILNode>(); // Do not modify entry data scope = new HashSet <ControlFlowNode>(scope); Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>(); agenda.Push(entryNode); while (agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { // Switch ILLabel[] caseLabels; ILExpression switchArg; ILLabel fallLabel; if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) { // Replace the switch code with ILSwitch ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg }; block.Body.RemoveTail(ILCode.Switch, ILCode.Br); block.Body.Add(ilSwitch); block.Body.Add(new ILExpression(ILCode.Br, fallLabel)); result.Add(block); // Remove the item so that it is not picked up as content scope.RemoveOrThrow(node); // Find the switch offset int addValue = 0; List <ILExpression> subArgs; if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) { ilSwitch.Condition = subArgs[0]; } // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>(); if (fallTarget != null) { frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget })); } foreach (ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) { frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget })); } } for (int i = 0; i < caseLabels.Length; i++) { ILLabel condLabel = caseLabels[i]; // Find or create new case block ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.CaseBlock() { Values = new List <int>(), EntryGoto = new ILExpression(ILCode.Br, condLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } caseBlock.Values.Add(i + addValue); } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); block.Body.RemoveTail(ILCode.Br); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, fallTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } } // Two-way branch ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; if (block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { // Swap bodies since that seems to be the usual C# order ILLabel temp = trueLabel; trueLabel = falseLabel; falseLabel = temp; condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } }; block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget)); } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach (var node in scope) { result.Add((ILNode)node.UserData); } return(result); }
private void CompileCondition(ILCondition node, ExpectType expectType) { ILExpression condition = node.Condition; while (condition != null) { if (condition.Code == ILCode.Call) { InterMethod callMethod = resolver.Resolve((MethodReference)condition.Operand, thisMethod.FullGenericArguments); if (callMethod.DeclaringType.Fullname == ClassNames.Intrinsics.ClassName) { if (callMethod.Name == ClassNames.Intrinsics.IsCILBoxing) { if (Program.BoxType == BoxingType.Cil) { CompileBlock(node.TrueBlock); } return; } if (callMethod.Name == ClassNames.Intrinsics.IsJavaBoxing) { if (Program.BoxType == BoxingType.Java) { CompileBlock(node.TrueBlock); } return; } } break; } condition = condition.Arguments.FirstOrDefault(); } string labelsSufix = rnd.Next().ToString(); string falseLabel = "false" + labelsSufix; string exitLabel = "exit" + labelsSufix; if (node.FalseBlock.Body.Count == 0) { falseLabel = exitLabel; } CompileCondition(new ILExpression(ILCode.LogicNot, null, node.Condition), falseLabel); //CompileExpression(node.Condition, ExpectType.Primitive); //Java.OpCodes branchInstr = Java.OpCodes.ifeq; //TranslateToBool(node.Condition.InferredType, ref branchInstr, node); //codeGenerator.Add(branchInstr, falseLabel, node); CompileBlock(node.TrueBlock, expectType); if (node.FalseBlock.Body.Count > 0) { codeGenerator.Add(Java.OpCodes._goto, exitLabel, node) .Label(falseLabel); CompileBlock(node.FalseBlock, expectType); } codeGenerator.Label(exitLabel); }
protected virtual ILCondition VisitCondition(ILCondition condition) { foreach (var child in condition.GetChildren()) Visit(child); return condition; }
bool TryMatchCondition(HashSet<ControlFlowNode> scope, IEnumerable<ControlFlowNode> scopeExcept, ControlFlowNode head, out ILCondition condition, out HashSet<ControlFlowNode> matchedNodes, out ILLabel entryLabel) { condition = null; matchedNodes = null; entryLabel = null; if (!scope.Contains(head) || scopeExcept.Contains(head)) return false; ILBasicBlock basicBlock = head.UserData as ILBasicBlock; if (basicBlock == null || basicBlock.Body.Count != 1) return false; ILExpression condBranch = basicBlock.Body[0] as ILExpression; if (condBranch != null && condBranch.Operand is ILLabel && condBranch.Arguments.Count > 0) { // We have found a two-way condition condition = new ILCondition() { Condition = condBranch, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, condBranch.Operand) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, basicBlock.FallthoughGoto.Operand) } }; // We are done with the node so "remove" it from scope scopeExcept = scopeExcept.Union(new[] {head}); matchedNodes = new HashSet<ControlFlowNode>() { head }; entryLabel = basicBlock.EntryLabel; // Optimize short-circut expressions while(true) { // Consider condition.TrueBlock { ILLabel nextLabel = (ILLabel)condition.TrueBlock.EntryGoto.Operand; ControlFlowNode nextTarget; labelToCfNode.TryGetValue(nextLabel, out nextTarget); ILCondition nextCond; HashSet<ControlFlowNode> nextMatchedNodes; ILLabel nextEnteryLabel; if (nextTarget != null && TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) && labelRefCount[nextEnteryLabel] == 1) { if (condition.FalseBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) { condition.Condition = new ILExpression(ILCode.LogicAnd, null, condition.Condition, nextCond.Condition); condition.TrueBlock = nextCond.TrueBlock; condition.FalseBlock = nextCond.FalseBlock; scopeExcept = scopeExcept.Union(nextMatchedNodes); matchedNodes.UnionWith(nextMatchedNodes); continue; } if (condition.FalseBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) { condition.Condition = new ILExpression(ILCode.LogicOr, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition); condition.TrueBlock = nextCond.TrueBlock; condition.FalseBlock = nextCond.FalseBlock; scopeExcept = scopeExcept.Union(nextMatchedNodes); matchedNodes.UnionWith(nextMatchedNodes); continue; } } } // Consider condition.FalseBlock { ILLabel nextLabel = (ILLabel)condition.FalseBlock.EntryGoto.Operand; ControlFlowNode nextTarget; labelToCfNode.TryGetValue(nextLabel, out nextTarget); ILCondition nextCond; HashSet<ControlFlowNode> nextMatchedNodes; ILLabel nextEnteryLabel; if (nextTarget != null && TryMatchCondition(scope, scopeExcept, nextTarget, out nextCond, out nextMatchedNodes, out nextEnteryLabel) && labelRefCount[nextEnteryLabel] == 1) { if (condition.TrueBlock.EntryGoto.Operand == nextCond.FalseBlock.EntryGoto.Operand) { condition.Condition = new ILExpression(ILCode.LogicAnd, null, new ILExpression(ILCode.LogicNot, null, condition.Condition), nextCond.Condition); condition.TrueBlock = nextCond.TrueBlock; condition.FalseBlock = nextCond.FalseBlock; scopeExcept = scopeExcept.Union(nextMatchedNodes); matchedNodes.UnionWith(nextMatchedNodes); continue; } if (condition.TrueBlock.EntryGoto.Operand == nextCond.TrueBlock.EntryGoto.Operand) { condition.Condition = new ILExpression(ILCode.LogicOr, null, condition.Condition, nextCond.Condition); condition.TrueBlock = nextCond.TrueBlock; condition.FalseBlock = nextCond.FalseBlock; scopeExcept = scopeExcept.Union(nextMatchedNodes); matchedNodes.UnionWith(nextMatchedNodes); continue; } } } break; } return true; } return false; }
List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode) { List<ILNode> result = new List<ILNode>(); // Do not modify entry data scope = new HashSet<ControlFlowNode>(scope); Stack<ControlFlowNode> agenda = new Stack<ControlFlowNode>(); agenda.Push(entryNode); while (agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { IList<ILExpression> conditions; ILLabel fallLabel; // Switch FakeSwitch fswitch; if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel)) { ILSwitch ilSwitch = new ILSwitch() { Condition = fswitch.SwitchExpression }; block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done! result.Add(block); // except add it to the result, DOLT scope.RemoveOrThrow(node);// Remove the item so that it is not picked up as content // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (fallTarget != null) frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget })); foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value)) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget })); } for (int i = 0; i < fswitch.CaseExpressions.Count; i++) { ILLabel condLabel = fswitch.CaseExpressions[i].Value; // Find or create new case block ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.ILCase() { Values = new List<ILExpression>(), EntryGoto = new ILExpression(GMCode.B, condLabel) }; ilSwitch.Cases.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, condTarget)) caseBlock.Body.Add(con); // caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++), new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } caseBlock.Values.Add(fswitch.CaseExpressions[i].Key); } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.ILCase() { EntryGoto = new ILExpression(GMCode.B, fallLabel) }; ilSwitch.Cases.Add(caseBlock); block.Body.RemoveTail(GMCode.B); scope.ExceptWith(content); foreach (var con in FindConditions(content, fallTarget)) caseBlock.Body.Add(con); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { ILLabel.Generate("SwitchBreak" ,(int)nextLabelIndex++), new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } } // Debug.Assert((block.Body.First() as ILLabel).Name != "L1938"); // Two-way branch ILLabel trueLabel; ILLabel falseLabel; IList<ILExpression> condExprs; if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) // be sure to invert this condition && condExprs.Count > 0) // its resolved { ILExpression condExpr = condExprs[0]; IList<ILNode> body = block.Body; // this is a simple condition, skip anything short curiket for now // Match a condition patern // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(), TrueBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, falseLabel) } }; block.Body.RemoveTail(GMCode.Bt, GMCode.B); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, trueTarget)) ilCond.TrueBlock.Body.Add(con); } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, falseTarget)) ilCond.FalseBlock.Body.Add(con); } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach (var node in scope) { result.Add((ILNode)node.UserData); } return result; }
public JSStatement TranslateNode(ILCondition condition) { JSStatement result = null; if (TranslateCallSiteConstruction(condition, out result)) return result; JSStatement falseBlock = null; if ((condition.FalseBlock != null) && (condition.FalseBlock.Body.Count > 0)) falseBlock = TranslateNode(condition.FalseBlock); result = new JSIfStatement( TranslateNode(condition.Condition), TranslateNode(condition.TrueBlock), falseBlock ); return result; }
bool HandleStringFixing(ILVariable pinnedVar, List <ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer) { // fixed (stloc(pinnedVar, ldloc(text))) { // var1 = var2 = conv.i(ldloc(pinnedVar)) // if (logicnot(logicnot(var1))) { // var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData)) // } // stloc(ptrVar, var2) // ... if (pos >= body.Count) { return(false); } ILVariable var1, var2; ILExpression varAssignment, ptrInitialization; if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization))) { return(false); } if (!(var1.IsGenerated && var2.IsGenerated)) { return(false); } if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U) { ptrInitialization = ptrInitialization.Arguments[0]; } if (!ptrInitialization.MatchLdloc(pinnedVar)) { return(false); } ILCondition ifStmt = body[pos + 1] as ILCondition; if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0))) { return(false); } if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1)) { return(false); } ILVariable assignedVar; ILExpression assignedExpr; if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add)) { return(false); } MethodReference calledMethod; if (!(assignedExpr.Arguments[0].MatchLdloc(var1))) { return(false); } if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod))) { return(false); } if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")) { return(false); } ILVariable pointerVar; if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) { pos += 3; fixedStmtInitializer.Operand = pointerVar; return(true); } return(false); }
public Dictionary <int, EventRegistration[]> DecompileEventMappings(string fullTypeName) { var result = new Dictionary <int, EventRegistration[]>(); TypeDefinition type = this.assembly.MainModule.GetType(fullTypeName); if (type == null) { return(result); } MethodDefinition def = null; foreach (var method in type.Methods) { if (method.Name == "System.Windows.Markup.IComponentConnector.Connect") { def = method; break; } } if (def == null) { return(result); } // decompile method and optimize the switch ILBlock ilMethod = new ILBlock(); ILAstBuilder astBuilder = new ILAstBuilder(); ilMethod.Body = astBuilder.Build(def, true); ILAstOptimizer optimizer = new ILAstOptimizer(); var context = new DecompilerContext(type.Module) { CurrentMethod = def, CurrentType = type }; optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.RemoveRedundantCode3); ILSwitch ilSwitch = ilMethod.Body.OfType <ILSwitch>().FirstOrDefault(); ILCondition condition = ilMethod.Body.OfType <ILCondition>().FirstOrDefault(); if (ilSwitch != null) { foreach (var caseBlock in ilSwitch.CaseBlocks) { if (caseBlock.Values == null) { continue; } var events = FindEvents(caseBlock); foreach (int id in caseBlock.Values) { result.Add(id, events); } } } else if (condition != null) { result.Add(1, FindEvents(condition.FalseBlock)); } return(result); }
List <ILNode> FindConditions(HashSet <ControlFlowNode> scope, ControlFlowNode entryNode) { List <ILNode> result = new List <ILNode>(); // Do not modify entry data scope = new HashSet <ControlFlowNode>(scope); Stack <ControlFlowNode> agenda = new Stack <ControlFlowNode>(); agenda.Push(entryNode); while (agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { IList <ILExpression> conditions; ILLabel fallLabel; // Switch FakeSwitch fswitch; if (block.MatchLastAndBr(GMCode.Switch, out fswitch, out conditions, out fallLabel)) { ILSwitch ilSwitch = new ILSwitch() { Condition = fswitch.SwitchExpression }; block.Body[block.Body.Count - 2] = ilSwitch; // replace it, nothing else needs to be done! result.Add(block); // except add it to the result, DOLT scope.RemoveOrThrow(node); // Remove the item so that it is not picked up as content // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet <ControlFlowNode> frontiers = new HashSet <ControlFlowNode>(); if (fallTarget != null) { frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new[] { fallTarget })); } foreach (ILLabel condLabel in fswitch.CaseExpressions.Select(x => x.Value)) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) { frontiers.UnionWith(condTarget.DominanceFrontier.Except(new[] { condTarget })); } } for (int i = 0; i < fswitch.CaseExpressions.Count; i++) { ILLabel condLabel = fswitch.CaseExpressions[i].Value; // Find or create new case block ILSwitch.ILCase caseBlock = ilSwitch.Cases.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.ILCase() { Values = new List <ILExpression>(), EntryGoto = new ILExpression(GMCode.B, condLabel) }; ilSwitch.Cases.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, condTarget)) { caseBlock.Body.Add(con); } // caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { ILLabel.Generate("SwitchBreak", (int)nextLabelIndex++), new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } caseBlock.Values.Add(fswitch.CaseExpressions[i].Key); } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.ILCase() { EntryGoto = new ILExpression(GMCode.B, fallLabel) }; ilSwitch.Cases.Add(caseBlock); block.Body.RemoveTail(GMCode.B); scope.ExceptWith(content); foreach (var con in FindConditions(content, fallTarget)) { caseBlock.Body.Add(con); } // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { ILLabel.Generate("SwitchBreak", (int)nextLabelIndex++), new ILExpression(GMCode.LoopOrSwitchBreak, null) } }); } } } // Debug.Assert((block.Body.First() as ILLabel).Name != "L1938"); // Two-way branch ILLabel trueLabel; ILLabel falseLabel; IList <ILExpression> condExprs; if (block.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExprs, out falseLabel) && // be sure to invert this condition condExprs.Count > 0) // its resolved { ILExpression condExpr = condExprs[0]; IList <ILNode> body = block.Body; // this is a simple condition, skip anything short curiket for now // Match a condition patern // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, //code == GMCode.Bf ? condExpr : condExpr.NegateCondition(), TrueBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(GMCode.B, falseLabel) } }; block.Body.RemoveTail(GMCode.Bt, GMCode.B); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, trueTarget)) { ilCond.TrueBlock.Body.Add(con); } } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet <ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); foreach (var con in FindConditions(content, falseTarget)) { ilCond.FalseBlock.Body.Add(con); } } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach (var node in scope) { result.Add((ILNode)node.UserData); } return(result); }
List<ILNode> FindConditions(HashSet<ControlFlowNode> scope, ControlFlowNode entryNode) { List<ILNode> result = new List<ILNode>(); // Do not modify entry data scope = new HashSet<ControlFlowNode>(scope); Stack<ControlFlowNode> agenda = new Stack<ControlFlowNode>(); agenda.Push(entryNode); while(agenda.Count > 0) { ControlFlowNode node = agenda.Pop(); // Find a block that represents a simple condition if (scope.Contains(node)) { ILBasicBlock block = (ILBasicBlock)node.UserData; { // Switch ILLabel[] caseLabels; ILExpression switchArg; ILLabel fallLabel; if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) { // Replace the switch code with ILSwitch ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg }; block.Body.RemoveTail(ILCode.Switch, ILCode.Br); block.Body.Add(ilSwitch); block.Body.Add(new ILExpression(ILCode.Br, fallLabel)); result.Add(block); // Remove the item so that it is not picked up as content scope.RemoveOrThrow(node); // Find the switch offset int addValue = 0; List<ILExpression> subArgs; if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) { ilSwitch.Condition = subArgs[0]; } // Pull in code of cases ControlFlowNode fallTarget = null; labelToCfNode.TryGetValue(fallLabel, out fallTarget); HashSet<ControlFlowNode> frontiers = new HashSet<ControlFlowNode>(); if (fallTarget != null) frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget })); foreach(ILLabel condLabel in caseLabels) { ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null) frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget })); } for (int i = 0; i < caseLabels.Length; i++) { ILLabel condLabel = caseLabels[i]; // Find or create new case block ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); if (caseBlock == null) { caseBlock = new ILSwitch.CaseBlock() { Values = new List<int>(), EntryGoto = new ILExpression(ILCode.Br, condLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); ControlFlowNode condTarget = null; labelToCfNode.TryGetValue(condLabel, out condTarget); if (condTarget != null && !frontiers.Contains(condTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, condTarget); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, condTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } caseBlock.Values.Add(i + addValue); } // Heuristis to determine if we want to use fallthough as default case if (fallTarget != null && !frontiers.Contains(fallTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, fallTarget); if (content.Any()) { var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) }; ilSwitch.CaseBlocks.Add(caseBlock); block.Body.RemoveTail(ILCode.Br); scope.ExceptWith(content); caseBlock.Body.AddRange(FindConditions(content, fallTarget)); // Add explicit break which should not be used by default, but the goto removal might decide to use it caseBlock.Body.Add(new ILBasicBlock() { Body = { new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, new ILExpression(ILCode.LoopOrSwitchBreak, null) } }); } } } // Two-way branch ILExpression condExpr; ILLabel trueLabel; ILLabel falseLabel; if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { // Swap bodies since that seems to be the usual C# order ILLabel temp = trueLabel; trueLabel = falseLabel; falseLabel = temp; condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); // Convert the brtrue to ILCondition ILCondition ilCond = new ILCondition() { Condition = condExpr, TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } }; block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); block.Body.Add(ilCond); result.Add(block); // Remove the item immediately so that it is not picked up as content scope.RemoveOrThrow(node); ControlFlowNode trueTarget = null; labelToCfNode.TryGetValue(trueLabel, out trueTarget); ControlFlowNode falseTarget = null; labelToCfNode.TryGetValue(falseLabel, out falseTarget); // Pull in the conditional code if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, trueTarget); scope.ExceptWith(content); ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget)); } if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { HashSet<ControlFlowNode> content = FindDominatedNodes(scope, falseTarget); scope.ExceptWith(content); ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); } } } // Add the node now so that we have good ordering if (scope.Contains(node)) { result.Add((ILNode)node.UserData); scope.Remove(node); } } // depth-first traversal of dominator tree for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { agenda.Push(node.DominatorTreeChildren[i]); } } // Add whatever is left foreach(var node in scope) { result.Add((ILNode)node.UserData); } return result; }
void CachedDelegateInitializationWithLocal(ILBlock block, ref int i) { // if (logicnot(ldloc(v))) { // stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method))) // } else { // } // ...(..., ldloc(v), ...) ILCondition c = block.Body[i] as ILCondition; if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) { return; } if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) { return; } if (!c.Condition.Match(ILCode.LogicNot)) { return; } ILExpression condition = c.Condition.Arguments.Single() as ILExpression; if (condition == null || condition.Code != ILCode.Ldloc) { return; } ILVariable v = (ILVariable)condition.Operand; ILExpression stloc = c.TrueBlock.Body[0] as ILExpression; if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v)) { return; } ILExpression newObj = stloc.Arguments[0]; if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) { return; } if (newObj.Arguments[0].Code != ILCode.Ldloc) { return; } if (newObj.Arguments[1].Code != ILCode.Ldftn) { return; } MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) { return; } ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); int ldlocOperandCount = followingNode .EnumerateSelfAndChildrenRecursive() .OfType <ILExpression>() .Count( e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v); if (followingNode != null && ldlocOperandCount == 1) { ILInlining inlining = new ILInlining(method); if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0)) { return; } // Find the store instruction that initializes the local to null: foreach (ILBlock storeBlock in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>()) { for (int j = 0; j < storeBlock.Body.Count; j++) { ILVariable storedVar; ILExpression storedExpr; if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull)) { // Remove the instruction storeBlock.Body.RemoveAt(j); if (storeBlock == block && j < i) { i--; } break; } } } block.Body[i] = stloc; // remove the 'if (v==null)' inlining = new ILInlining(method); inlining.InlineIfPossible(block.Body, ref i); } }