protected virtual void OnPhiVariableAssigned(int instructionOffset, ClassHierarchyNode variableNode) { V_0 = this.offsetToExpression.get_Item(instructionOffset).get_ExpressionType(); if (V_0 != null) { V_1 = this.GetTypeNode(V_0); V_1.AddSupertype(variableNode); dummyVar1 = this.resultingGraph.Add(V_1); return; } V_2 = this.GetVariables(instructionOffset).GetEnumerator(); try { while (V_2.MoveNext()) { V_3 = V_2.get_Current(); V_1 = this.GetVariableNode(V_3); V_1.AddSupertype(variableNode); dummyVar0 = this.resultingGraph.Add(V_1); } } finally { if (V_2 != null) { V_2.Dispose(); } } return; }
protected void MergeNodes(ICollection <ClassHierarchyNode> nodeCollection) { if (nodeCollection.get_Count() <= 1) { return; } V_0 = new ClassHierarchyNode(nodeCollection); V_1 = V_0.get_ContainedNodes().GetEnumerator(); try { while (V_1.MoveNext()) { V_2 = V_1.get_Current(); dummyVar0 = this.inferenceGraph.Remove(V_2); } } finally { if (V_1 != null) { V_1.Dispose(); } } this.inferenceGraph.Add(V_0); return; }
/// <summary> /// Handles the assignment of phi variables. /// </summary> /// <param name="instructionOffset">The offset of the instruction, that put the value on the stack.</param> /// <param name="variableNode">The graph node corresponding to the phi variable.</param> /// <param name="nodes">The graph.</param> protected override void OnPhiVariableAssigned(int instructionOffset, ClassHierarchyNode variableNode) { /// This key should allways be present. Expression instructionExpression = offsetToExpression[instructionOffset]; /// Determine the type of the assigned value. TypeReference assignedType = instructionExpression.ExpressionType; if (instructionExpression is LiteralExpression) { int literal = (int)((instructionExpression as LiteralExpression).Value); if (literal == 0 || literal == 1) { assignedType = typeSystem.Boolean; } else if (literal <= byte.MaxValue && literal >= byte.MinValue) { assignedType = typeSystem.Byte; } else if (literal < char.MaxValue && literal >= char.MinValue) { /// Both char and short can be used here. assignedType = typeSystem.Char; } } /// Add the edge in the graph. ClassHierarchyNode supertypeNode = GetTypeNode(assignedType); supertypeNode.AddSupertype(variableNode); resultingGraph.Add(supertypeNode); }
/// <summary> /// Handles all nodes that have single child constraint as described in <see cref="Chapter 6 Integer inference"/> /// in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> private void MergeWithSingleChild() { bool merged = false; do { ICollection <ClassHierarchyNode> toMerge = null; foreach (ClassHierarchyNode node in inferenceGraph) { if (!node.IsHardNode) { if (node.CanAssignTo.Count == 1 && node.SubTypes.Count == 0) { ClassHierarchyNode x = null; //x = node.CanAssignTo.First(); w/o Linq foreach (ClassHierarchyNode p in node.CanAssignTo) { x = p; break; } toMerge = new ClassHierarchyNode[] { node, x }; merged = true; break; } } } if (merged) { MergeNodes(toMerge); } } while (merged); }
/// <summary> /// Handles the assignment of phi variables. /// </summary> /// <param name="instructionOffset">The instruction that pushes the value on the stack.</param> /// <param name="variableNode">The graph node corresponding to the variable being assigned.</param> protected virtual void OnPhiVariableAssigned(int instructionOffset, ClassHierarchyNode variableNode) { Expression instructionExpression = offsetToExpression[instructionOffset]; // this key should allways be present //TypeReference assignedType = ExpressionTypeInferer.GetExpressionType(instructionExpression, context.Method.Module.TypeSystem); TypeReference assignedType = instructionExpression.ExpressionType; ClassHierarchyNode supertypeNode; if (assignedType == null) { ///Then an expression, containing one or more phi variables is being assigned to another phi variable IEnumerable <VariableReference> usedPhiVariables = GetVariables(instructionOffset); //VariableReference assigningVariable = (instructionExpression as VariableReferenceExpression).Variable; foreach (VariableReference assigningVariable in usedPhiVariables) { supertypeNode = GetVariableNode(assigningVariable); supertypeNode.AddSupertype(variableNode); resultingGraph.Add(supertypeNode); } return; //supertypeNode = GetVariableNode(assigningVariable); } supertypeNode = GetTypeNode(assignedType); supertypeNode.AddSupertype(variableNode); resultingGraph.Add(supertypeNode); }
private void AddEdge(ClassHierarchyNode biggerTypeNode, ClassHierarchyNode smallerTypeNode) { smallerTypeNode.AddSupertype(biggerTypeNode); dummyVar0 = this.resultingGraph.Add(smallerTypeNode); dummyVar1 = this.resultingGraph.Add(biggerTypeNode); return; }
protected override void OnPhiVariableAssigned(int instructionOffset, ClassHierarchyNode variableNode) { V_0 = this.offsetToExpression.get_Item(instructionOffset); V_1 = V_0.get_ExpressionType(); if (V_0 as LiteralExpression != null) { V_3 = (Int32)(V_0 as LiteralExpression).get_Value(); if (V_3 == 0 || V_3 == 1) { V_1 = this.typeSystem.get_Boolean(); } else { if (V_3 > 0xff || V_3 < 0) { if (V_3 < 0xffff && V_3 >= 0) { V_1 = this.typeSystem.get_Char(); } } else { V_1 = this.typeSystem.get_Byte(); } } } V_2 = this.GetTypeNode(V_1); V_2.AddSupertype(variableNode); dummyVar0 = this.resultingGraph.Add(V_2); return; }
/// <summary> /// Adds an edge from <paramref name="smallerType"/> to <paramref name="biggerType"/>. /// </summary> /// <param name="biggerTypeNode">The type the edge points to.</param> /// <param name="smallerTypeNode">The type the edge comes from.</param> private void AddEdge(ClassHierarchyNode biggerTypeNode, ClassHierarchyNode smallerTypeNode) { // smallerTypeNode can assign to BiggerTypeNode smallerTypeNode.AddSupertype(biggerTypeNode); resultingGraph.Add(smallerTypeNode); resultingGraph.Add(biggerTypeNode); }
/// <summary> /// Adds the node, representing System.Object to the graph. /// </summary> private void AddObjectClassNodeIfMIssing() { TypeReference tr = typeSystem.Object; ClassHierarchyNode objectNode = GetTypeNode(tr); resultingGraph.Add(objectNode); }
/// <summary> /// Realises the logic for merging with single parent. /// </summary> /// <param name="chooseParent">Predicate that determines if the parent node is legal to merge.</param> /// <returns>Returns true if there was a merge.</returns> private bool MergeSingleParent(Func <ClassHierarchyNode, bool> chooseParentPred) { bool result = false; ClassHierarchyNode[] toMerge = null; foreach (ClassHierarchyNode childNode in inferenceGraph) { if (childNode.IsHardNode) { continue; } if (childNode.SubTypes.Count == 1) { ClassHierarchyNode parentNode = childNode.SubTypes.First(); if (chooseParentPred(parentNode)) { result = true; toMerge = new ClassHierarchyNode[] { childNode, parentNode }; break; } } } if (result) { MergeNodes(toMerge); } return(result); }
/// <summary> /// Handles the case of PhiVariable usages. /// </summary> /// <param name="instructionOffset">The offset of the instruction that pops the variable from the stack.</param> /// <param name="variableNode">The graph node for the variable.</param> protected virtual void OnPhiVariableUsed(int instructionOffset, ClassHierarchyNode variableNode) { ///The usages of the variable bring no value to this algorithm. In the paper they are included, because in Java Bytecode the local method variables ///don't have type, and can be potentionally used before being assigned. Phi variables, however, are always assigned first and used later. Thus, the ///information from the assignments should be enough for legal type inference. return; //Instruction instr = offsetToInstruction[instructionOffset]; //if (instr.OpCode.Code == Code.Dup || instr.OpCode.Code == Code.Pop) //{ // return; //} //ClassHierarchyNode typeNode = GetUseExpressionTypeNode(instr, record.Variable); ////this should not be happening when the array support is added //if (typeNode == null) //{ // //only phi variables were part of the expression // List<ClassHierarchyNode> phiVariableNodes = GetUsedPhiVariableNodes(instr.Offset); // for (int i = 0; i < phiVariableNodes.Count; i++) // { // for (int j = i + 1; j < phiVariableNodes.Count; j++) // { // //phi1 <-> phi2 // phiVariableNodes[i].AddSupertype(phiVariableNodes[j]); // phiVariableNodes[j].AddSupertype(phiVariableNodes[i]); // } // } // return; //} //variableNode.AddSupertype(typeNode); //nodes.Add(typeNode); }
/// <summary> /// Adds <paramref name="supertype"/> to the collection of nodes, this one can assign to. /// Also adds this node in <paramref name="supertype"/>'s collection of nodes, that can assign to it. /// </summary> /// <param name="supertype">The node, representing supertype of the current node.</param> public void AddSupertype(ClassHierarchyNode supertype) { if (!CanAssignTo.Contains(supertype)) { CanAssignTo.Add(supertype); supertype.SubTypes.Add(this); } }
public void AddSupertype(ClassHierarchyNode supertype) { if (!this.get_CanAssignTo().Contains(supertype)) { this.get_CanAssignTo().Add(supertype); supertype.get_SubTypes().Add(this); } return; }
/// <summary> /// Removes <paramref name="subType"/> from <paramref name="superType"/>'s collection of nodes, <paramref name="superType"/> can be assigned from. /// Also updates the collection of nodes <paramref name="subType"/> can assign to. /// </summary> /// <param name="superType"></param> /// <param name="subType"></param> private void RemoveSubtype(ClassHierarchyNode superType, ClassHierarchyNode subType) { if (!superType.SubTypes.Contains(subType)) { throw new ArgumentOutOfRangeException(string.Format("No such relation between {0} and {1}.", this, subType)); } superType.SubTypes.Remove(subType); subType.CanAssignTo.Remove(superType); }
private void MergeWithSingleChild() { V_0 = false; do { V_1 = null; V_2 = this.inferenceGraph.GetEnumerator(); try { while (V_2.MoveNext()) { V_3 = V_2.get_Current(); if (V_3.get_IsHardNode() || V_3.get_CanAssignTo().get_Count() != 1 || V_3.get_SubTypes().get_Count() != 0) { continue; } V_4 = null; V_5 = V_3.get_CanAssignTo().GetEnumerator(); try { if (V_5.MoveNext()) { V_4 = V_5.get_Current(); } } finally { if (V_5 != null) { V_5.Dispose(); } } stackVariable27 = new ClassHierarchyNode[2]; stackVariable27[0] = V_3; stackVariable27[1] = V_4; V_1 = (ICollection <ClassHierarchyNode>)stackVariable27; V_0 = true; goto Label0; } } finally { if (V_2 != null) { V_2.Dispose(); } } Label0: if (!V_0) { continue; } this.MergeNodes(V_1); }while (V_0); return; }
protected override ClassHierarchyNode GetTypeNode(TypeReference assignedType) { V_0 = assignedType.get_FullName(); if (!this.typeNameToNode.ContainsKey(V_0)) { V_1 = new ClassHierarchyNode(assignedType); this.typeNameToNode.Add(V_0, V_1); } return(this.typeNameToNode.get_Item(V_0)); }
private void RemoveBooleanAsASubtype(ClassHierarchyNode variableNode) { V_0 = this.GetTypeNode(this.typeSystem.get_Boolean()); if (variableNode.get_SubTypes().Contains(V_0)) { dummyVar0 = variableNode.get_SubTypes().Remove(V_0); dummyVar1 = V_0.get_CanAssignTo().Remove(variableNode); } return; }
private void RemoveSubtype(ClassHierarchyNode superType, ClassHierarchyNode subType) { if (!superType.get_SubTypes().Contains(subType)) { throw new ArgumentOutOfRangeException(String.Format("No such relation between {0} and {1}.", this, subType)); } dummyVar0 = superType.get_SubTypes().Remove(subType); dummyVar1 = subType.get_CanAssignTo().Remove(superType); return; }
/// <summary> /// Locates the node in the graph, holding <paramref name="assignedType"/>. If no such node exists, it's created. /// </summary> /// <param name="assignedType">The type we want to get the node for.</param> /// <returns>Returns the graph node.</returns> protected override ClassHierarchyNode GetTypeNode(TypeReference assignedType) { string typeName = assignedType.FullName; if (!typeNameToNode.ContainsKey(typeName)) { ClassHierarchyNode typeNode = new ClassHierarchyNode(assignedType); typeNameToNode.Add(typeName, typeNode); } return typeNameToNode[typeName]; }
private void RemoveBooleanAsASubtype(ClassHierarchyNode variableNode) { ClassHierarchyNode booleanNode = GetTypeNode(typeSystem.Boolean); if (variableNode.SubTypes.Contains(booleanNode)) { variableNode.SubTypes.Remove(booleanNode); booleanNode.CanAssignTo.Remove(variableNode); } }
protected virtual ClassHierarchyNode MergeWithVariableTypeIfNeeded(VariableReference variable, ClassHierarchyNode variableNode) { /// The node should be merget with its type in the normal inference. if (variable.VariableType != null) { ClassHierarchyNode variableTypeNode = GetTypeNode(variable.VariableType); variableNode = new ClassHierarchyNode(new ClassHierarchyNode[] { variableNode, variableTypeNode }); } return(variableNode); }
/// <summary> /// Handles the usage of phi variables. /// </summary> /// <param name="instructionOffset">The offset of the instruction, that pops the phi variable from the stack.</param> /// <param name="record">The VariableDefineUseRecord associated with the instruction.</param> /// <param name="variableNode">The node in the craph corresponding to the phi variable.</param> /// <param name="nodes"> The graph. </param> protected override void OnPhiVariableUsed(int instructionOffset, ClassHierarchyNode variableNode) { Instruction instr = offsetToInstruction[instructionOffset]; if (instr.OpCode.Code == Code.Dup || instr.OpCode.Code == Code.Pop) { ///No information regarding the type of the phi variable can be extracted from pop/dup instructions return; } ///Get the use type of the phi variable. ClassHierarchyNode typeNode = GetUseExpressionTypeNode(instr, variableNode.Variable); if (instr.OpCode.Code == Code.Switch) { variableNode.AddSupertype(typeNode); resultingGraph.Add(typeNode); return; } ///It is possible, that a phi variable is being used with another one. This case needs special care. if (typeNode.NodeType.FullName == "System.Int32" && OnlyPhiVariablesUsed(offsetToExpression[instr.Offset])) { ///Only phi variables were part of the expression. List <ClassHierarchyNode> phiVariableNodes = GetUsedPhiVariableNodes(instr.Offset); for (int i = 0; i < phiVariableNodes.Count; i++) { for (int j = i + 1; j < phiVariableNodes.Count; j++) { ///Add edge between the phi variables. phiVariableNodes[i].AddSupertype(phiVariableNodes[j]); phiVariableNodes[j].AddSupertype(phiVariableNodes[i]); } } if (IsArithmeticOperation(instr.OpCode.Code)) { for (int i = 0; i < phiVariableNodes.Count; i++) { notPossibleBooleanNodes.Add(phiVariableNodes[i]); ClassHierarchyNode integerTypeNode = GetTypeNode(typeSystem.Int32); if (!integerTypeNode.CanAssignTo.Contains(phiVariableNodes[i])) { integerTypeNode.CanAssignTo.Add(phiVariableNodes[i]); phiVariableNodes[i].SubTypes.Add(integerTypeNode); } } } return; } variableNode.AddSupertype(typeNode); resultingGraph.Add(typeNode); }
/// <summary> /// Locates the node in the graph, holding <paramref name="assignedType"/>. If no such node exists, it's created. /// </summary> /// <param name="assignedType">The type we want to get the node for.</param> /// <returns>Returns the graph node.</returns> protected override ClassHierarchyNode GetTypeNode(TypeReference assignedType) { string typeName = assignedType.FullName; if (!typeNameToNode.ContainsKey(typeName)) { ClassHierarchyNode typeNode = new ClassHierarchyNode(assignedType); typeNameToNode.Add(typeName, typeNode); } return(typeNameToNode[typeName]); }
/// <summary> /// Handles the usage of phi variables. /// </summary> /// <param name="instructionOffset">The offset of the instruction, that pops the phi variable from the stack.</param> /// <param name="record">The VariableDefineUseRecord associated with the instruction.</param> /// <param name="variableNode">The node in the craph corresponding to the phi variable.</param> /// <param name="nodes"> The graph. </param> protected override void OnPhiVariableUsed(int instructionOffset, ClassHierarchyNode variableNode) { Instruction instr = offsetToInstruction[instructionOffset]; if (instr.OpCode.Code == Code.Dup || instr.OpCode.Code == Code.Pop) { ///No information regarding the type of the phi variable can be extracted from pop/dup instructions return; } ///Get the use type of the phi variable. ClassHierarchyNode typeNode = GetUseExpressionTypeNode(instr, variableNode.Variable); if (instr.OpCode.Code == Code.Switch) { variableNode.AddSupertype(typeNode); resultingGraph.Add(typeNode); return; } ///It is possible, that a phi variable is being used with another one. This case needs special care. if (typeNode.NodeType.FullName == "System.Int32" && OnlyPhiVariablesUsed(offsetToExpression[instr.Offset])) { ///Only phi variables were part of the expression. List<ClassHierarchyNode> phiVariableNodes = GetUsedPhiVariableNodes(instr.Offset); for (int i = 0; i < phiVariableNodes.Count; i++) { for (int j = i + 1; j < phiVariableNodes.Count; j++) { ///Add edge between the phi variables. phiVariableNodes[i].AddSupertype(phiVariableNodes[j]); phiVariableNodes[j].AddSupertype(phiVariableNodes[i]); } } if (IsArithmeticOperation(instr.OpCode.Code)) { for (int i = 0; i < phiVariableNodes.Count; i++) { notPossibleBooleanNodes.Add(phiVariableNodes[i]); ClassHierarchyNode integerTypeNode = GetTypeNode(typeSystem.Int32); if (!integerTypeNode.CanAssignTo.Contains(phiVariableNodes[i])) { integerTypeNode.CanAssignTo.Add(phiVariableNodes[i]); phiVariableNodes[i].SubTypes.Add(integerTypeNode); } } } return; } variableNode.AddSupertype(typeNode); resultingGraph.Add(typeNode); }
/// <summary> /// Finds the ClassHierarchyNode corresponding to the <paramref name="variable"/>. If no such node exists, it's created. /// </summary> /// <param name="variable">The variable we search the node for.</param> /// <returns>Returns the corresponding node in the graph.</returns> protected ClassHierarchyNode GetVariableNode(VariableReference variable) { string variableName = variable.Name; if (!variableNameToNode.ContainsKey(variableName)) { ClassHierarchyNode variableNode = new ClassHierarchyNode(variable); variableNode = MergeWithVariableTypeIfNeeded(variable, variableNode); variableNameToNode.Add(variableName, variableNode); } return(variableNameToNode[variableName]); }
protected virtual ClassHierarchyNode MergeWithVariableTypeIfNeeded(VariableReference variable, ClassHierarchyNode variableNode) { if (variable.get_VariableType() != null) { V_0 = this.GetTypeNode(variable.get_VariableType()); stackVariable8 = new ClassHierarchyNode[2]; stackVariable8[0] = variableNode; stackVariable8[1] = V_0; variableNode = new ClassHierarchyNode(stackVariable8); } return(variableNode); }
/// <summary> /// The entry point of the class. /// </summary> /// <returns>Returns a collection of all nodes in the built graph.</returns> internal ICollection <ClassHierarchyNode> BuildHierarchy(HashSet <VariableReference> resolvedVariables) { StackUsageData stackData = methodContext.StackData; foreach (KeyValuePair <VariableDefinition, StackVariableDefineUseInfo> pair in stackData.VariableToDefineUseInfo) { VariableDefinition variableDef = pair.Key; if (resolvedVariables.Contains(variableDef)) { continue; } ///As this method is shared with IntegerTypesHierarchyByilder here is where the check if the phi variable should be used comes in place. ///For the purposes of TypeInferer all variables that don't have type yet should be considered. ///for the purposes of IntegerTypeInferer only variabless assigned Int32 as their type should be considered. if (!ShouldConsiderVariable(variableDef)) { continue; } ///Add a node for each variable and process all its appearances in the code. ClassHierarchyNode variableNode = GetVariableNode(variableDef); resultingGraph.Add(variableNode); foreach (int defineOffset in pair.Value.DefinedAt) { OnPhiVariableAssigned(defineOffset, variableNode); } foreach (int usageOffset in pair.Value.UsedAt) { OnPhiVariableUsed(usageOffset, variableNode); } } RemoveImpossibleEdges(); HashSet <ClassHierarchyNode> hardNodes = new HashSet <ClassHierarchyNode>(); foreach (ClassHierarchyNode node in resultingGraph) { if (node.IsHardNode) { hardNodes.Add(node); } } BuildUpHardNodesHierarchy(hardNodes); return(resultingGraph); }
protected override void OnPhiVariableUsed(int instructionOffset, ClassHierarchyNode variableNode) { V_0 = this.offsetToInstruction.get_Item(instructionOffset); if (V_0.get_OpCode().get_Code() == 36 || V_0.get_OpCode().get_Code() == 37) { return; } V_1 = this.GetUseExpressionTypeNode(V_0, variableNode.get_Variable()); if (V_0.get_OpCode().get_Code() == 68) { variableNode.AddSupertype(V_1); dummyVar0 = this.resultingGraph.Add(V_1); return; } if (!String.op_Equality(V_1.get_NodeType().get_FullName(), "System.Int32") || !this.OnlyPhiVariablesUsed(this.offsetToExpression.get_Item(V_0.get_Offset()))) { variableNode.AddSupertype(V_1); dummyVar2 = this.resultingGraph.Add(V_1); return; } V_3 = this.GetUsedPhiVariableNodes(V_0.get_Offset()); V_4 = 0; while (V_4 < V_3.get_Count()) { V_5 = V_4 + 1; while (V_5 < V_3.get_Count()) { V_3.get_Item(V_4).AddSupertype(V_3.get_Item(V_5)); V_3.get_Item(V_5).AddSupertype(V_3.get_Item(V_4)); V_5 = V_5 + 1; } V_4 = V_4 + 1; } if (this.IsArithmeticOperation(V_0.get_OpCode().get_Code())) { V_6 = 0; while (V_6 < V_3.get_Count()) { dummyVar1 = this.notPossibleBooleanNodes.Add(V_3.get_Item(V_6)); V_7 = this.GetTypeNode(this.typeSystem.get_Int32()); if (!V_7.get_CanAssignTo().Contains(V_3.get_Item(V_6))) { V_7.get_CanAssignTo().Add(V_3.get_Item(V_6)); V_3.get_Item(V_6).get_SubTypes().Add(V_7); } V_6 = V_6 + 1; } } return; }
private void RecursiveDfs(ClassHierarchyNode node) { this.preorderNumber = this.preorderNumber + 1; this.used.Add(node, this.preorderNumber); this.s.Push(node); this.p.Push(node); V_0 = node.get_CanAssignTo().GetEnumerator(); try { while (V_0.MoveNext()) { V_1 = V_0.get_Current(); if (this.used.ContainsKey(V_1)) { if (this.nodeToComponent.ContainsKey(V_1)) { continue; } V_2 = this.used.get_Item(V_1); while (V_2 < this.used.get_Item(this.p.Peek())) { dummyVar0 = this.p.Pop(); } } else { this.RecursiveDfs(V_1); } } } finally { if (V_0 != null) { V_0.Dispose(); } } if (this.p.Peek() == node) { while (this.s.Peek() != node) { V_3 = this.s.Pop(); this.nodeToComponent.Add(V_3, this.componentCount); } this.nodeToComponent.Add(this.p.Pop(), this.componentCount); dummyVar1 = this.s.Pop(); this.componentCount = this.componentCount + 1; } return; }
protected virtual ClassHierarchyNode GetTypeNode(TypeReference type) { V_0 = type.get_FullName(); if (String.op_Equality(V_0, "System.Byte") || String.op_Equality(V_0, "System.SByte") || String.op_Equality(V_0, "System.Char") || String.op_Equality(V_0, "System.Int16") || String.op_Equality(V_0, "System.UInt16") || String.op_Equality(V_0, "System.Boolean")) { V_0 = "System.Int32"; } if (!this.typeNameToNode.ContainsKey(V_0)) { V_1 = new ClassHierarchyNode(type); this.typeNameToNode.Add(V_0, V_1); } return(this.typeNameToNode.get_Item(V_0)); }
/// <summary> /// As integer values can be ordered depending on their size, the graph algorithm used in TypeInferer isn't needed here. /// Instead, we might use the indexes to determine which is the smallest type big enough to contain every type provided in /// <paramref name="typeNodes"/>. /// </summary> /// <param name="typeNodes">The list of types.</param> /// <returns>The common parent node.</returns> protected override ClassHierarchyNode FindLowestCommonAncestor(ICollection <ClassHierarchyNode> typeNodes) { ClassHierarchyNode result = null; int maxIndex = Int32.MinValue; foreach (ClassHierarchyNode node in typeNodes) { int currentIndex = ExpressionTypeInferer.GetTypeIndex(node.NodeType); if (currentIndex > maxIndex) { maxIndex = currentIndex; result = node; } } return(result); }
/// <summary> /// Builds the hierarchy between the hard nodes. /// </summary> /// <param name="hardNodes">Collection of the hard nodes.</param> protected virtual void BuildUpHardNodesHierarchy(IEnumerable <ClassHierarchyNode> hardNodes) { Queue <ClassHierarchyNode> queuedNodes = new Queue <ClassHierarchyNode>(hardNodes); HashSet <ClassHierarchyNode> processedNodes = new HashSet <ClassHierarchyNode>(); while (queuedNodes.Count > 0) { ClassHierarchyNode currentType = queuedNodes.Dequeue(); processedNodes.Add(currentType); resultingGraph.Add(currentType); TypeDefinition currentNodeType = currentType.NodeType.Resolve(); TypeReference baseTypeRef = null; if (currentNodeType == null) { continue; } baseTypeRef = currentNodeType.BaseType; if (baseTypeRef != null) { ClassHierarchyNode baseType = GetTypeNode(baseTypeRef); currentType.AddSupertype(baseType); if (!processedNodes.Contains(baseType)) { queuedNodes.Enqueue(baseType); } } if (currentNodeType.IsInterface) { ClassHierarchyNode objectNode = GetTypeNode(typeSystem.Object); currentType.AddSupertype(objectNode); } IEnumerable <TypeReference> interfaces = currentType.NodeType.Resolve().Interfaces; foreach (TypeReference interfaceRef in interfaces) { ClassHierarchyNode implementedInterface = GetTypeNode(interfaceRef); currentType.AddSupertype(implementedInterface); if (!processedNodes.Contains(implementedInterface)) { queuedNodes.Enqueue(implementedInterface); } } } AddObjectClassNodeIfMIssing(); }
/// <summary> /// Replaces multiple parent dependencies as described in <see cref="Chapter 6 Integer inference"/> /// in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> private void ReplaceMultipleParentDependencies() { bool merged = false; do { merged = false; ICollection<ClassHierarchyNode> toMerge = null; foreach (ClassHierarchyNode node in inferenceGraph) { bool flag = true; if (!node.IsHardNode) { foreach (ClassHierarchyNode subtype in node.SubTypes) { if (!subtype.IsHardNode) { flag = false; break; } } if (!flag || node.SubTypes.Count == 0) { continue; } merged = true; ClassHierarchyNode type = FindLowestCommonAncestor(node.SubTypes); toMerge = new ClassHierarchyNode[] { node, type }; break; } } if (merged) { MergeNodes(toMerge); } } while (merged); }
/// <summary> /// Replaces multiple child constraints as described in <see cref="Chapter 6 Integer inference"/> /// in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> private void ReplaceMultipleChildConstraints() { bool merged = false; do { merged = false; ICollection<ClassHierarchyNode> toMerge = null; foreach (ClassHierarchyNode node in inferenceGraph) { if (!node.IsHardNode) { bool flag = true; foreach (ClassHierarchyNode canAssignTo in node.CanAssignTo) { if (!canAssignTo.IsHardNode) { flag = false; break; } } if (!flag || node.CanAssignTo.Count == 0) { continue; } ///Now it's sure the node has only type predecessors. ///Now find the smallest type it can assign to and assign it to the node. merged = true; ClassHierarchyNode type = FindGreatestCommonDescendant(node.CanAssignTo); toMerge = new ClassHierarchyNode[] { node, type }; break; } } if (merged) { MergeNodes(toMerge); } } while (merged); }
protected override ClassHierarchyNode MergeWithVariableTypeIfNeeded(VariableReference variable, ClassHierarchyNode variableNode) { /// The variable node should not be merged with its type in integer inference, because /// that will efectively assume all phi variables are integers. return variableNode; }
/// <summary> /// Merges nodes with LowestCommonAncestor constraints as described in <see cref="Single Constraints (page 11)"/> /// in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> /// <returns>Returns true if a merge was made.</returns> private bool MergeWithLowestCommonAncestor() { bool shouldMerge = false; ClassHierarchyNode[] toMerge = null; foreach (ClassHierarchyNode node in inferenceGraph) { if (node.IsHardNode) { continue; } shouldMerge = true; HashSet<ClassHierarchyNode> classNodes = new HashSet<ClassHierarchyNode>(); foreach (ClassHierarchyNode childNode in node.SubTypes) { ///Only class nodes should be able to assign to the type of the current node. if (!childNode.IsClassNode) { shouldMerge = false; break; } classNodes.Add(childNode); } if (shouldMerge) { ClassHierarchyNode lcaNode = FindLowestCommonAncestor(classNodes); if (lcaNode == null || lcaNode == node) { shouldMerge = false; continue; } toMerge = new ClassHierarchyNode[] { lcaNode, node }; break; } } if (shouldMerge) { MergeNodes(toMerge); } return shouldMerge; }
/// <summary> /// Merges Single Child constraints as described in <see cref="Single Constraints (page 11)"/> in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> private void MergeSingleChildConstraints() { bool changed = true; while (changed) { ClassHierarchyNode[] toMerge = null; changed = false; foreach (ClassHierarchyNode node in inferenceGraph) { if (node.SubTypes.Count == 1 && !node.IsHardNode) { ClassHierarchyNode childNode = node.SubTypes.First(); toMerge = new ClassHierarchyNode[] { node, childNode }; changed = true; break; } } if (changed) { MergeNodes(toMerge); } } }
/// <summary> /// Locates the graph node corresponding to the supplied <paramref name="type"/>. If it doesn't exist, it's created. /// </summary> /// <param name="type">A type whose graph node is being searched.</param> /// <returns>Returns the graph node.</returns> protected virtual ClassHierarchyNode GetTypeNode(TypeReference type) { string typeName = type.FullName; ///All types, smaller than 4 bytes are represented by Int32 at this point. if (typeName == "System.Byte" || typeName == "System.SByte" || typeName == "System.Char" || typeName == "System.Int16" || typeName == "System.UInt16" || typeName == "System.Boolean") { typeName = "System.Int32"; } if (!typeNameToNode.ContainsKey(typeName)) { ClassHierarchyNode typeNode = new ClassHierarchyNode(type); typeNameToNode.Add(typeName, typeNode); } return typeNameToNode[typeName]; }
/// <summary> /// Finds the ClassHierarchyNode corresponding to the <paramref name="variable"/>. If no such node exists, it's created. /// </summary> /// <param name="variable">The variable we search the node for.</param> /// <returns>Returns the corresponding node in the graph.</returns> protected ClassHierarchyNode GetVariableNode(VariableReference variable) { string variableName = variable.Name; if (!variableNameToNode.ContainsKey(variableName)) { ClassHierarchyNode variableNode = new ClassHierarchyNode(variable); variableNode = MergeWithVariableTypeIfNeeded(variable, variableNode); variableNameToNode.Add(variableName, variableNode); } return variableNameToNode[variableName]; }
protected virtual ClassHierarchyNode MergeWithVariableTypeIfNeeded(VariableReference variable, ClassHierarchyNode variableNode) { /// The node should be merget with its type in the normal inference. if (variable.VariableType != null) { ClassHierarchyNode variableTypeNode = GetTypeNode(variable.VariableType); variableNode = new ClassHierarchyNode(new ClassHierarchyNode[] { variableNode, variableTypeNode }); } return variableNode; }
/// <summary> /// Handles all nodes that have single child constraint as described in <see cref="Chapter 6 Integer inference"/> /// in <see cref="Efficient Inference of Static Types for Java Bytecode.pdf"/>. /// </summary> private void MergeWithSingleChild() { bool merged = false; do { ICollection<ClassHierarchyNode> toMerge = null; foreach (ClassHierarchyNode node in inferenceGraph) { if (!node.IsHardNode) { if (node.CanAssignTo.Count == 1 && node.SubTypes.Count == 0) { ClassHierarchyNode x = null; //x = node.CanAssignTo.First(); w/o Linq foreach (ClassHierarchyNode p in node.CanAssignTo) { x = p; break; } toMerge = new ClassHierarchyNode[]{node,x}; merged = true; break; } } } if (merged) { MergeNodes(toMerge); } } while (merged); }
/// <summary> /// Handles the assignment of phi variables. /// </summary> /// <param name="instructionOffset">The instruction that pushes the value on the stack.</param> /// <param name="variableNode">The graph node corresponding to the variable being assigned.</param> protected virtual void OnPhiVariableAssigned(int instructionOffset, ClassHierarchyNode variableNode) { Expression instructionExpression = offsetToExpression[instructionOffset]; // this key should allways be present //TypeReference assignedType = ExpressionTypeInferer.GetExpressionType(instructionExpression, context.Method.Module.TypeSystem); TypeReference assignedType = instructionExpression.ExpressionType; ClassHierarchyNode supertypeNode; if (assignedType == null) { ///Then an expression, containing one or more phi variables is being assigned to another phi variable IEnumerable<VariableReference> usedPhiVariables = GetVariables(instructionOffset); //VariableReference assigningVariable = (instructionExpression as VariableReferenceExpression).Variable; foreach (VariableReference assigningVariable in usedPhiVariables) { supertypeNode = GetVariableNode(assigningVariable); supertypeNode.AddSupertype(variableNode); resultingGraph.Add(supertypeNode); } return; //supertypeNode = GetVariableNode(assigningVariable); } supertypeNode = GetTypeNode(assignedType); supertypeNode.AddSupertype(variableNode); resultingGraph.Add(supertypeNode); }
/// <summary> /// Merges the nodes in <paramref name="nodeCollection"/> in one node and attaches the result to the graph. /// </summary> /// <param name="nodeCollection">The collection of nodes to be merged.</param> protected void MergeNodes(ICollection<ClassHierarchyNode> nodeCollection) { if (nodeCollection.Count <= 1) { return; } ///Merge component. ClassHierarchyNode mergedNode = new ClassHierarchyNode(nodeCollection); ///Attach the merged node. foreach (ClassHierarchyNode oldNode in mergedNode.ContainedNodes) { inferenceGraph.Remove(oldNode); } inferenceGraph.Add(mergedNode); }
/// <summary> /// Realises the logic for merging with single parent. /// </summary> /// <param name="chooseParent">Predicate that determines if the parent node is legal to merge.</param> /// <returns>Returns true if there was a merge.</returns> private bool MergeSingleParent(Func<ClassHierarchyNode, bool> chooseParentPred) { bool result = false; ClassHierarchyNode[] toMerge = null; foreach (ClassHierarchyNode childNode in inferenceGraph) { if (childNode.IsHardNode) { continue; } if (childNode.SubTypes.Count == 1) { ClassHierarchyNode parentNode = childNode.SubTypes.First(); if (chooseParentPred(parentNode)) { result = true; toMerge = new ClassHierarchyNode[] { childNode, parentNode }; break; } } } if (result) { MergeNodes(toMerge); } return result; }
/// <summary> /// Realises the steps from 1 to 4 as described above. /// </summary> /// <param name="node">The node which connected component is to be found.</param> private void RecursiveDfs(ClassHierarchyNode node) { preorderNumber++; used.Add(node, preorderNumber); s.Push(node); p.Push(node); foreach (ClassHierarchyNode supernode in node.CanAssignTo) { if (!used.ContainsKey(supernode)) { RecursiveDfs(supernode); } else { if (!nodeToComponent.ContainsKey(supernode)) { int supernodeNumber = used[supernode]; while (supernodeNumber < used[p.Peek()]) { p.Pop(); } } } } if (p.Peek() == node) { while (s.Peek() != node) { ClassHierarchyNode componentMember = s.Pop(); nodeToComponent.Add(componentMember, componentCount); } nodeToComponent.Add(p.Pop(), componentCount); s.Pop(); componentCount++; } }