def computeStatement(self, constraint_collection): # The tried block can be processed normally. tried_statement_sequence = self.getBlockTry() # May be "None" from the outset, so guard against that, later we are # going to remove it. if tried_statement_sequence is not None: result = tried_statement_sequence.computeStatementsSequence( constraint_collection = constraint_collection ) if result is not tried_statement_sequence: self.setBlockTry(result) tried_statement_sequence = result if tried_statement_sequence is None: return None, "new_statements", """\ Removed try/except with empty tried block.""" # TODO: Need not to remove all knowledge, but only the parts that were # touched. constraint_collection.removeAllKnowledge() if self.getExceptionHandling() is not None: from nuitka.optimizations.ConstraintCollections import \ ConstraintCollectionBranch collection_exception_handling = ConstraintCollectionBranch( parent = constraint_collection, branch = self.getExceptionHandling() ) # Without exception handlers remaining, nothing else to do. They may # e.g. be removed as only re-raising. if self.getExceptionHandling() and \ self.getExceptionHandling().getStatements()[0].\ isStatementReraiseException(): return tried_statement_sequence, "new_statements", """\ Removed try/except without any remaing handlers.""" # Remove exception handling, if it cannot happen. if not tried_statement_sequence.mayRaiseException(BaseException): return tried_statement_sequence, "new_statements", """\ Removed try/except with tried block that cannot raise.""" # Give up, merging this is too hard for now, any amount of the tried # sequence may have executed together with one of the handlers, or all # of tried and no handlers. TODO: improve this to an actual merge, even # if a pessimistic one. constraint_collection.removeAllKnowledge() return self, None, None
def computeExpressionRaw(self, constraint_collection): # Children can tell all we need to know, pylint: disable=W0613 # Query the truth value after the expression is evaluated, once it is # evaluated in onExpression, it is known. constraint_collection.onExpression(expression=self.getCondition()) condition = self.getCondition() # No need to look any further, if the condition raises, the branches do # not matter at all. if condition.willRaiseException(BaseException): return condition, "new_raise", """\ Conditional statements already raises implicitely in condition, removing \ branches.""" # If the condition raises, we let that escape. if condition.willRaiseException(BaseException): return condition, "new_raise", """\ Conditional expression raises in condition.""" from nuitka.optimizations.ConstraintCollections import \ ConstraintCollectionBranch # Decide this based on truth value of condition. truth_value = condition.getTruthValue() # TODO: We now know that condition evaluates to true for the yes branch # and to not true for no branch, the branch should know that. yes_branch = self.getExpressionYes() # Continue to execute for yes branch unless we know it's not going to be # relevant. if truth_value is not False: branch_yes_collection = ConstraintCollectionBranch( parent=constraint_collection, branch=yes_branch) # May have just gone away, so fetch it again. yes_branch = self.getExpressionYes() # If it's aborting, it doesn't contribute to merging. if yes_branch.willRaiseException(BaseException): branch_yes_collection = None else: branch_yes_collection = None no_branch = self.getExpressionNo() # Continue to execute for yes branch. if truth_value is not True: branch_no_collection = ConstraintCollectionBranch( parent=constraint_collection, branch=no_branch) # May have just gone away, so fetch it again. no_branch = self.getExpressionNo() # If it's aborting, it doesn't contribute to merging. if no_branch.willRaiseException(BaseException): branch_no_collection = None else: branch_no_collection = None # Merge into parent execution. constraint_collection.mergeBranches(branch_yes_collection, branch_no_collection) if truth_value is True: from .NodeMakingHelpers import wrapExpressionWithNodeSideEffects return (wrapExpressionWithNodeSideEffects( new_node=self.getExpressionYes(), old_node=condition), "new_expression", "Conditional expression predicted to yes case") elif truth_value is False: from .NodeMakingHelpers import wrapExpressionWithNodeSideEffects return (wrapExpressionWithNodeSideEffects( new_node=self.getExpressionNo(), old_node=condition), "new_expression", "Conditional expression predicted to no case") else: return self, None, None
def computeStatement( self, constraint_collection ): # This is rather complex stuff, pylint: disable=R0912 # Query the truth value before the expression is evaluated, once it is evaluated # in onExpression, it may change. condition = self.getCondition() truth_value = condition.getTruthValue() constraint_collection.onExpression( condition ) condition = self.getCondition() from nuitka.optimizations.ConstraintCollections import ConstraintCollectionBranch # TODO: We now know that condition evaluates to true for the yes branch # and to not true for no branch yes_branch = self.getBranchYes() if yes_branch is not None: branch_yes_collection = ConstraintCollectionBranch( constraint_collection ) branch_yes_collection.process( yes_branch ) # May have just gone away. yes_branch = self.getBranchYes() else: branch_yes_collection = None no_branch = self.getBranchNo() if no_branch is not None: branch_no_collection = ConstraintCollectionBranch( constraint_collection ) branch_no_collection.process( no_branch ) # May have just gone away. no_branch = self.getBranchNo() else: branch_no_collection = None # Merge into parent constraint collection. constraint_collection.mergeBranches( branch_yes_collection, branch_no_collection ) if yes_branch is not None and no_branch is not None: # TODO: Merging should be done by method. constraint_collection.variables = constraint_collection.mergeBranchVariables( branch_yes_collection.variables, branch_no_collection.variables ) elif yes_branch is not None: constraint_collection.mergeBranch( branch_yes_collection ) elif no_branch is not None: constraint_collection.mergeBranch( branch_no_collection ) else: from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode # With both branches eliminated, the condition remains as a side effect. result = makeStatementExpressionOnlyReplacementNode( expression = condition, node = self ) return result, "new_statements", """\ Both branches have no effect, reduced to evaluate condition.""" if yes_branch is None: # Would be eliminated already, if there wasn't any "no" branch either. assert no_branch is not None from .OperatorNodes import ExpressionOperationNOT new_statement = StatementConditional( condition = ExpressionOperationNOT( operand = condition, source_ref = condition.getSourceReference() ), yes_branch = no_branch, no_branch = None, source_ref = self.getSourceReference() ) return new_statement, "new_statements", """\ Empty 'yes' branch for condition was replaced with inverted condition check.""" # Note: Checking the condition late, so that the surviving branches got processed # already. Returning without doing that, will lead to errorneous assumptions. if truth_value is not None: from .NodeMakingHelpers import wrapStatementWithSideEffects if truth_value is True: choice = "true" new_statement = self.getBranchYes() else: choice = "false" new_statement = self.getBranchNo() new_statement = wrapStatementWithSideEffects( new_node = new_statement, old_node = condition, allow_none = True # surviving branch may empty ) return new_statement, "new_statements", """\ Condition for branch was predicted to be always %s.""" % choice elif condition.willRaiseException( BaseException ): from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode result = makeStatementExpressionOnlyReplacementNode( expression = condition, node = self ) return result, "new_raise", """\ Conditional statements already raises implicitely in condition, removing branches""" return self, None, None
def computeStatement(self, constraint_collection): # This is rather complex stuff, pylint: disable=R0912 # Query the truth value after the expression is evaluated, once it is # evaluated in onExpression, it is known. constraint_collection.onExpression(expression=self.getCondition()) condition = self.getCondition() # No need to look any further, if the condition raises, the branches do # not matter at all. if condition.willRaiseException(BaseException): from .NodeMakingHelpers import makeStatementExpressionOnlyReplacementNode result = makeStatementExpressionOnlyReplacementNode( expression=condition, node=self) return result, "new_raise", """\ Conditional statements already raises implicitely in condition, removing \ branches.""" from nuitka.optimizations.ConstraintCollections import \ ConstraintCollectionBranch # Consider to not execute branches that we know to be true, but execute # the ones that may be true, potentially both. truth_value = condition.getTruthValue() # TODO: We now know that condition evaluates to true for the yes branch # and to not true for no branch, the branch should know that. yes_branch = self.getBranchYes() # Handle branches that became empty behind our back if yes_branch is not None: if not yes_branch.getStatements(): yes_branch = None # Continue to execute for yes branch unless we know it's not going to be # relevant. if yes_branch is not None and truth_value is not False: branch_yes_collection = ConstraintCollectionBranch( parent=constraint_collection, branch=yes_branch) # May have just gone away, so fetch it again. yes_branch = self.getBranchYes() # If it's aborting, it doesn't contribute to merging. if yes_branch is None or yes_branch.isStatementAborting(): branch_yes_collection = None else: branch_yes_collection = None no_branch = self.getBranchNo() # Handle branches that became empty behind our back if no_branch is not None: if not no_branch.getStatements(): no_branch = None # Continue to execute for yes branch. if no_branch is not None and truth_value is not True: branch_no_collection = ConstraintCollectionBranch( parent=constraint_collection, branch=no_branch) # May have just gone away, so fetch it again. no_branch = self.getBranchNo() # If it's aborting, it doesn't contribute to merging. if no_branch is None or no_branch.isStatementAborting(): branch_no_collection = None else: branch_no_collection = None # Merge into parent execution. constraint_collection.mergeBranches(branch_yes_collection, branch_no_collection) # Both branches may have become empty. if yes_branch is None and no_branch is None: from .NodeMakingHelpers import \ makeStatementExpressionOnlyReplacementNode # With both branches eliminated, the condition remains as a side # effect. result = makeStatementExpressionOnlyReplacementNode( expression=condition, node=self) return result, "new_statements", """\ Both branches have no effect, reduced to evaluate condition.""" if yes_branch is None: # Would be eliminated already, if there wasn't any "no" branch # either. assert no_branch is not None from .OperatorNodes import ExpressionOperationNOT new_statement = StatementConditional( condition=ExpressionOperationNOT( operand=condition, source_ref=condition.getSourceReference()), yes_branch=no_branch, no_branch=None, source_ref=self.getSourceReference()) return new_statement, "new_statements", """\ Empty 'yes' branch for condition was replaced with inverted condition check.""" # Note: Checking the condition late, so that the surviving branch got # processed already. Returning without doing that, will corrupt the SSA # results. TODO: Could pretend the other branch didn't exist to save # complexity the merging of processing. if truth_value is not None: from .NodeMakingHelpers import wrapStatementWithSideEffects if truth_value is True: choice = "true" new_statement = self.getBranchYes() else: choice = "false" new_statement = self.getBranchNo() new_statement = wrapStatementWithSideEffects( new_node=new_statement, old_node=condition, allow_none=True # surviving branch may empty ) return new_statement, "new_statements", """\ Condition for branch was predicted to be always %s.""" % choice return self, None, None